From 1fcb30dee9487719947786ab91b76ddc0e5ca1b1 Mon Sep 17 00:00:00 2001
From: shuiyuPyLab
Date: Sun, 9 Aug 2026 10:15:16 +0800
Subject: [PATCH] =?UTF-8?q?chore:=20=E9=A1=B9=E7=9B=AE=E5=B7=B2=E8=BF=81?=
=?UTF-8?q?=E7=A7=BB=E8=87=B3=20Gitee/GitHub=EF=BC=8C=E4=BB=85=E4=BF=9D?=
=?UTF-8?q?=E7=95=99=E8=BF=81=E7=A7=BB=E8=AF=B4=E6=98=8E=20(tombstone)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 4 -
LICENSE | 21 -
README.md | 3 +-
android_pyapi.egg-info/PKG-INFO | 264 -
android_pyapi.egg-info/SOURCES.txt | 230 -
android_pyapi.egg-info/dependency_links.txt | 1 -
android_pyapi.egg-info/requires.txt | 26 -
android_pyapi.egg-info/top_level.txt | 1 -
android_pyapi/__init__.py | 604 --
android_pyapi/_core.py | 186 -
android_pyapi/_linux_impl.py | 1266 -----
android_pyapi/_windows_impl.py | 1380 -----
android_pyapi/android/__init__.py | 0
android_pyapi/android/accessibilityservice.py | 382 --
android_pyapi/android/accounts.py | 456 --
android_pyapi/android/animation.py | 951 ----
android_pyapi/android/app.py | 2521 ---------
android_pyapi/android/app_actionbar.py | 539 --
android_pyapi/android/app_admin.py | 424 --
android_pyapi/android/app_assist.py | 469 --
android_pyapi/android/app_backup.py | 477 --
android_pyapi/android/app_dialog.py | 874 ---
android_pyapi/android/app_fragment.py | 1055 ----
android_pyapi/android/app_job.py | 444 --
android_pyapi/android/app_notification.py | 1307 -----
android_pyapi/android/app_people.py | 268 -
android_pyapi/android/app_role.py | 117 -
android_pyapi/android/app_search.py | 494 --
android_pyapi/android/app_slice.py | 409 --
android_pyapi/android/app_tasks.py | 969 ----
android_pyapi/android/app_time.py | 181 -
android_pyapi/android/app_usage.py | 527 --
android_pyapi/android/app_voiceinteractor.py | 590 --
android_pyapi/android/app_wallpaper.py | 571 --
android_pyapi/android/appwidget.py | 360 --
android_pyapi/android/bluetooth.py | 849 ---
android_pyapi/android/bluetooth_le.py | 512 --
android_pyapi/android/companion.py | 415 --
android_pyapi/android/companion_ext.py | 716 ---
android_pyapi/android/content.py | 2054 -------
android_pyapi/android/content_intent.py | 2087 -------
android_pyapi/android/content_om.py | 551 --
android_pyapi/android/content_pm.py | 801 ---
android_pyapi/android/content_res.py | 587 --
android_pyapi/android/content_sync.py | 915 ---
android_pyapi/android/credentials.py | 418 --
android_pyapi/android/database.py | 1092 ----
android_pyapi/android/database_ext.py | 866 ---
android_pyapi/android/database_sqlite.py | 1118 ----
android_pyapi/android/drm.py | 1090 ----
android_pyapi/android/gesture.py | 545 --
android_pyapi/android/gesture_ext.py | 1158 ----
android_pyapi/android/graphics.py | 3455 ------------
android_pyapi/android/graphics_drawable.py | 1128 ----
.../android/graphics_drawable_ext.py | 668 ---
.../android/graphics_drawable_shapes.py | 589 --
android_pyapi/android/graphics_fonts.py | 298 -
android_pyapi/android/graphics_pdf.py | 335 --
android_pyapi/android/graphics_surface.py | 699 ---
android_pyapi/android/graphics_text.py | 779 ---
android_pyapi/android/hardware.py | 746 ---
android_pyapi/android/hardware_biometrics.py | 291 -
android_pyapi/android/hardware_camera2.py | 761 ---
.../android/hardware_camera2_params.py | 854 ---
android_pyapi/android/hardware_consumerir.py | 93 -
android_pyapi/android/hardware_display.py | 299 -
android_pyapi/android/hardware_fingerprint.py | 179 -
android_pyapi/android/hardware_hdmi.py | 775 ---
android_pyapi/android/hardware_input.py | 254 -
android_pyapi/android/hardware_light.py | 660 ---
android_pyapi/android/hardware_location.py | 848 ---
android_pyapi/android/hardware_radio.py | 417 --
android_pyapi/android/hardware_sensor_ext.py | 831 ---
android_pyapi/android/hardware_serial.py | 513 --
android_pyapi/android/hardware_thermal.py | 218 -
android_pyapi/android/hardware_usb.py | 409 --
android_pyapi/android/inputmethod.py | 804 ---
android_pyapi/android/inputmethodservice.py | 1078 ----
android_pyapi/android/location.py | 1266 -----
android_pyapi/android/location_ext.py | 464 --
android_pyapi/android/location_geofence.py | 537 --
android_pyapi/android/managers.py | 1773 ------
android_pyapi/android/media.py | 2525 ---------
android_pyapi/android/media_async.py | 1621 ------
android_pyapi/android/media_audio.py | 1538 ------
android_pyapi/android/media_audiofx.py | 547 --
android_pyapi/android/media_browse.py | 310 --
android_pyapi/android/media_capture.py | 748 ---
android_pyapi/android/media_effect.py | 615 ---
android_pyapi/android/media_face.py | 499 --
android_pyapi/android/media_image.py | 649 ---
android_pyapi/android/media_midi.py | 315 --
android_pyapi/android/media_projection.py | 171 -
android_pyapi/android/media_remoteblob.py | 633 ---
android_pyapi/android/media_session.py | 854 ---
android_pyapi/android/media_tv.py | 359 --
android_pyapi/android/media_tv_ext.py | 1500 -----
android_pyapi/android/mtp.py | 476 --
android_pyapi/android/net.py | 1559 ------
android_pyapi/android/net_ethernet.py | 551 --
android_pyapi/android/net_ext.py | 1447 -----
android_pyapi/android/net_hotspot2.py | 375 --
android_pyapi/android/net_http.py | 643 ---
android_pyapi/android/net_nsd.py | 514 --
android_pyapi/android/net_rtp.py | 246 -
android_pyapi/android/net_sip.py | 639 ---
android_pyapi/android/net_ssl.py | 406 --
android_pyapi/android/net_vpn.py | 279 -
android_pyapi/android/net_wifi.py | 1136 ----
android_pyapi/android/net_wifi_aware.py | 428 --
android_pyapi/android/net_wifi_rtt.py | 319 --
android_pyapi/android/nfc.py | 390 --
android_pyapi/android/nfc_ext.py | 816 ---
android_pyapi/android/opengl.py | 464 --
android_pyapi/android/os.py | 2370 --------
android_pyapi/android/os_health.py | 215 -
android_pyapi/android/os_power.py | 902 ---
android_pyapi/android/os_storage.py | 387 --
android_pyapi/android/os_user.py | 408 --
android_pyapi/android/permission.py | 162 -
android_pyapi/android/preference.py | 654 ---
android_pyapi/android/print.py | 581 --
android_pyapi/android/printservice.py | 917 ---
android_pyapi/android/provider.py | 688 ---
android_pyapi/android/provider_calendar.py | 1379 -----
android_pyapi/android/provider_contacts.py | 776 ---
android_pyapi/android/provider_settings.py | 1660 ------
android_pyapi/android/renderscript.py | 903 ---
android_pyapi/android/se.py | 175 -
android_pyapi/android/security.py | 182 -
android_pyapi/android/service_autofill.py | 423 --
android_pyapi/android/service_controls.py | 350 --
android_pyapi/android/service_dreams.py | 140 -
android_pyapi/android/service_media.py | 812 ---
android_pyapi/android/service_notification.py | 378 --
.../android/service_quicksettings.py | 214 -
android_pyapi/android/service_voice.py | 869 ---
android_pyapi/android/service_vr.py | 62 -
android_pyapi/android/service_wallpaper.py | 264 -
android_pyapi/android/sip.py | 519 --
android_pyapi/android/speech.py | 370 --
android_pyapi/android/speech_tts.py | 401 --
android_pyapi/android/system.py | 592 --
android_pyapi/android/telecom.py | 737 ---
android_pyapi/android/telephony.py | 709 ---
android_pyapi/android/telephony_cdma.py | 714 ---
android_pyapi/android/telephony_data.py | 1200 ----
android_pyapi/android/telephony_euicc.py | 1181 ----
android_pyapi/android/telephony_gsm.py | 1082 ----
android_pyapi/android/telephony_ims.py | 1545 ------
android_pyapi/android/telephony_mbms.py | 1180 ----
android_pyapi/android/test.py | 485 --
android_pyapi/android/text.py | 1167 ----
android_pyapi/android/text_format.py | 456 --
android_pyapi/android/text_method.py | 676 ---
android_pyapi/android/text_style.py | 974 ----
android_pyapi/android/text_util.py | 297 -
android_pyapi/android/transition.py | 504 --
android_pyapi/android/util.py | 1111 ----
android_pyapi/android/uwb.py | 420 --
android_pyapi/android/view.py | 4207 --------------
android_pyapi/android/view_accessibility.py | 1488 -----
.../android/view_accessibility_ext.py | 744 ---
android_pyapi/android/view_animation.py | 935 ----
android_pyapi/android/view_animator.py | 887 ---
android_pyapi/android/view_autofill.py | 313 --
android_pyapi/android/view_dragndrop.py | 248 -
android_pyapi/android/view_ext.py | 2520 ---------
android_pyapi/android/view_gesture.py | 647 ---
android_pyapi/android/view_haptic.py | 381 --
android_pyapi/android/view_inputmethod.py | 859 ---
android_pyapi/android/view_textclassifier.py | 426 --
android_pyapi/android/view_textservice.py | 395 --
android_pyapi/android/view_translation.py | 435 --
android_pyapi/android/view_window.py | 969 ----
android_pyapi/android/webkit.py | 992 ----
android_pyapi/android/webkit_ext.py | 1554 ------
android_pyapi/android/widget.py | 4891 -----------------
android_pyapi/android/widget_adapter.py | 1145 ----
android_pyapi/android/widget_ext.py | 2232 --------
android_pyapi/dalvik/__init__.py | 0
android_pyapi/dalvik/system.py | 721 ---
android_pyapi/java/__init__.py | 4 -
android_pyapi/java/beans.py | 806 ---
android_pyapi/java/crypto.py | 628 ---
android_pyapi/java/io.py | 2120 -------
android_pyapi/java/io_ext.py | 1414 -----
android_pyapi/java/io_file.py | 1451 -----
android_pyapi/java/lang.py | 2128 -------
android_pyapi/java/lang_annotation.py | 303 -
android_pyapi/java/lang_invoke.py | 766 ---
android_pyapi/java/lang_management.py | 830 ---
android_pyapi/java/lang_ref.py | 386 --
android_pyapi/java/lang_reflect.py | 968 ----
android_pyapi/java/math.py | 683 ---
android_pyapi/java/net.py | 1759 ------
android_pyapi/java/nio.py | 622 ---
android_pyapi/java/nio_byteorder.py | 33 -
android_pyapi/java/nio_channels.py | 1103 ----
android_pyapi/java/nio_charset.py | 573 --
android_pyapi/java/nio_file.py | 703 ---
android_pyapi/java/rmi.py | 776 ---
android_pyapi/java/security.py | 1145 ----
android_pyapi/java/security_cert.py | 907 ---
android_pyapi/java/security_spec.py | 697 ---
android_pyapi/java/sql.py | 2242 --------
android_pyapi/java/text.py | 1041 ----
android_pyapi/java/time.py | 1619 ------
android_pyapi/java/util.py | 4096 --------------
android_pyapi/java/util_concurrent.py | 2037 -------
android_pyapi/java/util_concurrent_atomic.py | 1044 ----
android_pyapi/java/util_concurrent_locks.py | 681 ---
android_pyapi/java/util_function.py | 599 --
android_pyapi/java/util_logging.py | 939 ----
android_pyapi/java/util_prefs.py | 544 --
android_pyapi/java/util_regex.py | 287 -
android_pyapi/java/util_stream.py | 1380 -----
android_pyapi/java/util_zip.py | 697 ---
android_pyapi/javax/__init__.py | 0
android_pyapi/javax/crypto.py | 1031 ----
android_pyapi/javax/net.py | 785 ---
android_pyapi/javax/security.py | 768 ---
android_pyapi/javax/sql.py | 1248 -----
android_pyapi/org/__init__.py | 0
android_pyapi/org/apache/__init__.py | 0
android_pyapi/org/apache/http.py | 1109 ----
android_pyapi/org/json.py | 910 ---
android_pyapi/org/w3c_dom.py | 1292 -----
android_pyapi/org/xml_pull.py | 589 --
android_pyapi/org/xml_sax.py | 890 ---
setup.py | 64 -
test_scripts/network_test.js | 0
test_scripts/quick_start.js | 0
test_scripts/system_tools.js | 0
test_scripts/test_android_api.py | 141 -
test_scripts/test_extended_api.py | 400 --
test_scripts/test_network.py | 73 -
test_scripts/test_system.py | 97 -
test_scripts/time.js | 0
test_windows.py | 145 -
240 files changed, 1 insertion(+), 186470 deletions(-)
delete mode 100644 .gitignore
delete mode 100644 LICENSE
delete mode 100644 android_pyapi.egg-info/PKG-INFO
delete mode 100644 android_pyapi.egg-info/SOURCES.txt
delete mode 100644 android_pyapi.egg-info/dependency_links.txt
delete mode 100644 android_pyapi.egg-info/requires.txt
delete mode 100644 android_pyapi.egg-info/top_level.txt
delete mode 100644 android_pyapi/__init__.py
delete mode 100644 android_pyapi/_core.py
delete mode 100644 android_pyapi/_linux_impl.py
delete mode 100644 android_pyapi/_windows_impl.py
delete mode 100644 android_pyapi/android/__init__.py
delete mode 100644 android_pyapi/android/accessibilityservice.py
delete mode 100644 android_pyapi/android/accounts.py
delete mode 100644 android_pyapi/android/animation.py
delete mode 100644 android_pyapi/android/app.py
delete mode 100644 android_pyapi/android/app_actionbar.py
delete mode 100644 android_pyapi/android/app_admin.py
delete mode 100644 android_pyapi/android/app_assist.py
delete mode 100644 android_pyapi/android/app_backup.py
delete mode 100644 android_pyapi/android/app_dialog.py
delete mode 100644 android_pyapi/android/app_fragment.py
delete mode 100644 android_pyapi/android/app_job.py
delete mode 100644 android_pyapi/android/app_notification.py
delete mode 100644 android_pyapi/android/app_people.py
delete mode 100644 android_pyapi/android/app_role.py
delete mode 100644 android_pyapi/android/app_search.py
delete mode 100644 android_pyapi/android/app_slice.py
delete mode 100644 android_pyapi/android/app_tasks.py
delete mode 100644 android_pyapi/android/app_time.py
delete mode 100644 android_pyapi/android/app_usage.py
delete mode 100644 android_pyapi/android/app_voiceinteractor.py
delete mode 100644 android_pyapi/android/app_wallpaper.py
delete mode 100644 android_pyapi/android/appwidget.py
delete mode 100644 android_pyapi/android/bluetooth.py
delete mode 100644 android_pyapi/android/bluetooth_le.py
delete mode 100644 android_pyapi/android/companion.py
delete mode 100644 android_pyapi/android/companion_ext.py
delete mode 100644 android_pyapi/android/content.py
delete mode 100644 android_pyapi/android/content_intent.py
delete mode 100644 android_pyapi/android/content_om.py
delete mode 100644 android_pyapi/android/content_pm.py
delete mode 100644 android_pyapi/android/content_res.py
delete mode 100644 android_pyapi/android/content_sync.py
delete mode 100644 android_pyapi/android/credentials.py
delete mode 100644 android_pyapi/android/database.py
delete mode 100644 android_pyapi/android/database_ext.py
delete mode 100644 android_pyapi/android/database_sqlite.py
delete mode 100644 android_pyapi/android/drm.py
delete mode 100644 android_pyapi/android/gesture.py
delete mode 100644 android_pyapi/android/gesture_ext.py
delete mode 100644 android_pyapi/android/graphics.py
delete mode 100644 android_pyapi/android/graphics_drawable.py
delete mode 100644 android_pyapi/android/graphics_drawable_ext.py
delete mode 100644 android_pyapi/android/graphics_drawable_shapes.py
delete mode 100644 android_pyapi/android/graphics_fonts.py
delete mode 100644 android_pyapi/android/graphics_pdf.py
delete mode 100644 android_pyapi/android/graphics_surface.py
delete mode 100644 android_pyapi/android/graphics_text.py
delete mode 100644 android_pyapi/android/hardware.py
delete mode 100644 android_pyapi/android/hardware_biometrics.py
delete mode 100644 android_pyapi/android/hardware_camera2.py
delete mode 100644 android_pyapi/android/hardware_camera2_params.py
delete mode 100644 android_pyapi/android/hardware_consumerir.py
delete mode 100644 android_pyapi/android/hardware_display.py
delete mode 100644 android_pyapi/android/hardware_fingerprint.py
delete mode 100644 android_pyapi/android/hardware_hdmi.py
delete mode 100644 android_pyapi/android/hardware_input.py
delete mode 100644 android_pyapi/android/hardware_light.py
delete mode 100644 android_pyapi/android/hardware_location.py
delete mode 100644 android_pyapi/android/hardware_radio.py
delete mode 100644 android_pyapi/android/hardware_sensor_ext.py
delete mode 100644 android_pyapi/android/hardware_serial.py
delete mode 100644 android_pyapi/android/hardware_thermal.py
delete mode 100644 android_pyapi/android/hardware_usb.py
delete mode 100644 android_pyapi/android/inputmethod.py
delete mode 100644 android_pyapi/android/inputmethodservice.py
delete mode 100644 android_pyapi/android/location.py
delete mode 100644 android_pyapi/android/location_ext.py
delete mode 100644 android_pyapi/android/location_geofence.py
delete mode 100644 android_pyapi/android/managers.py
delete mode 100644 android_pyapi/android/media.py
delete mode 100644 android_pyapi/android/media_async.py
delete mode 100644 android_pyapi/android/media_audio.py
delete mode 100644 android_pyapi/android/media_audiofx.py
delete mode 100644 android_pyapi/android/media_browse.py
delete mode 100644 android_pyapi/android/media_capture.py
delete mode 100644 android_pyapi/android/media_effect.py
delete mode 100644 android_pyapi/android/media_face.py
delete mode 100644 android_pyapi/android/media_image.py
delete mode 100644 android_pyapi/android/media_midi.py
delete mode 100644 android_pyapi/android/media_projection.py
delete mode 100644 android_pyapi/android/media_remoteblob.py
delete mode 100644 android_pyapi/android/media_session.py
delete mode 100644 android_pyapi/android/media_tv.py
delete mode 100644 android_pyapi/android/media_tv_ext.py
delete mode 100644 android_pyapi/android/mtp.py
delete mode 100644 android_pyapi/android/net.py
delete mode 100644 android_pyapi/android/net_ethernet.py
delete mode 100644 android_pyapi/android/net_ext.py
delete mode 100644 android_pyapi/android/net_hotspot2.py
delete mode 100644 android_pyapi/android/net_http.py
delete mode 100644 android_pyapi/android/net_nsd.py
delete mode 100644 android_pyapi/android/net_rtp.py
delete mode 100644 android_pyapi/android/net_sip.py
delete mode 100644 android_pyapi/android/net_ssl.py
delete mode 100644 android_pyapi/android/net_vpn.py
delete mode 100644 android_pyapi/android/net_wifi.py
delete mode 100644 android_pyapi/android/net_wifi_aware.py
delete mode 100644 android_pyapi/android/net_wifi_rtt.py
delete mode 100644 android_pyapi/android/nfc.py
delete mode 100644 android_pyapi/android/nfc_ext.py
delete mode 100644 android_pyapi/android/opengl.py
delete mode 100644 android_pyapi/android/os.py
delete mode 100644 android_pyapi/android/os_health.py
delete mode 100644 android_pyapi/android/os_power.py
delete mode 100644 android_pyapi/android/os_storage.py
delete mode 100644 android_pyapi/android/os_user.py
delete mode 100644 android_pyapi/android/permission.py
delete mode 100644 android_pyapi/android/preference.py
delete mode 100644 android_pyapi/android/print.py
delete mode 100644 android_pyapi/android/printservice.py
delete mode 100644 android_pyapi/android/provider.py
delete mode 100644 android_pyapi/android/provider_calendar.py
delete mode 100644 android_pyapi/android/provider_contacts.py
delete mode 100644 android_pyapi/android/provider_settings.py
delete mode 100644 android_pyapi/android/renderscript.py
delete mode 100644 android_pyapi/android/se.py
delete mode 100644 android_pyapi/android/security.py
delete mode 100644 android_pyapi/android/service_autofill.py
delete mode 100644 android_pyapi/android/service_controls.py
delete mode 100644 android_pyapi/android/service_dreams.py
delete mode 100644 android_pyapi/android/service_media.py
delete mode 100644 android_pyapi/android/service_notification.py
delete mode 100644 android_pyapi/android/service_quicksettings.py
delete mode 100644 android_pyapi/android/service_voice.py
delete mode 100644 android_pyapi/android/service_vr.py
delete mode 100644 android_pyapi/android/service_wallpaper.py
delete mode 100644 android_pyapi/android/sip.py
delete mode 100644 android_pyapi/android/speech.py
delete mode 100644 android_pyapi/android/speech_tts.py
delete mode 100644 android_pyapi/android/system.py
delete mode 100644 android_pyapi/android/telecom.py
delete mode 100644 android_pyapi/android/telephony.py
delete mode 100644 android_pyapi/android/telephony_cdma.py
delete mode 100644 android_pyapi/android/telephony_data.py
delete mode 100644 android_pyapi/android/telephony_euicc.py
delete mode 100644 android_pyapi/android/telephony_gsm.py
delete mode 100644 android_pyapi/android/telephony_ims.py
delete mode 100644 android_pyapi/android/telephony_mbms.py
delete mode 100644 android_pyapi/android/test.py
delete mode 100644 android_pyapi/android/text.py
delete mode 100644 android_pyapi/android/text_format.py
delete mode 100644 android_pyapi/android/text_method.py
delete mode 100644 android_pyapi/android/text_style.py
delete mode 100644 android_pyapi/android/text_util.py
delete mode 100644 android_pyapi/android/transition.py
delete mode 100644 android_pyapi/android/util.py
delete mode 100644 android_pyapi/android/uwb.py
delete mode 100644 android_pyapi/android/view.py
delete mode 100644 android_pyapi/android/view_accessibility.py
delete mode 100644 android_pyapi/android/view_accessibility_ext.py
delete mode 100644 android_pyapi/android/view_animation.py
delete mode 100644 android_pyapi/android/view_animator.py
delete mode 100644 android_pyapi/android/view_autofill.py
delete mode 100644 android_pyapi/android/view_dragndrop.py
delete mode 100644 android_pyapi/android/view_ext.py
delete mode 100644 android_pyapi/android/view_gesture.py
delete mode 100644 android_pyapi/android/view_haptic.py
delete mode 100644 android_pyapi/android/view_inputmethod.py
delete mode 100644 android_pyapi/android/view_textclassifier.py
delete mode 100644 android_pyapi/android/view_textservice.py
delete mode 100644 android_pyapi/android/view_translation.py
delete mode 100644 android_pyapi/android/view_window.py
delete mode 100644 android_pyapi/android/webkit.py
delete mode 100644 android_pyapi/android/webkit_ext.py
delete mode 100644 android_pyapi/android/widget.py
delete mode 100644 android_pyapi/android/widget_adapter.py
delete mode 100644 android_pyapi/android/widget_ext.py
delete mode 100644 android_pyapi/dalvik/__init__.py
delete mode 100644 android_pyapi/dalvik/system.py
delete mode 100644 android_pyapi/java/__init__.py
delete mode 100644 android_pyapi/java/beans.py
delete mode 100644 android_pyapi/java/crypto.py
delete mode 100644 android_pyapi/java/io.py
delete mode 100644 android_pyapi/java/io_ext.py
delete mode 100644 android_pyapi/java/io_file.py
delete mode 100644 android_pyapi/java/lang.py
delete mode 100644 android_pyapi/java/lang_annotation.py
delete mode 100644 android_pyapi/java/lang_invoke.py
delete mode 100644 android_pyapi/java/lang_management.py
delete mode 100644 android_pyapi/java/lang_ref.py
delete mode 100644 android_pyapi/java/lang_reflect.py
delete mode 100644 android_pyapi/java/math.py
delete mode 100644 android_pyapi/java/net.py
delete mode 100644 android_pyapi/java/nio.py
delete mode 100644 android_pyapi/java/nio_byteorder.py
delete mode 100644 android_pyapi/java/nio_channels.py
delete mode 100644 android_pyapi/java/nio_charset.py
delete mode 100644 android_pyapi/java/nio_file.py
delete mode 100644 android_pyapi/java/rmi.py
delete mode 100644 android_pyapi/java/security.py
delete mode 100644 android_pyapi/java/security_cert.py
delete mode 100644 android_pyapi/java/security_spec.py
delete mode 100644 android_pyapi/java/sql.py
delete mode 100644 android_pyapi/java/text.py
delete mode 100644 android_pyapi/java/time.py
delete mode 100644 android_pyapi/java/util.py
delete mode 100644 android_pyapi/java/util_concurrent.py
delete mode 100644 android_pyapi/java/util_concurrent_atomic.py
delete mode 100644 android_pyapi/java/util_concurrent_locks.py
delete mode 100644 android_pyapi/java/util_function.py
delete mode 100644 android_pyapi/java/util_logging.py
delete mode 100644 android_pyapi/java/util_prefs.py
delete mode 100644 android_pyapi/java/util_regex.py
delete mode 100644 android_pyapi/java/util_stream.py
delete mode 100644 android_pyapi/java/util_zip.py
delete mode 100644 android_pyapi/javax/__init__.py
delete mode 100644 android_pyapi/javax/crypto.py
delete mode 100644 android_pyapi/javax/net.py
delete mode 100644 android_pyapi/javax/security.py
delete mode 100644 android_pyapi/javax/sql.py
delete mode 100644 android_pyapi/org/__init__.py
delete mode 100644 android_pyapi/org/apache/__init__.py
delete mode 100644 android_pyapi/org/apache/http.py
delete mode 100644 android_pyapi/org/json.py
delete mode 100644 android_pyapi/org/w3c_dom.py
delete mode 100644 android_pyapi/org/xml_pull.py
delete mode 100644 android_pyapi/org/xml_sax.py
delete mode 100644 setup.py
delete mode 100644 test_scripts/network_test.js
delete mode 100644 test_scripts/quick_start.js
delete mode 100644 test_scripts/system_tools.js
delete mode 100644 test_scripts/test_android_api.py
delete mode 100644 test_scripts/test_extended_api.py
delete mode 100644 test_scripts/test_network.py
delete mode 100644 test_scripts/test_system.py
delete mode 100644 test_scripts/time.js
delete mode 100644 test_windows.py
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index bb7f1a2..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-__pycache__/
-*.pyc
-*.pyo
-.DS_Store
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 7203af6..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2026 shuiyu
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/README.md b/README.md
index d162484..74857a2 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,7 @@
你好呀~这个仓库已经搬到更好用的地方啦。
-为了让代码管理更清爽、多平台同步更省心,我们把原先分散的镜像统一收拢到
-**Gitee** 与 **GitHub** 主仓维护,这里就只保留这张"迁移小纸条"咯。
+为了让代码管理更清爽、多平台同步更省心,我们把原先分散的镜像统一收拢到主仓维护,这里就只保留这张"迁移小纸条"咯。
📦 新家在这里:
- Gitee:https://gitee.com/shuiyu1123/Android-pyApi
diff --git a/android_pyapi.egg-info/PKG-INFO b/android_pyapi.egg-info/PKG-INFO
deleted file mode 100644
index 603666b..0000000
--- a/android_pyapi.egg-info/PKG-INFO
+++ /dev/null
@@ -1,264 +0,0 @@
-Metadata-Version: 2.4
-Name: android-pyapi
-Version: 1.0.0
-Summary: Android API for Python — 在桌面/Linux 上原生运行 Android API
-Home-page: https://gitee.com/shuiyu1123/Android-pyApi
-Author: shuiyu1123
-License: MIT
-Classifier: Development Status :: 4 - Beta
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Operating System :: POSIX :: Linux
-Classifier: Operating System :: MacOS
-Classifier: Operating System :: Microsoft :: Windows
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: System :: Hardware
-Requires-Python: >=3.8
-Description-Content-Type: text/markdown
-License-File: LICENSE
-Provides-Extra: linux
-Requires-Dist: psutil; extra == "linux"
-Requires-Dist: requests; extra == "linux"
-Requires-Dist: Pillow; extra == "linux"
-Requires-Dist: opencv-python; extra == "linux"
-Requires-Dist: numpy; extra == "linux"
-Provides-Extra: windows
-Requires-Dist: psutil; extra == "windows"
-Requires-Dist: requests; extra == "windows"
-Requires-Dist: Pillow; extra == "windows"
-Requires-Dist: opencv-python; extra == "windows"
-Requires-Dist: numpy; extra == "windows"
-Requires-Dist: pyautogui; extra == "windows"
-Requires-Dist: pyperclip; extra == "windows"
-Requires-Dist: screeninfo; extra == "windows"
-Requires-Dist: pywin32; extra == "windows"
-Requires-Dist: wmi; extra == "windows"
-Requires-Dist: pycaw; extra == "windows"
-Requires-Dist: comtypes; extra == "windows"
-Requires-Dist: win10toast; extra == "windows"
-Provides-Extra: dev
-Requires-Dist: pytest; extra == "dev"
-Requires-Dist: pytest-cov; extra == "dev"
-Dynamic: author
-Dynamic: classifier
-Dynamic: description
-Dynamic: description-content-type
-Dynamic: home-page
-Dynamic: license
-Dynamic: license-file
-Dynamic: provides-extra
-Dynamic: requires-python
-Dynamic: summary
-
-# Android-pyApi
-
-> **Android API for Python** — 在桌面/Linux 上原生运行 Android API 的 Python 库
-
-[](https://opensource.org/licenses/MIT)
-[](https://www.python.org/downloads/)
-[](#)
-
-## 这是什么
-
-Android-pyApi 将完整的 Android SDK API 翻译为纯 Python 实现,让你在桌面环境直接调用 Android API——不需要模拟器、不需要真机、不需要 Android Studio。
-
-**213 个模块,178,000+ 行代码,覆盖 android/java/javax/org/dalvik 全包。**
-
-在 Linux 上,系统级 API(网络、传感器、蓝牙、音频、位置等)使用真实系统调用,返回真实数据。
-
-## 核心特性
-
-### API 覆盖
-
-| 包 | 模块数 | 内容 |
-|---|---|---|
-| `android.*` | 167 | app, content, os, view, widget, graphics, media, hardware, net, telephony, provider 等 |
-| `java.*` | 35 | lang, io, util, net, nio, security, crypto, sql, math, time 等 |
-| `javax.*` | 4 | net, crypto, security, sql |
-| `org.*` | 5 | json, w3c_dom, xml_sax, xml_pull, apache_http |
-| `dalvik.*` | 1 | system |
-
-### Linux 真实实现
-
-在 Linux 环境下,以下 API 使用真实系统调用而非存根:
-
-| API | 实现方式 | 真实行为 |
-|-----|---------|---------|
-| ConnectivityManager | `ip` 命令 + `/proc/net` | 真实 IP、接口、DNS、网关 |
-| LocationManager | IP 地理定位 | 真实经纬度、城市、ISP |
-| SensorManager | `/sys/class/hwmon` | 真实温度、CPU 频率、风扇 |
-| AudioManager | `amixer` (ALSA) | 真实音量控制 |
-| BluetoothAdapter | `bluetoothctl` (BlueZ) | 真实扫描、配对、连接 |
-| ClipboardManager | `xclip` | 真实剪贴板读写 |
-| PowerManager / BatteryManager | `psutil` + `/sys/class/power_supply` | 真实 CPU、内存、电池 |
-| TelephonyManager | MAC 地址 + 内核版本 | 真实设备 ID |
-| NotificationManager | `notify-send` | 真实桌面通知 |
-| Activity / Display | `xdotool` + X11 | 真实屏幕尺寸、截屏 |
-| ActivityManager | `psutil` + `/proc` | 真实进程列表 |
-| Shell | `subprocess` | 真实命令执行 |
-| Camera | OpenCV / V4L2 | 真实拍照 |
-| UI 自动化 | `xdotool` | 真实点击、输入、按键 |
-
-### Windows 真实实现
-
-在 Windows 环境下,以下 API 使用真实系统调用而非存根:
-
-| API | 实现方式 | 真实行为 |
-|-----|---------|---------|
-| ConnectivityManager | `ipconfig` + `netsh` + `socket` | 真实 IP、接口、DNS、网关、WiFi 信息 |
-| LocationManager | IP 地理定位 | 真实经纬度、城市、ISP |
-| SensorManager | `wmi` + `psutil` | 真实温度、CPU 频率、风扇转速 |
-| AudioManager | `pycaw` / PowerShell | 真实音量控制、静音 |
-| BluetoothAdapter | PowerShell Bluetooth cmdlets | 真实设备列表、配对状态 |
-| ClipboardManager | `pyperclip` | 真实剪贴板读写 |
-| PowerManager / BatteryManager | `psutil` | 真实 CPU、内存、电池状态 |
-| NotificationManager | `win10toast` / PowerShell | 真实桌面通知 (Toast) |
-| Activity / Display | `pyautogui` + `screeninfo` + `win32api` | 真实屏幕尺寸、截屏 |
-| ActivityManager | `psutil` + `tasklist` | 真实进程列表 |
-| Shell | `subprocess` + PowerShell | 真实命令执行 |
-| Camera | OpenCV | 真实拍照 |
-| UI 自动化 | `pyautogui` + `win32gui` | 真实点击、输入、按键、窗口操作 |
-
-### 跨平台
-
-- **Linux** — 系统级 API 使用真实实现 (`_linux_impl.py`)
-- **Windows** — 系统级 API 使用真实实现 (`_windows_impl.py`)
-- **macOS** — 系统级 API 使用存根(后续支持)
-- **API 形状** — 所有平台一致,方法签名完全对齐 Android SDK
-
-## 安装
-
-```bash
-# 从源码安装
-git clone https://gitee.com/shuiyu1123/Android-pyApi.git
-cd Android-pyApi
-pip install -e .
-
-# 或直接使用
-export PYTHONPATH=/path/to/Android-pyApi:$PYTHONPATH
-```
-
-### 可选依赖
-
-```bash
-# Python 库 (所有平台通用)
-pip install psutil requests Pillow opencv-python numpy
-
-# Linux 系统工具
-sudo apt install xclip xdotool libnotify-bin alsa-utils bluez lm-sensors
-
-# Windows 专用库 (推荐安装以启用完整功能)
-pip install pyautogui pyperclip screeninfo pywin32 wmi pycaw comtypes win10toast
-```
-
-## 快速开始
-
-```python
-from android_pyapi import Intent, Uri, Bundle, File, JSONObject, ArrayList, HashMap
-
-# Intent — Android 最核心的 API
-intent = Intent("android.intent.action.VIEW")
-intent.setData(Uri.parse("https://example.com"))
-intent.putExtra("key", "value")
-print(intent.getAction()) # android.intent.action.VIEW
-print(intent.getData()) # https://example.com
-print(intent.getStringExtra("key")) # value
-
-# java.util 集合
-lst = ArrayList()
-lst.add("hello")
-lst.add("world")
-print(lst.size()) # 2
-print(lst.get(0)) # hello
-
-# JSONObject
-json = JSONObject()
-json.put("name", "test")
-json.put("version", 42)
-print(json.toString()) # {"name":"test","version":42}
-
-# Linux 真实实现
-from android_pyapi import Build, LocationManager, ConnectivityManager
-print(Build.MODEL) # 真实主机名
-print(Build.MANUFACTURER) # Linux
-
-loc = LocationManager().getLastKnownLocation("network")
-print(loc) # 真实经纬度
-```
-
-## 项目结构
-
-```
-android_pyapi/
-├── _core.py # Stub 基类、全局上下文
-├── _linux_impl.py # Linux 真实实现层 (14个实现类)
-├── _windows_impl.py # Windows 真实实现层 (14个实现类)
-├── __init__.py # 统一导出
-├── android/ # 167 个 Android 模块
-│ ├── app.py # Activity, Service, Fragment, Notification
-│ ├── content.py # Context, Intent, ContentResolver, ClipboardManager
-│ ├── os.py # Handler, Looper, Bundle, Build, PowerManager
-│ ├── view.py # View, ViewGroup, MotionEvent, KeyEvent
-│ ├── widget.py # TextView, Button, ListView, RecyclerView, Toast
-│ ├── graphics.py # Bitmap, Canvas, Paint, Color, Path, Matrix
-│ ├── hardware.py # SensorManager, Camera, BiometricPrompt
-│ ├── net.py # ConnectivityManager, NetworkInfo
-│ ├── telephony.py # TelephonyManager, SmsManager
-│ ├── location.py # LocationManager, Location, Geocoder
-│ ├── media.py # AudioManager, MediaPlayer, MediaRecorder
-│ └── ...
-├── java/ # 35 个 Java 标准库模块
-│ ├── lang.py # String, Math, System, Thread, Exception 体系
-│ ├── io.py # File, InputStream, OutputStream, Reader, Writer
-│ ├── util.py # ArrayList, HashMap, Calendar, Collections, UUID
-│ ├── net.py # URL, HttpURLConnection, Socket
-│ └── ...
-├── javax/ # 4 个 javax 模块
-├── org/ # 5 个 org 模块
-└── dalvik/ # 1 个 dalvik 模块
-```
-
-## 设计理念
-
-### 不是模拟器
-
-Android-pyApi 不是 Android 模拟器。它不包含 ART 虚拟机、SurfaceFlinger、binder 等底层基础设施。
-
-它是 **API 兼容层**:
-- **API 形状** — 类名、方法签名、常量值完全对齐 Android SDK
-- **系统级行为** — 在 Linux 上用真实系统调用实现
-- **框架级行为** — Activity 生命周期、View 渲染等保持存根(桌面无对应框架)
-
-### 渐进式真实化
-
-```
-存根 (所有平台) → Linux 真实实现 → macOS 真实实现 → Windows 真实实现
-```
-
-每个 API 从"返回硬编码值"逐步演进为"调用真实系统功能"。
-
-## 使用场景
-
-- **Android 脚本开发** — 在桌面编写和调试依赖 Android API 的 Python 脚本
-- **跨平台工具** — 用 Android API 风格编写跨平台系统工具
-- **学习 Android API** — 不需要 Android Studio 就能探索 API
-- **自动化测试** — 在 CI/CD 中测试 Android API 调用逻辑
-- **IoT / 嵌入式** — 在 Linux 设备上用 Android API 风格操作硬件
-
-## 贡献
-
-欢迎贡献!特别需要:
-
-- macOS 真实实现层 (`_macos_impl.py`)
-- 更多 API 的真实行为实现
-- 测试用例
-
-## License
-
-[MIT](LICENSE)
diff --git a/android_pyapi.egg-info/SOURCES.txt b/android_pyapi.egg-info/SOURCES.txt
deleted file mode 100644
index e585b57..0000000
--- a/android_pyapi.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,230 +0,0 @@
-LICENSE
-README.md
-setup.py
-android_pyapi/__init__.py
-android_pyapi/_core.py
-android_pyapi/_linux_impl.py
-android_pyapi/_windows_impl.py
-android_pyapi.egg-info/PKG-INFO
-android_pyapi.egg-info/SOURCES.txt
-android_pyapi.egg-info/dependency_links.txt
-android_pyapi.egg-info/requires.txt
-android_pyapi.egg-info/top_level.txt
-android_pyapi/android/__init__.py
-android_pyapi/android/accessibilityservice.py
-android_pyapi/android/accounts.py
-android_pyapi/android/animation.py
-android_pyapi/android/app.py
-android_pyapi/android/app_actionbar.py
-android_pyapi/android/app_admin.py
-android_pyapi/android/app_assist.py
-android_pyapi/android/app_backup.py
-android_pyapi/android/app_dialog.py
-android_pyapi/android/app_fragment.py
-android_pyapi/android/app_job.py
-android_pyapi/android/app_notification.py
-android_pyapi/android/app_people.py
-android_pyapi/android/app_role.py
-android_pyapi/android/app_search.py
-android_pyapi/android/app_slice.py
-android_pyapi/android/app_tasks.py
-android_pyapi/android/app_time.py
-android_pyapi/android/app_usage.py
-android_pyapi/android/app_voiceinteractor.py
-android_pyapi/android/app_wallpaper.py
-android_pyapi/android/appwidget.py
-android_pyapi/android/bluetooth.py
-android_pyapi/android/bluetooth_le.py
-android_pyapi/android/companion.py
-android_pyapi/android/companion_ext.py
-android_pyapi/android/content.py
-android_pyapi/android/content_intent.py
-android_pyapi/android/content_om.py
-android_pyapi/android/content_pm.py
-android_pyapi/android/content_res.py
-android_pyapi/android/content_sync.py
-android_pyapi/android/credentials.py
-android_pyapi/android/database.py
-android_pyapi/android/database_ext.py
-android_pyapi/android/database_sqlite.py
-android_pyapi/android/drm.py
-android_pyapi/android/gesture.py
-android_pyapi/android/gesture_ext.py
-android_pyapi/android/graphics.py
-android_pyapi/android/graphics_drawable.py
-android_pyapi/android/graphics_drawable_ext.py
-android_pyapi/android/graphics_drawable_shapes.py
-android_pyapi/android/graphics_fonts.py
-android_pyapi/android/graphics_pdf.py
-android_pyapi/android/graphics_surface.py
-android_pyapi/android/graphics_text.py
-android_pyapi/android/hardware.py
-android_pyapi/android/hardware_biometrics.py
-android_pyapi/android/hardware_camera2.py
-android_pyapi/android/hardware_camera2_params.py
-android_pyapi/android/hardware_consumerir.py
-android_pyapi/android/hardware_display.py
-android_pyapi/android/hardware_fingerprint.py
-android_pyapi/android/hardware_hdmi.py
-android_pyapi/android/hardware_input.py
-android_pyapi/android/hardware_light.py
-android_pyapi/android/hardware_location.py
-android_pyapi/android/hardware_radio.py
-android_pyapi/android/hardware_sensor_ext.py
-android_pyapi/android/hardware_serial.py
-android_pyapi/android/hardware_thermal.py
-android_pyapi/android/hardware_usb.py
-android_pyapi/android/inputmethod.py
-android_pyapi/android/inputmethodservice.py
-android_pyapi/android/location.py
-android_pyapi/android/location_ext.py
-android_pyapi/android/location_geofence.py
-android_pyapi/android/managers.py
-android_pyapi/android/media.py
-android_pyapi/android/media_async.py
-android_pyapi/android/media_audio.py
-android_pyapi/android/media_audiofx.py
-android_pyapi/android/media_browse.py
-android_pyapi/android/media_capture.py
-android_pyapi/android/media_effect.py
-android_pyapi/android/media_face.py
-android_pyapi/android/media_image.py
-android_pyapi/android/media_midi.py
-android_pyapi/android/media_projection.py
-android_pyapi/android/media_remoteblob.py
-android_pyapi/android/media_session.py
-android_pyapi/android/media_tv.py
-android_pyapi/android/media_tv_ext.py
-android_pyapi/android/mtp.py
-android_pyapi/android/net.py
-android_pyapi/android/net_ethernet.py
-android_pyapi/android/net_ext.py
-android_pyapi/android/net_hotspot2.py
-android_pyapi/android/net_http.py
-android_pyapi/android/net_nsd.py
-android_pyapi/android/net_rtp.py
-android_pyapi/android/net_sip.py
-android_pyapi/android/net_ssl.py
-android_pyapi/android/net_vpn.py
-android_pyapi/android/net_wifi.py
-android_pyapi/android/net_wifi_aware.py
-android_pyapi/android/net_wifi_rtt.py
-android_pyapi/android/nfc.py
-android_pyapi/android/nfc_ext.py
-android_pyapi/android/opengl.py
-android_pyapi/android/os.py
-android_pyapi/android/os_health.py
-android_pyapi/android/os_power.py
-android_pyapi/android/os_storage.py
-android_pyapi/android/os_user.py
-android_pyapi/android/permission.py
-android_pyapi/android/preference.py
-android_pyapi/android/print.py
-android_pyapi/android/printservice.py
-android_pyapi/android/provider.py
-android_pyapi/android/provider_calendar.py
-android_pyapi/android/provider_contacts.py
-android_pyapi/android/provider_settings.py
-android_pyapi/android/renderscript.py
-android_pyapi/android/se.py
-android_pyapi/android/security.py
-android_pyapi/android/service_autofill.py
-android_pyapi/android/service_controls.py
-android_pyapi/android/service_dreams.py
-android_pyapi/android/service_media.py
-android_pyapi/android/service_notification.py
-android_pyapi/android/service_quicksettings.py
-android_pyapi/android/service_voice.py
-android_pyapi/android/service_vr.py
-android_pyapi/android/service_wallpaper.py
-android_pyapi/android/sip.py
-android_pyapi/android/speech.py
-android_pyapi/android/speech_tts.py
-android_pyapi/android/system.py
-android_pyapi/android/telecom.py
-android_pyapi/android/telephony.py
-android_pyapi/android/telephony_cdma.py
-android_pyapi/android/telephony_data.py
-android_pyapi/android/telephony_euicc.py
-android_pyapi/android/telephony_gsm.py
-android_pyapi/android/telephony_ims.py
-android_pyapi/android/telephony_mbms.py
-android_pyapi/android/test.py
-android_pyapi/android/text.py
-android_pyapi/android/text_format.py
-android_pyapi/android/text_method.py
-android_pyapi/android/text_style.py
-android_pyapi/android/text_util.py
-android_pyapi/android/transition.py
-android_pyapi/android/util.py
-android_pyapi/android/uwb.py
-android_pyapi/android/view.py
-android_pyapi/android/view_accessibility.py
-android_pyapi/android/view_accessibility_ext.py
-android_pyapi/android/view_animation.py
-android_pyapi/android/view_animator.py
-android_pyapi/android/view_autofill.py
-android_pyapi/android/view_dragndrop.py
-android_pyapi/android/view_ext.py
-android_pyapi/android/view_gesture.py
-android_pyapi/android/view_haptic.py
-android_pyapi/android/view_inputmethod.py
-android_pyapi/android/view_textclassifier.py
-android_pyapi/android/view_textservice.py
-android_pyapi/android/view_translation.py
-android_pyapi/android/view_window.py
-android_pyapi/android/webkit.py
-android_pyapi/android/webkit_ext.py
-android_pyapi/android/widget.py
-android_pyapi/android/widget_adapter.py
-android_pyapi/android/widget_ext.py
-android_pyapi/dalvik/__init__.py
-android_pyapi/dalvik/system.py
-android_pyapi/java/__init__.py
-android_pyapi/java/beans.py
-android_pyapi/java/crypto.py
-android_pyapi/java/io.py
-android_pyapi/java/io_ext.py
-android_pyapi/java/io_file.py
-android_pyapi/java/lang.py
-android_pyapi/java/lang_annotation.py
-android_pyapi/java/lang_invoke.py
-android_pyapi/java/lang_management.py
-android_pyapi/java/lang_ref.py
-android_pyapi/java/lang_reflect.py
-android_pyapi/java/math.py
-android_pyapi/java/net.py
-android_pyapi/java/nio.py
-android_pyapi/java/nio_byteorder.py
-android_pyapi/java/nio_channels.py
-android_pyapi/java/nio_charset.py
-android_pyapi/java/nio_file.py
-android_pyapi/java/rmi.py
-android_pyapi/java/security.py
-android_pyapi/java/security_cert.py
-android_pyapi/java/security_spec.py
-android_pyapi/java/sql.py
-android_pyapi/java/text.py
-android_pyapi/java/time.py
-android_pyapi/java/util.py
-android_pyapi/java/util_concurrent.py
-android_pyapi/java/util_concurrent_atomic.py
-android_pyapi/java/util_concurrent_locks.py
-android_pyapi/java/util_function.py
-android_pyapi/java/util_logging.py
-android_pyapi/java/util_prefs.py
-android_pyapi/java/util_regex.py
-android_pyapi/java/util_stream.py
-android_pyapi/java/util_zip.py
-android_pyapi/javax/__init__.py
-android_pyapi/javax/crypto.py
-android_pyapi/javax/net.py
-android_pyapi/javax/security.py
-android_pyapi/javax/sql.py
-android_pyapi/org/__init__.py
-android_pyapi/org/json.py
-android_pyapi/org/w3c_dom.py
-android_pyapi/org/xml_pull.py
-android_pyapi/org/xml_sax.py
-android_pyapi/org/apache/__init__.py
-android_pyapi/org/apache/http.py
\ No newline at end of file
diff --git a/android_pyapi.egg-info/dependency_links.txt b/android_pyapi.egg-info/dependency_links.txt
deleted file mode 100644
index 8b13789..0000000
--- a/android_pyapi.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/android_pyapi.egg-info/requires.txt b/android_pyapi.egg-info/requires.txt
deleted file mode 100644
index e01aae4..0000000
--- a/android_pyapi.egg-info/requires.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-
-[dev]
-pytest
-pytest-cov
-
-[linux]
-psutil
-requests
-Pillow
-opencv-python
-numpy
-
-[windows]
-psutil
-requests
-Pillow
-opencv-python
-numpy
-pyautogui
-pyperclip
-screeninfo
-pywin32
-wmi
-pycaw
-comtypes
-win10toast
diff --git a/android_pyapi.egg-info/top_level.txt b/android_pyapi.egg-info/top_level.txt
deleted file mode 100644
index f6b9637..0000000
--- a/android_pyapi.egg-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-android_pyapi
diff --git a/android_pyapi/__init__.py b/android_pyapi/__init__.py
deleted file mode 100644
index 183018d..0000000
--- a/android_pyapi/__init__.py
+++ /dev/null
@@ -1,604 +0,0 @@
-"""
-Android-pyApi — Android API 全面 Python 翻译
-==============================================
-方法签名完全对齐 Android SDK,跨平台运行于 Windows/macOS/Linux。
-
-用法:
- from android_pyapi import Intent, Context, Uri, Bitmap, View
- from android_pyapi.java.io import File, FileInputStream
- from android_pyapi.java.util import ArrayList, HashMap
- from android_pyapi.org.json import JSONObject, JSONArray
-
-设计原则:
- 1. 方法名、参数名、返回类型完全对齐 Android SDK
- 2. 能桌面实现的 → 真实实现 (基于 PIL/sqlite3/socket 等)
- 3. 无法桌面实现的 → 返回合理默认值或抛出 AndroidOnlyError
- 4. 所有常量值与 Android SDK 一致
-"""
-
-from ._core import (
- AndroidOnlyError,
- Stub,
- android_context,
- get_context,
- _sdcard_root,
- _app_data_dir,
- _package_name,
-)
-
-# android.* 包
-from .android.app import *
-from .android.content import *
-from .android.content_pm import *
-from .android.os import *
-from .android.view import *
-from .android.view_accessibility import *
-from .android.view_animation import *
-from .android.view_inputmethod import *
-from .android.widget import *
-from .android.graphics import *
-from .android.graphics_drawable import *
-from .android.graphics_pdf import *
-from .android.net import *
-from .android.net_wifi import *
-from .android.media import *
-from .android.hardware import *
-from .android.hardware_camera2 import *
-from .android.hardware_biometrics import *
-from .android.location import *
-from .android.database import *
-from .android.database_sqlite import *
-from .android.provider import *
-from .android.telephony import *
-from .android.bluetooth import *
-from .android.bluetooth_le import *
-from .android.text import *
-from .android.util import *
-from .android.preference import *
-from .android.webkit import *
-from .android.nfc import *
-from .android.speech_tts import *
-from .android.inputmethod import *
-from .android.app_admin import *
-from .android.app_backup import *
-from .android.app_job import *
-from .android.app_people import *
-from .android.app_role import *
-from .android.app_usage import *
-from .android.appwidget import *
-from .android.companion import *
-from .android.credentials import *
-from .android.hardware_display import *
-from .android.hardware_fingerprint import *
-from .android.hardware_input import *
-from .android.hardware_usb import *
-from .android.media_audiofx import *
-from .android.media_browse import *
-from .android.media_midi import *
-from .android.media_projection import *
-from .android.media_session import *
-from .android.media_tv import *
-from .android.mtp import *
-from .android.opengl import *
-from .android.print import *
-from .android.renderscript import *
-from .android.se import *
-from .android.security import *
-from .android.service_autofill import *
-from .android.service_controls import *
-from .android.service_dreams import *
-from .android.service_notification import *
-from .android.service_quicksettings import *
-from .android.service_vr import *
-from .android.service_wallpaper import *
-from .android.sip import *
-from .android.speech import *
-from .android.system import *
-from .android.telecom import *
-from .android.test import *
-from .android.transition import *
-from .android.uwb import *
-from .android.view_autofill import *
-from .android.view_textclassifier import *
-from .android.view_translation import *
-from .android.content_res import *
-from .android.accounts import *
-from .android.animation import *
-from .android.permission import *
-from .android.accessibilityservice import *
-from .android.os_storage import *
-from .android.os_health import *
-from .android.os_user import *
-from .android.app_slice import *
-from .android.app_time import *
-from .android.hardware_radio import *
-from .android.hardware_consumerir import *
-from .android.hardware_thermal import *
-from .android.location_ext import *
-from .android.net_ssl import *
-from .android.net_wifi_aware import *
-from .android.text_method import *
-from .android.text_style import *
-from .android.text_format import *
-from .android.text_util import *
-from .android.graphics_fonts import *
-from .android.graphics_drawable_ext import *
-from .android.view_textservice import *
-from .android.net_rtp import *
-from .android.net_vpn import *
-from .android.net_wifi_rtt import *
-from .android.net_hotspot2 import *
-from .android.app_assist import *
-from .android.app_search import *
-from .android.gesture import *
-from .android.nfc_ext import *
-from .android.telephony_mbms import *
-from .android.telephony_ims import *
-from .android.telephony_euicc import *
-from .android.telephony_data import *
-from .android.telephony_gsm import *
-from .android.telephony_cdma import *
-from .android.printservice import *
-from .android.service_voice import *
-from .android.service_media import *
-from .android.inputmethodservice import *
-from .android.hardware_camera2_params import *
-from .android.graphics_text import *
-from .android.graphics_drawable_shapes import *
-from .android.graphics_surface import *
-from .android.database_ext import *
-from .android.drm import *
-from .android.app_notification import *
-from .android.app_fragment import *
-from .android.app_dialog import *
-from .android.app_actionbar import *
-from .android.app_wallpaper import *
-from .android.app_voiceinteractor import *
-from .android.content_sync import *
-from .android.content_om import *
-from .android.managers import *
-from .android.net_nsd import *
-from .android.net_sip import *
-from .android.net_http import *
-from .android.os_power import *
-from .android.hardware_light import *
-from .android.hardware_hdmi import *
-from .android.media_effect import *
-from .android.media_face import *
-from .android.media_async import *
-from .android.media_image import *
-from .android.media_capture import *
-from .android.view_ext import *
-from .android.widget_ext import *
-from .android.view_accessibility_ext import *
-from .android.view_dragndrop import *
-from .android.view_gesture import *
-from .android.view_haptic import *
-from .android.webkit_ext import *
-from .android.location_geofence import *
-from .android.provider_contacts import *
-from .android.provider_calendar import *
-from .android.provider_settings import *
-from .android.media_tv_ext import *
-from .android.media_audio import *
-from .android.media_remoteblob import *
-from .android.net_ext import *
-from .android.net_ethernet import *
-from .android.hardware_sensor_ext import *
-from .android.hardware_location import *
-from .android.hardware_serial import *
-from .android.app_tasks import *
-from .android.companion_ext import *
-from .android.view_animator import *
-from .android.view_window import *
-from .android.widget_adapter import *
-from .android.content_intent import *
-from .android.gesture_ext import *
-
-# java.* 包
-from .java.io import *
-from .java.net import *
-from .java.util import *
-from .java.util_regex import *
-from .java.util_zip import *
-from .java.util_concurrent import *
-from .java.lang import *
-from .java.math import *
-from .java.text import *
-from .java.time import *
-from .java.nio import *
-from .java.nio_file import *
-from .java.security import *
-from .java.crypto import *
-from .java.lang_ref import *
-from .java.lang_reflect import *
-from .java.lang_annotation import *
-from .java.nio_channels import *
-from .java.nio_charset import *
-from .java.security_cert import *
-from .java.security_spec import *
-from .java.sql import *
-from .java.beans import *
-from .java.rmi import *
-from .java.util_function import *
-from .java.util_logging import *
-from .java.util_stream import *
-from .java.util_prefs import *
-from .java.lang_invoke import *
-from .java.lang_management import *
-from .java.nio_byteorder import *
-from .java.io_ext import *
-from .java.io_file import *
-from .java.util_concurrent_atomic import *
-from .java.util_concurrent_locks import *
-
-# javax.* 包
-from .javax.net import *
-from .javax.crypto import *
-from .javax.security import *
-from .javax.sql import *
-
-# org.* 包
-from .org.json import *
-from .org.w3c_dom import *
-from .org.xml_sax import *
-from .org.xml_pull import *
-from .org.apache.http import *
-
-# dalvik.* 包
-from .dalvik.system import *
-
-# Base64 (标准 Android API)
-import base64 as _base64
-
-class Base64:
- DEFAULT = 0
- NO_PADDING = 1
- NO_WRAP = 2
- CRLF = 4
- URL_SAFE = 8
- NO_CLOSE = 16
-
- @staticmethod
- def encodeToString(input_data, flags=0):
- if isinstance(input_data, str):
- input_data = input_data.encode('utf-8')
- return _base64.b64encode(input_data).decode('ascii')
-
- @staticmethod
- def decode(str_val, flags=0):
- return _base64.b64decode(str_val)
-
- @staticmethod
- def encode(input_data, flags=0):
- if isinstance(input_data, str):
- input_data = input_data.encode('utf-8')
- return _base64.b64encode(input_data)
-
-# Scanner (java.util)
-class Scanner:
- def __init__(self, source):
- if isinstance(source, str):
- self._source = source
- else:
- self._source = str(source)
- self._pos = 0
-
- def next(self):
- while self._pos < len(self._source) and self._source[self._pos].isspace():
- self._pos += 1
- start = self._pos
- while self._pos < len(self._source) and not self._source[self._pos].isspace():
- self._pos += 1
- if start == self._pos:
- raise Exception("NoSuchElementException")
- return self._source[start:self._pos]
-
- def hasNext(self):
- pos = self._pos
- while pos < len(self._source) and self._source[pos].isspace():
- pos += 1
- return pos < len(self._source)
-
- def nextInt(self):
- return int(self.next())
-
- def close(self):
- pass
-
-# Timer (java.util)
-class Timer:
- def __init__(self, name=None, daemon=False):
- import threading
- self._thread = None
- self._tasks = []
-
- def schedule(self, task, delay=None, period=None):
- import threading
- if delay is None:
- self._run_once(task)
- elif period is None:
- self._run_delayed(task, delay)
- else:
- self._run_periodic(task, delay, period)
-
- def _run_once(self, task):
- t = threading.Thread(target=task.run)
- t.daemon = True
- self._tasks.append(t)
- t.start()
-
- def _run_delayed(self, task, delay_ms):
- import threading
- def _run():
- import time
- time.sleep(delay_ms / 1000.0)
- task.run()
- t = threading.Thread(target=_run)
- t.daemon = True
- self._tasks.append(t)
- t.start()
-
- def _run_periodic(self, task, delay_ms, period_ms):
- import threading
- def _run():
- import time
- time.sleep(delay_ms / 1000.0)
- while True:
- task.run()
- time.sleep(period_ms / 1000.0)
- t = threading.Thread(target=_run)
- t.daemon = True
- self._tasks.append(t)
- t.start()
-
- def cancel(self):
- pass
-
- def purge(self):
- return 0
-
-
-class TimerTask:
- def __init__(self):
- self._cancelled = False
-
- def run(self):
- pass
-
- def cancel(self):
- self._cancelled = True
-
- def scheduledExecutionTime(self):
- return 0
-
-__version__ = "1.0.0"
-__all__ = [
- # android — 核心
- "AccessibilityNodeInfo", "AccessibilityService",
- "AccessibilityServiceInfo",
- "Account", "AccountManager",
- "Activity", "ActivityManager",
- "Fragment", "FragmentManager", "FragmentTransaction",
- "Dialog", "AlertDialog", "ProgressDialog",
- "DatePickerDialog", "TimePickerDialog",
- "Service", "Application",
- "PendingIntent", "ComponentName", "AlarmManager",
- "NotificationChannel", "NotificationChannelGroup",
- "NotificationCompat", "TaskStackBuilder",
- "AlphaAnimation",
- "Animation",
- "Animator", "ValueAnimator", "ObjectAnimator", "AnimatorSet",
- "AppWidgetManager", "AppWidgetProvider", "AppWidgetProviderInfo",
- "AssistManager", "AssistStructure",
- "AudioManager",
- "AutofillManager", "AutofillValue",
- "BackupAgent", "BackupManager",
- "Base64",
- "BatteryManager",
- "BiometricPrompt",
- "Bitmap", "BitmapDrawable", "BitmapFactory",
- "Camera",
- "Region", "PathMeasure",
- "NinePatch", "Picture", "PictureDrawable",
- "PorterDuff", "PorterDuffXfermode",
- "Shader", "LinearGradient", "RadialGradient", "SweepGradient",
- "BitmapShader", "ComposeShader",
- "CornerPathEffect", "DashPathEffect", "PathDashPathEffect",
- "SumPathEffect",
- "BluetoothAdapter", "BluetoothDevice",
- "BroadcastReceiver",
- "Build",
- "Bundle",
- "Button",
- "CalendarContract",
- "Call",
- "CameraManager",
- "Canvas",
- "CheckBox",
- "Color",
- "CompanionDeviceManager",
- "ConnectivityManager",
- "ConsumerIrManager",
- "ContentResolver",
- "ContentValues",
- "ContactsContract",
- "Context",
- "CredentialManager",
- "Cursor",
- "DevicePolicyManager",
- "DisplayManager",
- "Drawable",
- "EditText",
- "Environment",
- "FingerprintManager",
- "Geocoder",
- "Gesture", "GestureOverlayView", "GestureLibrary",
- "Handler",
- "Html",
- "ImageView",
- "InputDevice",
- "KeyEvent", "MotionEvent",
- "GestureDetector", "ScaleGestureDetector",
- "SurfaceHolder", "Surface", "SurfaceView", "TextureView",
- "ViewOutlineProvider",
- "WindowManager", "Window",
- "LayoutInflater", "Menu", "MenuItem", "ContextMenu",
- "Display", "DisplayMetrics",
- "InputManager",
- "InputMethodManager",
- "Intent",
- "IntentFilter",
- "JobInfo", "JobScheduler", "JobService",
- "KeyChain",
- "ListView",
- "Location", "LocationManager",
- "Log",
- "Looper",
- "Matrix",
- "MediaBrowser", "MediaController",
- "MediaPlayer",
- "MediaProjectionManager",
- "MediaRecorder",
- "MediaMetadataRetriever",
- "MediaSession",
- "MediaStore",
- "Message",
- "MidiDevice", "MidiManager",
- "MtpDevice",
- "NfcAdapter", "NdefMessage", "NdefRecord", "Tag",
- "NetworkInfo",
- "Os", "OsConstants",
- "PackageInfo", "PackageManager",
- "Paint",
- "PdfRenderer",
- "PeopleManager",
- "PermissionManager",
- "PowerManager",
- "PrintAttributes", "PrintDocumentAdapter", "PrintManager",
- "LinearLayout", "FrameLayout", "RelativeLayout",
- "TableLayout", "TableRow",
- "BaseAdapter", "ArrayAdapter", "SimpleAdapter", "CursorAdapter",
- "ImageButton", "ToggleButton", "RadioButton", "SeekBar", "RatingBar",
- "ViewSwitcher", "TextSwitcher", "ImageSwitcher",
- "SearchView", "NumberPicker", "Chronometer",
- "TabHost", "TabWidget", "ViewAnimator",
- "ZoomControls", "DigitalClock", "AnalogClock",
- "ProgressBar",
- "RadioManager", "RadioTuner",
- "Rect", "RectF",
- "RecyclerView",
- "Resources", "AssetManager",
- "RoleManager",
- "ScrollView",
- "SearchManager", "SearchableInfo",
- "SensorManager",
- "Settings",
- "SharedPreferences",
- "Slice", "SliceManager", "SliceProvider",
- "SmsManager",
- "SpannableString",
- "SpannableStringBuilder",
- "SpeechRecognizer",
- "Spinner",
- "SQLiteDatabase", "SQLiteOpenHelper", "SQLiteStatement",
- "MatrixCursor",
- "StorageManager", "StorageVolume",
- "StructStat",
- "Switch",
- "TelecomManager",
- "TelephonyManager",
- "TextClassifier",
- "TextToSpeech",
- "TextUtils",
- "TextView",
- "ThermalManager",
- "TimeManager",
- "Toast",
- "TrafficStats",
- "TranslateAnimation",
- "TranslationManager",
- "TvInputManager",
- "Typeface",
- "TypedValue",
- "Uri",
- "UsageStatsManager",
- "UsbDevice", "UsbManager",
- "UserManager", "UserHandle",
- "UwbManager",
- "View", "ViewGroup",
- "VirtualDisplay",
- "Vibrator", "VibratorEffect",
- "VpnManager", "VpnService",
- "WebView",
- "WifiAwareManager",
- "WifiManager",
- "WifiRttManager",
- # java
- "File", "FileInputStream", "FileOutputStream",
- "BufferedReader", "BufferedWriter",
- "InputStreamReader", "OutputStreamWriter",
- "URL", "HttpURLConnection", "Socket", "ServerSocket",
- "NetworkInterface", "InetAddress", "InetSocketAddress", "InterfaceAddress",
- "ArrayList", "HashMap", "HashSet", "LinkedList",
- "TreeMap", "LinkedHashMap", "PriorityQueue",
- "Collections", "Arrays", "Calendar", "Date", "Random",
- "UUID", "Scanner", "Timer", "TimerTask",
- "Pattern", "Matcher",
- "ZipFile", "GZIPInputStream", "GZIPOutputStream",
- "ExecutorService", "Executors", "Future", "Callable",
- "String", "StringBuilder", "StringBuffer",
- "Integer", "Math", "System", "Thread",
- "BigInteger", "BigDecimal",
- # Java Exception 体系
- "Throwable", "Exception", "RuntimeException", "Error",
- "NullPointerException", "IllegalArgumentException", "IllegalStateException",
- "IndexOutOfBoundsException", "ArrayIndexOutOfBoundsException",
- "StringIndexOutOfBoundsException", "ClassCastException",
- "UnsupportedOperationException", "ArithmeticException",
- "NumberFormatException", "SecurityException",
- "ConcurrentModificationException", "NegativeArraySizeException",
- "NoSuchFieldException", "NoSuchMethodException", "InterruptedException",
- "CloneNotSupportedException", "IllegalMonitorStateException",
- "IllegalThreadStateException", "EnumConstantNotPresentException",
- "TypeNotPresentException",
- # Java Exception 体系 (扩展)
- "ClassNotFoundException", "IllegalAccessException",
- "InstantiationException", "InvocationTargetException",
- "NoSuchElementException", "AssertionError",
- "OutOfMemoryError", "StackOverflowError", "NoClassDefFoundError",
- "UnsatisfiedLinkError", "LinkageError", "VerifyError",
- "AbstractMethodError", "IncompatibleClassChangeError",
- "ExceptionInInitializerError",
- "SimpleDateFormat", "DecimalFormat",
- "LocalDateTime", "LocalDate", "LocalTime", "Instant", "Duration", "Period",
- "ChronoUnit", "ChronoField", "DayOfWeek", "Month", "ZoneId", "ZoneOffset",
- "DateTimeFormatter",
- "ByteBuffer", "Files", "Path", "Paths",
- "MessageDigest", "SecureRandom",
- "Cipher", "Mac", "KeyGenerator",
- "SecretKey", "SecretKeySpec",
- "Reference", "SoftReference", "WeakReference", "PhantomReference",
- "Field", "Method", "Constructor", "Proxy", "Modifier",
- "Annotation", "Retention", "Target", "RetentionPolicy", "ElementType",
- "Channel", "Selector", "SelectionKey", "SocketChannel", "ServerSocketChannel",
- "FileChannel", "DatagramChannel",
- "Charset", "CharsetEncoder", "CharsetDecoder", "StandardCharsets",
- "CoderResult",
- # javax
- "SSLSocketFactory", "SSLServerSocketFactory",
- "SSLSocket", "SSLServerSocket", "HttpsURLConnection",
- "TrustManager", "X509TrustManager", "KeyManager", "X509KeyManager",
- "Cipher", "KeyGenerator", "Mac", "SecretKey", "SecretKeySpec",
- "Subject", "Principal", "Policy",
- "DataSource", "RowSet", "CachedRowSet", "RowSetListener",
- # org
- "JSONObject", "JSONArray", "JSONException",
- "Document", "Node", "Element", "Attr", "Text", "NodeList",
- "XMLReader", "ContentHandler", "InputSource", "SAXException",
- "XmlPullParser", "XmlSerializer", "XmlPullParserFactory",
- "HttpResponse", "HttpEntity", "HttpClient", "DefaultHttpClient",
- "HttpGet", "HttpPost", "HttpPut", "HttpDelete",
- # dalvik
- "DexClassLoader", "PathClassLoader", "DexFile",
-]
diff --git a/android_pyapi/_core.py b/android_pyapi/_core.py
deleted file mode 100644
index d8b2990..0000000
--- a/android_pyapi/_core.py
+++ /dev/null
@@ -1,186 +0,0 @@
-"""
-Android-pyApi 核心基础设施
-"""
-
-import os
-import sys
-import platform
-import tempfile
-import json
-import hashlib
-import random
-import time
-from typing import Any, Dict, List, Optional, Callable
-
-
-class AndroidOnlyError(Exception):
- """当调用仅 Android 可用的 API 时抛出"""
- pass
-
-
-class Stub:
- """
- 通用 Android API 存根基类。
- 子类可以覆盖具体方法实现真实逻辑;
- 未覆盖的方法调用会返回合理默认值。
- """
-
- _android_only = False
-
- def __init__(self, *args, **kwargs):
- pass
-
- def __getattr__(self, name: str):
- if name.startswith("_"):
- raise AttributeError(name)
-
- def _stub_method(*args, **kwargs):
- if self._android_only:
- raise AndroidOnlyError(
- f"{self.__class__.__name__}.{name}() 仅在 Android 设备上可用"
- )
- return None
-
- return _stub_method
-
- def toString(self) -> str:
- return f"{self.__class__.__name__}@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
- def getClass(self) -> type:
- return self.__class__
-
-
-# ═══════════════════════════════════════════════════════════════
-# 全局路径和环境
-# ═══════════════════════════════════════════════════════════════
-
-_package_name = "com.ai.assistance.operit"
-_sdcard_root = os.path.join(os.path.expanduser("~"), "Android-compat", "sdcard")
-_app_data_dir = os.path.join(os.path.expanduser("~"), "Android-compat", "app-data")
-
-
-def _ensure_dirs():
- dirs = [
- _sdcard_root,
- os.path.join(_sdcard_root, "Download"),
- os.path.join(_sdcard_root, "DCIM"),
- os.path.join(_sdcard_root, "DCIM", "Screenshots"),
- os.path.join(_sdcard_root, "Documents"),
- os.path.join(_sdcard_root, "Music"),
- os.path.join(_sdcard_root, "Movies"),
- os.path.join(_sdcard_root, "Pictures"),
- os.path.join(_sdcard_root, "Android", "data"),
- os.path.join(_sdcard_root, "Android", "data", _package_name, "files"),
- os.path.join(_sdcard_root, "Android", "data", _package_name, "cache"),
- _app_data_dir,
- os.path.join(_app_data_dir, "files"),
- os.path.join(_app_data_dir, "cache"),
- os.path.join(_app_data_dir, "shared_prefs"),
- ]
- for d in dirs:
- os.makedirs(d, exist_ok=True)
-
-
-_ensure_dirs()
-
-
-def resolve_android_path(path: str) -> str:
- """将 Android 路径解析为桌面路径"""
- if path.startswith("/sdcard"):
- return os.path.join(_sdcard_root, path[7:].lstrip("/"))
- if path.startswith("/data/data/"):
- return os.path.join(_app_data_dir, path[11:].lstrip("/"))
- if path.startswith("content://"):
- # 简单解析 content URI
- from urllib.parse import urlparse
- parsed = urlparse(path)
- return parsed.path or path
- if path.startswith("file://"):
- from urllib.parse import unquote
- return unquote(path[7:])
- return path
-
-
-def to_android_path(desktop_path: str) -> str:
- """将桌面路径映射回 Android 路径"""
- if desktop_path.startswith(_sdcard_root):
- rel = os.path.relpath(desktop_path, _sdcard_root)
- return f"/sdcard/{rel}"
- if desktop_path.startswith(_app_data_dir):
- rel = os.path.relpath(desktop_path, _app_data_dir)
- return f"/data/data/{_package_name}/{rel}"
- return desktop_path
-
-
-# ═══════════════════════════════════════════════════════════════
-# 全局 Context 单例
-# ═══════════════════════════════════════════════════════════════
-
-class _GlobalContext:
- """全局应用上下文占位符,在 android.content 模块中被替换为真实 Context"""
-
- @property
- def packageName(self):
- return _package_name
-
- def getPackageName(self):
- return _package_name
-
- def getFilesDir(self):
- return os.path.join(_app_data_dir, "files")
-
- def getCacheDir(self):
- return os.path.join(_app_data_dir, "cache")
-
- def getExternalFilesDir(self, type_=None):
- base = os.path.join(_sdcard_root, "Android", "data", _package_name, "files")
- if type_:
- base = os.path.join(base, type_)
- os.makedirs(base, exist_ok=True)
- return base
-
- def getExternalStorageDirectory(self):
- return _sdcard_root
-
- def getSystemService(self, name):
- return None # 由具体模块填充
-
-
-android_context = _GlobalContext()
-
-
-def get_context():
- """获取全局 Android Context"""
- return android_context
-
-
-# ═══════════════════════════════════════════════════════════════
-# 可选依赖检测
-# ═══════════════════════════════════════════════════════════════
-
-def _check_optional(name: str) -> bool:
- """检查可选依赖是否可用"""
- try:
- __import__(name)
- return True
- except ImportError:
- return False
-
-
-HAS_PIL = _check_optional("PIL")
-HAS_REQUESTS = _check_optional("requests")
-HAS_HTTPX = _check_optional("httpx")
-HAS_PYAUTOGUI = _check_optional("pyautogui")
-HAS_SCREENINFO = _check_optional("screeninfo")
-HAS_PSUTIL = _check_optional("psutil")
-HAS_PYMUPDF = _check_optional("fitz")
-HAS_PDF2IMAGE = _check_optional("pdf2image")
-HAS_CRYPTOGRAPHY = _check_optional("cryptography")
-HAS_PYPERCLIP = _check_optional("pyperclip")
-HAS_JPYPE = _check_optional("jpype")
diff --git a/android_pyapi/_linux_impl.py b/android_pyapi/_linux_impl.py
deleted file mode 100644
index d9c30c7..0000000
--- a/android_pyapi/_linux_impl.py
+++ /dev/null
@@ -1,1266 +0,0 @@
-"""
-Linux 真实实现层
-================
-在 Linux 环境下,将 Android API 的存根行为替换为真实的系统调用。
-使 Android-pyApi 从"存根库"变为"可用的生产力工具"。
-
-覆盖能力:
- - 网络: ip 命令, /proc/net, socket
- - 蓝牙: bluetoothctl / dbus
- - 传感器: /sys/class/hwmon, /sys/class/thermal, sensors
- - 音频: amixer / ALSA
- - 剪贴板: xclip
- - 电源/电池: /sys/class/power_supply, psutil
- - 位置: IP 地理定位 (requests)
- - 通知: notify-send
- - Shell: subprocess
- - 显示: xdotool, X11
- - UI自动化: xdotool
- - 摄像头: opencv (V4L2)
- - 进程管理: psutil, /proc
- - 文件: 原生 Python os
- - 媒体: ffmpeg/ffprobe
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import re
-import json
-import time
-import socket
-import struct
-import shutil
-import subprocess
-import platform
-import hashlib
-from pathlib import Path
-from datetime import datetime
-from typing import Any, Dict, List, Optional, Tuple
-
-# ═══════════════════════════════════════════════════════════════
-# 能力检测
-# ═══════════════════════════════════════════════════════════════
-
-IS_LINUX = platform.system() == "Linux"
-
-def _which(name: str) -> Optional[str]:
- return shutil.which(name)
-
-HAS_IP = _which("ip") is not None
-HAS_BLUETOOTHCTL = _which("bluetoothctl") is not None
-HAS_AMIXER = _which("amixer") is not None
-HAS_XCLIP = _which("xclip") is not None
-HAS_XDOTOOL = _which("xdotool") is not None
-HAS_NOTIFY_SEND = _which("notify-send") is not None
-HAS_SENSORS = _which("sensors") is not None
-HAS_FFMPEG = _which("ffmpeg") is not None
-HAS_FFPROBE = _which("ffprobe") is not None
-HAS_XRANDR = _which("xrandr") is not None
-
-try:
- import psutil
- HAS_PSUTIL = True
-except ImportError:
- HAS_PSUTIL = False
-
-try:
- import requests
- HAS_REQUESTS = True
-except ImportError:
- HAS_REQUESTS = False
-
-try:
- import cv2
- HAS_CV2 = True
-except ImportError:
- HAS_CV2 = False
-
-try:
- import numpy as np
- HAS_NUMPY = True
-except ImportError:
- HAS_NUMPY = False
-
-try:
- from PIL import Image, ImageDraw, ImageGrab
- HAS_PIL = True
-except ImportError:
- HAS_PIL = False
-
-try:
- import dbus
- HAS_DBUS = True
-except ImportError:
- HAS_DBUS = False
-
-
-def _run(cmd: List[str] or str, timeout: int = 10, capture: bool = True) -> Tuple[int, str, str]:
- """执行命令,返回 (exit_code, stdout, stderr)"""
- try:
- if isinstance(cmd, str):
- result = subprocess.run(cmd, shell=True, capture_output=capture,
- text=True, timeout=timeout)
- else:
- result = subprocess.run(cmd, capture_output=capture,
- text=True, timeout=timeout)
- return result.returncode, result.stdout.strip(), result.stderr.strip()
- except subprocess.TimeoutExpired:
- return -1, "", "timeout"
- except Exception as e:
- return -1, "", str(e)
-
-
-def _read_file(path: str) -> Optional[str]:
- try:
- with open(path, "r") as f:
- return f.read().strip()
- except Exception:
- return None
-
-
-def _read_file_int(path: str) -> Optional[int]:
- val = _read_file(path)
- if val is not None:
- try:
- return int(val)
- except ValueError:
- return None
- return None
-
-
-def _list_dir(path: str) -> List[str]:
- try:
- return os.listdir(path)
- except Exception:
- return []
-
-
-# ═══════════════════════════════════════════════════════════════
-# 网络 — 真实实现
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxNetwork:
- """真实网络信息 — 通过 ip 命令和 /proc/net"""
-
- @staticmethod
- def get_interfaces() -> List[dict]:
- """获取网络接口列表"""
- if not HAS_IP:
- return []
- code, out, _ = _run(["ip", "-j", "addr", "show"])
- if code == 0 and out:
- try:
- return json.loads(out)
- except json.JSONDecodeError:
- pass
- # 回退到 /proc/net
- interfaces = []
- for name in _list_dir("/sys/class/net/"):
- state = _read_file(f"/sys/class/net/{name}/operstate") or "unknown"
- mac = _read_file(f"/sys/class/net/{name}/address") or ""
- interfaces.append({"ifname": name, "operstate": state, "address": mac})
- return interfaces
-
- @staticmethod
- def get_ip_address(interface: str = None) -> str:
- """获取IP地址"""
- # 优先用 socket 获取外网IP
- try:
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- s.connect(("8.8.8.8", 80))
- ip = s.getsockname()[0]
- s.close()
- return ip
- except Exception:
- pass
- # 回退到 hostname
- try:
- return socket.gethostbyname(socket.gethostname())
- except Exception:
- return "127.0.0.1"
-
- @staticmethod
- def get_wifi_info() -> dict:
- """获取WiFi信息"""
- # 尝试 /proc/net/wireless
- data = _read_file("/proc/net/wireless")
- if data:
- lines = data.strip().split("\n")
- if len(lines) >= 3:
- parts = lines[2].split()
- if len(parts) >= 7:
- return {
- "ssid": "",
- "interface": parts[0].rstrip(":"),
- "status": parts[1],
- "quality": float(parts[2]),
- "signal": float(parts[3]),
- "noise": float(parts[4]),
- }
- # 尝试 nmcli
- code, out, _ = _run(["nmcli", "-t", "-f", "active,ssid,signal", "dev", "wifi"])
- if code == 0 and out:
- for line in out.split("\n"):
- if line.startswith("yes:"):
- parts = line.split(":")
- if len(parts) >= 3:
- return {"ssid": parts[1], "signal": int(parts[2])}
- return {"ssid": "", "signal": 0}
-
- @staticmethod
- def get_connectivity() -> bool:
- """检测网络连通性"""
- # 方法1: 尝试 TCP 连接到公共 DNS
- for host, port in [("8.8.8.8", 53), ("1.1.1.1", 53), ("114.114.114.114", 53)]:
- try:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.settimeout(3)
- s.connect((host, port))
- s.close()
- return True
- except Exception:
- continue
- # 方法2: 尝试 HTTP 请求
- if HAS_REQUESTS:
- try:
- requests.get("http://www.baidu.com", timeout=3)
- return True
- except Exception:
- pass
- # 方法3: 检查是否有非 lo 接口且状态为 UP
- for iface in LinuxNetwork.get_interfaces():
- name = iface.get("ifname", iface.get("name", ""))
- state = iface.get("operstate", iface.get("state", ""))
- if name and name != "lo" and state in ("up", "UP"):
- return True
- return False
-
- @staticmethod
- def get_dns_servers() -> List[str]:
- """获取DNS服务器"""
- data = _read_file("/etc/resolv.conf")
- if data:
- dns = []
- for line in data.split("\n"):
- line = line.strip()
- if line.startswith("nameserver"):
- parts = line.split()
- if len(parts) >= 2:
- dns.append(parts[1])
- return dns
- return []
-
- @staticmethod
- def get_gateway() -> str:
- """获取默认网关"""
- data = _read_file("/proc/net/route")
- if data:
- for line in data.split("\n")[1:]:
- parts = line.split()
- if len(parts) >= 3 and parts[1] == "00000000":
- # 网关是十六进制小端
- gw_hex = parts[2]
- try:
- gw_bytes = bytes.fromhex(gw_hex)
- gw = socket.inet_ntoa(gw_bytes[::-1])
- return gw
- except Exception:
- pass
- return ""
-
- @staticmethod
- def get_mac_address(interface: str = None) -> str:
- """获取MAC地址"""
- if interface is None:
- ifaces = _list_dir("/sys/class/net/")
- if ifaces and "lo" in ifaces:
- ifaces.remove("lo")
- if ifaces:
- interface = ifaces[0]
- if interface:
- return _read_file(f"/sys/class/net/{interface}/address") or ""
- return ""
-
- @staticmethod
- def get_rx_tx_bytes(interface: str = None) -> dict:
- """获取网络收发字节数"""
- if interface is None:
- ifaces = _list_dir("/sys/class/net/")
- if "lo" in ifaces:
- ifaces.remove("lo")
- if ifaces:
- interface = ifaces[0]
- if interface:
- rx = _read_file_int(f"/sys/class/net/{interface}/statistics/rx_bytes") or 0
- tx = _read_file_int(f"/sys/class/net/{interface}/statistics/tx_bytes") or 0
- return {"rx_bytes": rx, "tx_bytes": tx, "interface": interface}
- return {"rx_bytes": 0, "tx_bytes": 0, "interface": ""}
-
-
-# ═══════════════════════════════════════════════════════════════
-# 蓝牙 — 真实实现 (bluetoothctl)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxBluetooth:
- """真实蓝牙操作 — 通过 bluetoothctl"""
-
- STATE_OFF = 10
- STATE_TURNING_ON = 11
- STATE_ON = 12
- STATE_TURNING_OFF = 13
-
- @staticmethod
- def get_state() -> int:
- if not HAS_BLUETOOTHCTL:
- return LinuxBluetooth.STATE_OFF
- code, out, _ = _run(["bluetoothctl", "show"])
- if "Powered: yes" in out:
- return LinuxBluetooth.STATE_ON
- return LinuxBluetooth.STATE_OFF
-
- @staticmethod
- def get_address() -> Optional[str]:
- """获取本机蓝牙适配器地址"""
- if not HAS_BLUETOOTHCTL:
- return None
- code, out, _ = _run(["bluetoothctl", "show"])
- if code == 0 and out:
- for line in out.split("\n"):
- line = line.strip()
- if line.startswith("Controller "):
- parts = line.split()
- if len(parts) >= 2:
- return parts[1]
- return None
-
- @staticmethod
- def get_name() -> Optional[str]:
- """获取本机蓝牙适配器名称 (Alias 优先, 回退到 Controller 行括号内名称)"""
- if not HAS_BLUETOOTHCTL:
- return None
- code, out, _ = _run(["bluetoothctl", "show"])
- if code == 0 and out:
- alias = None
- controller_name = None
- for line in out.split("\n"):
- stripped = line.strip()
- if stripped.startswith("Controller ") and "(" in stripped:
- start = stripped.find("(")
- end = stripped.find(")", start)
- if start != -1 and end != -1:
- controller_name = stripped[start + 1:end]
- elif stripped.startswith("Alias:"):
- alias = stripped[len("Alias:"):].strip()
- if alias:
- return alias
- if controller_name:
- return controller_name
- return None
-
- @staticmethod
- def enable() -> bool:
- if not HAS_BLUETOOTHCTL:
- return False
- code, _, _ = _run(["bluetoothctl", "power", "on"])
- return code == 0
-
- @staticmethod
- def disable() -> bool:
- if not HAS_BLUETOOTHCTL:
- return False
- code, _, _ = _run(["bluetoothctl", "power", "off"])
- return code == 0
-
- @staticmethod
- def get_bonded_devices() -> List[dict]:
- if not HAS_BLUETOOTHCTL:
- return []
- code, out, _ = _run(["bluetoothctl", "devices", "Paired"])
- devices = []
- for line in out.split("\n"):
- if line.startswith("Device "):
- parts = line.split(None, 2)
- if len(parts) >= 3:
- devices.append({
- "address": parts[1],
- "name": parts[2],
- "bonded": True,
- })
- return devices
-
- @staticmethod
- def scan(timeout: int = 10) -> List[dict]:
- if not HAS_BLUETOOTHCTL:
- return []
- # 启动扫描
- _run(["bluetoothctl", "scan", "on"], timeout=2)
- time.sleep(min(timeout, 5))
- _run(["bluetoothctl", "scan", "off"], timeout=2)
- # 获取设备列表
- code, out, _ = _run(["bluetoothctl", "devices"])
- devices = []
- for line in out.split("\n"):
- if line.startswith("Device "):
- parts = line.split(None, 2)
- if len(parts) >= 3:
- devices.append({
- "address": parts[1],
- "name": parts[2],
- })
- return devices
-
- @staticmethod
- def pair(address: str) -> bool:
- if not HAS_BLUETOOTHCTL:
- return False
- code, _, _ = _run(["bluetoothctl", "pair", address], timeout=30)
- return code == 0
-
- @staticmethod
- def connect(address: str) -> bool:
- if not HAS_BLUETOOTHCTL:
- return False
- code, _, _ = _run(["bluetoothctl", "connect", address], timeout=15)
- return code == 0
-
- @staticmethod
- def disconnect(address: str) -> bool:
- if not HAS_BLUETOOTHCTL:
- return False
- code, _, _ = _run(["bluetoothctl", "disconnect", address], timeout=10)
- return code == 0
-
- @staticmethod
- def unpair(address: str) -> bool:
- if not HAS_BLUETOOTHCTL:
- return False
- code, _, _ = _run(["bluetoothctl", "remove", address], timeout=10)
- return code == 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# 传感器 — 真实实现 (/sys/class/hwmon, /sys/class/thermal)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxSensors:
- """真实传感器数据 — 通过 /sys 文件系统"""
-
- # Android Sensor Types
- TYPE_ACCELEROMETER = 1
- TYPE_GYROSCOPE = 4
- TYPE_LIGHT = 5
- TYPE_PRESSURE = 6
- TYPE_PROXIMITY = 8
- TYPE_TEMPERATURE = 7
- TYPE_RELATIVE_HUMIDITY = 12
- TYPE_AMBIENT_TEMPERATURE = 13
-
- @staticmethod
- def get_temperatures() -> List[dict]:
- """获取温度传感器读数"""
- temps = []
- # /sys/class/thermal
- for name in _list_dir("/sys/class/thermal/"):
- if name.startswith("thermal_zone"):
- temp = _read_file_int(f"/sys/class/thermal/{name}/temp")
- typ = _read_file(f"/sys/class/thermal/{name}/type") or ""
- if temp is not None:
- temps.append({
- "name": name,
- "type": typ,
- "value": temp / 1000.0, # millicelsius -> celsius
- "unit": "°C",
- })
- # /sys/class/hwmon
- for name in _list_dir("/sys/class/hwmon/"):
- temp_files = [f for f in _list_dir(f"/sys/class/hwmon/{name}/")
- if f.startswith("temp") and f.endswith("_input")]
- for tf in temp_files:
- temp = _read_file_int(f"/sys/class/hwmon/{name}/{tf}")
- label_file = tf.replace("_input", "_label")
- label = _read_file(f"/sys/class/hwmon/{name}/{label_file}") or tf
- if temp is not None:
- temps.append({
- "name": f"{name}/{label}",
- "type": "hwmon",
- "value": temp / 1000.0,
- "unit": "°C",
- })
- return temps
-
- @staticmethod
- def get_fan_speeds() -> List[dict]:
- """获取风扇转速"""
- fans = []
- for name in _list_dir("/sys/class/hwmon/"):
- fan_files = [f for f in _list_dir(f"/sys/class/hwmon/{name}/")
- if f.startswith("fan") and f.endswith("_input")]
- for ff in fan_files:
- rpm = _read_file_int(f"/sys/class/hwmon/{name}/{ff}")
- label_file = ff.replace("_input", "_label")
- label = _read_file(f"/sys/class/hwmon/{name}/{label_file}") or ff
- if rpm is not None:
- fans.append({"name": label, "rpm": rpm})
- return fans
-
- @staticmethod
- def get_cpu_frequency() -> List[dict]:
- """获取CPU频率"""
- freqs = []
- for name in _list_dir("/sys/devices/system/cpu/"):
- if name.startswith("cpu") and name[3:].isdigit():
- cpu_id = name[3:]
- cur = _read_file_int(f"/sys/devices/system/cpu/{name}/cpufreq/scaling_cur_freq")
- if cur is not None:
- freqs.append({
- "cpu": int(cpu_id),
- "freq_mhz": cur / 1000.0,
- })
- return freqs
-
- @staticmethod
- def get_light_level() -> Optional[float]:
- """获取环境光传感器 (如果有)"""
- for name in _list_dir("/sys/class/hwmon/"):
- for f in _list_dir(f"/sys/class/hwmon/{name}/"):
- if "in" in f and f.endswith("_input"):
- val = _read_file_int(f"/sys/class/hwmon/{name}/{f}")
- if val is not None:
- return val / 1000.0
- return None
-
- @staticmethod
- def get_all_sensors() -> dict:
- """获取所有传感器数据"""
- return {
- "temperatures": LinuxSensors.get_temperatures(),
- "fans": LinuxSensors.get_fan_speeds(),
- "cpu_freq": LinuxSensors.get_cpu_frequency(),
- "light": LinuxSensors.get_light_level(),
- }
-
-
-# ═══════════════════════════════════════════════════════════════
-# 音频 — 真实实现 (amixer / ALSA)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxAudio:
- """真实音频控制 — 通过 amixer"""
-
- @staticmethod
- def get_volume() -> int:
- """获取当前音量 (0-100)"""
- if not HAS_AMIXER:
- return 0
- code, out, _ = _run(["amixer", "sget", "Master"])
- if code == 0:
- match = re.search(r'\[(\d+)%\]', out)
- if match:
- return int(match.group(1))
- return 0
-
- @staticmethod
- def set_volume(volume: int) -> bool:
- """设置音量 (0-100)"""
- if not HAS_AMIXER:
- return False
- volume = max(0, min(100, volume))
- code, _, _ = _run(["amixer", "sset", "Master", f"{volume}%"])
- return code == 0
-
- @staticmethod
- def get_mute() -> bool:
- """获取静音状态"""
- if not HAS_AMIXER:
- return False
- code, out, _ = _run(["amixer", "sget", "Master"])
- if code == 0:
- return "[on]" not in out
- return False
-
- @staticmethod
- def set_mute(mute: bool) -> bool:
- """设置静音"""
- if not HAS_AMIXER:
- return False
- cmd = "mute" if mute else "unmute"
- code, _, _ = _run(["amixer", "sset", "Master", cmd])
- return code == 0
-
- @staticmethod
- def get_audio_devices() -> List[dict]:
- """获取音频设备列表"""
- devices = []
- if HAS_AMIXER:
- code, out, _ = _run(["amixer", "controls"])
- if code == 0:
- for line in out.split("\n"):
- devices.append({"name": line, "type": "alsa"})
- return devices
-
-
-# ═══════════════════════════════════════════════════════════════
-# 剪贴板 — 真实实现 (xclip)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxClipboard:
- """真实剪贴板 — 通过 xclip"""
-
- @staticmethod
- def read() -> str:
- if HAS_XCLIP:
- code, out, _ = _run(["xclip", "-selection", "clipboard", "-o"])
- if code == 0:
- return out
- # 回退到 tkinter
- try:
- import tkinter
- root = tkinter.Tk()
- root.withdraw()
- text = root.clipboard_get()
- root.destroy()
- return text
- except Exception:
- return ""
-
- @staticmethod
- def write(text: str) -> bool:
- if HAS_XCLIP:
- try:
- proc = subprocess.Popen(
- ["xclip", "-selection", "clipboard"],
- stdin=subprocess.PIPE, text=True
- )
- proc.communicate(text)
- return proc.returncode == 0
- except Exception:
- pass
- # 回退到 tkinter
- try:
- import tkinter
- root = tkinter.Tk()
- root.withdraw()
- root.clipboard_clear()
- root.clipboard_append(text)
- root.update()
- root.destroy()
- return True
- except Exception:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# 电源/电池 — 真实实现 (/sys/class/power_supply, psutil)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxPower:
- """真实电源/电池信息"""
-
- BATTERY_STATUS_UNKNOWN = 1
- BATTERY_STATUS_CHARGING = 2
- BATTERY_STATUS_DISCHARGING = 3
- BATTERY_STATUS_NOT_CHARGING = 4
- BATTERY_STATUS_FULL = 5
-
- @staticmethod
- def get_battery_info() -> dict:
- """获取电池信息"""
- info = {"present": False, "level": -1, "status": "unknown",
- "temperature": 0, "voltage": 0, "technology": ""}
- # /sys/class/power_supply
- for name in _list_dir("/sys/class/power_supply/"):
- typ = _read_file(f"/sys/class/power_supply/{name}/type") or ""
- if "Battery" in typ:
- info["present"] = True
- info["technology"] = _read_file(f"/sys/class/power_supply/{name}/technology") or ""
- capacity = _read_file_int(f"/sys/class/power_supply/{name}/capacity")
- if capacity is not None:
- info["level"] = capacity
- status = _read_file(f"/sys/class/power_supply/{name}/status") or ""
- info["status"] = status.lower()
- # 电压 (微伏)
- volt = _read_file_int(f"/sys/class/power_supply/{name}/voltage_now")
- if volt is not None:
- info["voltage"] = volt / 1000000.0
- # 温度 (十分之一度)
- temp = _read_file_int(f"/sys/class/power_supply/{name}/temp")
- if temp is not None:
- info["temperature"] = temp / 10.0
- return info
- # psutil 回退
- if HAS_PSUTIL:
- try:
- battery = psutil.sensors_battery()
- if battery:
- info["present"] = True
- info["level"] = battery.percent
- info["status"] = "charging" if battery.power_plugged else "discharging"
- except Exception:
- pass
- return info
-
- @staticmethod
- def get_power_status() -> dict:
- """获取电源状态"""
- info = LinuxPower.get_battery_info()
- return {
- "battery_present": info["present"],
- "battery_level": info["level"],
- "battery_status": info["status"],
- "is_charging": "charging" in info["status"],
- "temperature": info["temperature"],
- "voltage": info["voltage"],
- }
-
- @staticmethod
- def get_cpu_usage() -> float:
- """获取CPU使用率"""
- if HAS_PSUTIL:
- return psutil.cpu_percent(interval=0.5)
- # /proc/stat 回退
- def read_cpu():
- data = _read_file("/proc/stat")
- if data:
- parts = data.split("\n")[0].split()[1:]
- return [int(x) for x in parts]
- return [0] * 10
- c1 = read_cpu()
- time.sleep(0.5)
- c2 = read_cpu()
- idle = c2[3] - c1[3]
- total = sum(c2) - sum(c1)
- if total > 0:
- return (1 - idle / total) * 100
- return 0.0
-
- @staticmethod
- def get_memory_info() -> dict:
- """获取内存信息"""
- if HAS_PSUTIL:
- mem = psutil.virtual_memory()
- return {
- "total": mem.total,
- "available": mem.available,
- "used": mem.used,
- "free": mem.free,
- "percent": mem.percent,
- }
- # /proc/meminfo 回退
- data = _read_file("/proc/meminfo")
- info = {}
- if data:
- for line in data.split("\n"):
- parts = line.split()
- if len(parts) >= 2:
- info[parts[0].rstrip(":")] = int(parts[1]) * 1024
- return {
- "total": info.get("MemTotal", 0),
- "available": info.get("MemAvailable", 0),
- "used": info.get("MemTotal", 0) - info.get("MemAvailable", 0),
- "free": info.get("MemFree", 0),
- "percent": 0,
- }
-
-
-# ═══════════════════════════════════════════════════════════════
-# 位置 — 真实实现 (IP 地理定位)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxLocation:
- """真实位置信息 — 通过 IP 地理定位"""
-
- _cached_location = None
- _cache_time = 0
-
- @staticmethod
- def get_location() -> dict:
- """通过 IP 获取地理位置"""
- if not HAS_REQUESTS:
- return {"latitude": 0.0, "longitude": 0.0, "accuracy": 0, "source": "none"}
-
- # 缓存 5 分钟
- now = time.time()
- if LinuxLocation._cached_location and now - LinuxLocation._cache_time < 300:
- return LinuxLocation._cached_location
-
- # 尝试多个 IP 定位服务
- services = [
- ("http://ip-api.com/json/", "ip-api"),
- ("https://ipapi.co/json/", "ipapi"),
- ("https://freeipapi.com/api/json", "freeipapi"),
- ]
-
- for url, source in services:
- try:
- resp = requests.get(url, timeout=5)
- if resp.status_code == 200:
- data = resp.json()
- lat = data.get("lat") or data.get("latitude") or 0.0
- lon = data.get("lon") or data.get("longitude") or 0.0
- location = {
- "latitude": float(lat),
- "longitude": float(lon),
- "accuracy": 50000, # IP定位精度约 50km
- "source": source,
- "city": data.get("city", ""),
- "region": data.get("regionName", data.get("region", "")),
- "country": data.get("country", data.get("country_name", "")),
- "country_code": data.get("countryCode", data.get("country", "")),
- "timezone": data.get("timezone", ""),
- "isp": data.get("isp", ""),
- }
- LinuxLocation._cached_location = location
- LinuxLocation._cache_time = now
- return location
- except Exception:
- continue
-
- return {"latitude": 0.0, "longitude": 0.0, "accuracy": 0, "source": "failed"}
-
-
-# ═══════════════════════════════════════════════════════════════
-# 通知 — 真实实现 (notify-send)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxNotify:
- """真实桌面通知 — 通过 notify-send"""
-
- @staticmethod
- def send(title: str, text: str, icon: str = None, urgency: str = "normal",
- timeout: int = -1) -> bool:
- if not HAS_NOTIFY_SEND:
- # 回退到 stderr
- print(f"[{title}] {text}", file=sys.stderr)
- return False
- cmd = ["notify-send"]
- cmd.extend(["-u", urgency])
- if timeout >= 0:
- cmd.extend(["-t", str(timeout)])
- if icon:
- cmd.extend(["-i", icon])
- cmd.extend([title, text])
- code, _, _ = _run(cmd)
- return code == 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# 显示/屏幕 — 真实实现 (xdotool, X11)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxDisplay:
- """真实显示/屏幕信息"""
-
- @staticmethod
- def get_screen_size() -> Tuple[int, int]:
- """获取屏幕尺寸"""
- if HAS_XDOTOOL:
- code, out, _ = _run(["xdotool", "getdisplaygeometry"])
- if code == 0:
- parts = out.split()
- if len(parts) >= 2:
- return int(parts[0]), int(parts[1])
- if HAS_XRANDR:
- code, out, _ = _run(["xrandr", "--current"])
- if code == 0:
- for line in out.split("\n"):
- if " connected" in line and "*" in line:
- match = re.search(r'(\d+)x(\d+)', line)
- if match:
- return int(match.group(1)), int(match.group(2))
- # 回退
- try:
- import tkinter
- root = tkinter.Tk()
- w = root.winfo_screenwidth()
- h = root.winfo_screenheight()
- root.destroy()
- return w, h
- except Exception:
- return 1920, 1080
-
- @staticmethod
- def screenshot(path: str = None) -> Optional[str]:
- """截屏"""
- if HAS_PIL:
- try:
- img = ImageGrab.grab()
- if path:
- img.save(path)
- return path
- else:
- buf = f"/tmp/screenshot_{int(time.time())}.png"
- img.save(buf)
- return buf
- except Exception:
- pass
- if HAS_XDOTOOL:
- # 用 xdotool + import
- if not path:
- path = f"/tmp/screenshot_{int(time.time())}.png"
- code, _, _ = _run(["import", "-window", "root", path])
- if code == 0:
- return path
- return None
-
- @staticmethod
- def get_mouse_position() -> Tuple[int, int]:
- """获取鼠标位置"""
- if HAS_XDOTOOL:
- code, out, _ = _run(["xdotool", "getmouselocation"])
- if code == 0:
- parts = out.split()
- x = int(parts[0].split(":")[1])
- y = int(parts[1].split(":")[1])
- return x, y
- return 0, 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# UI 自动化 — 真实实现 (xdotool)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxUIAutomation:
- """真实 UI 自动化 — 通过 xdotool"""
-
- @staticmethod
- def click(x: int, y: int) -> bool:
- if not HAS_XDOTOOL:
- return False
- code, _, _ = _run(["xdotool", "mousemove", str(x), str(y), "click", "1"])
- return code == 0
-
- @staticmethod
- def double_click(x: int, y: int) -> bool:
- if not HAS_XDOTOOL:
- return False
- code, _, _ = _run(["xdotool", "mousemove", str(x), str(y), "click", "--repeat", "2", "1"])
- return code == 0
-
- @staticmethod
- def right_click(x: int, y: int) -> bool:
- if not HAS_XDOTOOL:
- return False
- code, _, _ = _run(["xdotool", "mousemove", str(x), str(y), "click", "3"])
- return code == 0
-
- @staticmethod
- def type_text(text: str) -> bool:
- if not HAS_XDOTOOL:
- return False
- code, _, _ = _run(["xdotool", "type", "--clearmodifiers", text])
- return code == 0
-
- @staticmethod
- def press_key(key: str) -> bool:
- if not HAS_XDOTOOL:
- return False
- # 转换常见键名
- key_map = {
- "enter": "Return", "return": "Return",
- "tab": "Tab", "escape": "Escape", "esc": "Escape",
- "backspace": "BackSpace", "delete": "Delete",
- "space": "space", "up": "Up", "down": "Down",
- "left": "Left", "right": "Right",
- "home": "Home", "end": "End",
- "page_up": "Page_Up", "page_down": "Page_Down",
- }
- xdotool_key = key_map.get(key.lower(), key)
- code, _, _ = _run(["xdotool", "key", xdotool_key])
- return code == 0
-
- @staticmethod
- def hotkey(*keys) -> bool:
- if not HAS_XDOTOOL:
- return False
- key_map = {
- "ctrl": "ctrl", "control": "ctrl",
- "alt": "alt", "shift": "shift",
- "super": "super", "win": "super", "meta": "super",
- }
- mapped = [key_map.get(k.lower(), k) for k in keys]
- combo = "+".join(mapped)
- code, _, _ = _run(["xdotool", "key", combo])
- return code == 0
-
- @staticmethod
- def scroll(amount: int) -> bool:
- if not HAS_XDOTOOL:
- return False
- button = "4" if amount > 0 else "5"
- count = abs(amount)
- code, _, _ = _run(["xdotool", "click", "--repeat", str(count), button])
- return code == 0
-
- @staticmethod
- def find_window(title: str) -> Optional[int]:
- """查找窗口"""
- if not HAS_XDOTOOL:
- return None
- code, out, _ = _run(["xdotool", "search", "--name", title])
- if code == 0 and out:
- return int(out.split("\n")[0])
- return None
-
- @staticmethod
- def activate_window(window_id: int) -> bool:
- if not HAS_XDOTOOL:
- return False
- code, _, _ = _run(["xdotool", "windowactivate", str(window_id)])
- return code == 0
-
- @staticmethod
- def close_window(window_id: int) -> bool:
- if not HAS_XDOTOOL:
- return False
- code, _, _ = _run(["xdotool", "windowclose", str(window_id)])
- return code == 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# 摄像头 — 真实实现 (opencv/V4L2)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxCamera:
- """真实摄像头 — 通过 OpenCV/V4L2"""
-
- @staticmethod
- def list_cameras() -> List[int]:
- """列出可用摄像头"""
- cameras = []
- for dev in _list_dir("/dev/"):
- if dev.startswith("video"):
- try:
- idx = int(dev[5:])
- cameras.append(idx)
- except ValueError:
- pass
- return cameras
-
- @staticmethod
- def capture(camera_id: int = 0, output_path: str = None) -> Optional[str]:
- """拍照"""
- if not HAS_CV2:
- return None
- cap = cv2.VideoCapture(camera_id)
- if not cap.isOpened():
- return None
- ret, frame = cap.read()
- cap.release()
- if not ret:
- return None
- if not output_path:
- output_path = f"/tmp/camera_{int(time.time())}.jpg"
- cv2.imwrite(output_path, frame)
- return output_path
-
- @staticmethod
- def get_camera_info(camera_id: int = 0) -> dict:
- """获取摄像头信息"""
- info = {"id": camera_id, "available": False, "width": 0, "height": 0}
- if HAS_CV2:
- cap = cv2.VideoCapture(camera_id)
- if cap.isOpened():
- info["available"] = True
- info["width"] = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
- info["height"] = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
- info["fps"] = cap.get(cv2.CAP_PROP_FPS)
- cap.release()
- return info
-
-
-# ═══════════════════════════════════════════════════════════════
-# 进程/应用管理 — 真实实现 (psutil, /proc)
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxProcess:
- """真实进程/应用管理"""
-
- @staticmethod
- def list_processes() -> List[dict]:
- """列出所有进程"""
- if HAS_PSUTIL:
- procs = []
- for p in psutil.process_iter(['pid', 'name', 'username', 'memory_percent',
- 'cpu_percent', 'status', 'cmdline']):
- try:
- info = p.info
- procs.append({
- "pid": info['pid'],
- "name": info['name'],
- "user": info['username'],
- "memory": info.get('memory_percent', 0),
- "cpu": info.get('cpu_percent', 0),
- "status": info['status'],
- "cmdline": " ".join(info.get('cmdline') or []),
- })
- except (psutil.NoSuchProcess, psutil.AccessDenied):
- pass
- return procs
- # /proc 回退
- procs = []
- for name in _list_dir("/proc/"):
- if name.isdigit():
- pid = int(name)
- comm = _read_file(f"/proc/{name}/comm") or ""
- cmdline = _read_file(f"/proc/{name}/cmdline") or ""
- status = _read_file(f"/proc/{name}/status") or ""
- user = ""
- for line in status.split("\n"):
- if line.startswith("Uid:"):
- uid = line.split()[1]
- try:
- import pwd
- user = pwd.getpwuid(int(uid)).pw_name
- except Exception:
- user = uid
- break
- procs.append({
- "pid": pid, "name": comm, "user": user,
- "cmdline": cmdline.replace("\x00", " "),
- "status": "", "memory": 0, "cpu": 0,
- })
- return procs
-
- @staticmethod
- def get_running_apps() -> List[dict]:
- """获取运行中的应用 (GUI 窗口)"""
- if not HAS_XDOTOOL:
- return []
- code, out, _ = _run(["xdotool", "search", "--onlyvisible", "--class", ""])
- apps = []
- if code == 0:
- seen = set()
- for wid in out.split("\n"):
- if wid and wid not in seen:
- seen.add(wid)
- # 获取窗口名称
- code2, name, _ = _run(["xdotool", "getwindowname", wid])
- if name:
- apps.append({"window_id": int(wid), "name": name})
- return apps
-
- @staticmethod
- def kill_process(pid: int) -> bool:
- """终止进程"""
- if HAS_PSUTIL:
- try:
- psutil.Process(pid).terminate()
- return True
- except Exception:
- return False
- code, _, _ = _run(["kill", str(pid)])
- return code == 0
-
- @staticmethod
- def start_app(name: str) -> bool:
- """启动应用"""
- code, _, _ = _run([name], timeout=1)
- # 非阻塞启动
- try:
- subprocess.Popen([name], stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
- return True
- except Exception:
- return False
-
- @staticmethod
- def get_system_info() -> dict:
- """获取系统信息"""
- info = {
- "platform": platform.system(),
- "hostname": socket.gethostname(),
- "kernel": platform.release(),
- "arch": platform.machine(),
- "python": platform.python_version(),
- }
- if HAS_PSUTIL:
- info["cpu_count"] = psutil.cpu_count()
- info["cpu_freq"] = psutil.cpu_freq().current if psutil.cpu_freq() else 0
- boot_time = psutil.boot_time()
- info["uptime"] = time.time() - boot_time
- mem = psutil.virtual_memory()
- info["memory_total"] = mem.total
- info["memory_used"] = mem.used
- info["memory_percent"] = mem.percent
- disk = psutil.disk_usage('/')
- info["disk_total"] = disk.total
- info["disk_used"] = disk.used
- info["disk_percent"] = disk.percent
- return info
-
-
-# ═══════════════════════════════════════════════════════════════
-# Shell — 真实实现
-# ═══════════════════════════════════════════════════════════════
-
-class LinuxShell:
- """真实 Shell 执行"""
-
- @staticmethod
- def exec(command: str, timeout: int = 30, root: bool = False) -> dict:
- """执行 Shell 命令"""
- if root and os.geteuid() != 0:
- command = f"sudo {command}"
- code, out, err = _run(command, timeout=timeout)
- return {
- "success": code == 0,
- "output": out + ("\n" + err if err else ""),
- "exit_code": code,
- "stdout": out,
- "stderr": err,
- }
-
- @staticmethod
- def exec_async(command: str) -> int:
- """异步执行命令,返回 PID"""
- proc = subprocess.Popen(command, shell=True,
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
- return proc.pid
-
-
-# ═══════════════════════════════════════════════════════════════
-# 统一入口
-# ═══════════════════════════════════════════════════════════════
-
-def get_linux_capabilities() -> dict:
- """获取当前 Linux 环境的可用能力"""
- return {
- "is_linux": IS_LINUX,
- "network": HAS_IP,
- "bluetooth": HAS_BLUETOOTHCTL,
- "audio": HAS_AMIXER,
- "clipboard": HAS_XCLIP,
- "ui_automation": HAS_XDOTOOL,
- "notifications": HAS_NOTIFY_SEND,
- "sensors": True, # /sys 总是可用
- "display": True,
- "camera": HAS_CV2,
- "ffmpeg": HAS_FFMPEG,
- "ffprobe": HAS_FFPROBE,
- "psutil": HAS_PSUTIL,
- "requests": HAS_REQUESTS,
- "PIL": HAS_PIL,
- "opencv": HAS_CV2,
- "numpy": HAS_NUMPY,
- "dbus": HAS_DBUS,
- "xrandr": HAS_XRANDR,
- }
-
-
-# 导出所有实现类
-__all__ = [
- "IS_LINUX", "get_linux_capabilities",
- "LinuxNetwork", "LinuxBluetooth", "LinuxSensors",
- "LinuxAudio", "LinuxClipboard", "LinuxPower",
- "LinuxLocation", "LinuxNotify", "LinuxDisplay",
- "LinuxUIAutomation", "LinuxCamera", "LinuxProcess",
- "LinuxShell",
- # 能力标志
- "HAS_IP", "HAS_BLUETOOTHCTL", "HAS_AMIXER", "HAS_XCLIP",
- "HAS_XDOTOOL", "HAS_NOTIFY_SEND", "HAS_SENSORS",
- "HAS_FFMPEG", "HAS_FFPROBE", "HAS_PSUTIL", "HAS_REQUESTS",
- "HAS_CV2", "HAS_NUMPY", "HAS_PIL", "HAS_DBUS", "HAS_XRANDR",
-]
diff --git a/android_pyapi/_windows_impl.py b/android_pyapi/_windows_impl.py
deleted file mode 100644
index 83e173f..0000000
--- a/android_pyapi/_windows_impl.py
+++ /dev/null
@@ -1,1380 +0,0 @@
-"""
-Windows 真实实现层
-==================
-在 Windows 环境下,将 Android API 的存根行为替换为真实的系统调用。
-使 Android-pyApi 从"存根库"变为"可用的生产力工具"。
-
-覆盖能力:
- - 网络: ipconfig, netsh, socket, wmi
- - 蓝牙: PowerShell Bluetooth cmdlets
- - 传感器: wmi, psutil
- - 音频: pycaw / PowerShell
- - 剪贴板: pyperclip / win32clipboard
- - 电源/电池: psutil, wmi
- - 位置: IP 地理定位 (requests)
- - 通知: win10toast / plyer
- - 显示: pyautogui, screeninfo, win32api
- - UI自动化: pyautogui
- - 摄像头: opencv
- - 进程管理: psutil, subprocess
- - 文件: 原生 Python os
- - 媒体: ffmpeg/ffprobe
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import re
-import json
-import time
-import socket
-import shutil
-import subprocess
-import platform
-import hashlib
-from pathlib import Path
-from datetime import datetime
-from typing import Any, Dict, List, Optional, Tuple
-
-# ═══════════════════════════════════════════════════════════════
-# 能力检测
-# ═══════════════════════════════════════════════════════════════
-
-IS_WINDOWS = platform.system() == "Windows"
-
-def _which(name: str) -> Optional[str]:
- return shutil.which(name)
-
-HAS_POWERSHELL = _which("powershell") is not None or _which("pwsh") is not None
-HAS_FFMPEG = _which("ffmpeg") is not None
-HAS_FFPROBE = _which("ffprobe") is not None
-
-try:
- import psutil
- HAS_PSUTIL = True
-except ImportError:
- HAS_PSUTIL = False
-
-try:
- import requests
- HAS_REQUESTS = True
-except ImportError:
- HAS_REQUESTS = False
-
-try:
- import cv2
- HAS_CV2 = True
-except ImportError:
- HAS_CV2 = False
-
-try:
- import numpy as np
- HAS_NUMPY = True
-except ImportError:
- HAS_NUMPY = False
-
-try:
- from PIL import Image, ImageDraw, ImageGrab
- HAS_PIL = True
-except ImportError:
- HAS_PIL = False
-
-try:
- import pyautogui
- HAS_PYAUTOGUI = True
-except ImportError:
- HAS_PYAUTOGUI = False
-
-try:
- import pyperclip
- HAS_PYPERCLIP = True
-except ImportError:
- HAS_PYPERCLIP = False
-
-try:
- from win10toast import ToastNotifier
- HAS_WIN10TOAST = True
-except ImportError:
- HAS_WIN10TOAST = False
-
-try:
- import wmi
- HAS_WMI = True
-except ImportError:
- HAS_WMI = False
-
-try:
- import win32api
- import win32con
- import win32gui
- HAS_WIN32 = True
-except ImportError:
- HAS_WIN32 = False
-
-try:
- from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
- from comtypes import CLSCTX_ALL
- HAS_PYCAW = True
-except ImportError:
- HAS_PYCAW = False
-
-try:
- from screeninfo import get_monitors
- HAS_SCREENINFO = True
-except ImportError:
- HAS_SCREENINFO = False
-
-
-def _run(cmd: List[str] or str, timeout: int = 10, capture: bool = True) -> Tuple[int, str, str]:
- """执行命令,返回 (exit_code, stdout, stderr)"""
- try:
- if isinstance(cmd, str):
- result = subprocess.run(cmd, shell=True, capture_output=capture,
- text=True, timeout=timeout, encoding='utf-8', errors='replace')
- else:
- result = subprocess.run(cmd, capture_output=capture,
- text=True, timeout=timeout, encoding='utf-8', errors='replace')
- return result.returncode, result.stdout.strip(), result.stderr.strip()
- except subprocess.TimeoutExpired:
- return -1, "", "timeout"
- except Exception as e:
- return -1, "", str(e)
-
-
-def _run_ps(script: str, timeout: int = 10) -> Tuple[int, str, str]:
- """执行 PowerShell 脚本"""
- ps_exe = "pwsh" if _which("pwsh") else "powershell"
- cmd = [ps_exe, "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", script]
- return _run(cmd, timeout=timeout)
-
-
-def _read_file(path: str) -> Optional[str]:
- try:
- with open(path, "r", encoding='utf-8', errors='replace') as f:
- return f.read().strip()
- except Exception:
- return None
-
-
-def _read_file_int(path: str) -> Optional[int]:
- val = _read_file(path)
- if val is not None:
- try:
- return int(val)
- except ValueError:
- return None
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# 网络 — 真实实现
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsNetwork:
- """真实网络信息 — 通过 ipconfig, netsh, socket"""
-
- @staticmethod
- def get_interfaces() -> List[dict]:
- """获取网络接口列表"""
- interfaces = []
- # 使用 PowerShell 获取网络适配器信息
- code, out, _ = _run_ps(
- "Get-NetAdapter | Select-Object Name, Status, MacAddress, InterfaceDescription | ConvertTo-Json"
- )
- if code == 0 and out:
- try:
- data = json.loads(out)
- if isinstance(data, dict):
- data = [data]
- for iface in data:
- interfaces.append({
- "ifname": iface.get("Name", ""),
- "operstate": iface.get("Status", ""),
- "address": iface.get("MacAddress", ""),
- "description": iface.get("InterfaceDescription", ""),
- })
- return interfaces
- except json.JSONDecodeError:
- pass
- # 回退到 ipconfig
- code, out, _ = _run("ipconfig /all")
- if code == 0:
- current = {}
- for line in out.split("\n"):
- line = line.strip()
- if "adapter" in line.lower() and ":" in line:
- if current:
- interfaces.append(current)
- current = {"ifname": line.split(":")[0].strip(), "operstate": "up", "address": ""}
- elif "Physical Address" in line or "物理地址" in line:
- current["address"] = line.split(":")[-1].strip()
- if current:
- interfaces.append(current)
- return interfaces
-
- @staticmethod
- def get_ip_address(interface: str = None) -> str:
- """获取IP地址"""
- try:
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- s.connect(("8.8.8.8", 80))
- ip = s.getsockname()[0]
- s.close()
- return ip
- except Exception:
- pass
- try:
- return socket.gethostbyname(socket.gethostname())
- except Exception:
- return "127.0.0.1"
-
- @staticmethod
- def get_wifi_info() -> dict:
- """获取WiFi信息"""
- code, out, _ = _run("netsh wlan show interfaces")
- if code == 0:
- info = {"ssid": "", "signal": 0, "status": "disconnected"}
- for line in out.split("\n"):
- line = line.strip()
- if "SSID" in line and "BSSID" not in line:
- parts = line.split(":", 1)
- if len(parts) >= 2:
- info["ssid"] = parts[1].strip()
- elif "Signal" in line:
- parts = line.split(":", 1)
- if len(parts) >= 2:
- signal_str = parts[1].strip().rstrip("%")
- try:
- info["signal"] = int(signal_str)
- except ValueError:
- pass
- elif "State" in line:
- parts = line.split(":", 1)
- if len(parts) >= 2:
- info["status"] = parts[1].strip().lower()
- return info
- return {"ssid": "", "signal": 0, "status": "unknown"}
-
- @staticmethod
- def get_connectivity() -> bool:
- """检测网络连通性"""
- for host, port in [("8.8.8.8", 53), ("1.1.1.1", 53), ("114.114.114.114", 53)]:
- try:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.settimeout(3)
- s.connect((host, port))
- s.close()
- return True
- except Exception:
- continue
- if HAS_REQUESTS:
- try:
- requests.get("http://www.baidu.com", timeout=3)
- return True
- except Exception:
- pass
- return False
-
- @staticmethod
- def get_dns_servers() -> List[str]:
- """获取DNS服务器"""
- code, out, _ = _run_ps(
- "Get-DnsClientServerAddress | Select-Object -ExpandProperty ServerAddresses"
- )
- if code == 0 and out:
- return [s.strip() for s in out.split("\n") if s.strip()]
- # 回退到 ipconfig
- code, out, _ = _run("ipconfig /all")
- if code == 0:
- dns = []
- for line in out.split("\n"):
- if "DNS" in line and ":" in line:
- parts = line.split(":", 1)
- if len(parts) >= 2:
- addr = parts[1].strip()
- if addr and not addr.startswith("("):
- dns.append(addr)
- return dns
- return []
-
- @staticmethod
- def get_gateway() -> str:
- """获取默认网关"""
- code, out, _ = _run("ipconfig")
- if code == 0:
- for line in out.split("\n"):
- if ("Default Gateway" in line or "默认网关" in line) and ":" in line:
- parts = line.split(":", 1)
- if len(parts) >= 2:
- gw = parts[1].strip()
- if gw and gw != "0.0.0.0":
- return gw
- return ""
-
- @staticmethod
- def get_mac_address(interface: str = None) -> str:
- """获取MAC地址"""
- code, out, _ = _run("getmac /fo csv /v")
- if code == 0:
- lines = out.split("\n")
- for line in lines[1:]: # 跳过标题行
- parts = line.split(",")
- if len(parts) >= 3:
- mac = parts[2].strip('"').replace("-", ":")
- if mac and mac != "N/A":
- return mac
- return ""
-
- @staticmethod
- def get_rx_tx_bytes(interface: str = None) -> dict:
- """获取网络收发字节数"""
- if HAS_PSUTIL:
- counters = psutil.net_io_counters(pernic=True)
- if interface and interface in counters:
- c = counters[interface]
- return {"rx_bytes": c.bytes_recv, "tx_bytes": c.bytes_sent, "interface": interface}
- elif counters:
- # 取第一个非回环接口
- for name, c in counters.items():
- if name.lower() != "lo":
- return {"rx_bytes": c.bytes_recv, "tx_bytes": c.bytes_sent, "interface": name}
- return {"rx_bytes": 0, "tx_bytes": 0, "interface": ""}
-
-
-# ═══════════════════════════════════════════════════════════════
-# 蓝牙 — 真实实现 (PowerShell)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsBluetooth:
- """真实蓝牙操作 — 通过 PowerShell Bluetooth cmdlets"""
-
- STATE_OFF = 10
- STATE_TURNING_ON = 11
- STATE_ON = 12
- STATE_TURNING_OFF = 13
-
- @staticmethod
- def get_state() -> int:
- code, out, _ = _run_ps(
- "Get-PnpDevice -Class Bluetooth | Where-Object {$_.FriendlyName -like '*Radio*' -or $_.FriendlyName -like '*Adapter*'} | Select-Object Status"
- )
- if code == 0 and "OK" in out:
- return WindowsBluetooth.STATE_ON
- return WindowsBluetooth.STATE_OFF
-
- @staticmethod
- def get_address() -> Optional[str]:
- code, out, _ = _run_ps(
- "Get-PnpDevice -Class Bluetooth -Status OK | Select-Object InstanceId | ConvertTo-Json"
- )
- if code == 0 and out:
- try:
- data = json.loads(out)
- if isinstance(data, dict):
- data = [data]
- for dev in data:
- instance_id = dev.get("InstanceId", "")
- # 从 InstanceId 提取 MAC 地址
- mac_match = re.search(r'([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}', instance_id)
- if mac_match:
- return mac_match.group().replace("-", ":")
- except json.JSONDecodeError:
- pass
- return None
-
- @staticmethod
- def get_name() -> Optional[str]:
- code, out, _ = _run_ps(
- "Get-PnpDevice -Class Bluetooth -Status OK | Where-Object {$_.FriendlyName -like '*Radio*' -or $_.FriendlyName -like '*Adapter*'} | Select-Object FriendlyName | ConvertTo-Json"
- )
- if code == 0 and out:
- try:
- data = json.loads(out)
- if isinstance(data, dict):
- return data.get("FriendlyName")
- elif isinstance(data, list) and data:
- return data[0].get("FriendlyName")
- except json.JSONDecodeError:
- pass
- return None
-
- @staticmethod
- def enable() -> bool:
- code, _, err = _run_ps(
- "Get-PnpDevice -Class Bluetooth | Enable-PnpDevice -Confirm:$false"
- )
- return code == 0
-
- @staticmethod
- def disable() -> bool:
- code, _, err = _run_ps(
- "Get-PnpDevice -Class Bluetooth | Disable-PnpDevice -Confirm:$false"
- )
- return code == 0
-
- @staticmethod
- def get_bonded_devices() -> List[dict]:
- code, out, _ = _run_ps(
- "Get-PnpDevice -Class Bluetooth -Status OK | Select-Object FriendlyName, InstanceId | ConvertTo-Json"
- )
- devices = []
- if code == 0 and out:
- try:
- data = json.loads(out)
- if isinstance(data, dict):
- data = [data]
- for dev in data:
- name = dev.get("FriendlyName", "")
- if name and "Enumerator" not in name:
- devices.append({
- "address": "",
- "name": name,
- "bonded": True,
- })
- except json.JSONDecodeError:
- pass
- return devices
-
- @staticmethod
- def scan(timeout: int = 10) -> List[dict]:
- """扫描蓝牙设备 (Windows 限制,只能列出已配对设备)"""
- return WindowsBluetooth.get_bonded_devices()
-
- @staticmethod
- def pair(address: str) -> bool:
- # Windows 需要通过设置界面配对
- code, _, _ = _run_ps("Start-Process ms-settings:bluetooth")
- return code == 0
-
- @staticmethod
- def connect(address: str) -> bool:
- return False # Windows 无命令行直接连接方式
-
- @staticmethod
- def disconnect(address: str) -> bool:
- return False
-
- @staticmethod
- def unpair(address: str) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# 传感器 — 真实实现 (wmi, psutil)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsSensors:
- """真实传感器数据 — 通过 WMI 和 psutil"""
-
- TYPE_ACCELEROMETER = 1
- TYPE_GYROSCOPE = 4
- TYPE_LIGHT = 5
- TYPE_PRESSURE = 6
- TYPE_PROXIMITY = 8
- TYPE_TEMPERATURE = 7
- TYPE_RELATIVE_HUMIDITY = 12
- TYPE_AMBIENT_TEMPERATURE = 13
-
- @staticmethod
- def get_temperatures() -> List[dict]:
- """获取温度传感器读数"""
- temps = []
- # 通过 WMI 获取 CPU 温度
- if HAS_WMI:
- try:
- w = wmi.WMI(namespace="root\\wmi")
- for sensor in w.MSAcpi_ThermalZoneTemperature():
- temp_celsius = (sensor.CurrentTemperature / 10.0) - 273.15
- temps.append({
- "name": sensor.InstanceName,
- "type": "thermal_zone",
- "value": temp_celsius,
- "unit": "°C",
- })
- except Exception:
- pass
- # 通过 psutil 获取 (如果支持)
- if HAS_PSUTIL:
- try:
- if hasattr(psutil, "sensors_temperatures"):
- for name, entries in psutil.sensors_temperatures().items():
- for entry in entries:
- temps.append({
- "name": f"{name}/{entry.label or 'unknown'}",
- "type": name,
- "value": entry.current,
- "unit": "°C",
- })
- except Exception:
- pass
- return temps
-
- @staticmethod
- def get_fan_speeds() -> List[dict]:
- """获取风扇转速"""
- fans = []
- if HAS_PSUTIL:
- try:
- if hasattr(psutil, "sensors_fans"):
- for name, entries in psutil.sensors_fans().items():
- for entry in entries:
- fans.append({
- "name": f"{name}/{entry.label or 'unknown'}",
- "rpm": entry.current,
- })
- except Exception:
- pass
- return fans
-
- @staticmethod
- def get_cpu_frequency() -> List[dict]:
- """获取CPU频率"""
- freqs = []
- if HAS_PSUTIL:
- try:
- cpu_freq = psutil.cpu_freq(percpu=True)
- if cpu_freq:
- for i, freq in enumerate(cpu_freq):
- freqs.append({
- "cpu": i,
- "freq_mhz": freq.current,
- })
- else:
- # 单个频率值
- freq = psutil.cpu_freq()
- if freq:
- freqs.append({
- "cpu": 0,
- "freq_mhz": freq.current,
- })
- except Exception:
- pass
- return freqs
-
- @staticmethod
- def get_light_level() -> Optional[float]:
- """获取环境光传感器 (Windows 通常无直接访问)"""
- return None
-
- @staticmethod
- def get_all_sensors() -> dict:
- """获取所有传感器数据"""
- return {
- "temperatures": WindowsSensors.get_temperatures(),
- "fans": WindowsSensors.get_fan_speeds(),
- "cpu_freq": WindowsSensors.get_cpu_frequency(),
- "light": WindowsSensors.get_light_level(),
- }
-
-
-# ═══════════════════════════════════════════════════════════════
-# 音频 — 真实实现 (pycaw / PowerShell)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsAudio:
- """真实音频控制 — 通过 pycaw 或 PowerShell"""
-
- @staticmethod
- def _get_pycaw_volume():
- """获取 pycaw 音量接口"""
- if not HAS_PYCAW:
- return None
- try:
- devices = AudioUtilities.GetSpeakers()
- interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
- return interface.QueryInterface(IAudioEndpointVolume)
- except Exception:
- return None
-
- @staticmethod
- def get_volume() -> int:
- """获取当前音量 (0-100)"""
- # 方法1: pycaw
- vol = WindowsAudio._get_pycaw_volume()
- if vol:
- try:
- return int(vol.GetMasterVolumeLevelScalar() * 100)
- except Exception:
- pass
- # 方法2: PowerShell
- code, out, _ = _run_ps(
- "(Get-AudioDevice -PlaybackVolume) 2>$null; if($?) {$out} else {(Get-WmiObject -Class Win32_SoundDevice | Select-Object -First 1).Volume}"
- )
- if code == 0 and out:
- try:
- return int(out.strip())
- except ValueError:
- pass
- return 50 # 默认值
-
- @staticmethod
- def set_volume(volume: int) -> bool:
- """设置音量 (0-100)"""
- volume = max(0, min(100, volume))
- # 方法1: pycaw
- vol = WindowsAudio._get_pycaw_volume()
- if vol:
- try:
- vol.SetMasterVolumeLevelScalar(volume / 100.0, None)
- return True
- except Exception:
- pass
- # 方法2: PowerShell
- code, _, _ = _run_ps(f"(Get-AudioDevice -PlaybackVolume {volume}) 2>$null")
- return code == 0
-
- @staticmethod
- def get_mute() -> bool:
- """获取静音状态"""
- vol = WindowsAudio._get_pycaw_volume()
- if vol:
- try:
- return vol.GetMute()
- except Exception:
- pass
- return False
-
- @staticmethod
- def set_mute(mute: bool) -> bool:
- """设置静音"""
- vol = WindowsAudio._get_pycaw_volume()
- if vol:
- try:
- vol.SetMute(mute, None)
- return True
- except Exception:
- pass
- return False
-
- @staticmethod
- def get_audio_devices() -> List[dict]:
- """获取音频设备列表"""
- devices = []
- code, out, _ = _run_ps(
- "Get-AudioDevice -List 2>$null; if(-not $?) { Get-WmiObject Win32_SoundDevice | Select-Object Name, Status }"
- )
- if code == 0 and out:
- for line in out.split("\n"):
- if line.strip():
- devices.append({"name": line.strip(), "type": "windows"})
- return devices
-
-
-# ═══════════════════════════════════════════════════════════════
-# 剪贴板 — 真实实现 (pyperclip)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsClipboard:
- """真实剪贴板 — 通过 pyperclip 或 tkinter"""
-
- @staticmethod
- def read() -> str:
- if HAS_PYPERCLIP:
- try:
- return pyperclip.paste()
- except Exception:
- pass
- # 回退到 tkinter
- try:
- import tkinter
- root = tkinter.Tk()
- root.withdraw()
- text = root.clipboard_get()
- root.destroy()
- return text
- except Exception:
- return ""
-
- @staticmethod
- def write(text: str) -> bool:
- if HAS_PYPERCLIP:
- try:
- pyperclip.copy(text)
- return True
- except Exception:
- pass
- # 回退到 tkinter
- try:
- import tkinter
- root = tkinter.Tk()
- root.withdraw()
- root.clipboard_clear()
- root.clipboard_append(text)
- root.update()
- root.destroy()
- return True
- except Exception:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# 电源/电池 — 真实实现 (psutil)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsPower:
- """真实电源/电池信息"""
-
- BATTERY_STATUS_UNKNOWN = 1
- BATTERY_STATUS_CHARGING = 2
- BATTERY_STATUS_DISCHARGING = 3
- BATTERY_STATUS_NOT_CHARGING = 4
- BATTERY_STATUS_FULL = 5
-
- @staticmethod
- def get_battery_info() -> dict:
- """获取电池信息"""
- info = {"present": False, "level": -1, "status": "unknown",
- "temperature": 0, "voltage": 0, "technology": ""}
- if HAS_PSUTIL:
- try:
- battery = psutil.sensors_battery()
- if battery:
- info["present"] = True
- info["level"] = battery.percent
- if battery.power_plugged:
- info["status"] = "charging" if battery.percent < 100 else "full"
- else:
- info["status"] = "discharging"
- if battery.secsleft and battery.secsleft > 0:
- info["seconds_left"] = battery.secsleft
- except Exception:
- pass
- return info
-
- @staticmethod
- def get_power_status() -> dict:
- """获取电源状态"""
- info = WindowsPower.get_battery_info()
- return {
- "battery_present": info["present"],
- "battery_level": info["level"],
- "battery_status": info["status"],
- "is_charging": "charging" in info["status"],
- "temperature": info["temperature"],
- "voltage": info["voltage"],
- }
-
- @staticmethod
- def get_cpu_usage() -> float:
- """获取CPU使用率"""
- if HAS_PSUTIL:
- return psutil.cpu_percent(interval=0.5)
- return 0.0
-
- @staticmethod
- def get_memory_info() -> dict:
- """获取内存信息"""
- if HAS_PSUTIL:
- mem = psutil.virtual_memory()
- return {
- "total": mem.total,
- "available": mem.available,
- "used": mem.used,
- "free": mem.free,
- "percent": mem.percent,
- }
- return {"total": 0, "available": 0, "used": 0, "free": 0, "percent": 0}
-
-
-# ═══════════════════════════════════════════════════════════════
-# 位置 — 真实实现 (IP 地理定位)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsLocation:
- """真实位置信息 — 通过 IP 地理定位"""
-
- _cached_location = None
- _cache_time = 0
-
- @staticmethod
- def get_location() -> dict:
- """通过 IP 获取地理位置"""
- if not HAS_REQUESTS:
- return {"latitude": 0.0, "longitude": 0.0, "accuracy": 0, "source": "none"}
-
- now = time.time()
- if WindowsLocation._cached_location and now - WindowsLocation._cache_time < 300:
- return WindowsLocation._cached_location
-
- services = [
- ("http://ip-api.com/json/", "ip-api"),
- ("https://ipapi.co/json/", "ipapi"),
- ("https://freeipapi.com/api/json", "freeipapi"),
- ]
-
- for url, source in services:
- try:
- resp = requests.get(url, timeout=5)
- if resp.status_code == 200:
- data = resp.json()
- lat = data.get("lat") or data.get("latitude") or 0.0
- lon = data.get("lon") or data.get("longitude") or 0.0
- location = {
- "latitude": float(lat),
- "longitude": float(lon),
- "accuracy": 50000,
- "source": source,
- "city": data.get("city", ""),
- "region": data.get("regionName", data.get("region", "")),
- "country": data.get("country", data.get("country_name", "")),
- "country_code": data.get("countryCode", data.get("country", "")),
- "timezone": data.get("timezone", ""),
- "isp": data.get("isp", ""),
- }
- WindowsLocation._cached_location = location
- WindowsLocation._cache_time = now
- return location
- except Exception:
- continue
-
- return {"latitude": 0.0, "longitude": 0.0, "accuracy": 0, "source": "failed"}
-
-
-# ═══════════════════════════════════════════════════════════════
-# 通知 — 真实实现 (win10toast / PowerShell)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsNotify:
- """真实桌面通知 — 通过 win10toast 或 PowerShell"""
-
- @staticmethod
- def send(title: str, text: str, icon: str = None, urgency: str = "normal",
- timeout: int = 5) -> bool:
- # 方法1: win10toast
- if HAS_WIN10TOAST:
- try:
- toaster = ToastNotifier()
- toaster.show_toast(title, text, duration=timeout, threaded=True)
- return True
- except Exception:
- pass
- # 方法2: PowerShell BurntToast 模块
- script = f'''
- try {{
- Import-Module BurntToast -ErrorAction Stop
- New-BurntToastNotification -Text "{title}", "{text}"
- }} catch {{
- [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
- [System.Windows.Forms.MessageBox]::Show("{text}", "{title}")
- }}
- '''
- code, _, _ = _run_ps(script)
- if code == 0:
- return True
- # 方法3: PowerShell 原生方式
- script = f'''
- [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
- [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
- $template = @"
-
-
-
- {title}
- {text}
-
-
-
-"@
- $xml = New-Object Windows.Data.Xml.Dom.XmlDocument
- $xml.LoadXml($template)
- $toast = [Windows.UI.Notifications.ToastNotification]::new($xml)
- [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("Android-pyApi").Show($toast)
- '''
- code, _, _ = _run_ps(script)
- return code == 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# 显示/屏幕 — 真实实现 (pyautogui, screeninfo, win32api)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsDisplay:
- """真实显示/屏幕信息"""
-
- @staticmethod
- def get_screen_size() -> Tuple[int, int]:
- """获取屏幕尺寸"""
- # 方法1: screeninfo
- if HAS_SCREENINFO:
- try:
- monitors = get_monitors()
- if monitors:
- m = monitors[0]
- return m.width, m.height
- except Exception:
- pass
- # 方法2: win32api
- if HAS_WIN32:
- try:
- width = win32api.GetSystemMetrics(0)
- height = win32api.GetSystemMetrics(1)
- return width, height
- except Exception:
- pass
- # 方法3: pyautogui
- if HAS_PYAUTOGUI:
- try:
- size = pyautogui.size()
- return size.width, size.height
- except Exception:
- pass
- # 方法4: tkinter
- try:
- import tkinter
- root = tkinter.Tk()
- w = root.winfo_screenwidth()
- h = root.winfo_screenheight()
- root.destroy()
- return w, h
- except Exception:
- return 1920, 1080
-
- @staticmethod
- def screenshot(path: str = None) -> Optional[str]:
- """截屏"""
- if HAS_PYAUTOGUI:
- try:
- img = pyautogui.screenshot()
- if path:
- img.save(path)
- return path
- else:
- buf = os.path.join(os.environ.get("TEMP", "C:\\Temp"),
- f"screenshot_{int(time.time())}.png")
- img.save(buf)
- return buf
- except Exception:
- pass
- if HAS_PIL:
- try:
- img = ImageGrab.grab()
- if path:
- img.save(path)
- return path
- else:
- buf = os.path.join(os.environ.get("TEMP", "C:\\Temp"),
- f"screenshot_{int(time.time())}.png")
- img.save(buf)
- return buf
- except Exception:
- pass
- return None
-
- @staticmethod
- def get_mouse_position() -> Tuple[int, int]:
- """获取鼠标位置"""
- if HAS_PYAUTOGUI:
- try:
- pos = pyautogui.position()
- return pos.x, pos.y
- except Exception:
- pass
- if HAS_WIN32:
- try:
- pos = win32api.GetCursorPos()
- return pos[0], pos[1]
- except Exception:
- pass
- return 0, 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# UI 自动化 — 真实实现 (pyautogui)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsUIAutomation:
- """真实 UI 自动化 — 通过 pyautogui"""
-
- @staticmethod
- def click(x: int, y: int) -> bool:
- if not HAS_PYAUTOGUI:
- return False
- try:
- pyautogui.click(x, y)
- return True
- except Exception:
- return False
-
- @staticmethod
- def double_click(x: int, y: int) -> bool:
- if not HAS_PYAUTOGUI:
- return False
- try:
- pyautogui.doubleClick(x, y)
- return True
- except Exception:
- return False
-
- @staticmethod
- def right_click(x: int, y: int) -> bool:
- if not HAS_PYAUTOGUI:
- return False
- try:
- pyautogui.rightClick(x, y)
- return True
- except Exception:
- return False
-
- @staticmethod
- def type_text(text: str) -> bool:
- if not HAS_PYAUTOGUI:
- return False
- try:
- pyautogui.typewrite(text, interval=0.02)
- return True
- except Exception:
- return False
-
- @staticmethod
- def press_key(key: str) -> bool:
- if not HAS_PYAUTOGUI:
- return False
- key_map = {
- "enter": "enter", "return": "enter",
- "tab": "tab", "escape": "escape", "esc": "escape",
- "backspace": "backspace", "delete": "delete",
- "space": "space", "up": "up", "down": "down",
- "left": "left", "right": "right",
- "home": "home", "end": "end",
- "page_up": "pageup", "page_down": "pagedown",
- }
- pyautogui_key = key_map.get(key.lower(), key)
- try:
- pyautogui.press(pyautogui_key)
- return True
- except Exception:
- return False
-
- @staticmethod
- def hotkey(*keys) -> bool:
- if not HAS_PYAUTOGUI:
- return False
- key_map = {
- "ctrl": "ctrl", "control": "ctrl",
- "alt": "alt", "shift": "shift",
- "super": "win", "win": "win", "meta": "win",
- }
- mapped = [key_map.get(k.lower(), k) for k in keys]
- try:
- pyautogui.hotkey(*mapped)
- return True
- except Exception:
- return False
-
- @staticmethod
- def scroll(amount: int) -> bool:
- if not HAS_PYAUTOGUI:
- return False
- try:
- pyautogui.scroll(amount)
- return True
- except Exception:
- return False
-
- @staticmethod
- def find_window(title: str) -> Optional[int]:
- """查找窗口"""
- if HAS_WIN32:
- try:
- hwnd = win32gui.FindWindow(None, title)
- if hwnd:
- return hwnd
- except Exception:
- pass
- # 模糊搜索
- if HAS_WIN32:
- found = []
- def callback(hwnd, _):
- if win32gui.IsWindowVisible(hwnd):
- window_title = win32gui.GetWindowText(hwnd)
- if title.lower() in window_title.lower():
- found.append(hwnd)
- return True
- try:
- win32gui.EnumWindows(callback, None)
- if found:
- return found[0]
- except Exception:
- pass
- return None
-
- @staticmethod
- def activate_window(window_id: int) -> bool:
- if HAS_WIN32:
- try:
- win32gui.SetForegroundWindow(window_id)
- return True
- except Exception:
- pass
- return False
-
- @staticmethod
- def close_window(window_id: int) -> bool:
- if HAS_WIN32:
- try:
- win32gui.PostMessage(window_id, win32con.WM_CLOSE, 0, 0)
- return True
- except Exception:
- pass
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# 摄像头 — 真实实现 (opencv)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsCamera:
- """真实摄像头 — 通过 OpenCV"""
-
- @staticmethod
- def list_cameras() -> List[int]:
- """列出可用摄像头"""
- cameras = []
- if HAS_CV2:
- for i in range(10):
- cap = cv2.VideoCapture(i)
- if cap.isOpened():
- cameras.append(i)
- cap.release()
- else:
- break
- return cameras
-
- @staticmethod
- def capture(camera_id: int = 0, output_path: str = None) -> Optional[str]:
- """拍照"""
- if not HAS_CV2:
- return None
- cap = cv2.VideoCapture(camera_id)
- if not cap.isOpened():
- return None
- ret, frame = cap.read()
- cap.release()
- if not ret:
- return None
- if not output_path:
- output_path = os.path.join(os.environ.get("TEMP", "C:\\Temp"),
- f"camera_{int(time.time())}.jpg")
- cv2.imwrite(output_path, frame)
- return output_path
-
- @staticmethod
- def get_camera_info(camera_id: int = 0) -> dict:
- """获取摄像头信息"""
- info = {"id": camera_id, "available": False, "width": 0, "height": 0}
- if HAS_CV2:
- cap = cv2.VideoCapture(camera_id)
- if cap.isOpened():
- info["available"] = True
- info["width"] = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
- info["height"] = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
- info["fps"] = cap.get(cv2.CAP_PROP_FPS)
- cap.release()
- return info
-
-
-# ═══════════════════════════════════════════════════════════════
-# 进程/应用管理 — 真实实现 (psutil)
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsProcess:
- """真实进程/应用管理"""
-
- @staticmethod
- def list_processes() -> List[dict]:
- """列出所有进程"""
- if HAS_PSUTIL:
- procs = []
- for p in psutil.process_iter(['pid', 'name', 'username', 'memory_percent',
- 'cpu_percent', 'status', 'cmdline']):
- try:
- info = p.info
- procs.append({
- "pid": info['pid'],
- "name": info['name'],
- "user": info['username'],
- "memory": info.get('memory_percent', 0),
- "cpu": info.get('cpu_percent', 0),
- "status": info['status'],
- "cmdline": " ".join(info.get('cmdline') or []),
- })
- except (psutil.NoSuchProcess, psutil.AccessDenied):
- pass
- return procs
- # 回退到 tasklist
- code, out, _ = _run("tasklist /fo csv /v")
- if code == 0:
- procs = []
- lines = out.split("\n")
- for line in lines[1:]:
- parts = line.split('","')
- if len(parts) >= 8:
- procs.append({
- "name": parts[0].strip('"'),
- "pid": int(parts[1].strip('"')),
- "user": parts[6].strip('"') if len(parts) > 6 else "",
- "status": parts[7].strip('"') if len(parts) > 7 else "",
- "memory": 0,
- "cpu": 0,
- "cmdline": "",
- })
- return procs
- return []
-
- @staticmethod
- def get_running_apps() -> List[dict]:
- """获取运行中的应用 (GUI 窗口)"""
- apps = []
- if HAS_WIN32:
- def callback(hwnd, _):
- if win32gui.IsWindowVisible(hwnd):
- title = win32gui.GetWindowText(hwnd)
- if title and title not in ("Default IME", "MSCTFIME UI"):
- apps.append({"window_id": hwnd, "name": title})
- return True
- try:
- win32gui.EnumWindows(callback, None)
- except Exception:
- pass
- return apps
-
- @staticmethod
- def kill_process(pid: int) -> bool:
- """终止进程"""
- if HAS_PSUTIL:
- try:
- psutil.Process(pid).terminate()
- return True
- except Exception:
- return False
- code, _, _ = _run(f"taskkill /pid {pid} /f")
- return code == 0
-
- @staticmethod
- def start_app(name: str) -> bool:
- """启动应用"""
- try:
- os.startfile(name)
- return True
- except Exception:
- pass
- try:
- subprocess.Popen(name, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
- return True
- except Exception:
- return False
-
- @staticmethod
- def get_system_info() -> dict:
- """获取系统信息"""
- info = {
- "platform": platform.system(),
- "hostname": socket.gethostname(),
- "kernel": platform.release(),
- "arch": platform.machine(),
- "python": platform.python_version(),
- "windows_edition": platform.win32_edition() if hasattr(platform, 'win32_edition') else "",
- "windows_version": platform.version(),
- }
- if HAS_PSUTIL:
- info["cpu_count"] = psutil.cpu_count()
- cpu_freq = psutil.cpu_freq()
- info["cpu_freq"] = cpu_freq.current if cpu_freq else 0
- boot_time = psutil.boot_time()
- info["uptime"] = time.time() - boot_time
- mem = psutil.virtual_memory()
- info["memory_total"] = mem.total
- info["memory_used"] = mem.used
- info["memory_percent"] = mem.percent
- disk = psutil.disk_usage('C:\\')
- info["disk_total"] = disk.total
- info["disk_used"] = disk.used
- info["disk_percent"] = disk.percent
- return info
-
-
-# ═══════════════════════════════════════════════════════════════
-# Shell — 真实实现
-# ═══════════════════════════════════════════════════════════════
-
-class WindowsShell:
- """真实 Shell 执行"""
-
- @staticmethod
- def exec(command: str, timeout: int = 30, root: bool = False) -> dict:
- """执行 Shell 命令"""
- if root:
- # 以管理员权限运行
- script = f'Start-Process cmd -ArgumentList "/c {command}" -Verb RunAs -Wait'
- code, out, err = _run_ps(script, timeout=timeout)
- else:
- code, out, err = _run(command, timeout=timeout)
- return {
- "success": code == 0,
- "output": out + ("\n" + err if err else ""),
- "exit_code": code,
- "stdout": out,
- "stderr": err,
- }
-
- @staticmethod
- def exec_async(command: str) -> int:
- """异步执行命令,返回 PID"""
- try:
- proc = subprocess.Popen(command, shell=True,
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
- return proc.pid
- except Exception:
- return -1
-
-
-# ═══════════════════════════════════════════════════════════════
-# 统一入口
-# ═══════════════════════════════════════════════════════════════
-
-def get_windows_capabilities() -> dict:
- """获取当前 Windows 环境的可用能力"""
- return {
- "is_windows": IS_WINDOWS,
- "network": True,
- "bluetooth": HAS_POWERSHELL,
- "audio": HAS_PYCAW or HAS_POWERSHELL,
- "clipboard": HAS_PYPERCLIP,
- "ui_automation": HAS_PYAUTOGUI,
- "notifications": HAS_WIN10TOAST or HAS_POWERSHELL,
- "sensors": HAS_WMI or HAS_PSUTIL,
- "display": True,
- "camera": HAS_CV2,
- "ffmpeg": HAS_FFMPEG,
- "ffprobe": HAS_FFPROBE,
- "psutil": HAS_PSUTIL,
- "requests": HAS_REQUESTS,
- "PIL": HAS_PIL,
- "opencv": HAS_CV2,
- "numpy": HAS_NUMPY,
- "wmi": HAS_WMI,
- "pyautogui": HAS_PYAUTOGUI,
- "pyperclip": HAS_PYPERCLIP,
- "pycaw": HAS_PYCAW,
- "win32": HAS_WIN32,
- "screeninfo": HAS_SCREENINFO,
- "win10toast": HAS_WIN10TOAST,
- }
-
-
-# 导出所有实现类
-__all__ = [
- "IS_WINDOWS", "get_windows_capabilities",
- "WindowsNetwork", "WindowsBluetooth", "WindowsSensors",
- "WindowsAudio", "WindowsClipboard", "WindowsPower",
- "WindowsLocation", "WindowsNotify", "WindowsDisplay",
- "WindowsUIAutomation", "WindowsCamera", "WindowsProcess",
- "WindowsShell",
- # 能力标志
- "HAS_POWERSHELL", "HAS_FFMPEG", "HAS_FFPROBE", "HAS_PSUTIL",
- "HAS_REQUESTS", "HAS_CV2", "HAS_NUMPY", "HAS_PIL",
- "HAS_PYAUTOGUI", "HAS_PYPERCLIP", "HAS_WIN10TOAST",
- "HAS_WMI", "HAS_WIN32", "HAS_PYCAW", "HAS_SCREENINFO",
-]
diff --git a/android_pyapi/android/__init__.py b/android_pyapi/android/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/android_pyapi/android/accessibilityservice.py b/android_pyapi/android/accessibilityservice.py
deleted file mode 100644
index e07e123..0000000
--- a/android_pyapi/android/accessibilityservice.py
+++ /dev/null
@@ -1,382 +0,0 @@
-"""
-Android accessibilityservice 组件 — AccessibilityService, AccessibilityServiceInfo, GestureDescription 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityServiceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityServiceInfo(Stub):
- """AccessibilityServiceInfo — 无障碍服务信息"""
-
- # Flags
- FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x00000001
- FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000002
- FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000004
- FLAG_REPORT_VIEW_IDS = 0x00000010
- FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000020
- FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000040
- FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x00000100
- FLAG_SERVICE_HANDLES_DOUBLETAP = 0x00000200
- FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000400
- FLAG_REQUEST_SHORTCUT_WARN_DIALOG = 0x00000800
- FLAG_SEND_TRACE_TO_DEBUG_TOOL = 0x00001000
-
- # Feedback types
- FEEDBACK_SPOKEN = 0x00000001
- FEEDBACK_HAPTIC = 0x00000002
- FEEDBACK_AUDIBLE = 0x00000004
- FEEDBACK_VISUAL = 0x00000008
- FEEDBACK_GENERIC = 0x00000010
- FEEDBACK_BRAILLE = 0x00000020
-
- # Capabilities
- CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001
- CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002
- CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004
- CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008
- CAPABILITY_CAN_CONTROL_MAGNIFICATION = 0x00000010
- CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020
- CAPABILITY_CAN_TAKE_SCREENSHOT = 0x00000040
-
- def __init__(self):
- super().__init__()
- self.eventTypes: int = 0
- self.feedbackType: int = self.FEEDBACK_GENERIC
- self.flags: int = 0
- self.notificationTimeout: int = 0
- self.fetchDescription: Optional[str] = None
- self.capabilities: int = 0
- self.packageNames: Optional[List[str]] = None
-
- def toString(self) -> str:
- return (f"AccessibilityServiceInfo{{eventTypes={self.eventTypes}, "
- f"feedbackType={self.feedbackType}, flags={self.flags}}}")
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureDescription
-# ═══════════════════════════════════════════════════════════════
-
-class GestureDescription(Stub):
- """GestureDescription — 手势描述"""
-
- class StrokeDescription(Stub):
- """GestureDescription.StrokeDescription — 笔画描述"""
-
- def __init__(self, path: Any, startTime: int, duration: int):
- super().__init__()
- self._path = path
- self._start_time = startTime
- self._duration = duration
-
- def getPath(self) -> Any:
- return self._path
-
- def getStartTime(self) -> int:
- return self._start_time
-
- def getDuration(self) -> int:
- return self._duration
-
- def toString(self) -> str:
- return f"StrokeDescription{{startTime={self._start_time}, duration={self._duration}}}"
-
- _MAX_STROKE_COUNT = 10
-
- @staticmethod
- def getMaxStrokeCount() -> int:
- return GestureDescription._MAX_STROKE_COUNT
-
- def __init__(self):
- super().__init__()
- self._strokes: List[GestureDescription.StrokeDescription] = []
-
- class Builder(Stub):
- """GestureDescription.Builder — 构建器"""
-
- def __init__(self):
- super().__init__()
- self._strokes: List[GestureDescription.StrokeDescription] = []
-
- def addStroke(self, stroke: GestureDescription.StrokeDescription) -> "GestureDescription.Builder":
- if len(self._strokes) < GestureDescription.getMaxStrokeCount():
- self._strokes.append(stroke)
- return self
-
- def build(self) -> "GestureDescription":
- desc = GestureDescription()
- desc._strokes = list(self._strokes)
- return desc
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureResultCallback
-# ═══════════════════════════════════════════════════════════════
-
-class GestureResultCallback(Stub):
- """GestureResultCallback — 手势结果回调"""
-
- def onCompleted(self, gestureDescription: GestureDescription):
- pass
-
- def onCancelled(self, gestureDescription: GestureDescription):
- pass
-
- def onGestureCancelled(self, gestureDescription: GestureDescription):
- self.onCancelled(gestureDescription)
-
- def onGestureCompleted(self, gestureDescription: GestureDescription):
- self.onCompleted(gestureDescription)
-
-
-# ═══════════════════════════════════════════════════════════════
-# MagnificationConfig
-# ═══════════════════════════════════════════════════════════════
-
-class MagnificationConfig(Stub):
- """MagnificationConfig — 放大配置"""
-
- MAGNIFICATION_MODE_FULLSCREEN = 1
- MAGNIFICATION_MODE_WINDOW = 2
-
- def __init__(self):
- super().__init__()
- self._mode: int = self.MAGNIFICATION_MODE_FULLSCREEN
- self._center_x: float = 0.0
- self._center_y: float = 0.0
- self._scale: float = 1.0
-
- def getMode(self) -> int:
- return self._mode
-
- def getCenterX(self) -> float:
- return self._center_x
-
- def getCenterY(self) -> float:
- return self._center_y
-
- def getScale(self) -> float:
- return self._scale
-
- def setMode(self, mode: int):
- self._mode = mode
-
- def setCenterX(self, centerX: float):
- self._center_x = centerX
-
- def setCenterY(self, centerY: float):
- self._center_y = centerY
-
- def setScale(self, scale: float):
- self._scale = scale
-
- def toString(self) -> str:
- return f"MagnificationConfig{{mode={self._mode}, scale={self._scale}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SoftKeyboardController
-# ═══════════════════════════════════════════════════════════════
-
-class SoftKeyboardController(Stub):
- """SoftKeyboardController — 软键盘控制器"""
-
- SHOW_MODE_AUTO = 0
- SHOW_MODE_HIDDEN = 1
- SHOW_MODE_IGNORE_HARD_KEYBOARD = 2
- SHOW_MODE_HIDDEN_IDLE_TIMEOUT = 3
-
- def __init__(self):
- super().__init__()
- self._show_mode: int = self.SHOW_MODE_AUTO
- self._listeners: List[Callable[[int], None]] = []
-
- def setShowMode(self, showMode: int):
- self._show_mode = showMode
-
- def getShowMode(self) -> int:
- return self._show_mode
-
- def addOnShowModeChangedListener(self, listener: Callable[[int], None]):
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeOnShowModeChangedListener(self, listener: Callable[[int], None]):
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def toString(self) -> str:
- return f"SoftKeyboardController@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FingerprintGestureController
-# ═══════════════════════════════════════════════════════════════
-
-class FingerprintGestureController(Stub):
- """FingerprintGestureController — 指纹手势控制器"""
-
- def __init__(self):
- super().__init__()
- self._callbacks: List[Any] = []
-
- def isGestureAvailable(self) -> bool:
- return False
-
- def onGestureDetectionActiveChange(self, active: bool):
- pass
-
- def registerFingerprintGestureCallback(self, callback: Any, handler: Any = None):
- if callback not in self._callbacks:
- self._callbacks.append(callback)
-
- def unregisterFingerprintGestureCallback(self, callback: Any):
- if callback in self._callbacks:
- self._callbacks.remove(callback)
-
- def toString(self) -> str:
- return f"FingerprintGestureController@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TouchInteractionController
-# ═══════════════════════════════════════════════════════════════
-
-class TouchInteractionController(Stub):
- """TouchInteractionController — 触控交互控制器"""
-
- def __init__(self):
- super().__init__()
-
- def performClick(self, x: int, y: int) -> bool:
- return True
-
- def performLongClick(self, x: int, y: int) -> bool:
- return True
-
- def requestDefer(self, timeout: int):
- pass
-
- def clearCache(self):
- pass
-
- def toString(self) -> str:
- return f"TouchInteractionController@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityService
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityService(Stub):
- """AccessibilityService — 无障碍服务"""
-
- # Global actions
- GLOBAL_ACTION_BACK = 1
- GLOBAL_ACTION_HOME = 2
- GLOBAL_ACTION_RECENTS = 3
- GLOBAL_ACTION_NOTIFICATIONS = 4
- GLOBAL_ACTION_QUICK_SETTINGS = 5
- GLOBAL_ACTION_POWER_DIALOG = 6
- GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7
- GLOBAL_ACTION_LOCK_SCREEN = 8
- GLOBAL_ACTION_TAKE_SCREENSHOT = 9
-
- # Show modes
- SHOW_MODE_AUTO = SoftKeyboardController.SHOW_MODE_AUTO
- SHOW_MODE_HIDDEN = SoftKeyboardController.SHOW_MODE_HIDDEN
- SHOW_MODE_IGNORE_HARD_KEYBOARD = SoftKeyboardController.SHOW_MODE_IGNORE_HARD_KEYBOARD
- SHOW_MODE_HIDDEN_IDLE_TIMEOUT = SoftKeyboardController.SHOW_MODE_HIDDEN_IDLE_TIMEOUT
-
- # Flags
- FLAG_REQUEST_TOUCH_EXPLORATION_MODE = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE
- FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
- FLAG_REQUEST_FILTER_KEY_EVENTS = AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS
- FLAG_REPORT_VIEW_IDS = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
- FLAG_RETRIEVE_INTERACTIVE_WINDOWS = AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS
- FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
- FLAG_REQUEST_ACCESSIBILITY_BUTTON = AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON
- FLAG_SERVICE_HANDLES_DOUBLETAP = AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLETAP
- FLAG_REQUEST_MULTI_FINGER_GESTURES = AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES
- FLAG_REQUEST_SHORTCUT_WARN_DIALOG = AccessibilityServiceInfo.FLAG_REQUEST_SHORTCUT_WARN_DIALOG
- FLAG_SEND_TRACE_TO_DEBUG_TOOL = AccessibilityServiceInfo.FLAG_SEND_TRACE_TO_DEBUG_TOOL
-
- def __init__(self):
- super().__init__()
- self._service_info = AccessibilityServiceInfo()
- self._soft_keyboard_controller = SoftKeyboardController()
- self._fingerprint_gesture_controller = FingerprintGestureController()
- self._touch_interaction_controller = TouchInteractionController()
-
- # ── Lifecycle ──
-
- def onAccessibilityEvent(self, event: Any):
- pass
-
- def onInterrupt(self):
- pass
-
- def onServiceConnected(self):
- pass
-
- def setServiceInfo(self, info: AccessibilityServiceInfo):
- self._service_info = info
-
- def getServiceInfo(self) -> AccessibilityServiceInfo:
- return self._service_info
-
- # ── Window ──
-
- def getWindows(self) -> List[Any]:
- return []
-
- def getRootInActiveWindow(self) -> Any:
- return None
-
- def findFocus(self, focusType: int) -> Any:
- return None
-
- # ── Actions ──
-
- def performGlobalAction(self, action: int) -> bool:
- return True
-
- # ── Controllers ──
-
- def getSoftKeyboardController(self) -> SoftKeyboardController:
- return self._soft_keyboard_controller
-
- def setGestureDetectionPassthrough(self, passthrough: bool):
- pass
-
- def toString(self) -> str:
- return f"AccessibilityService@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "AccessibilityService",
- "AccessibilityServiceInfo",
- "GestureDescription",
- "GestureResultCallback",
- "MagnificationConfig",
- "SoftKeyboardController",
- "FingerprintGestureController",
- "TouchInteractionController",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/accounts.py b/android_pyapi/android/accounts.py
deleted file mode 100644
index 4d6d4e5..0000000
--- a/android_pyapi/android/accounts.py
+++ /dev/null
@@ -1,456 +0,0 @@
-"""
-Android accounts 组件 — AccountManager, Account, AuthenticatorDescription 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import threading
-import uuid
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# Account
-# ═══════════════════════════════════════════════════════════════
-
-class Account(Stub):
- """Account — 账户"""
-
- def __init__(self, name: str, type_: str):
- super().__init__()
- self.name: str = name
- self.type: str = type_
- self._extras: Dict[str, Any] = {}
-
- def toString(self) -> str:
- return f"Account{{name={self.name}, type={self.type}}}"
-
- def describeContents(self) -> int:
- return 0
-
- def hashCode(self) -> int:
- return hash((self.name, self.type)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Account):
- return False
- return self.name == other.name and self.type == other.type
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccountManagerFuture
-# ═══════════════════════════════════════════════════════════════
-
-class AccountManagerFuture(Stub):
- """AccountManagerFuture — 异步结果"""
-
- def __init__(self):
- super().__init__()
- self._result: Any = None
- self._exception: Optional[Exception] = None
- self._done: bool = False
- self._event = threading.Event()
-
- def getResult(self) -> Any:
- self._event.wait()
- if self._exception:
- raise self._exception
- return self._result
-
- def getException(self) -> Optional[Exception]:
- return self._exception
-
- def isDone(self) -> bool:
- return self._done
-
- def isCancelled(self) -> bool:
- return False
-
- def cancel(self, mayInterruptIfRunning: bool) -> bool:
- return False
-
- def _set_result(self, result: Any):
- self._result = result
- self._done = True
- self._event.set()
-
- def _set_exception(self, exc: Exception):
- self._exception = exc
- self._done = True
- self._event.set()
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccountManagerCallback
-# ═══════════════════════════════════════════════════════════════
-
-class AccountManagerCallback(Stub):
- """AccountManagerCallback — 回调接口"""
-
- def run(self, future: AccountManagerFuture):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AuthenticatorDescription
-# ═══════════════════════════════════════════════════════════════
-
-class AuthenticatorDescription(Stub):
- """AuthenticatorDescription — 认证器描述"""
-
- KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse"
-
- def __init__(self, type_: str, packageName: str = "",
- labelId: int = 0, iconId: int = 0,
- smallIconId: int = 0, accountPreferencesId: int = 0,
- customTokens: bool = False, prefMinId: int = 0):
- super().__init__()
- self.type: str = type_
- self.packageName: str = packageName
- self.labelId: int = labelId
- self.iconId: int = iconId
- self.smallIconId: int = smallIconId
- self.accountPreferencesId: int = accountPreferencesId
- self.customTokens: bool = customTokens
- self.prefMinId: int = prefMinId
-
- def toString(self) -> str:
- return f"AuthenticatorDescription{{type={self.type}}}"
-
- def hashCode(self) -> int:
- return hash(self.type) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, AuthenticatorDescription):
- return False
- return self.type == other.type
-
-
-# ═══════════════════════════════════════════════════════════════
-# OnAccountsUpdateListener
-# ═══════════════════════════════════════════════════════════════
-
-class OnAccountsUpdateListener(Stub):
- """OnAccountsUpdateListener — 账户更新监听器"""
-
- def onAccountsUpdated(self, accounts: Optional[List[Account]]):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccountManager
-# ═══════════════════════════════════════════════════════════════
-
-class AccountManager(Stub):
- """AccountManager — 账户管理器"""
-
- ACTION_ACCOUNT_REMOVED = "android.accounts.action.ACCOUNT_REMOVED"
- ACTION_VISIBLE_ACCOUNTS_CHANGED = "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED"
- KEY_ACCOUNTS = "accounts"
- KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse"
- KEY_ACCOUNT_TYPE = "accountType"
- KEY_AUTHTOKEN = "authtoken"
- KEY_AUTH_FAILED_MESSAGE = "authFailedMessage"
- KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey"
- KEY_BOOLEAN_RESULT = "booleanResult"
- KEY_ERROR_CODE = "errorCode"
- KEY_ERROR_MESSAGE = "errorMessage"
- KEY_INTENT = "intent"
- KEY_LAST_SEEN_PIN = "lastSeenPin"
- KEY_PASSWORD = "password"
- KEY_USERDATA = "userdata"
- LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED"
- PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.legacy_not_visible"
- PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android.accounts.legacy_visible"
- PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android.accounts.legacy_not_visible"
-
- ERROR_CODE_REMOTE_EXCEPTION = 1
- ERROR_CODE_NETWORK_ERROR = 2
- ERROR_CODE_CANCELED = 3
- ERROR_CODE_INVALID_RESPONSE = 4
- ERROR_CODE_UNSUPPORTED_OPERATION = 5
- ERROR_CODE_BAD_ARGUMENTS = 6
- ERROR_CODE_BAD_AUTHENTICATION = 7
- ERROR_CODE_BAD_REQUEST = 8
- ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE = 101
-
- def __init__(self):
- super().__init__()
- self._lock = threading.Lock()
- self._accounts: Dict[str, Account] = {}
- self._passwords: Dict[str, str] = {}
- self._userdata: Dict[str, Dict[str, str]] = {}
- self._auth_tokens: Dict[str, Dict[str, str]] = {}
- self._listeners: List[OnAccountsUpdateListener] = []
- self._listener_handler: Dict[OnAccountsUpdateListener, Any] = {}
-
- @staticmethod
- def get(context: Any = None) -> "AccountManager":
- return AccountManager()
-
- # ── Account listing ──
-
- def getAccounts(self) -> List[Account]:
- with self._lock:
- return list(self._accounts.values())
-
- def getAccountsByType(self, type_: str) -> List[Account]:
- with self._lock:
- return [a for a in self._accounts.values() if a.type == type_]
-
- def getAccountsByTypeAndFeatures(self, type_: str,
- features: List[str],
- callback: Optional[AccountManagerCallback] = None,
- handler: Any = None) -> AccountManagerFuture:
- future = AccountManagerFuture()
- accounts = self.getAccountsByType(type_)
- if callback:
- callback.run(future)
- future._set_result(accounts)
- return future
-
- def getAccountsForPackage(self, packageName: str,
- uid: int = -1) -> List[Account]:
- return self.getAccounts()
-
- def getSharedAccounts(self, userId: int) -> List[Account]:
- return self.getAccounts()
-
- # ── CRUD ──
-
- def addAccount(self, accountType: str, authTokenType: Optional[str] = None,
- requiredFeatures: Optional[List[str]] = None,
- addAccountOptions: Optional[Dict[str, Any]] = None,
- activity: Any = None,
- callback: Optional[AccountManagerCallback] = None,
- handler: Any = None) -> AccountManagerFuture:
- future = AccountManagerFuture()
- name = f"account_{uuid.uuid4().hex[:8]}"
- account = Account(name, accountType)
- with self._lock:
- self._accounts[f"{name}:{accountType}"] = account
- future._set_result(None)
- if callback:
- callback.run(future)
- return future
-
- def addAccountExplicitly(self, account: Account,
- password: Optional[str] = None,
- userdata: Optional[Dict[str, Any]] = None) -> bool:
- key = f"{account.name}:{account.type}"
- with self._lock:
- if key in self._accounts:
- return False
- self._accounts[key] = account
- if password is not None:
- self._passwords[key] = password
- if userdata:
- self._userdata[key] = {k: str(v) for k, v in userdata.items()}
- return True
-
- def removeAccount(self, account: Account,
- callback: Optional[AccountManagerCallback] = None,
- handler: Any = None) -> AccountManagerFuture:
- future = AccountManagerFuture()
- key = f"{account.name}:{account.type}"
- with self._lock:
- self._accounts.pop(key, None)
- self._passwords.pop(key, None)
- self._userdata.pop(key, None)
- self._auth_tokens.pop(key, None)
- future._set_result(True)
- if callback:
- callback.run(future)
- return future
-
- def renameAccount(self, account: Account, newName: str) -> AccountManagerFuture:
- future = AccountManagerFuture()
- key = f"{account.name}:{account.type}"
- with self._lock:
- if key in self._accounts:
- new_key = f"{newName}:{account.type}"
- self._accounts[new_key] = Account(newName, account.type)
- if key in self._passwords:
- self._passwords[new_key] = self._passwords.pop(key)
- if key in self._userdata:
- self._userdata[new_key] = self._userdata.pop(key)
- if key in self._auth_tokens:
- self._auth_tokens[new_key] = self._auth_tokens.pop(key)
- del self._accounts[key]
- future._set_result(account)
- return future
-
- # ── Password ──
-
- def getPassword(self, account: Account) -> Optional[str]:
- key = f"{account.name}:{account.type}"
- with self._lock:
- return self._passwords.get(key)
-
- def setPassword(self, account: Account, password: str):
- key = f"{account.name}:{account.type}"
- with self._lock:
- if password:
- self._passwords[key] = password
- else:
- self._passwords.pop(key, None)
-
- def clearPassword(self, account: Account):
- self.setPassword(account, "")
-
- # ── User data ──
-
- def getUserData(self, account: Account, key: str) -> Optional[str]:
- ak = f"{account.name}:{account.type}"
- with self._lock:
- userdata = self._userdata.get(ak, {})
- return userdata.get(key)
-
- def setUserData(self, account: Account, key: str, value: str):
- ak = f"{account.name}:{account.type}"
- with self._lock:
- if ak not in self._userdata:
- self._userdata[ak] = {}
- self._userdata[ak][key] = value
-
- # ── Auth tokens ──
-
- def getAuthToken(self, account: Account, authTokenType: str,
- notifyAuthFailure: bool = True,
- callback: Optional[AccountManagerCallback] = None,
- handler: Any = None) -> AccountManagerFuture:
- future = AccountManagerFuture()
- key = f"{account.name}:{account.type}"
- with self._lock:
- tokens = self._auth_tokens.get(key, {})
- token = tokens.get(authTokenType)
- future._set_result(token)
- if callback:
- callback.run(future)
- return future
-
- def peekAuthToken(self, account: Account, authTokenType: str) -> Optional[str]:
- key = f"{account.name}:{account.type}"
- with self._lock:
- tokens = self._auth_tokens.get(key, {})
- return tokens.get(authTokenType)
-
- def addAuthToken(self, account: Account, authTokenType: str, authToken: str):
- key = f"{account.name}:{account.type}"
- with self._lock:
- if key not in self._auth_tokens:
- self._auth_tokens[key] = {}
- self._auth_tokens[key][authTokenType] = authToken
-
- def setAuthToken(self, account: Account, authTokenType: str, authToken: str):
- self.addAuthToken(account, authTokenType, authToken)
-
- def invalidateAuthToken(self, accountType: str, authToken: str):
- with self._lock:
- for key in list(self._auth_tokens.keys()):
- if key.endswith(f":{accountType}"):
- tokens = self._auth_tokens[key]
- for ttype, token in list(tokens.items()):
- if token == authToken:
- del tokens[ttype]
-
- # ── Features ──
-
- def hasFeatures(self, account: Account, features: List[str],
- callback: AccountManagerCallback, handler: Any = None) -> AccountManagerFuture:
- future = AccountManagerFuture()
- future._set_result(True)
- if callback:
- callback.run(future)
- return future
-
- # ── Create account ──
-
- def createAccount(self, accountType: str, authTokenType: Optional[str] = None,
- requiredFeatures: Optional[List[str]] = None,
- options: Optional[Dict[str, Any]] = None,
- activity: Any = None,
- callback: Optional[AccountManagerCallback] = None,
- handler: Any = None) -> AccountManagerFuture:
- return self.addAccount(accountType, authTokenType, requiredFeatures,
- options, activity, callback, handler)
-
- # ── Shared accounts ──
-
- def removeSharedAccount(self, account: Account,
- callback: Optional[AccountManagerCallback] = None,
- handler: Any = None) -> AccountManagerFuture:
- return self.removeAccount(account, callback, handler)
-
- def updateAppPermission(self, account: Account, authTokenType: str, uid: int, value: bool):
- pass
-
- def setAuthTokenType(self, account: Account, authTokenType: str):
- pass
-
- # ── Confirm / Edit ──
-
- def confirmCredentials(self, account: Account,
- options: Optional[Dict[str, Any]] = None,
- activity: Any = None,
- callback: Optional[AccountManagerCallback] = None,
- handler: Any = None) -> AccountManagerFuture:
- future = AccountManagerFuture()
- future._set_result(None)
- if callback:
- callback.run(future)
- return future
-
- def editProperties(self, accountType: str,
- activity: Any = None,
- callback: Optional[AccountManagerCallback] = None,
- handler: Any = None) -> AccountManagerFuture:
- future = AccountManagerFuture()
- future._set_result(None)
- if callback:
- callback.run(future)
- return future
-
- # ── Listeners ──
-
- def addOnAccountsUpdatedListener(self, listener: OnAccountsUpdateListener,
- handler: Any = None,
- updateImmediately: bool = False):
- with self._lock:
- self._listeners.append(listener)
- self._listener_handler[listener] = handler
-
- def removeOnAccountsUpdatedListener(self, listener: OnAccountsUpdateListener):
- with self._lock:
- if listener in self._listeners:
- self._listeners.remove(listener)
- self._listener_handler.pop(listener, None)
-
- def _notify_listeners(self):
- with self._lock:
- accounts = list(self._accounts.values())
- for listener in self._listeners:
- listener.onAccountsUpdated(accounts)
-
- def toString(self) -> str:
- return f"AccountManager@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Account",
- "AccountManager",
- "AccountManagerFuture",
- "AccountManagerCallback",
- "AuthenticatorDescription",
- "OnAccountsUpdateListener",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/animation.py b/android_pyapi/android/animation.py
deleted file mode 100644
index 5c03bc1..0000000
--- a/android_pyapi/android/animation.py
+++ /dev/null
@@ -1,951 +0,0 @@
-"""
-Android animation 组件 — Animator, ValueAnimator, ObjectAnimator, 插值器等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import threading
-import time as _time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, TypeVar
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# TypeEvaluator
-# ═══════════════════════════════════════════════════════════════
-
-class TypeEvaluator(Stub):
- """TypeEvaluator — 类型估值器接口"""
-
- def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> Any:
- return startValue
-
-
-class FloatEvaluator(TypeEvaluator):
- """FloatEvaluator — 浮点估值器"""
-
- def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> float:
- sv = float(startValue)
- ev = float(endValue)
- return sv + fraction * (ev - sv)
-
-
-class IntEvaluator(TypeEvaluator):
- """IntEvaluator — 整数估值器"""
-
- def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> int:
- sv = int(startValue)
- ev = int(endValue)
- return int(sv + fraction * (ev - sv))
-
-
-class PointFEvaluator(TypeEvaluator):
- """PointFEvaluator — PointF 估值器"""
-
- def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> Any:
- if hasattr(startValue, 'x') and hasattr(startValue, 'y'):
- sv_x, sv_y = startValue.x, startValue.y
- ev_x, ev_y = endValue.x, endValue.y
- class PointF:
- def __init__(self, x, y):
- self.x = x
- self.y = y
- return PointF(sv_x + fraction * (ev_x - sv_x),
- sv_y + fraction * (ev_y - sv_y))
- return startValue
-
-
-class RectEvaluator(TypeEvaluator):
- """RectEvaluator — Rect 估值器"""
-
- def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> Any:
- if hasattr(startValue, 'left') and hasattr(startValue, 'top'):
- class Rect:
- def __init__(self, l, t, r, b):
- self.left = l
- self.top = t
- self.right = r
- self.bottom = b
- return Rect(
- int(startValue.left + fraction * (endValue.left - startValue.left)),
- int(startValue.top + fraction * (endValue.top - startValue.top)),
- int(startValue.right + fraction * (endValue.right - startValue.right)),
- int(startValue.bottom + fraction * (endValue.bottom - startValue.bottom)),
- )
- return startValue
-
-
-class ArgbEvaluator(TypeEvaluator):
- """ArgbEvaluator — ARGB 颜色估值器"""
-
- def evaluate(self, fraction: float, startValue: Any, endValue: Any) -> int:
- sv = int(startValue)
- ev = int(endValue)
- a = ((sv >> 24) & 0xFF) + int(fraction * (((ev >> 24) & 0xFF) - ((sv >> 24) & 0xFF)))
- r = ((sv >> 16) & 0xFF) + int(fraction * (((ev >> 16) & 0xFF) - ((sv >> 16) & 0xFF)))
- g = ((sv >> 8) & 0xFF) + int(fraction * (((ev >> 8) & 0xFF) - ((sv >> 8) & 0xFF)))
- b = (sv & 0xFF) + int(fraction * ((ev & 0xFF) - (sv & 0xFF)))
- return (min(a, 255) << 24) | (min(r, 255) << 16) | (min(g, 255) << 8) | min(b, 255)
-
-
-# ═══════════════════════════════════════════════════════════════
-# TimeInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class TimeInterpolator(Stub):
- """TimeInterpolator — 时间插值器接口"""
-
- def getInterpolation(self, input_: float) -> float:
- return input_
-
-
-class AccelerateDecelerateInterpolator(TimeInterpolator):
- """AccelerateDecelerateInterpolator — 加速减速插值器"""
-
- def getInterpolation(self, input_: float) -> float:
- return (math.cos((input_ + 1) * math.pi) / 2.0) + 0.5
-
-
-class AccelerateInterpolator(TimeInterpolator):
- """AccelerateInterpolator — 加速插值器"""
-
- def __init__(self, factor: float = 1.0):
- super().__init__()
- self._factor = factor
-
- def getInterpolation(self, input_: float) -> float:
- if self._factor == 1.0:
- return input_ * input_
- return input_ ** (2.0 * self._factor)
-
-
-class DecelerateInterpolator(TimeInterpolator):
- """DecelerateInterpolator — 减速插值器"""
-
- def __init__(self, factor: float = 1.0):
- super().__init__()
- self._factor = factor
-
- def getInterpolation(self, input_: float) -> float:
- if self._factor == 1.0:
- return 1.0 - (1.0 - input_) * (1.0 - input_)
- return 1.0 - (1.0 - input_) ** (2.0 * self._factor)
-
-
-class LinearInterpolator(TimeInterpolator):
- """LinearInterpolator — 线性插值器"""
-
- def getInterpolation(self, input_: float) -> float:
- return input_
-
-
-class BounceInterpolator(TimeInterpolator):
- """BounceInterpolator — 弹跳插值器"""
-
- def getInterpolation(self, input_: float) -> float:
- t = input_
- if t < 0.363636:
- return 7.5625 * t * t
- elif t < 0.727272:
- t -= 0.545454
- return 7.5625 * t * t + 0.75
- elif t < 0.909090:
- t -= 0.818181
- return 7.5625 * t * t + 0.9375
- else:
- t -= 0.954545
- return 7.5625 * t * t + 0.984375
-
-
-class AnticipateInterpolator(TimeInterpolator):
- """AnticipateInterpolator — 预期插值器"""
-
- def __init__(self, tension: float = 2.0):
- super().__init__()
- self._tension = tension
-
- def getInterpolation(self, input_: float) -> float:
- return input_ * input_ * ((self._tension + 1) * input_ - self._tension)
-
-
-class OvershootInterpolator(TimeInterpolator):
- """OvershootInterpolator — 过冲插值器"""
-
- def __init__(self, tension: float = 2.0):
- super().__init__()
- self._tension = tension
-
- def getInterpolation(self, input_: float) -> float:
- t = input_ - 1.0
- return t * t * ((self._tension + 1) * t + self._tension) + 1.0
-
-
-class AnticipateOvershootInterpolator(TimeInterpolator):
- """AnticipateOvershootInterpolator — 预期过冲插值器"""
-
- def __init__(self, tension: float = 2.0, extraTension: float = 1.5):
- super().__init__()
- self._tension = tension
- self._extra_tension = extraTension
-
- def getInterpolation(self, input_: float) -> float:
- if input_ < 0.5:
- t = input_ * 2.0
- return 0.5 * t * t * ((self._tension + 1) * t - self._tension)
- else:
- t = (input_ - 0.5) * 2.0 - 1.0
- return 0.5 * (t * t * ((self._tension + 1) * t + self._tension) + 2.0)
-
-
-class CycleInterpolator(TimeInterpolator):
- """CycleInterpolator — 周期插值器"""
-
- def __init__(self, cycles: float = 1.0):
- super().__init__()
- self._cycles = cycles
-
- def getInterpolation(self, input_: float) -> float:
- return math.sin(2 * math.pi * self._cycles * input_)
-
-
-class PathInterpolator(TimeInterpolator):
- """PathInterpolator — 路径插值器"""
-
- def __init__(self, controlX1: float = 0.0, controlY1: float = 0.0,
- controlX2: float = 1.0, controlY2: float = 1.0):
- super().__init__()
- self._cx1 = controlX1
- self._cy1 = controlY1
- self._cx2 = controlX2
- self._cy2 = controlY2
-
- def getInterpolation(self, input_: float) -> float:
- # Cubic bezier approximation
- t = input_
- return (3 * self._cy1 * t * (1 - t) ** 2 +
- 3 * self._cy2 * t ** 2 * (1 - t) +
- t ** 3)
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimatorListener
-# ═══════════════════════════════════════════════════════════════
-
-class AnimatorListener(Stub):
- """AnimatorListener — 动画监听器"""
-
- def onAnimationStart(self, animation: "Animator"):
- pass
-
- def onAnimationEnd(self, animation: "Animator"):
- pass
-
- def onAnimationCancel(self, animation: "Animator"):
- pass
-
- def onAnimationRepeat(self, animation: "Animator"):
- pass
-
-
-class AnimatorPauseListener(Stub):
- """AnimatorPauseListener — 动画暂停监听器"""
-
- def onAnimationPause(self, animation: "Animator"):
- pass
-
- def onAnimationResume(self, animation: "Animator"):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Animator
-# ═══════════════════════════════════════════════════════════════
-
-class Animator(Stub):
- """Animator — 动画基类"""
-
- def __init__(self):
- super().__init__()
- self._duration: int = 300
- self._start_delay: int = 0
- self._interpolator: Optional[TimeInterpolator] = None
- self._listeners: List[AnimatorListener] = []
- self._pause_listeners: List[AnimatorPauseListener] = []
- self._running: bool = False
- self._started: bool = False
- self._paused: bool = False
- self._start_time: float = 0.0
-
- def start(self):
- self._running = True
- self._started = True
- self._start_time = _time.time() + self._start_delay / 1000.0
- self._notify_start()
-
- def end(self):
- if self._running:
- self._running = False
- self._notify_end()
-
- def cancel(self):
- if self._running:
- self._running = False
- self._started = False
- self._notify_cancel()
-
- def pause(self):
- if self._running and not self._paused:
- self._paused = True
- for l in self._pause_listeners:
- l.onAnimationPause(self)
-
- def resume(self):
- if self._paused:
- self._paused = False
- for l in self._pause_listeners:
- l.onAnimationResume(self)
-
- def isRunning(self) -> bool:
- return self._running
-
- def isStarted(self) -> bool:
- return self._started
-
- def isPaused(self) -> bool:
- return self._paused
-
- def addListener(self, listener: AnimatorListener):
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeListener(self, listener: AnimatorListener):
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def getListeners(self) -> List[AnimatorListener]:
- return list(self._listeners)
-
- def addPauseListener(self, listener: AnimatorPauseListener):
- if listener not in self._pause_listeners:
- self._pause_listeners.append(listener)
-
- def removePauseListener(self, listener: AnimatorPauseListener):
- if listener in self._pause_listeners:
- self._pause_listeners.remove(listener)
-
- def setDuration(self, duration: int) -> "Animator":
- self._duration = duration
- return self
-
- def getDuration(self) -> int:
- return self._duration
-
- def setStartDelay(self, startDelay: int) -> "Animator":
- self._start_delay = startDelay
- return self
-
- def getStartDelay(self) -> int:
- return self._start_delay
-
- def setInterpolator(self, interpolator: TimeInterpolator):
- self._interpolator = interpolator
-
- def getInterpolator(self) -> Optional[TimeInterpolator]:
- return self._interpolator
-
- def clone(self) -> "Animator":
- cloned = Animator()
- cloned._duration = self._duration
- cloned._start_delay = self._start_delay
- cloned._interpolator = self._interpolator
- return cloned
-
- def _notify_start(self):
- for l in self._listeners:
- l.onAnimationStart(self)
-
- def _notify_end(self):
- for l in self._listeners:
- l.onAnimationEnd(self)
-
- def _notify_cancel(self):
- for l in self._listeners:
- l.onAnimationCancel(self)
-
- def _notify_repeat(self):
- for l in self._listeners:
- l.onAnimationRepeat(self)
-
- def toString(self) -> str:
- return f"Animator@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ValueAnimator.AnimatorUpdateListener
-# ═══════════════════════════════════════════════════════════════
-
-class ValueAnimator:
- class AnimatorUpdateListener(Stub):
- """AnimatorUpdateListener — 值更新监听器"""
-
- def onAnimationUpdate(self, animation: "ValueAnimator"):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ValueAnimator
-# ═══════════════════════════════════════════════════════════════
-
-class ValueAnimator(Animator):
- """ValueAnimator — 值动画"""
-
- INFINITE = -1
- RESTART = 1
- REVERSE = 2
-
- def __init__(self):
- super().__init__()
- self._values: List[Any] = []
- self._animated_value: Any = None
- self._animated_fraction: float = 0.0
- self._repeat_count: int = 0
- self._repeat_mode: int = self.RESTART
- self._evaluator: Optional[TypeEvaluator] = None
- self._update_listeners: List[ValueAnimator.AnimatorUpdateListener] = []
- self._current_play_time: int = 0
- self._reverse_direction: bool = False
- self._property_name: Optional[str] = None
-
- @staticmethod
- def ofInt(*values: int) -> "ValueAnimator":
- anim = ValueAnimator()
- anim._values = list(values)
- anim._evaluator = IntEvaluator()
- return anim
-
- @staticmethod
- def ofFloat(*values: float) -> "ValueAnimator":
- anim = ValueAnimator()
- anim._values = list(values)
- anim._evaluator = FloatEvaluator()
- return anim
-
- @staticmethod
- def ofObject(*values: Any) -> "ValueAnimator":
- anim = ValueAnimator()
- anim._values = list(values)
- return anim
-
- def setIntValues(self, *values: int):
- self._values = list(values)
-
- def setFloatValues(self, *values: float):
- self._values = list(values)
-
- def setObjectValues(self, *values: Any):
- self._values = list(values)
-
- def getAnimatedValue(self) -> Any:
- return self._animated_value
-
- def getAnimatedFraction(self) -> float:
- return self._animated_fraction
-
- def setRepeatCount(self, count: int):
- self._repeat_count = count
-
- def getRepeatCount(self) -> int:
- return self._repeat_count
-
- def setRepeatMode(self, mode: int):
- self._repeat_mode = mode
-
- def getRepeatMode(self) -> int:
- return self._repeat_mode
-
- def setEvaluator(self, evaluator: TypeEvaluator):
- self._evaluator = evaluator
-
- def getEvaluator(self) -> Optional[TypeEvaluator]:
- return self._evaluator
-
- def setCurrentPlayTime(self, playTime: int):
- self._current_play_time = playTime
- if self._duration > 0:
- self._animated_fraction = playTime / self._duration
- self._evaluate()
-
- def getCurrentPlayTime(self) -> int:
- return self._current_play_time
-
- def reverse(self):
- self._reverse_direction = not self._reverse_direction
- self.start()
-
- def addUpdateListener(self, listener: ValueAnimator.AnimatorUpdateListener):
- if listener not in self._update_listeners:
- self._update_listeners.append(listener)
-
- def removeUpdateListener(self, listener: ValueAnimator.AnimatorUpdateListener):
- if listener in self._update_listeners:
- self._update_listeners.remove(listener)
-
- def removeAllUpdateListeners(self):
- self._update_listeners.clear()
-
- def start(self):
- super().start()
- if len(self._values) >= 2:
- self._evaluate()
-
- def _evaluate(self):
- if len(self._values) >= 2 and self._evaluator:
- fraction = self._animated_fraction
- if self._interpolator:
- fraction = self._interpolator.getInterpolation(fraction)
- self._animated_value = self._evaluator.evaluate(
- fraction, self._values[0], self._values[-1]
- )
- for l in self._update_listeners:
- l.onAnimationUpdate(self)
-
- def clone(self) -> "ValueAnimator":
- cloned = ValueAnimator()
- cloned._values = list(self._values)
- cloned._duration = self._duration
- cloned._start_delay = self._start_delay
- cloned._repeat_count = self._repeat_count
- cloned._repeat_mode = self._repeat_mode
- cloned._evaluator = self._evaluator
- cloned._interpolator = self._interpolator
- return cloned
-
- def toString(self) -> str:
- return f"ValueAnimator@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ObjectAnimator
-# ═══════════════════════════════════════════════════════════════
-
-class ObjectAnimator(ValueAnimator):
- """ObjectAnimator — 对象属性动画"""
-
- def __init__(self):
- super().__init__()
- self._target: Any = None
- self._property_name: Optional[str] = None
-
- @staticmethod
- def ofInt(target: Any, propertyName: str, *values: int) -> "ObjectAnimator":
- anim = ObjectAnimator()
- anim._target = target
- anim._property_name = propertyName
- anim._values = list(values)
- anim._evaluator = IntEvaluator()
- return anim
-
- @staticmethod
- def ofFloat(target: Any, propertyName: str, *values: float) -> "ObjectAnimator":
- anim = ObjectAnimator()
- anim._target = target
- anim._property_name = propertyName
- anim._values = list(values)
- anim._evaluator = FloatEvaluator()
- return anim
-
- @staticmethod
- def ofObject(target: Any, propertyName: str, *values: Any) -> "ObjectAnimator":
- anim = ObjectAnimator()
- anim._target = target
- anim._property_name = propertyName
- anim._values = list(values)
- return anim
-
- def setPropertyName(self, propertyName: str):
- self._property_name = propertyName
-
- def getPropertyName(self) -> Optional[str]:
- return self._property_name
-
- def getTarget(self) -> Any:
- return self._target
-
- def setTarget(self, target: Any):
- self._target = target
-
- def setProperty(self, property_: Any):
- pass
-
- def setupStartValues(self):
- pass
-
- def setupEndValues(self):
- pass
-
- def clone(self) -> "ObjectAnimator":
- cloned = ObjectAnimator()
- cloned._target = self._target
- cloned._property_name = self._property_name
- cloned._values = list(self._values)
- cloned._duration = self._duration
- cloned._start_delay = self._start_delay
- cloned._evaluator = self._evaluator
- cloned._interpolator = self._interpolator
- return cloned
-
- def toString(self) -> str:
- return f"ObjectAnimator{{property={self._property_name}, target={self._target}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimatorSet
-# ═══════════════════════════════════════════════════════════════
-
-class AnimatorSet(Animator):
- """AnimatorSet — 动画集合"""
-
- def __init__(self):
- super().__init__()
- self._children: List[Animator] = []
- self._play_order: List[Animator] = []
-
- def play(self, anim: Animator) -> "AnimatorSet.Builder":
- return self.Builder(self, anim)
-
- def playSequentially(self, *items: Animator):
- self._children = list(items)
- self._play_order = list(items)
-
- def playTogether(self, *items: Animator):
- self._children = list(items)
- self._play_order = list(items)
-
- def start(self):
- super().start()
- for anim in self._play_order:
- anim.start()
-
- def end(self):
- super().end()
- for anim in self._play_order:
- anim.end()
-
- def cancel(self):
- super().cancel()
- for anim in self._play_order:
- anim.cancel()
-
- class Builder(Stub):
- """AnimatorSet.Builder — 构建器"""
-
- def __init__(self, parent: "AnimatorSet", anim: Animator):
- super().__init__()
- self._parent = parent
- self._current = anim
-
- def with_(self, anim: Animator) -> "AnimatorSet.Builder":
- self._parent._play_order.append(anim)
- return self
-
- def before(self, anim: Animator) -> "AnimatorSet.Builder":
- self._parent._play_order.append(anim)
- return self
-
- def after(self, anim: Animator) -> "AnimatorSet.Builder":
- idx = self._parent._play_order.index(self._current) if self._current in self._parent._play_order else -1
- if idx >= 0:
- self._parent._play_order.insert(idx + 1, anim)
- else:
- self._parent._play_order.append(anim)
- return self
-
- def after(self, delay: int) -> "AnimatorSet.Builder":
- return self
-
- def toString(self) -> str:
- return f"AnimatorSet{{{len(self._children)} animations}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TimeAnimator
-# ═══════════════════════════════════════════════════════════════
-
-class TimeAnimator(ValueAnimator):
- """TimeAnimator — 时间动画"""
-
- class TimeListener(Stub):
- """TimeListener — 时间监听器"""
-
- def onTimeUpdate(self, animation: "TimeAnimator", elapsedTime: int, totalTime: int):
- pass
-
- def __init__(self):
- super().__init__()
- self._time_listener: Optional[TimeAnimator.TimeListener] = None
- self._elapsed_time: int = 0
- self._total_time: int = 0
-
- def setTimeListener(self, listener: TimeAnimator.TimeListener):
- self._time_listener = listener
-
- def start(self):
- super().start()
- if self._time_listener:
- self._time_listener.onTimeUpdate(self, self._elapsed_time, self._total_time)
-
- def toString(self) -> str:
- return f"TimeAnimator@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Keyframe
-# ═══════════════════════════════════════════════════════════════
-
-class Keyframe(Stub):
- """Keyframe — 关键帧"""
-
- def __init__(self, fraction: float):
- super().__init__()
- self._fraction: float = fraction
- self._value: Any = None
- self._type: Optional[type] = None
- self._interpolator: Optional[TimeInterpolator] = None
-
- @staticmethod
- def ofInt(fraction: float, value: int) -> "Keyframe":
- kf = Keyframe(fraction)
- kf._value = value
- kf._type = int
- return kf
-
- @staticmethod
- def ofFloat(fraction: float, value: float) -> "Keyframe":
- kf = Keyframe(fraction)
- kf._value = value
- kf._type = float
- return kf
-
- @staticmethod
- def ofObject(fraction: float, value: Any = None) -> "Keyframe":
- kf = Keyframe(fraction)
- kf._value = value
- return kf
-
- def setValue(self, value: Any):
- self._value = value
-
- def getValue(self) -> Any:
- return self._value
-
- def setFraction(self, fraction: float):
- self._fraction = fraction
-
- def getFraction(self) -> float:
- return self._fraction
-
- def getType(self) -> Optional[type]:
- return self._type
-
- def setInterpolator(self, interpolator: Optional[TimeInterpolator]):
- self._interpolator = interpolator
-
- def getInterpolator(self) -> Optional[TimeInterpolator]:
- return self._interpolator
-
- def clone(self) -> "Keyframe":
- kf = Keyframe(self._fraction)
- kf._value = self._value
- kf._type = self._type
- kf._interpolator = self._interpolator
- return kf
-
- def toString(self) -> str:
- return f"Keyframe{{fraction={self._fraction}, value={self._value}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PropertyValuesHolder
-# ═══════════════════════════════════════════════════════════════
-
-class PropertyValuesHolder(Stub):
- """PropertyValuesHolder — 属性值持有者"""
-
- def __init__(self):
- super().__init__()
- self._property_name: str = ""
- self._values: List[Any] = []
- self._animated_value: Any = None
- self._evaluator: Optional[TypeEvaluator] = None
- self._keyframes: List[Keyframe] = []
-
- @staticmethod
- def ofInt(propertyName: str, *values: int) -> "PropertyValuesHolder":
- holder = PropertyValuesHolder()
- holder._property_name = propertyName
- holder._values = list(values)
- return holder
-
- @staticmethod
- def ofFloat(propertyName: str, *values: float) -> "PropertyValuesHolder":
- holder = PropertyValuesHolder()
- holder._property_name = propertyName
- holder._values = list(values)
- return holder
-
- @staticmethod
- def ofObject(propertyName: str, *values: Any) -> "PropertyValuesHolder":
- holder = PropertyValuesHolder()
- holder._property_name = propertyName
- holder._values = list(values)
- return holder
-
- @staticmethod
- def ofKeyframes(propertyName: str, *keyframes: Keyframe) -> "PropertyValuesHolder":
- holder = PropertyValuesHolder()
- holder._property_name = propertyName
- holder._keyframes = list(keyframes)
- return holder
-
- def setPropertyName(self, propertyName: str):
- self._property_name = propertyName
-
- def getPropertyName(self) -> str:
- return self._property_name
-
- def getAnimatedValue(self) -> Any:
- return self._animated_value
-
- def setEvaluator(self, evaluator: TypeEvaluator):
- self._evaluator = evaluator
-
- def clone(self) -> "PropertyValuesHolder":
- holder = PropertyValuesHolder()
- holder._property_name = self._property_name
- holder._values = list(self._values)
- holder._keyframes = list(self._keyframes)
- holder._evaluator = self._evaluator
- return holder
-
- def toString(self) -> str:
- return f"PropertyValuesHolder{{property={self._property_name}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TypeConverter
-# ═══════════════════════════════════════════════════════════════
-
-class TypeConverter(Stub):
- """TypeConverter — 类型转换器"""
-
- def convert(self, value: Any) -> Any:
- return value
-
-
-# ═══════════════════════════════════════════════════════════════
-# LayoutTransition
-# ═══════════════════════════════════════════════════════════════
-
-class LayoutTransition(Stub):
- """LayoutTransition — 布局过渡动画"""
-
- APPEARING = 0
- CHANGE_APPEARING = 1
- CHANGE_DISAPPEARING = 2
- DISAPPEARING = 3
- CHANGING = 4
-
- def __init__(self):
- super().__init__()
- self._animators: Dict[int, Optional[Animator]] = {
- self.APPEARING: None,
- self.CHANGE_APPEARING: None,
- self.CHANGE_DISAPPEARING: None,
- self.DISAPPEARING: None,
- self.CHANGING: None,
- }
-
- def setAnimator(self, transitionType: int, animator: Animator):
- self._animators[transitionType] = animator
-
- def getAnimator(self, transitionType: int) -> Optional[Animator]:
- return self._animators.get(transitionType)
-
- def startTransition(self, container: Any, transitionType: int):
- pass
-
- def endTransition(self, transitionType: int):
- pass
-
- def toString(self) -> str:
- return f"LayoutTransition@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# StateListAnimator
-# ═══════════════════════════════════════════════════════════════
-
-class StateListAnimator(Stub):
- """StateListAnimator — 状态列表动画"""
-
- def __init__(self):
- super().__init__()
- self._tuples: List[Tuple[List[int], Animator]] = []
- self._target: Any = None
-
- def addState(self, specs: List[int], animator: Animator):
- self._tuples.append((specs, animator))
-
- def setTarget(self, target: Any):
- self._target = target
-
- def clone(self) -> "StateListAnimator":
- cloned = StateListAnimator()
- cloned._tuples = list(self._tuples)
- return cloned
-
- def toString(self) -> str:
- return f"StateListAnimator{{{len(self._tuples)} states}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Animator",
- "ValueAnimator",
- "ObjectAnimator",
- "AnimatorSet",
- "TimeAnimator",
- "AnimatorListener",
- "AnimatorPauseListener",
- "TypeEvaluator",
- "FloatEvaluator",
- "IntEvaluator",
- "PointFEvaluator",
- "RectEvaluator",
- "ArgbEvaluator",
- "TypeConverter",
- "Keyframe",
- "PropertyValuesHolder",
- "LayoutTransition",
- "StateListAnimator",
- "TimeInterpolator",
- "AccelerateDecelerateInterpolator",
- "AccelerateInterpolator",
- "AnticipateInterpolator",
- "AnticipateOvershootInterpolator",
- "BounceInterpolator",
- "CycleInterpolator",
- "DecelerateInterpolator",
- "LinearInterpolator",
- "OvershootInterpolator",
- "PathInterpolator",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/app.py b/android_pyapi/android/app.py
deleted file mode 100644
index ab8cd54..0000000
--- a/android_pyapi/android/app.py
+++ /dev/null
@@ -1,2521 +0,0 @@
-"""
-Android App 组件 — Activity, Service, Intent, Notification 等
-方法签名完全对齐 Android SDK
-"""
-
-import json
-import os
-import time
-import re
-import sys
-import threading
-from datetime import datetime
-from typing import Any, Dict, List, Optional, Tuple, Callable, Union
-from urllib.parse import urlparse, urlunparse
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-from ..java.lang import IllegalStateException
-
-try:
- from .._linux_impl import IS_LINUX, LinuxNotify, LinuxShell, LinuxProcess, LinuxDisplay, LinuxUIAutomation, LinuxPower
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Intent
-# ═══════════════════════════════════════════════════════════════
-
-class Intent(Stub):
- """Android Intent — 组件间消息传递"""
-
- # Action 常量
- ACTION_MAIN = "android.intent.action.MAIN"
- ACTION_VIEW = "android.intent.action.VIEW"
- ACTION_EDIT = "android.intent.action.EDIT"
- ACTION_SEND = "android.intent.action.SEND"
- ACTION_CALL = "android.intent.action.CALL"
- ACTION_DIAL = "android.intent.action.DIAL"
- ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH"
- ACTION_PICK = "android.intent.action.PICK"
- ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT"
- ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE"
- ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"
- ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED"
- ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED"
- ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW"
- ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY"
- ACTION_TIME_TICK = "android.intent.action.TIME_TICK"
- ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED"
- ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON"
- ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF"
- ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE_CHANGED"
-
- # Flag 常量
- FLAG_ACTIVITY_NEW_TASK = 0x10000000
- FLAG_ACTIVITY_CLEAR_TOP = 0x04000000
- FLAG_ACTIVITY_SINGLE_TOP = 0x20000000
- FLAG_ACTIVITY_NO_HISTORY = 0x40000000
- FLAG_FROM_BACKGROUND = 0x00004000
- FLAG_RECEIVER_FOREGROUND = 0x10000000
- FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020
-
- # Category 常量
- CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"
- CATEGORY_DEFAULT = "android.intent.category.DEFAULT"
- CATEGORY_HOME = "android.intent.category.HOME"
- CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE"
- CATEGORY_OPENABLE = "android.intent.category.OPENABLE"
-
- def __init__(self, action: Optional[str] = None, uri: Optional[str] = None):
- super().__init__()
- self._action = action
- self._uri = uri
- self._data_str = None
- self._type = None
- self._extras: Dict[str, Any] = {}
- self._flags = 0
- self._categories: List[str] = []
- self._package = None
- self._component: Optional[Tuple[str, str]] = None # (pkg, cls)
- self._clip_data = None
-
- def setClass(self, package_context: Any, cls: type) -> "Intent":
- self._package = package_context.packageName if hasattr(package_context, 'packageName') else _package_name
- self._component = (self._package, cls.__name__ if isinstance(cls, type) else str(cls))
- return self
-
- def setAction(self, action: str) -> "Intent":
- self._action = action
- return self
-
- def getAction(self) -> Optional[str]:
- return self._action
-
- def setData(self, uri: str) -> "Intent":
- self._data_str = uri
- return self
-
- def getData(self) -> Optional[str]:
- return self._data_str
-
- def setType(self, type_: str) -> "Intent":
- self._type = type_
- return self
-
- def getType(self) -> Optional[str]:
- return self._type
-
- def setDataAndType(self, uri: str, type_: str) -> "Intent":
- self._data_str = uri
- self._type = type_
- return self
-
- def putExtra(self, name: str, value: Any) -> "Intent":
- self._extras[name] = value
- return self
-
- def getStringExtra(self, name: str) -> Optional[str]:
- return self._extras.get(name)
-
- def getIntExtra(self, name: str, default: int = 0) -> int:
- return self._extras.get(name, default)
-
- def getBooleanExtra(self, name: str, default: bool = False) -> bool:
- return self._extras.get(name, default)
-
- def getLongExtra(self, name: str, default: int = 0) -> int:
- return self._extras.get(name, default)
-
- def getFloatExtra(self, name: str, default: float = 0.0) -> float:
- return self._extras.get(name, default)
-
- def getDoubleExtra(self, name: str, default: float = 0.0) -> float:
- return self._extras.get(name, default)
-
- def getSerializableExtra(self, name: str):
- return self._extras.get(name)
-
- def getIntegerArrayListExtra(self, name: str) -> Optional[List[int]]:
- return self._extras.get(name)
-
- def getStringArrayListExtra(self, name: str) -> Optional[List[str]]:
- return self._extras.get(name)
-
- def getExtras(self) -> Dict[str, Any]:
- return self._extras
-
- def hasExtra(self, name: str) -> bool:
- return name in self._extras
-
- def removeExtra(self, name: str):
- self._extras.pop(name, None)
-
- def addCategory(self, category: str) -> "Intent":
- if category not in self._categories:
- self._categories.append(category)
- return self
-
- def getCategories(self) -> Optional[List[str]]:
- return self._categories if self._categories else None
-
- def hasCategory(self, category: str) -> bool:
- return category in self._categories
-
- def setFlags(self, flags: int) -> "Intent":
- self._flags = flags
- return self
-
- def getFlags(self) -> int:
- return self._flags
-
- def addFlags(self, flags: int) -> "Intent":
- self._flags |= flags
- return self
-
- def setPackage(self, package_name: str) -> "Intent":
- self._package = package_name
- return self
-
- def getPackage(self) -> Optional[str]:
- return self._package
-
- def setClassName(self, package_name: str, class_name: str) -> "Intent":
- self._component = (package_name, class_name)
- return self
-
- def resolveActivity(self, pm) -> Optional["ComponentName"]:
- from .content import ComponentName
- if self._component:
- return ComponentName(self._component[0], self._component[1])
- return None
-
- def createChooser(self, title: str) -> "Intent":
- """Create a chooser intent"""
- return self
-
- def toURI(self) -> str:
- return str(self._uri or self._data_str or "")
-
- def toString(self) -> str:
- return (
- f"Intent {{ act={self._action} "
- f"pkg={self._package} "
- f"cmp={self._component} "
- f"hasExtras={bool(self._extras)} }}"
- )
-
- def clone(self) -> "Intent":
- cloned = Intent(self._action, self._uri)
- cloned._data_str = self._data_str
- cloned._type = self._type
- cloned._extras = dict(self._extras)
- cloned._flags = self._flags
- cloned._categories = list(self._categories)
- cloned._package = self._package
- cloned._component = self._component
- return cloned
-
- def fillIn(self, other: "Intent", flags: int = 0) -> int:
- filled = 0
- if other._action and not self._action:
- self._action = other._action; filled |= 1
- if other._data_str and not self._data_str:
- self._data_str = other._data_str; filled |= 2
- if other._type and not self._type:
- self._type = other._type; filled |= 4
- if other._categories:
- for c in other._categories:
- if c not in self._categories:
- self._categories.append(c)
- filled |= 8
- return filled
-
- def filterEquals(self, other: "Intent") -> bool:
- return (
- self._action == other._action
- and self._data_str == other._data_str
- and self._type == other._type
- and self._package == other._package
- and self._component == other._component
- )
-
- def filterHashCode(self) -> int:
- return hash((self._action, self._data_str, self._type, self._package, self._component)) & 0x7FFFFFFF
-
- def getParcelableExtra(self, name):
- return self._extras.get(name) if self._extras else None
-
- def setComponent(self, component):
- self._component = component
- return self
-
- def getComponent(self):
- return getattr(self, '_component', None)
-
- def getDataString(self):
- data = self.getData()
- return str(data) if data else None
-
- def getScheme(self):
- data = self.getData()
- if data:
- return data.getScheme()
- return None
-
- def putExtras(self, src):
- if src._extras:
- if self._extras is None:
- self._extras = {}
- self._extras.update(src._extras)
- return self
-
- def putIntegerArrayListExtra(self, name, value):
- if self._extras is None:
- self._extras = {}
- self._extras[name] = value
- return self
-
- def putStringArrayListExtra(self, name, value):
- if self._extras is None:
- self._extras = {}
- self._extras[name] = value
- return self
-
- def putParcelableArrayListExtra(self, name, value):
- if self._extras is None:
- self._extras = {}
- self._extras[name] = value
- return self
-
- def getBundleExtra(self, name):
- return self._extras.get(name) if self._extras else None
-
- def putBundleExtra(self, name, value):
- if self._extras is None:
- self._extras = {}
- self._extras[name] = value
- return self
-
- def getParcelableArrayListExtra(self, name):
- return self._extras.get(name) if self._extras else None
-
- def getStringArrayExtra(self, name):
- return self._extras.get(name) if self._extras else None
-
- def getIntArrayExtra(self, name):
- return self._extras.get(name) if self._extras else None
-
- def getBooleanArrayExtra(self, name):
- return self._extras.get(name) if self._extras else None
-
- def getCharSequenceExtra(self, name):
- return self._extras.get(name) if self._extras else None
-
- def getCharSequenceArrayListExtra(self, name):
- return self._extras.get(name) if self._extras else None
-
- def removeCategory(self, category):
- if self._categories:
- self._categories.discard(category)
- return self
-
- def setSelector(self, selector):
- self._selector = selector
-
- def getSelector(self):
- return getattr(self, '_selector', None)
-
- def setSourceBounds(self, bounds):
- self._source_bounds = bounds
-
- def getSourceBounds(self):
- return getattr(self, '_source_bounds', None)
-
- def makeMainActivity(self, component):
- self.addCategory("android.intent.category.LAUNCHER")
- self.setComponent(component)
- return self
-
- def cloneFilter(self):
- new_intent = Intent(self.getAction())
- if self._categories:
- new_intent._categories = set(self._categories)
- if self._type:
- new_intent._type = self._type
- return new_intent
-
-
-# ═══════════════════════════════════════════════════════════════
-# ComponentName (forward reference)
-# ═══════════════════════════════════════════════════════════════
-
-class ComponentName(Stub):
- """Identifies a specific component class within a package"""
-
- def __init__(self, pkg: str, cls: str):
- super().__init__()
- self._package = pkg
- self._classname = cls
-
- def getPackageName(self) -> str:
- return self._package
-
- def getClassName(self) -> str:
- return self._classname
-
- def getShortClassName(self) -> str:
- return self._classname.split(".")[-1] if "." in self._classname else self._classname
-
- def flattenToString(self) -> str:
- return f"{self._package}/{self._classname}"
-
- def flattenToShortString(self) -> str:
- return f"{self._package}/{self.getShortClassName()}"
-
- @staticmethod
- def unflattenFromString(str_: str) -> Optional["ComponentName"]:
- if "/" in str_:
- parts = str_.split("/", 1)
- return ComponentName(parts[0], parts[1])
- return None
-
- def toString(self) -> str:
- return f"ComponentInfo{{{self._package}/{self._classname}}}"
-
- def __repr__(self):
- return self.toString()
-
-
-# ═══════════════════════════════════════════════════════════════
-# PendingIntent
-# ═══════════════════════════════════════════════════════════════
-
-class PendingIntent(Stub):
- """A description of an Intent and target action to perform with it"""
-
- FLAG_ONE_SHOT = 1 << 30
- FLAG_NO_CREATE = 1 << 29
- FLAG_CANCEL_CURRENT = 1 << 28
- FLAG_UPDATE_CURRENT = 1 << 27
- FLAG_IMMUTABLE = 1 << 26
-
- _pending_intents: Dict[int, "PendingIntent"] = {}
- _next_id = 1000
-
- def __init__(self, intent: Intent, request_code: int, flags: int):
- super().__init__()
- self._intent = intent
- self._request_code = request_code
- self._flags = flags
- self._id = PendingIntent._next_id
- PendingIntent._next_id += 1
- PendingIntent._pending_intents[self._id] = self
-
- @staticmethod
- def getActivity(context, request_code: int, intent: Intent, flags: int) -> "PendingIntent":
- pi = PendingIntent(intent, request_code, flags)
- pi._type = "activity"
- return pi
-
- @staticmethod
- def getBroadcast(context, request_code: int, intent: Intent, flags: int) -> "PendingIntent":
- pi = PendingIntent(intent, request_code, flags)
- pi._type = "broadcast"
- return pi
-
- @staticmethod
- def getService(context, request_code: int, intent: Intent, flags: int) -> "PendingIntent":
- pi = PendingIntent(intent, request_code, flags)
- pi._type = "service"
- return pi
-
- @staticmethod
- def getActivities(context, request_code: int, intents: List[Intent], flags: int) -> "PendingIntent":
- pi = PendingIntent(intents[0] if intents else Intent(), request_code, flags)
- pi._type = "activities"
- pi._intents = intents
- return pi
-
- def send(self):
- """Simulate sending the pending intent"""
- pass
-
- def cancel(self):
- PendingIntent._pending_intents.pop(self._id, None)
-
- def getIntent(self) -> Intent:
- return self._intent
-
- def getTargetPackage(self) -> str:
- return self._intent.getPackage() or ""
-
- def toString(self) -> str:
- return f"PendingIntent{{{hex(id(self))}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AlarmManager
-# ═══════════════════════════════════════════════════════════════
-
-class AlarmManager(Stub):
- """AlarmManager — 调度定时操作"""
-
- RTC_WAKEUP = 0
- RTC = 1
- ELAPSED_REALTIME = 3
- ELAPSED_REALTIME_WAKEUP = 2
- INTERVAL_FIFTEEN_MINUTES = 900000
- INTERVAL_HALF_HOUR = 1800000
- INTERVAL_HOUR = 3600000
- INTERVAL_DAY = 86400000
-
- def __init__(self):
- super().__init__()
- self._alarms: Dict[int, Dict] = {}
-
- def set(self, type_: int, trigger_at_ms: int, operation: PendingIntent):
- self._alarms[id(operation)] = {
- "type": type_,
- "trigger_at": trigger_at_ms,
- "operation": operation,
- "repeating": False,
- }
-
- def setRepeating(self, type_: int, trigger_at_ms: int, interval_ms: int, operation: PendingIntent):
- self._alarms[id(operation)] = {
- "type": type_,
- "trigger_at": trigger_at_ms,
- "interval": interval_ms,
- "operation": operation,
- "repeating": True,
- }
-
- def setExact(self, type_: int, trigger_at_ms: int, operation: PendingIntent):
- self.set(type_, trigger_at_ms, operation)
-
- def setAndAllowWhileIdle(self, type_: int, trigger_at_ms: int, operation: PendingIntent):
- self.set(type_, trigger_at_ms, operation)
-
- def setExactAndAllowWhileIdle(self, type_: int, trigger_at_ms: int, operation: PendingIntent):
- self.set(type_, trigger_at_ms, operation)
-
- def cancel(self, operation: PendingIntent):
- self._alarms.pop(id(operation), None)
-
- def getNextAlarmClock(self):
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# NotificationChannel
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationChannel(Stub):
- """Notification channel for Android O+"""
-
- IMPORTANCE_NONE = 0
- IMPORTANCE_MIN = 1
- IMPORTANCE_LOW = 2
- IMPORTANCE_DEFAULT = 3
- IMPORTANCE_HIGH = 4
- IMPORTANCE_MAX = 5
- IMPORTANCE_UNSPECIFIED = -1000
-
- def __init__(self, channel_id: str, name: str, importance: int):
- super().__init__()
- self._id = channel_id
- self._name = name
- self._importance = importance
- self._description = ""
- self._enabled = True
- self._show_badge = True
- self._sound = None
- self._lights = False
- self._vibration = True
- self._bypass_dnd = False
- self._lockscreen_visibility = 0
- self._group = None
- self._can_bubble = False
-
- def getId(self) -> str:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getImportance(self) -> int:
- return self._importance
-
- def setDescription(self, description: str):
- self._description = description
-
- def getDescription(self) -> str:
- return self._description
-
- def setShowBadge(self, show_badge: bool):
- self._show_badge = show_badge
-
- def canShowBadge(self) -> bool:
- return self._show_badge
-
- def enableLights(self, lights: bool):
- self._lights = lights
-
- def shouldShowLights(self) -> bool:
- return self._lights
-
- def enableVibration(self, vibration: bool):
- self._vibration = vibration
-
- def shouldVibrate(self) -> bool:
- return self._vibration
-
- def setBypassDnd(self, bypass_dnd: bool):
- self._bypass_dnd = bypass_dnd
-
- def canBypassDnd(self) -> bool:
- return self._bypass_dnd
-
- def setSound(self, sound: Any, audio_attributes: Any = None):
- self._sound = sound
-
- def getSound(self):
- return self._sound
-
- def setGroup(self, group_id: str):
- self._group = group_id
-
- def getGroup(self) -> Optional[str]:
- return self._group
-
- def setLockScreenVisibility(self, visibility: int):
- self._lockscreen_visibility = visibility
-
- def getLockScreenVisibility(self) -> int:
- return self._lockscreen_visibility
-
- def toString(self) -> str:
- return f"NotificationChannel(id={self._id}, name={self._name}, importance={self._importance})"
-
-
-class NotificationChannelGroup(Stub):
- """Group of notification channels"""
-
- def __init__(self, group_id: str, name: str):
- super().__init__()
- self._id = group_id
- self._name = name
- self._channels: List[NotificationChannel] = []
-
- def getId(self) -> str:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getChannels(self) -> List[NotificationChannel]:
- return list(self._channels)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Notification
-# ═══════════════════════════════════════════════════════════════
-
-class Notification(Stub):
- """Android Notification"""
-
- DEFAULT_ALL = -1
- DEFAULT_SOUND = 1
- DEFAULT_VIBRATE = 2
- DEFAULT_LIGHTS = 4
- EXTRA_TITLE = "android.title"
- EXTRA_TEXT = "android.text"
- EXTRA_SUB_TEXT = "android.subText"
- EXTRA_INFO_TEXT = "android.infoText"
- EXTRA_SUMMARY_TEXT = "android.summaryText"
- EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID"
- EXTRA_BIG_TEXT = "android.bigText"
- EXTRA_PICTURE = "android.picture"
- PRIORITY_MIN = -2
- PRIORITY_LOW = -1
- PRIORITY_DEFAULT = 0
- PRIORITY_HIGH = 1
- PRIORITY_MAX = 2
- VISIBILITY_PRIVATE = 0
- VISIBILITY_PUBLIC = 1
- VISIBILITY_SECRET = -1
-
- class Builder(Stub):
- """Notification builder pattern"""
-
- def __init__(self, context, channel_id: Optional[str] = None):
- super().__init__()
- self._context = context
- self._channel_id = channel_id or ""
- self._title = ""
- self._text = ""
- self._sub_text = ""
- self._info_text = ""
- self._summary_text = ""
- self._big_text = ""
- self._small_icon = 0
- self._large_icon = None
- self._color = 0
- self._priority = Notification.PRIORITY_DEFAULT
- self._defaults = 0
- self._auto_cancel = False
- self._ongoing = False
- self._when = 0
- self._number = 0
- self._content_intent = None
- self._delete_intent = None
- self._full_screen_intent = None
- self._ticker = ""
- self._visibility = Notification.VISIBILITY_PRIVATE
- self._category = ""
- self._group = ""
- self._group_summary = False
- self._public_version = None
- self._extras: Dict[str, Any] = {}
- self._actions: List[Dict] = []
- self._style = None
- self._badge_icon_type = 0
- self._settings_text = None
- self._uses_channel_defaults = False
-
- def setChannelId(self, channel_id: str) -> "Notification.Builder":
- self._channel_id = channel_id
- return self
-
- def setContentTitle(self, title: str) -> "Notification.Builder":
- self._title = title
- return self
-
- def setContentText(self, text: str) -> "Notification.Builder":
- self._text = text
- return self
-
- def setSubText(self, text: str) -> "Notification.Builder":
- self._sub_text = text
- return self
-
- def setContentInfo(self, info: str) -> "Notification.Builder":
- self._info_text = info
- return self
-
- def setSummaryText(self, text: str) -> "Notification.Builder":
- self._summary_text = text
- return self
-
- def setSmallIcon(self, icon: int) -> "Notification.Builder":
- self._small_icon = icon
- return self
-
- def setLargeIcon(self, icon: Any) -> "Notification.Builder":
- self._large_icon = icon
- return self
-
- def setColor(self, color: int) -> "Notification.Builder":
- self._color = color
- return self
-
- def setPriority(self, priority: int) -> "Notification.Builder":
- self._priority = priority
- return self
-
- def setDefaults(self, defaults: int) -> "Notification.Builder":
- self._defaults = defaults
- return self
-
- def setAutoCancel(self, auto_cancel: bool) -> "Notification.Builder":
- self._auto_cancel = auto_cancel
- return self
-
- def setOngoing(self, ongoing: bool) -> "Notification.Builder":
- self._ongoing = ongoing
- return self
-
- def setWhen(self, when: int) -> "Notification.Builder":
- self._when = when
- return self
-
- def setNumber(self, number: int) -> "Notification.Builder":
- self._number = number
- return self
-
- def setContentIntent(self, intent: PendingIntent) -> "Notification.Builder":
- self._content_intent = intent
- return self
-
- def setDeleteIntent(self, intent: PendingIntent) -> "Notification.Builder":
- self._delete_intent = intent
- return self
-
- def setFullScreenIntent(self, intent: PendingIntent, high_priority: bool) -> "Notification.Builder":
- self._full_screen_intent = intent
- return self
-
- def setTicker(self, ticker: str) -> "Notification.Builder":
- self._ticker = ticker
- return self
-
- def setVisibility(self, visibility: int) -> "Notification.Builder":
- self._visibility = visibility
- return self
-
- def setCategory(self, category: str) -> "Notification.Builder":
- self._category = category
- return self
-
- def setGroup(self, group: str) -> "Notification.Builder":
- self._group = group
- return self
-
- def setGroupSummary(self, is_group_summary: bool) -> "Notification.Builder":
- self._group_summary = is_group_summary
- return self
-
- def setPublicVersion(self, notification: "Notification") -> "Notification.Builder":
- self._public_version = notification
- return self
-
- def addAction(self, icon: int, title: str, intent: PendingIntent) -> "Notification.Builder":
- self._actions.append({"icon": icon, "title": title, "intent": intent})
- return self
-
- def setStyle(self, style: Any) -> "Notification.Builder":
- self._style = style
- return self
-
- def setBadgeIconType(self, icon_type: int) -> "Notification.Builder":
- self._badge_icon_type = icon_type
- return self
-
- def setSettingsText(self, text: str) -> "Notification.Builder":
- self._settings_text = text
- return self
-
- def addExtras(self, extras: Dict[str, Any]) -> "Notification.Builder":
- if extras:
- self._extras.update(extras)
- return self
-
- def extend(self, builder: Any) -> "Notification.Builder":
- return self
-
- def build(self) -> "Notification":
- n = Notification()
- n._channel_id = self._channel_id
- n._title = self._title
- n._text = self._text
- n._sub_text = self._sub_text
- n._info_text = self._info_text
- n._summary_text = self._summary_text
- n._big_text = self._big_text
- n._small_icon = self._small_icon
- n._large_icon = self._large_icon
- n._color = self._color
- n._priority = self._priority
- n._defaults = self._defaults
- n._auto_cancel = self._auto_cancel
- n._ongoing = self._ongoing
- n._when = self._when or int(time.time() * 1000)
- n._number = self._number
- n._content_intent = self._content_intent
- n._delete_intent = self._delete_intent
- n._full_screen_intent = self._full_screen_intent
- n._ticker = self._ticker
- n._visibility = self._visibility
- n._category = self._category
- n._group = self._group
- n._group_summary = self._group_summary
- n._public_version = self._public_version
- n._actions = list(self._actions)
- n._style = self._style
- n._extras = dict(self._extras)
- return n
-
- def setProgress(self, max, progress, indeterminate):
- self._progress_max = max
- self._progress = progress
- self._progress_indeterminate = indeterminate
- return self
-
- def setShowWhen(self, show):
- self._show_when = show
- return self
-
- def setOnlyAlertOnce(self, onlyAlertOnce):
- self._only_alert_once = onlyAlertOnce
- return self
-
- def setLocalOnly(self, localOnly):
- self._local_only = localOnly
- return self
-
- def setSound(self, sound):
- self._sound = sound
- return self
-
- def setVibrate(self, pattern):
- self._vibrate = pattern
- return self
-
- def setLights(self, argb, onMs, offMs):
- self._light_color = argb
- self._light_on = onMs
- self._light_off = offMs
- return self
-
- def setSortKey(self, sortKey):
- self._sort_key = sortKey
- return self
-
- def setTimeoutAfter(self, timeoutMs):
- self._timeout_after = timeoutMs
- return self
-
- def setColorized(self, colorize):
- self._colorized = colorize
- return self
-
- def setUsesChronometer(self, usesChronometer):
- self._uses_chronometer = usesChronometer
- return self
-
- def setShortcutId(self, shortcutId):
- self._shortcut_id = shortcutId
- return self
-
- def setContent(self, views):
- self._content_view = views
- return self
-
- def __init__(self):
- super().__init__()
- self._channel_id = ""
- self._title = ""
- self._text = ""
- self._sub_text = ""
- self._info_text = ""
- self._summary_text = ""
- self._big_text = ""
- self._small_icon = 0
- self._large_icon = None
- self._color = 0
- self._priority = self.PRIORITY_DEFAULT
- self._defaults = 0
- self._auto_cancel = False
- self._ongoing = False
- self._when = 0
- self._number = 0
- self._content_intent = None
- self._delete_intent = None
- self._full_screen_intent = None
- self._ticker = ""
- self._visibility = self.VISIBILITY_PRIVATE
- self._category = ""
- self._group = ""
- self._group_summary = False
- self._public_version = None
- self._extras: Dict[str, Any] = {}
- self._actions: List[Dict] = []
- self._style = None
-
- def getChannelId(self) -> str:
- return self._channel_id
-
- def toString(self) -> str:
- return f"Notification(channel={self._channel_id}, title={self._title})"
-
-
-class NotificationCompat(Stub):
- """NotificationCompat — 兼容版本"""
-
- class Builder(Stub):
- def __init__(self, context, channel_id: Optional[str] = None):
- super().__init__()
- self._builder = Notification.Builder(context, channel_id)
-
- def setContentTitle(self, title: str) -> "NotificationCompat.Builder":
- self._builder.setContentTitle(title)
- return self
-
- def setContentText(self, text: str) -> "NotificationCompat.Builder":
- self._builder.setContentText(text)
- return self
-
- def setSmallIcon(self, icon: int) -> "NotificationCompat.Builder":
- self._builder.setSmallIcon(icon)
- return self
-
- def setPriority(self, priority: int) -> "NotificationCompat.Builder":
- self._builder.setPriority(priority)
- return self
-
- def setAutoCancel(self, auto_cancel: bool) -> "NotificationCompat.Builder":
- self._builder.setAutoCancel(auto_cancel)
- return self
-
- def setContentIntent(self, intent: PendingIntent) -> "NotificationCompat.Builder":
- self._builder.setContentIntent(intent)
- return self
-
- def setDefaults(self, defaults: int) -> "NotificationCompat.Builder":
- self._builder.setDefaults(defaults)
- return self
-
- def build(self) -> Notification:
- return self._builder.build()
-
-
-# ═══════════════════════════════════════════════════════════════
-# NotificationManager
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationManager(Stub):
- """NotificationManager — 发送通知"""
-
- IMPORTANCE_NONE = 0
- IMPORTANCE_MIN = 1
- IMPORTANCE_LOW = 2
- IMPORTANCE_DEFAULT = 3
- IMPORTANCE_HIGH = 4
- IMPORTANCE_MAX = 5
- IMPORTANCE_UNSPECIFIED = -1000
-
- def __init__(self):
- super().__init__()
- self._notifications: Dict[int, Notification] = {}
- self._channels: Dict[str, NotificationChannel] = {}
- self._groups: Dict[str, NotificationChannelGroup] = {}
- self._notification_id_counter = 0
-
- def notify(self, id_: int, notification: Notification):
- self._notifications[id_] = notification
- if _USE_LINUX:
- title = getattr(notification, "_title", "") or ""
- text = getattr(notification, "_text", "") or ""
- if title or text:
- LinuxNotify.send(title, text)
- else:
- sys.stderr.write(
- f"[NotificationManager] notify id={id_}: "
- f"title={notification._title} text={notification._text}\n"
- )
-
- def notifyAsPackage(self, package_name: str, tag: Optional[str], id_: int, notification: Notification):
- self.notify(id_, notification)
-
- def cancel(self, id_: int):
- self._notifications.pop(id_, None)
-
- def cancelAll(self):
- self._notifications.clear()
-
- def cancelAsPackage(self, package_name: str, tag: Optional[str], id_: int):
- self.cancel(id_)
-
- def createNotificationChannel(self, channel: NotificationChannel):
- self._channels[channel.getId()] = channel
- sys.stderr.write(
- f"[NotificationManager] create channel: {channel.getId()}\n"
- )
-
- def createNotificationChannels(self, channels: List[NotificationChannel]):
- for c in channels:
- self.createNotificationChannel(c)
-
- def getNotificationChannel(self, channel_id: str) -> Optional[NotificationChannel]:
- return self._channels.get(channel_id)
-
- def getNotificationChannels(self) -> List[NotificationChannel]:
- return list(self._channels.values())
-
- def deleteNotificationChannel(self, channel_id: str):
- self._channels.pop(channel_id, None)
-
- def createNotificationChannelGroup(self, group: NotificationChannelGroup):
- self._groups[group.getId()] = group
-
- def getNotificationChannelGroups(self) -> List[NotificationChannelGroup]:
- return list(self._groups.values())
-
- def getActiveNotifications(self) -> List[Notification]:
- return list(self._notifications.values())
-
- def areNotificationsEnabled(self) -> bool:
- return True
-
- def isNotificationPolicyAccessGranted(self) -> bool:
- return True
-
- def matchesCallFilter(self, address: Any) -> bool:
- return True
-
- def toString(self) -> str:
- return f"NotificationManager(notifications={len(self._notifications)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Dialog / AlertDialog / ProgressDialog / DatePickerDialog / TimePickerDialog
-# ═══════════════════════════════════════════════════════════════
-
-class Dialog(Stub):
- """Base dialog class"""
-
- def __init__(self, context, theme_res_id: int = 0):
- super().__init__()
- self._context = context
- self._theme_res_id = theme_res_id
- self._showing = False
- self._cancelable = True
- self._on_cancel_listener = None
- self._on_dismiss_listener = None
- self._on_show_listener = None
- self._title = ""
- self._window = None
-
- def show(self):
- self._showing = True
- sys.stderr.write(f"[Dialog] show: {self.__class__.__name__}\n")
-
- def dismiss(self):
- self._showing = False
- sys.stderr.write(f"[Dialog] dismiss: {self.__class__.__name__}\n")
-
- def isShowing(self) -> bool:
- return self._showing
-
- def cancel(self):
- self.dismiss()
- if self._on_cancel_listener:
- self._on_cancel_listener.onCancel(self)
-
- def setCancelable(self, flag: bool):
- self._cancelable = flag
-
- def setCanceledOnTouchOutside(self, cancel: bool):
- pass
-
- def setTitle(self, title: str):
- self._title = title
-
- def getContext(self):
- return self._context
-
- def setOnCancelListener(self, listener):
- self._on_cancel_listener = listener
-
- def setOnDismissListener(self, listener):
- self._on_dismiss_listener = listener
-
- def setOnShowListener(self, listener):
- self._on_show_listener = listener
-
- def getWindow(self):
- return self._window
-
- def findViewById(self, id_: int):
- return None
-
- def onBackPressed(self):
- if self._cancelable:
- self.cancel()
-
-
-class AlertDialog(Dialog):
- """Alert dialog with builder pattern"""
-
- BUTTON_POSITIVE = -1
- BUTTON_NEGATIVE = -2
- BUTTON_NEUTRAL = -3
-
- def __init__(self, context, theme_res_id: int = 0):
- super().__init__(context, theme_res_id)
- self._message = ""
- self._buttons: Dict[int, Dict] = {}
- self._items: List[str] = []
- self._single_choice_items = None
- self._multi_choice_items = None
- self._selected_index = -1
- self._selected_indices: List[int] = []
- self._view = None
- self._icon = 0
- self._custom_title = None
-
- class Builder(Stub):
- """AlertDialog builder"""
- def __init__(self, context, theme_res_id: int = 0):
- super().__init__()
- self._context = context
- self._theme_res_id = theme_res_id
- self._title = ""
- self._message = ""
- self._positive_text = ""
- self._positive_listener = None
- self._negative_text = ""
- self._negative_listener = None
- self._neutral_text = ""
- self._neutral_listener = None
- self._cancelable = True
- self._on_cancel_listener = None
- self._items: List[str] = []
- self._on_item_click_listener = None
- self._single_choice_items = None
- self._single_choice_selected = -1
- self._single_choice_listener = None
- self._multi_choice_items = None
- self._multi_choice_selected = None
- self._multi_choice_listener = None
- self._icon = 0
- self._view = None
- self._custom_title_view = None
-
- def setTitle(self, title: str) -> "AlertDialog.Builder":
- self._title = title
- return self
-
- def setMessage(self, message: str) -> "AlertDialog.Builder":
- self._message = message
- return self
-
- def setPositiveButton(self, text: str, listener=None) -> "AlertDialog.Builder":
- self._positive_text = text
- self._positive_listener = listener
- return self
-
- def setNegativeButton(self, text: str, listener=None) -> "AlertDialog.Builder":
- self._negative_text = text
- self._negative_listener = listener
- return self
-
- def setNeutralButton(self, text: str, listener=None) -> "AlertDialog.Builder":
- self._neutral_text = text
- self._neutral_listener = listener
- return self
-
- def setCancelable(self, cancelable: bool) -> "AlertDialog.Builder":
- self._cancelable = cancelable
- return self
-
- def setOnCancelListener(self, listener) -> "AlertDialog.Builder":
- self._on_cancel_listener = listener
- return self
-
- def setItems(self, items: List[str], listener=None) -> "AlertDialog.Builder":
- self._items = list(items)
- self._on_item_click_listener = listener
- return self
-
- def setSingleChoiceItems(self, items: List[str], checked_item: int, listener=None) -> "AlertDialog.Builder":
- self._single_choice_items = list(items)
- self._single_choice_selected = checked_item
- self._single_choice_listener = listener
- return self
-
- def setMultiChoiceItems(self, items: List[str], checked_items: List[bool], listener=None) -> "AlertDialog.Builder":
- self._multi_choice_items = list(items)
- self._multi_choice_selected = checked_items or []
- self._multi_choice_listener = listener
- return self
-
- def setIcon(self, icon: int) -> "AlertDialog.Builder":
- self._icon = icon
- return self
-
- def setView(self, view: Any) -> "AlertDialog.Builder":
- self._view = view
- return self
-
- def setCustomTitle(self, view: Any) -> "AlertDialog.Builder":
- self._custom_title_view = view
- return self
-
- def create(self) -> "AlertDialog":
- dialog = AlertDialog(self._context, self._theme_res_id)
- dialog._title = self._title
- dialog._message = self._message
- dialog._cancelable = self._cancelable
- dialog._icon = self._icon
- dialog._view = self._view
- if self._positive_text:
- dialog._buttons[AlertDialog.BUTTON_POSITIVE] = {
- "text": self._positive_text,
- "listener": self._positive_listener,
- }
- if self._negative_text:
- dialog._buttons[AlertDialog.BUTTON_NEGATIVE] = {
- "text": self._negative_text,
- "listener": self._negative_listener,
- }
- if self._neutral_text:
- dialog._buttons[AlertDialog.BUTTON_NEUTRAL] = {
- "text": self._neutral_text,
- "listener": self._neutral_listener,
- }
- dialog._items = list(self._items)
- dialog._single_choice_items = self._single_choice_items
- dialog._multi_choice_items = self._multi_choice_items
- return dialog
-
- def show(self) -> "AlertDialog":
- dialog = self.create()
- dialog.show()
- return dialog
-
-
-class ProgressDialog(AlertDialog):
- """Progress dialog with a progress bar"""
-
- STYLE_SPINNER = 0
- STYLE_HORIZONTAL = 1
-
- def __init__(self, context, theme_res_id: int = 0):
- super().__init__(context, theme_res_id)
- self._progress_style = ProgressDialog.STYLE_SPINNER
- self._progress = 0
- self._max = 100
- self._indeterminate = True
- self._progress_number_format = "%d/%d"
- self._progress_percent_format = "%d%%"
-
- def setProgressStyle(self, style: int):
- self._progress_style = style
-
- def setProgress(self, value: int):
- self._progress = value
-
- def getProgress(self) -> int:
- return self._progress
-
- def setMax(self, max_: int):
- self._max = max_
-
- def getMax(self) -> int:
- return self._max
-
- def setIndeterminate(self, indeterminate: bool):
- self._indeterminate = indeterminate
-
- def isIndeterminate(self) -> bool:
- return self._indeterminate
-
- def incrementProgressBy(self, diff: int):
- self._progress = min(self._max, max(0, self._progress + diff))
-
- @staticmethod
- def show(context, title: str, message: str, indeterminate: bool = True, cancelable: bool = False) -> "ProgressDialog":
- dialog = ProgressDialog(context)
- dialog.setTitle(title)
- dialog._message = message
- dialog._indeterminate = indeterminate
- dialog.setCancelable(cancelable)
- dialog.show()
- return dialog
-
-
-class DatePickerDialog(AlertDialog):
- """Date picker dialog"""
-
- def __init__(self, context, listener=None, year: int = 2024, month: int = 0, day_of_month: int = 1, theme_res_id: int = 0):
- super().__init__(context, theme_res_id)
- self._listener = listener
- self._year = year
- self._month = month
- self._day_of_month = day_of_month
- self._date_picker = None
-
- def getDatePicker(self):
- return self._date_picker
-
- def updateDate(self, year: int, month: int, day_of_month: int):
- self._year = year
- self._month = month
- self._day_of_month = day_of_month
-
- def onDateChanged(self, view, year: int, month: int, day: int):
- self._year = year
- self._month = month
- self._day_of_month = day
-
- class OnDateSetListener:
- def onDateSet(self, view, year: int, month: int, day_of_month: int):
- pass
-
-
-class TimePickerDialog(AlertDialog):
- """Time picker dialog"""
-
- def __init__(self, context, listener=None, hour_of_day: int = 12, minute: int = 0, is24_hour_view: bool = True, theme_res_id: int = 0):
- super().__init__(context, theme_res_id)
- self._listener = listener
- self._hour_of_day = hour_of_day
- self._minute = minute
- self._is24_hour_view = is24_hour_view
-
- class OnTimeSetListener:
- def onTimeSet(self, view, hour_of_day: int, minute: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Fragment / FragmentManager / FragmentTransaction
-# ═══════════════════════════════════════════════════════════════
-
-class Fragment(Stub):
- """Fragment — UI 片段"""
-
- def __init__(self):
- super().__init__()
- self._arguments: Optional[Bundle] = None
- self._activity = None
- self._view = None
- self._fragment_manager = None
- self._state = 0
- self._tag = None
- self._id = -1
- self._container_id = -1
- self._menu = True
- self._retain_instance = False
- self._target_fragment = None
- self._target_request_code = -1
- self._user_visible_hint = True
-
- def setArguments(self, args: "Bundle"):
- self._arguments = args
-
- def getArguments(self) -> Optional["Bundle"]:
- return self._arguments
-
- def getActivity(self):
- return self._activity
-
- def getContext(self):
- return self._activity
-
- def getFragmentManager(self) -> Optional["FragmentManager"]:
- return self._fragment_manager
-
- def getView(self):
- return self._view
-
- def getResources(self):
- if self._activity:
- return getattr(self._activity, 'getResources', lambda: None)()
- return None
-
- def getString(self, res_id: int, *args) -> str:
- return str(res_id)
-
- def getTag(self) -> Optional[str]:
- return self._tag
-
- def setId(self, id_: int):
- self._id = id_
-
- def getId(self) -> int:
- return self._id
-
- def onAttach(self, context):
- pass
-
- def onCreate(self, savedInstanceState: Optional["Bundle"] = None):
- pass
-
- def onCreateView(self, inflater, container, savedInstanceState):
- return None
-
- def onViewCreated(self, view, savedInstanceState: Optional["Bundle"] = None):
- pass
-
- def onStart(self):
- pass
-
- def onResume(self):
- pass
-
- def onPause(self):
- pass
-
- def onStop(self):
- pass
-
- def onDestroyView(self):
- pass
-
- def onDestroy(self):
- pass
-
- def onDetach(self):
- pass
-
- def onActivityCreated(self, savedInstanceState: Optional["Bundle"] = None):
- pass
-
- def onSaveInstanceState(self, out_state: "Bundle"):
- pass
-
- def onViewStateRestored(self, savedInstanceState: Optional["Bundle"] = None):
- pass
-
- def isAdded(self) -> bool:
- return self._activity is not None
-
- def isDetached(self) -> bool:
- return self._activity is None
-
- def isVisible(self) -> bool:
- return False
-
- def isRemoving(self) -> bool:
- return False
-
- def isInLayout(self) -> bool:
- return False
-
- def isResumed(self) -> bool:
- return self._state >= 7
-
- def setHasOptionsMenu(self, has_menu: bool):
- self._menu = has_menu
-
- def setRetainInstance(self, retain: bool):
- self._retain_instance = retain
-
- def getRetainInstance(self) -> bool:
- return self._retain_instance
-
- def setTargetFragment(self, fragment: "Fragment", request_code: int):
- self._target_fragment = fragment
- self._target_request_code = request_code
-
- def getTargetFragment(self) -> Optional["Fragment"]:
- return self._target_fragment
-
- def getTargetRequestCode(self) -> int:
- return self._target_request_code
-
- def setUserVisibleHint(self, is_visible_to_user: bool):
- self._user_visible_hint = is_visible_to_user
-
- def getUserVisibleHint(self) -> bool:
- return self._user_visible_hint
-
- def registerForContextMenu(self, view):
- pass
-
- def unregisterForContextMenu(self, view):
- pass
-
- def getChildFragmentManager(self):
- if not hasattr(self, '_child_fragment_manager'):
- from .app import FragmentManager
- self._child_fragment_manager = FragmentManager()
- return self._child_fragment_manager
-
- def getParentFragment(self):
- return getattr(self, '_parent_fragment', None)
-
- def onCreateOptionsMenu(self, menu, inflater):
- return False
-
- def onPrepareOptionsMenu(self, menu):
- return False
-
- def onOptionsItemSelected(self, item):
- return False
-
- def onCreateContextMenu(self, menu, v, menuInfo):
- pass
-
- def onContextItemSelected(self, item):
- return False
-
- def onContextMenuClosed(self, menu):
- pass
-
- def onConfigurationChanged(self, newConfig):
- pass
-
- def onLowMemory(self):
- pass
-
- def onHiddenChanged(self, hidden):
- self._hidden = hidden
-
- def getLayoutInflater(self):
- return getattr(self, '_layout_inflater', None)
-
- def onGetLayoutInflater(self, savedInstanceState):
- return self.getLayoutInflater()
-
- def requireContext(self):
- if not hasattr(self, '_context') or self._context is None:
- raise IllegalStateException("Fragment " + self.__class__.__name__ + " not attached to a context")
- return self._context
-
- def requireActivity(self):
- if not hasattr(self, '_activity') or self._activity is None:
- raise IllegalStateException("Fragment " + self.__class__.__name__ + " not attached to an activity")
- return self._activity
-
- def requireView(self):
- if not hasattr(self, '_view') or self._view is None:
- raise IllegalStateException("Fragment " + self.__class__.__name__ + " view is null")
- return self._view
-
- def requireFragmentManager(self):
- fm = getattr(self, '_fragment_manager', None)
- if fm is None:
- raise IllegalStateException("Fragment " + self.__class__.__name__ + " not associated with a fragment manager")
- return fm
-
- def setMenuVisibility(self, menuVisible):
- self._menu_visible = menuVisible
-
- def onMenuVisibilityChanged(self, menuVisible):
- pass
-
- def postponeEnterTransition(self):
- pass
-
- def startPostponedEnterTransition(self):
- pass
-
- def getEnterTransition(self):
- return getattr(self, '_enter_transition', None)
-
- def setEnterTransition(self, transition):
- self._enter_transition = transition
-
- def onInflate(self, context, attrs, savedInstanceState):
- pass
-
-
-class FragmentTransaction(Stub):
- """FragmentTransaction — 管理 Fragment 事务"""
-
- TRANSIT_ENTER_MASK = 0x1000
- TRANSIT_EXIT_MASK = 0x2000
- TRANSIT_FRAGMENT_FADE = 0x1001
- TRANSIT_FRAGMENT_OPEN = 0x1003
- TRANSIT_FRAGMENT_CLOSE = 0x1004
- TRANSIT_NONE = 0
- TRANSIT_UNSET = -1
-
- def __init__(self):
- super().__init__()
- self._ops: List[Dict] = []
- self._transition = FragmentTransaction.TRANSIT_NONE
- self._transition_style = 0
- self._allow_state_loss = False
- self._commit_allowing_state_loss = False
-
- def add(self, container_view_id: int, fragment: Fragment, tag: Optional[str] = None) -> "FragmentTransaction":
- self._ops.append({"type": "add", "id": container_view_id, "fragment": fragment, "tag": tag})
- return self
-
- def replace(self, container_view_id: int, fragment: Fragment, tag: Optional[str] = None) -> "FragmentTransaction":
- self._ops.append({"type": "replace", "id": container_view_id, "fragment": fragment, "tag": tag})
- return self
-
- def remove(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"type": "remove", "fragment": fragment})
- return self
-
- def hide(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"type": "hide", "fragment": fragment})
- return self
-
- def show(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"type": "show", "fragment": fragment})
- return self
-
- def detach(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"type": "detach", "fragment": fragment})
- return self
-
- def attach(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"type": "attach", "fragment": fragment})
- return self
-
- def addToBackStack(self, name: Optional[str] = None) -> "FragmentTransaction":
- self._ops.append({"type": "addToBackStack", "name": name})
- return self
-
- def setTransition(self, transit: int) -> "FragmentTransaction":
- self._transition = transit
- return self
-
- def setTransitionStyle(self, style: int) -> "FragmentTransaction":
- self._transition_style = style
- return self
-
- def setCustomAnimations(self, enter: int, exit: int, pop_enter: int = 0, pop_exit: int = 0) -> "FragmentTransaction":
- return self
-
- def disallowAddToBackStack(self) -> "FragmentTransaction":
- return self
-
- def setBreadCrumbShortTitle(self, title: str) -> "FragmentTransaction":
- return self
-
- def setBreadCrumbTitle(self, title: str) -> "FragmentTransaction":
- return self
-
- def commit(self) -> int:
- return 0
-
- def commitAllowingStateLoss(self) -> int:
- return 0
-
- def commitNow(self) -> int:
- return 0
-
- def commitNowAllowingStateLoss(self) -> int:
- return 0
-
- def isAddToBackStackAllowed(self) -> bool:
- return True
-
-
-class FragmentManager(Stub):
- """FragmentManager — Fragment 管理器"""
-
- POP_BACK_STACK_INCLUSIVE = 1
-
- def __init__(self):
- super().__init__()
- self._fragments: Dict[str, Fragment] = {}
- self._back_stack: List[Dict] = []
-
- def beginTransaction(self) -> FragmentTransaction:
- return FragmentTransaction()
-
- def findFragmentById(self, id_: int) -> Optional[Fragment]:
- for f in self._fragments.values():
- if f.getId() == id_:
- return f
- return None
-
- def findFragmentByTag(self, tag: str) -> Optional[Fragment]:
- return self._fragments.get(tag)
-
- def popBackStack(self):
- if self._back_stack:
- self._back_stack.pop()
-
- def popBackStackImmediate(self, name: str, flags: int) -> bool:
- return True
-
- def getBackStackEntryCount(self) -> int:
- return len(self._back_stack)
-
- def getFragment(self, bundle: "Bundle", key: str) -> Optional[Fragment]:
- return None
-
- def getFragments(self) -> List[Fragment]:
- return list(self._fragments.values())
-
- def saveFragmentInstanceState(self, fragment: Fragment):
- return None
-
- def isDestroyed(self) -> bool:
- return False
-
- def isStateSaved(self) -> bool:
- return False
-
- def putFragment(self, bundle: "Bundle", key: str, fragment: Fragment):
- pass
-
- def executePendingTransactions(self) -> bool:
- return True
-
- def clearFragmentResult(self, request_key: str):
- pass
-
- def setFragmentResult(self, request_key: str, result: "Bundle"):
- pass
-
- def setFragmentResultListener(self, lifecycle: Any, listener: Any):
- pass
-
- def registerFragmentLifecycleCallbacks(self, cb: Any, recursive: bool):
- pass
-
- def unregisterFragmentLifecycleCallbacks(self, cb: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Activity
-# ═══════════════════════════════════════════════════════════════
-
-class Activity(Stub):
- """Activity — 应用界面入口"""
-
- # 结果码
- RESULT_OK = -1
- RESULT_CANCELED = 0
- RESULT_FIRST_USER = 1
-
- def __init__(self):
- super().__init__()
- self._created = False
- self._started = False
- self._resumed = False
- self._destroyed = False
- self._intent: Optional[Intent] = None
- self._callbacks: Dict[int, Tuple[int, Intent]] = {}
- self._fragment_manager = FragmentManager()
- self._application = None
- self._title = ""
- self._request_code_counter = 0
-
- def onCreate(self, savedInstanceState: Optional["Bundle"] = None):
- self._created = True
- sys.stderr.write(f"[Activity] onCreate: {self.__class__.__name__}\n")
-
- def onStart(self):
- self._started = True
- sys.stderr.write(f"[Activity] onStart: {self.__class__.__name__}\n")
-
- def onResume(self):
- self._resumed = True
- sys.stderr.write(f"[Activity] onResume: {self.__class__.__name__}\n")
-
- def onPause(self):
- self._resumed = False
- sys.stderr.write(f"[Activity] onPause: {self.__class__.__name__}\n")
-
- def onStop(self):
- self._started = False
- sys.stderr.write(f"[Activity] onStop: {self.__class__.__name__}\n")
-
- def onDestroy(self):
- self._destroyed = True
- self._created = False
- sys.stderr.write(f"[Activity] onDestroy: {self.__class__.__name__}\n")
-
- def onRestart(self):
- sys.stderr.write(f"[Activity] onRestart: {self.__class__.__name__}\n")
-
- def onBackPressed(self):
- sys.stderr.write("[Activity] onBackPressed\n")
-
- def onSaveInstanceState(self, out_state: "Bundle"):
- pass
-
- def onRestoreInstanceState(self, savedInstanceState: "Bundle"):
- pass
-
- def onNewIntent(self, intent: Intent):
- self._intent = intent
-
- def onActivityResult(self, request_code: int, result_code: int, data: Optional[Intent]):
- pass
-
- def onRequestPermissionsResult(self, request_code: int, permissions: List[str], grant_results: List[int]):
- pass
-
- def setContentView(self, layout_res_id: int):
- sys.stderr.write(f"[Activity] setContentView: {layout_res_id}\n")
-
- def findViewById(self, id_: int) -> Any:
- return None
-
- def startActivity(self, intent: Intent):
- sys.stderr.write(
- f"[Activity] startActivity: action={intent.getAction()} "
- f"pkg={intent.getPackage()}\n"
- )
-
- def startActivityForResult(self, intent: Intent, request_code: int, options: Optional["Bundle"] = None):
- sys.stderr.write(
- f"[Activity] startActivityForResult: code={request_code} "
- f"action={intent.getAction()}\n"
- )
-
- def setResult(self, result_code: int, data: Optional[Intent] = None):
- sys.stderr.write(f"[Activity] setResult: code={result_code}\n")
-
- def finish(self):
- sys.stderr.write(f"[Activity] finish: {self.__class__.__name__}\n")
- self.onPause()
- self.onStop()
- self.onDestroy()
-
- def finishActivity(self, request_code: int):
- pass
-
- def getIntent(self) -> Optional[Intent]:
- return self._intent
-
- def setIntent(self, intent: Intent):
- self._intent = intent
-
- def getString(self, res_id: int, *args) -> str:
- return str(res_id)
-
- def getResources(self):
- return None
-
- def getApplication(self):
- return self._application
-
- def getFragmentManager(self) -> FragmentManager:
- return self._fragment_manager
-
- def getSupportFragmentManager(self) -> FragmentManager:
- return self._fragment_manager
-
- def getPackageManager(self):
- from .content_pm import PackageManager
- return PackageManager()
-
- def getPackageName(self) -> str:
- return _package_name
-
- def getContentResolver(self):
- from .content import ContentResolver
- return ContentResolver()
-
- def getSystemService(self, name: str):
- return android_context.getSystemService(name)
-
- def isFinishing(self) -> bool:
- return self._destroyed
-
- def isDestroyed(self) -> bool:
- return self._destroyed
-
- def recreate(self):
- self.onDestroy()
- self.onCreate(None)
- self.onStart()
- self.onResume()
-
- def getPreferences(self, mode: int):
- from .content import SharedPreferences
- return SharedPreferences(_package_name + "_preferences")
-
- def getSharedPreferences(self, name: str, mode: int):
- from .content import SharedPreferences
- return SharedPreferences(name)
-
- def getApplicationContext(self):
- return android_context
-
- def getBaseContext(self):
- return android_context
-
- def getCallingActivity(self) -> Optional[ComponentName]:
- return None
-
- def getCallingPackage(self) -> Optional[str]:
- return None
-
- def getTaskId(self) -> int:
- return 1
-
- def hasWindowFocus(self) -> bool:
- return True
-
- def isInMultiWindowMode(self) -> bool:
- return False
-
- def isInPictureInPictureMode(self) -> bool:
- return False
-
- def moveTaskToBack(self, non_root: bool) -> bool:
- return True
-
- def onLowMemory(self):
- pass
-
- def onTrimMemory(self, level: int):
- pass
-
- def onConfigurationChanged(self, config):
- pass
-
- def onMultiWindowModeChanged(self, is_in_multi_window_mode: bool, new_config):
- pass
-
- def onPictureInPictureModeChanged(self, is_in_pip_mode: bool, new_config):
- pass
-
- # ─── 生命周期 (扩展) ───────────────────────────────────────
-
- def onPostCreate(self, savedInstanceState):
- pass
-
- def onPostResume(self):
- pass
-
- def onUserLeaveHint(self):
- pass
-
- def onUserInteraction(self):
- pass
-
- def onCreateContextMenu(self, menu, v, menuInfo):
- pass
-
- def onContextMenuClosed(self, menu):
- pass
-
- def onContextItemSelected(self, item):
- return False
-
- def onWindowFocusChanged(self, hasFocus):
- pass
-
- def onWindowAttributesChanged(self, params):
- pass
-
- def onContentChanged(self):
- pass
-
- def onAttachedToWindow(self):
- pass
-
- def onDetachedFromWindow(self):
- pass
-
- def onTitleChanged(self, title, color):
- pass
-
- # ─── 权限 (扩展) ───────────────────────────────────────────
-
- def requestPermissions(self, permissions, requestCode):
- pass
-
- def checkSelfPermission(self, permission):
- return 0 # PERMISSION_GRANTED
-
- def shouldShowRequestPermissionRationale(self, permission):
- return False
-
- # ─── UI (扩展) ─────────────────────────────────────────────
-
- def getWindow(self):
- if not hasattr(self, '_window'):
- from .view import Window
- self._window = Window()
- return self._window
-
- def getWindowManager(self):
- if not hasattr(self, '_window_manager'):
- from .view import WindowManager
- self._window_manager = WindowManager()
- return self._window_manager
-
- def setRequestedOrientation(self, requestedOrientation):
- self._requested_orientation = requestedOrientation
-
- def getRequestedOrientation(self):
- return getattr(self, '_requested_orientation', 0)
-
- def runOnUiThread(self, action):
- import threading
- # 在桌面环境直接执行
- action()
-
- def overridePendingTransition(self, enterAnim, exitAnim):
- pass
-
- def getActionBar(self):
- return getattr(self, '_action_bar', None)
-
- def setActionBar(self, toolbar):
- self._action_bar = toolbar
-
- def getMenuInflater(self):
- from .view import MenuInflater
- return MenuInflater()
-
- def onCreateOptionsMenu(self, menu):
- return True
-
- def onPrepareOptionsMenu(self, menu):
- return True
-
- def onOptionsItemSelected(self, item):
- return False
-
- def registerForContextMenu(self, view):
- pass
-
- def unregisterForContextMenu(self, view):
- pass
-
- def openContextMenu(self, view):
- pass
-
- def finishAffinity(self):
- self.finish()
-
- def invalidateOptionsMenu(self):
- pass
-
- def setVisible(self, visible):
- self._visible = visible
-
- def setTheme(self, resid):
- self._theme = resid
-
- def getTheme(self):
- return getattr(self, '_theme', 0)
-
- def getDeviceInfo(self):
- """获取设备信息"""
- if _USE_LINUX:
- return LinuxProcess.get_system_info()
- return {}
-
- def executeShell(self, command):
- """执行 Shell 命令"""
- if _USE_LINUX:
- return LinuxShell.exec(command)
- return {"success": False, "output": "Shell not available"}
-
- def screenshot(self, path=None):
- """截屏"""
- if _USE_LINUX:
- return LinuxDisplay.screenshot(path)
- return None
-
- def getScreenSize(self):
- """获取屏幕尺寸"""
- if _USE_LINUX:
- return LinuxDisplay.get_screen_size()
- return (1920, 1080)
-
- def click(self, x, y):
- """点击屏幕坐标"""
- if _USE_LINUX:
- return LinuxUIAutomation.click(x, y)
- return False
-
- def typeText(self, text):
- """输入文本"""
- if _USE_LINUX:
- return LinuxUIAutomation.type_text(text)
- return False
-
- def pressKey(self, key):
- """按键"""
- if _USE_LINUX:
- return LinuxUIAutomation.press_key(key)
- return False
-
- def requestWindowFeature(self, featureId):
- self._window_features = getattr(self, '_window_features', set())
- self._window_features.add(featureId)
- return True
-
- def setTitle(self, title):
- self._title = title
-
- def getTitle(self):
- return getattr(self, '_title', '')
-
- def onKeyDown(self, keyCode, event):
- return False
-
- def onKeyUp(self, keyCode, event):
- return False
-
- def onTouchEvent(self, event):
- return False
-
- def enterPictureInPictureMode(self):
- pass
-
- def getReferrer(self):
- return getattr(self, '_referrer', None)
-
- def setReferrer(self, referrer):
- self._referrer = referrer
-
- def isTaskRoot(self):
- return True
-
- def getChangingConfigurations(self):
- return getattr(self, '_changing_config', 0)
-
- def navigateUpTo(self, intent):
- return True
-
- def shouldUpRecreateTask(self, intent):
- return False
-
- def getParentActivityIntent(self):
- return None
-
- def onOptionsMenuClosed(self, menu):
- pass
-
- def setVolumeControlStream(self, streamType):
- self._volume_control_stream = streamType
-
- def getVolumeControlStream(self):
- return getattr(self, '_volume_control_stream', 0)
-
- def getLocalClassName(self):
- return self.__class__.__name__
-
- def finishAndRemoveTask(self):
- self.finish()
-
- def getLoaderManager(self):
- if not hasattr(self, '_loader_manager'):
- self._loader_manager = type('LoaderManager', (), {
- 'initLoader': lambda *a: None,
- 'restartLoader': lambda *a: None,
- 'destroyLoader': lambda *a: None,
- 'getLoader': lambda *a: None,
- })()
- return self._loader_manager
-
- def onRetainNonConfigurationInstance(self):
- return None
-
- def getLastNonConfigurationInstance(self):
- return getattr(self, '_last_non_config_instance', None)
-
- def setProgressBarVisibility(self, visible):
- pass
-
- def setProgress(self, progress):
- pass
-
- def setSecondaryProgress(self, secondaryProgress):
- pass
-
- def onSearchRequested(self):
- return False
-
- def startSearch(self, initialQuery, selectInitial, appSearchData, globalSearch):
- pass
-
- def startIntentSender(self, intent, fillInIntent, flagsMask, flagsValues, extraFlags):
- pass
-
- def startIntentSenderForResult(self, intent, requestCode, fillInIntent, flagsMask, flagsValues, extraFlags):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Service
-# ═══════════════════════════════════════════════════════════════
-
-class Service(Stub):
- """Service — 后台服务"""
-
- START_CONTINUATION_MASK = 0xF
- START_FLAG_REDELIVERY = 1
- START_FLAG_RETRY = 2
- START_NOT_STICKY = 2
- START_REDELIVER_INTENT = 3
- START_STICKY = 1
- START_STICKY_COMPATIBILITY = 0
- STOP_FOREGROUND_DETACH = 1
- STOP_FOREGROUND_REMOVE = 2
-
- def __init__(self):
- super().__init__()
- self._started = False
-
- def onCreate(self):
- self._started = True
- sys.stderr.write(f"[Service] onCreate: {self.__class__.__name__}\n")
-
- def onStartCommand(self, intent: Optional[Intent], flags: int, start_id: int) -> int:
- return Service.START_NOT_STICKY
-
- def onBind(self, intent: Intent):
- return None
-
- def onUnbind(self, intent: Intent) -> bool:
- return False
-
- def onRebind(self, intent: Intent):
- pass
-
- def onDestroy(self):
- self._started = False
- sys.stderr.write(f"[Service] onDestroy: {self.__class__.__name__}\n")
-
- def stopSelf(self):
- self.onDestroy()
-
- def stopSelfResult(self, start_id: int) -> bool:
- self.onDestroy()
- return True
-
- def startForeground(self, id_: int, notification: Notification):
- pass
-
- def stopForeground(self, flags: int):
- pass
-
- def getApplication(self):
- return None
-
- def getClass(self):
- return self.__class__
-
-
-# ═══════════════════════════════════════════════════════════════
-# Application
-# ═══════════════════════════════════════════════════════════════
-
-class Application(Stub):
- """Application — 应用级别上下文"""
-
- def __init__(self):
- super().__init__()
- self._activity_lifecycle_callbacks: List = []
- self._on_low_memory_listeners: List = []
- self._on_trim_memory_listeners: List = []
-
- def onCreate(self):
- sys.stderr.write(f"[Application] onCreate: {self.__class__.__name__}\n")
-
- def onTerminate(self):
- pass
-
- def onConfigurationChanged(self, new_config):
- pass
-
- def onLowMemory(self):
- pass
-
- def onTrimMemory(self, level: int):
- pass
-
- def registerActivityLifecycleCallbacks(self, callback):
- self._activity_lifecycle_callbacks.append(callback)
-
- def unregisterActivityLifecycleCallbacks(self, callback):
- try:
- self._activity_lifecycle_callbacks.remove(callback)
- except ValueError:
- pass
-
- def getApplicationContext(self):
- return android_context
-
- def getPackageManager(self):
- from .content_pm import PackageManager
- return PackageManager()
-
- def getContentResolver(self):
- from .content import ContentResolver
- return ContentResolver()
-
- def getSystemService(self, name: str):
- return android_context.getSystemService(name)
-
- def getSharedPreferences(self, name: str, mode: int):
- from .content import SharedPreferences
- return SharedPreferences(name)
-
- def getFilesDir(self):
- return os.path.join(_app_data_dir, "files")
-
- def getCacheDir(self):
- return os.path.join(_app_data_dir, "cache")
-
- def getBaseContext(self):
- return android_context
-
-
-# ═══════════════════════════════════════════════════════════════
-# ActivityManager
-# ═══════════════════════════════════════════════════════════════
-
-class ActivityManager(Stub):
- """ActivityManager — 管理 Activity 运行状态"""
-
- RECENT_IGNORE_UNAVAILABLE = 0x02
- RECENT_WITH_EXCLUDED = 0x01
- MOVE_TASK_WITH_HOME = 0x01
- MOVE_TASK_NO_USER_ACTION = 0x02
-
- class RunningAppProcessInfo(Stub):
- """Information about a running process"""
- IMPORTANCE_FOREGROUND = 100
- IMPORTANCE_VISIBLE = 200
- IMPORTANCE_SERVICE = 300
- IMPORTANCE_BACKGROUND = 400
- IMPORTANCE_EMPTY = 500
- IMPORTANCE_FOREGROUND_SERVICE = 125
- IMPORTANCE_TOP_SLEEPING = 150
- IMPORTANCE_CACHED = 400
- IMPORTANCE_GONE = 1000
-
- def __init__(self):
- super().__init__()
- self.processName = ""
- self.pid = 0
- self.uid = 0
- self.importance = self.IMPORTANCE_FOREGROUND
- self.lru = 0
- self.importanceReasonCode = 0
- self.importanceReasonPid = 0
- self.importanceReasonComponent = None
- self.pkgList: List[str] = []
-
- class AppTask(Stub):
- """Represents a task managed by ActivityManager"""
- def finishAndRemoveTask(self):
- pass
- def getTaskInfo(self):
- return None
- def moveToFront(self):
- pass
- def setExcludeFromRecents(self, exclude: bool):
- pass
-
- class MemoryInfo(Stub):
- """Memory information"""
- def __init__(self):
- super().__init__()
- self.availMem = 0
- self.totalMem = 0
- self.threshold = 0
- self.lowMemory = False
-
- def __init__(self):
- super().__init__()
- self._memory_info = self.MemoryInfo()
-
- def getMemoryInfo(self) -> "ActivityManager.MemoryInfo":
- if _USE_LINUX:
- return LinuxPower.get_memory_info()
- return self._memory_info
-
- def getRunningAppProcesses(self) -> Optional[List["ActivityManager.RunningAppProcessInfo"]]:
- if _USE_LINUX:
- return LinuxProcess.list_processes()
- return []
-
- def killBackgroundProcesses(self, package_name: str):
- pass
-
- def clearApplicationUserData(self) -> bool:
- return True
-
- def getRecentTasks(self, max_num: int, flags: int) -> List:
- return []
-
- def getAppTasks(self) -> List["ActivityManager.AppTask"]:
- return []
-
- def moveTaskToFront(self, task_id: int, flags: int):
- pass
-
- def isBackgroundRestricted(self) -> bool:
- return False
-
- def isLowRamDevice(self) -> bool:
- return False
-
- def getLauncherLargeIconSize(self) -> int:
- return 48
-
-
-# ═══════════════════════════════════════════════════════════════
-# TaskStackBuilder
-# ═══════════════════════════════════════════════════════════════
-
-class TaskStackBuilder(Stub):
- """Builder for synthetic back stack"""
-
- def __init__(self, context):
- super().__init__()
- self._context = context
- self._intents: List[Intent] = []
-
- @staticmethod
- def create(context) -> "TaskStackBuilder":
- return TaskStackBuilder(context)
-
- def addNextIntent(self, intent: Intent) -> "TaskStackBuilder":
- self._intents.append(intent)
- return self
-
- def addNextIntentWithParentStack(self, intent: Intent) -> "TaskStackBuilder":
- self._intents.append(intent)
- return self
-
- def addParentStack(self, activity_cls: type) -> "TaskStackBuilder":
- return self
-
- def startActivities(self, options: Optional["Bundle"] = None):
- for intent in self._intents:
- sys.stderr.write(f"[TaskStackBuilder] start activity: {intent}\n")
-
- def startActivitiesIfNeeded(self, options: Optional["Bundle"] = None):
- self.startActivities(options)
-
- def getIntent(self, request_code: int) -> Optional[Intent]:
- if self._intents:
- return self._intents[-1]
- return None
-
- def editIntentAt(self, index: int) -> Optional[Intent]:
- if 0 <= index < len(self._intents):
- return self._intents[index]
- return None
-
- def getIntentCount(self) -> int:
- return len(self._intents)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Bundle (forward reference for Fragment uses)
-# ═══════════════════════════════════════════════════════════════
-
-from .os import Bundle
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Intent",
- "ComponentName",
- "PendingIntent",
- "AlarmManager",
- "Notification",
- "NotificationChannel",
- "NotificationChannelGroup",
- "NotificationManager",
- "NotificationCompat",
- "Dialog",
- "AlertDialog",
- "ProgressDialog",
- "DatePickerDialog",
- "TimePickerDialog",
- "Fragment",
- "FragmentManager",
- "FragmentTransaction",
- "Activity",
- "Service",
- "Application",
- "ActivityManager",
- "TaskStackBuilder",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/app_actionbar.py b/android_pyapi/android/app_actionbar.py
deleted file mode 100644
index c2f0c1f..0000000
--- a/android_pyapi/android/app_actionbar.py
+++ /dev/null
@@ -1,539 +0,0 @@
-"""
-Android ActionBar API — ActionBar, ActionBar.Tab, ActionBar.TabListener, ActionBar.LayoutParams
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-from typing import Any, Dict, List, Optional, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# DISPLAY_* 常量
-DISPLAY_USE_LOGO = 0x0001
-DISPLAY_SHOW_HOME = 0x0002
-DISPLAY_HOME_AS_UP = 0x0004
-DISPLAY_SHOW_TITLE = 0x0008
-DISPLAY_SHOW_CUSTOM = 0x0010
-DISPLAY_TITLE_MULTIPLE_LINES = 0x0020
-
-# NAVIGATION_MODE_* 常量
-NAVIGATION_MODE_STANDARD = 0
-NAVIGATION_MODE_LIST = 1
-NAVIGATION_MODE_TABS = 2
-
-# TAB 状态常量
-TAB_STATE_CREATED = 1
-TAB_STATE_INITIALIZED = 2
-TAB_STATE_SELECTED = 3
-TAB_STATE_UNSELECTED = 4
-TAB_STATE_RESELECTED = 5
-
-# 其它常量
-SHOW_AS_ACTION_NEVER = 0
-SHOW_AS_ACTION_IF_ROOM = 1
-SHOW_AS_ACTION_ALWAYS = 2
-SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8
-SHOW_AS_ACTION_WITH_TEXT = 4
-
-
-# ═══════════════════════════════════════════════════════════════
-# ActionBar
-# ═══════════════════════════════════════════════════════════════
-
-class ActionBar(Stub):
- """ActionBar — 操作栏 (桌面存根)"""
-
- DISPLAY_USE_LOGO = DISPLAY_USE_LOGO
- DISPLAY_SHOW_HOME = DISPLAY_SHOW_HOME
- DISPLAY_HOME_AS_UP = DISPLAY_HOME_AS_UP
- DISPLAY_SHOW_TITLE = DISPLAY_SHOW_TITLE
- DISPLAY_SHOW_CUSTOM = DISPLAY_SHOW_CUSTOM
- DISPLAY_HOME_AS_UP_FLAG = DISPLAY_HOME_AS_UP
- DISPLAY_TITLE_MULTIPLE_LINES = DISPLAY_TITLE_MULTIPLE_LINES
-
- NAVIGATION_MODE_STANDARD = NAVIGATION_MODE_STANDARD
- NAVIGATION_MODE_LIST = NAVIGATION_MODE_LIST
- NAVIGATION_MODE_TABS = NAVIGATION_MODE_TABS
-
- def __init__(self):
- super().__init__()
- self._mTitle: Optional[str] = None
- self._mSubtitle: Optional[str] = None
- self._mLogo: Optional[Any] = None
- self._mIcon: Optional[Any] = None
- self._mCustomView: Optional[Any] = None
- self._mDisplayOptions = DISPLAY_SHOW_HOME | DISPLAY_SHOW_TITLE
- self._mNavigationMode = NAVIGATION_MODE_STANDARD
- self._mSelectedNavigationIndex = 0
- self._mListNavigationCallbacks: Optional[Callable] = None
- self._mTabs: List["ActionBar.Tab"] = []
- self._mSelectedTab: Optional["ActionBar.Tab"] = None
- self._mHomeButtonEnabled = True
- self._mShowing = True
- self._mElevation = 0.0
- self._mHideOffset = 0
- self._mHideOnContentScroll = False
- self._mBackgroundDrawable: Optional[Any] = None
- self._mStackedBackgroundDrawable: Optional[Any] = None
- self._mSplitBackgroundDrawable: Optional[Any] = None
- self._mCustomViewLayoutParams: Optional["ActionBar.LayoutParams"] = None
- self._mContext: Optional[Any] = None
- self._mThemedContext: Optional[Any] = None
- self._mMenuVisibilityListeners: List[Callable] = []
- self._mMenuVisible = True
- self._mShowHideAnimationEnabled = False
- self._mShowHideAnimationListener: Optional[Any] = None
- self._mActionMode: Optional[Any] = None
- self._mActionModeListener: Optional[Any] = None
- self._mTabListener: Optional["ActionBar.TabListener"] = None
-
- def setTitle(self, title: str) -> None:
- self._mTitle = title
-
- def setTitle(self, titleResId: int) -> None:
- self._mTitle = f"title_{titleResId}"
-
- def getTitle(self) -> Optional[str]:
- return self._mTitle
-
- def setSubtitle(self, subtitle: str) -> None:
- self._mSubtitle = subtitle
-
- def setSubtitle(self, subtitleResId: int) -> None:
- self._mSubtitle = f"subtitle_{subtitleResId}"
-
- def getSubtitle(self) -> Optional[str]:
- return self._mSubtitle
-
- def setLogo(self, logo: Any) -> None:
- self._mLogo = logo
-
- def setIcon(self, icon: Any) -> None:
- self._mIcon = icon
-
- def setIcon(self, iconResId: int) -> None:
- pass
-
- def setLogo(self, logoResId: int) -> None:
- pass
-
- def setHomeButtonEnabled(self, enabled: bool) -> None:
- self._mHomeButtonEnabled = enabled
-
- def isHomeButtonEnabled(self) -> bool:
- return self._mHomeButtonEnabled
-
- def setDisplayOptions(self, options: int) -> None:
- self._mDisplayOptions = options
-
- def setDisplayOptions(self, options: int, mask: int) -> None:
- self._mDisplayOptions = (self._mDisplayOptions & ~mask) | (options & mask)
-
- def getDisplayOptions(self) -> int:
- return self._mDisplayOptions
-
- def setNavigationMode(self, mode: int) -> None:
- self._mNavigationMode = mode
-
- def getNavigationMode(self) -> int:
- return self._mNavigationMode
-
- def setSelectedNavigationItem(self, position: int) -> None:
- self._mSelectedNavigationIndex = position
- if self._mNavigationMode == NAVIGATION_MODE_TABS:
- if 0 <= position < len(self._mTabs):
- self._mSelectedTab = self._mTabs[position]
-
- def getSelectedNavigationIndex(self) -> int:
- if self._mNavigationMode == NAVIGATION_MODE_TABS and self._mSelectedTab:
- try:
- return self._mTabs.index(self._mSelectedTab)
- except ValueError:
- pass
- return self._mSelectedNavigationIndex
-
- def setListNavigationCallbacks(self, adapter: Any, callback: Any) -> None:
- self._mListNavigationCallbacks = callback
-
- def getListNavigationCallbacks(self) -> Optional[Any]:
- return self._mListNavigationCallbacks
-
- def getSelectedTab(self) -> Optional["ActionBar.Tab"]:
- return self._mSelectedTab
-
- def addTab(self, tab: "ActionBar.Tab") -> None:
- self._mTabs.append(tab)
- if len(self._mTabs) == 1:
- self._mSelectedTab = tab
-
- def addTab(self, tab: "ActionBar.Tab", setSelected: bool) -> None:
- self._mTabs.append(tab)
- if setSelected:
- self._mSelectedTab = tab
-
- def addTab(self, tab: "ActionBar.Tab", position: int, setSelected: bool) -> None:
- if position < 0:
- position = 0
- if position > len(self._mTabs):
- position = len(self._mTabs)
- self._mTabs.insert(position, tab)
- if setSelected:
- self._mSelectedTab = tab
-
- def removeTab(self, tab: "ActionBar.Tab") -> None:
- if tab in self._mTabs:
- self._mTabs.remove(tab)
- if self._mSelectedTab is tab:
- self._mSelectedTab = self._mTabs[0] if self._mTabs else None
-
- def removeTabAt(self, position: int) -> None:
- if 0 <= position < len(self._mTabs):
- tab = self._mTabs[position]
- self._mTabs.pop(position)
- if self._mSelectedTab is tab:
- self._mSelectedTab = self._mTabs[0] if self._mTabs else None
-
- def removeAllTabs(self) -> None:
- self._mTabs.clear()
- self._mSelectedTab = None
-
- def selectTab(self, tab: "ActionBar.Tab") -> None:
- if tab in self._mTabs:
- old = self._mSelectedTab
- self._mSelectedTab = tab
- if old and old._mListener:
- old._mListener.onTabUnselected(old, None)
- if tab._mListener:
- tab._mListener.onTabSelected(tab, None)
-
- def getTabCount(self) -> int:
- return len(self._mTabs)
-
- def getTabAt(self, index: int) -> Optional["ActionBar.Tab"]:
- if 0 <= index < len(self._mTabs):
- return self._mTabs[index]
- return None
-
- def newTab(self) -> "ActionBar.Tab":
- return ActionBar.Tab()
-
- def setCustomView(self, view: Any) -> None:
- self._mCustomView = view
-
- def setCustomView(self, view: Any, layoutParams: "ActionBar.LayoutParams") -> None:
- self._mCustomView = view
- self._mCustomViewLayoutParams = layoutParams
-
- def setCustomView(self, layoutResId: int) -> None:
- pass
-
- def getCustomView(self) -> Optional[Any]:
- return self._mCustomView
-
- def setBackgroundDrawable(self, drawable: Any) -> None:
- self._mBackgroundDrawable = drawable
-
- def setStackedBackgroundDrawable(self, drawable: Any) -> None:
- self._mStackedBackgroundDrawable = drawable
-
- def setSplitBackgroundDrawable(self, drawable: Any) -> None:
- self._mSplitBackgroundDrawable = drawable
-
- def show(self) -> None:
- self._mShowing = True
-
- def hide(self) -> None:
- self._mShowing = False
-
- def isShowing(self) -> bool:
- return self._mShowing
-
- def setShowHideAnimationEnabled(self, enabled: bool) -> None:
- self._mShowHideAnimationEnabled = enabled
-
- def getThemedContext(self) -> Optional[Any]:
- return self._mThemedContext or self._mContext
-
- def setHomeAsUpIndicator(self, indicator: Any) -> None:
- pass
-
- def setHomeAsUpIndicator(self, indicatorResId: int) -> None:
- pass
-
- def setHomeActionContentDescription(self, description: str) -> None:
- pass
-
- def setHomeActionContentDescription(self, resId: int) -> None:
- pass
-
- def setElevation(self, elevation: float) -> None:
- self._mElevation = elevation
-
- def getElevation(self) -> float:
- return self._mElevation
-
- def setHideOffset(self, offset: int) -> None:
- self._mHideOffset = offset
-
- def getHideOffset(self) -> int:
- return self._mHideOffset
-
- def setHideOnContentScrollEnabled(self, hideOnContentScroll: bool) -> None:
- self._mHideOnContentScroll = hideOnContentScroll
-
- def isHideOnContentScrollEnabled(self) -> bool:
- return self._mHideOnContentScroll
-
- def getContext(self) -> Optional[Any]:
- return self._mContext
-
- def addOnMenuVisibilityListener(self, listener: Callable) -> None:
- if listener not in self._mMenuVisibilityListeners:
- self._mMenuVisibilityListeners.append(listener)
-
- def removeOnMenuVisibilityListener(self, listener: Callable) -> None:
- if listener in self._mMenuVisibilityListeners:
- self._mMenuVisibilityListeners.remove(listener)
-
- def dispatchMenuVisibilityChanged(self, isVisible: bool) -> None:
- self._mMenuVisible = isVisible
- for listener in self._mMenuVisibilityListeners:
- listener(isVisible)
-
- def startActionMode(self, callback: Any) -> Optional[Any]:
- self._mActionMode = callback
- return None
-
- def invalidateOptionsMenu(self) -> None:
- pass
-
- def onConfigurationChanged(self, config: Any) -> None:
- pass
-
- def onDestroy(self) -> None:
- self._mTabs.clear()
- self._mSelectedTab = None
-
- def toString(self) -> str:
- return (
- f"ActionBar(title={self._mTitle}, subtitle={self._mSubtitle}, "
- f"tabs={len(self._mTabs)}, display=0x{self._mDisplayOptions:x}, "
- f"showing={self._mShowing})"
- )
-
- # ═══════════════════════════════════════════════════════════
- # ActionBar.Tab
- # ═══════════════════════════════════════════════════════════
-
- class Tab(Stub):
- """ActionBar.Tab — 操作栏标签"""
-
- INVALID_POSITION = -1
-
- def __init__(self):
- super().__init__()
- self._mListener: Optional["ActionBar.TabListener"] = None
- self._mObjectTag: Optional[Any] = None
- self._mPosition = Tab.INVALID_POSITION
- self._mIcon: Optional[Any] = None
- self._mText: Optional[str] = None
- self._mContentDescription: Optional[str] = None
- self._mCustomView: Optional[Any] = None
- self._mParentActionBar: Optional["ActionBar"] = None
- self._mIconResId = 0
-
- def getPosition(self) -> int:
- return self._mPosition
-
- def getIcon(self) -> Optional[Any]:
- return self._mIcon
-
- def getText(self) -> Optional[str]:
- return self._mText
-
- def setIcon(self, icon: Any) -> "ActionBar.Tab":
- self._mIcon = icon
- return self
-
- def setIcon(self, iconResId: int) -> "ActionBar.Tab":
- self._mIconResId = iconResId
- return self
-
- def setText(self, text: str) -> "ActionBar.Tab":
- self._mText = text
- return self
-
- def setText(self, textResId: int) -> "ActionBar.Tab":
- self._mText = f"tab_text_{textResId}"
- return self
-
- def setCustomView(self, view: Any) -> "ActionBar.Tab":
- self._mCustomView = view
- return self
-
- def setCustomView(self, layoutResId: int) -> "ActionBar.Tab":
- return self
-
- def getCustomView(self) -> Optional[Any]:
- return self._mCustomView
-
- def setTag(self, tag: Any) -> "ActionBar.Tab":
- self._mObjectTag = tag
- return self
-
- def getTag(self) -> Optional[Any]:
- return self._mObjectTag
-
- def setTabListener(self, listener: "ActionBar.TabListener") -> "ActionBar.Tab":
- self._mListener = listener
- return self
-
- def getTabListener(self) -> Optional["ActionBar.TabListener"]:
- return self._mListener
-
- def setContentDescription(self, description: str) -> "ActionBar.Tab":
- self._mContentDescription = description
- return self
-
- def getContentDescription(self) -> Optional[str]:
- return self._mContentDescription
-
- def select(self) -> None:
- if self._mParentActionBar:
- self._mParentActionBar.selectTab(self)
-
- def isSelected(self) -> bool:
- if self._mParentActionBar:
- return self._mParentActionBar.getSelectedTab() is self
- return False
-
- def toString(self) -> str:
- return f"ActionBar.Tab(text={self._mText}, position={self._mPosition})"
-
- # ═══════════════════════════════════════════════════════════
- # ActionBar.TabListener
- # ═══════════════════════════════════════════════════════════
-
- class TabListener(Stub):
- """ActionBar.TabListener — 标签事件监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onTabSelected(self, tab: "ActionBar.Tab", ft: Any) -> None:
- pass
-
- def onTabUnselected(self, tab: "ActionBar.Tab", ft: Any) -> None:
- pass
-
- def onTabReselected(self, tab: "ActionBar.Tab", ft: Any) -> None:
- pass
-
- def toString(self) -> str:
- return "ActionBar.TabListener"
-
- # ═══════════════════════════════════════════════════════════
- # ActionBar.LayoutParams
- # ═══════════════════════════════════════════════════════════
-
- class LayoutParams(Stub):
- """ActionBar.LayoutParams — 操作栏布局参数"""
-
- # 对齐方式
- GRAVITY_LEFT = 0x03
- GRAVITY_CENTER_HORIZONTAL = 0x01
- GRAVITY_RIGHT = 0x05
- GRAVITY_TOP = 0x30
- GRAVITY_CENTER_VERTICAL = 0x10
- GRAVITY_BOTTOM = 0x50
- GRAVITY_CENTER = 0x11
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._gravity = LayoutParams.GRAVITY_CENTER_VERTICAL
- self._width = -1 # MATCH_PARENT
- self._height = -2 # WRAP_CONTENT
- self._margin_left = 0
- self._margin_top = 0
- self._margin_right = 0
- self._margin_bottom = 0
-
- def __init__(self, gravity: int):
- super().__init__()
- self._gravity = gravity
- self._width = -1
- self._height = -1
-
- def __init__(self, width: int, height: int):
- super().__init__()
- self._width = width
- self._height = height
- self._gravity = LayoutParams.GRAVITY_CENTER_VERTICAL
-
- def __init__(self, width: int, height: int, gravity: int):
- super().__init__()
- self._width = width
- self._height = height
- self._gravity = gravity
-
- def getGravity(self) -> int:
- return self._gravity
-
- def setGravity(self, gravity: int) -> None:
- self._gravity = gravity
-
- def getWidth(self) -> int:
- return self._width
-
- def setWidth(self, width: int) -> None:
- self._width = width
-
- def getHeight(self) -> int:
- return self._height
-
- def setHeight(self, height: int) -> None:
- self._height = height
-
- def getMargins(self) -> Tuple[int, int, int, int]:
- return (self._margin_left, self._margin_top, self._margin_right, self._margin_bottom)
-
- def setMargins(self, left: int, top: int, right: int, bottom: int) -> None:
- self._margin_left = left
- self._margin_top = top
- self._margin_right = right
- self._margin_bottom = bottom
-
- def toString(self) -> str:
- return f"ActionBar.LayoutParams(width={self._width}, height={self._height}, gravity=0x{self._gravity:x})"
-
- # 兼容多个 __init__ 签名
- def __init__(self, *args, **kwargs):
- super().__init__()
- self._gravity = LayoutParams.GRAVITY_CENTER_VERTICAL
- self._width = -1
- self._height = -1
- self._margin_left = 0
- self._margin_top = 0
- self._margin_right = 0
- self._margin_bottom = 0
- if len(args) == 1:
- if isinstance(args[0], int):
- self._gravity = args[0]
- elif isinstance(args[0], ActionBar.LayoutParams):
- other = args[0]
- self._width = other._width
- self._height = other._height
- self._gravity = other._gravity
- elif len(args) == 2:
- self._width, self._height = args
- elif len(args) == 3:
- self._width, self._height, self._gravity = args
\ No newline at end of file
diff --git a/android_pyapi/android/app_admin.py b/android_pyapi/android/app_admin.py
deleted file mode 100644
index 6727e86..0000000
--- a/android_pyapi/android/app_admin.py
+++ /dev/null
@@ -1,424 +0,0 @@
-"""
-Android Device Administration API — DevicePolicyManager, DeviceAdminInfo, DeviceAdminReceiver, SystemUpdatePolicy
-方法签名完全对齐 Android SDK
-"""
-
-import os as _os
-import sys
-import tempfile
-import shutil
-from typing import Any, Dict, List, Optional, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "DevicePolicyManager",
- "DeviceAdminInfo",
- "DeviceAdminReceiver",
- "SystemUpdatePolicy",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# DevicePolicyManager 常量
-# ═══════════════════════════════════════════════════════════════
-
-class DevicePolicyManager(Stub):
- """DevicePolicyManager — 设备策略管理器 (桌面存根)"""
-
- # --- Action 常量 ---
- ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN"
- ACTION_DEVICE_ADMIN_SET_DOWNLOAD_URL = "android.app.action.DEVICE_ADMIN_SET_DOWNLOAD_URL"
- ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE"
- ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE"
- ACTION_PROVISION_FINANCED_DEVICE = "android.app.action.PROVISION_FINANCED_DEVICE"
- ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE"
- ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED"
- ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED"
- ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD"
- ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD"
- ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION"
- ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED"
- ACTION_APPLICATION_VERB = "android.app.action.APPLICATION_VERB"
- ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED"
- ACTION_ORG_OWNED_PROVISIONING = "android.app.action.ORG_OWNED_PROVISIONING"
- ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE"
- ACTION_ADMIN_SERVICE = "android.app.action.ADMIN_SERVICE"
-
- # --- Password quality constants ---
- PASSWORD_QUALITY_UNSPECIFIED = 0
- PASSWORD_QUALITY_BIOMETRIC_WEAK = 0x8000
- PASSWORD_QUALITY_SOMETHING = 0x10000
- PASSWORD_QUALITY_NUMERIC = 0x20000
- PASSWORD_QUALITY_NUMERIC_COMPLEX = 0x30000
- PASSWORD_QUALITY_ALPHABETIC = 0x40000
- PASSWORD_QUALITY_ALPHANUMERIC = 0x50000
- PASSWORD_QUALITY_COMPLEX = 0x60000
- PASSWORD_QUALITY_MANAGED = 0x80000
-
- # --- Encryption status ---
- ENCRYPTION_STATUS_UNSUPPORTED = 0
- ENCRYPTION_STATUS_INACTIVE = 1
- ENCRYPTION_STATUS_ACTIVATING = 2
- ENCRYPTION_STATUS_ACTIVE = 3
- ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4
-
- # --- Keyguard disable flags ---
- KEYGUARD_DISABLE_FEATURES_NONE = 0
- KEYGUARD_DISABLE_FEATURES_ALL = 0x7FFFFFFF
- KEYGUARD_DISABLE_SECURE_CAMERA = 2
- KEYGUARD_DISABLE_SECURE_NOTIFICATIONS = 4
- KEYGUARD_DISABLE_TRUST_AGENTS = 8
- KEYGUARD_DISABLE_FINGERPRINT = 16
- KEYGUARD_DISABLE_REMOTE_INPUT = 32
- KEYGUARD_DISABLE_FACE = 64
- KEYGUARD_DISABLE_IRIS = 128
- KEYGUARD_DISABLE_PASSCODE = 256
-
- # --- Lock screen info flags ---
- FLAG_EVOLVING_DEVICE_ADMIN = 1 << 0
- FLAG_PARENT_CAN_ACCESS_LOCK_SCREEN = 1 << 1
- FLAG_SELF_PROFILE_DISABLED = 1 << 2
-
- # --- Other constants ---
- PERMISSION_GRANT_STATE_DEFAULT = 0
- PERMISSION_GRANT_STATE_GRANTED = 1
- PERMISSION_GRANT_STATE_DENIED = 2
- STATE_USER_SETUP_COMPLETE = 1
- STATE_USER_UNMANAGED = 0
- STATE_USER_MANAGED = 2
- LEAVE_ALL_KEYS = 0xFFFFFFFF
- WIPE_EXTERNAL_STORAGE = 1
- WIPE_RESET_PROTECTION_DATA = 2
- WIPE_SILENTLY = 4
- SKIP_SETUP_WIZARD = 1
- SETTINGS_HOME = "settings_home"
- SETTINGS_GLOBAL = "settings_global"
- SETTINGS_SECURE = "settings_secure"
- SETTINGS_SYSTEM = "settings_system"
- LOCK_TASK_FEATURE_NONE = 0
- LOCK_TASK_FEATURE_SYSTEM_INFO = 1
- LOCK_TASK_FEATURE_KEYGUARD = 2
- LOCK_TASK_FEATURE_HOME = 4
- LOCK_TASK_FEATURE_GLOBAL_ACTIONS = 8
- LOCK_TASK_FEATURE_NOTIFICATIONS = 16
- LOCK_TASK_FEATURE_OVERVIEW = 32
- LOCK_TASK_FEATURE_CREDENTIALS = 64
- LOCK_TASK_FEATURE_ACCESSIBILITY = 128
- LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START = 256
-
- def __init__(self):
- super().__init__()
- self._active_admins: List[Dict[str, Any]] = []
- self._password_quality = self.PASSWORD_QUALITY_UNSPECIFIED
- self._camera_disabled = False
- self._keyguard_disabled = False
-
- def isAdminActive(self, admin: "DeviceAdminInfo") -> bool:
- """检查设备管理器是否已激活"""
- return any(a.getComponent() == admin.getComponent() for a in self._active_admins)
-
- def isDeviceOwnerApp(self, packageName: str) -> bool:
- """检查应用是否为设备所有者"""
- return False
-
- def isProfileOwnerApp(self, packageName: str) -> bool:
- """检查应用是否为配置文件所有者"""
- return False
-
- def resetPassword(self, password: str, flags: int = 0) -> bool:
- """重置设备密码 (桌面存根)"""
- raise AndroidOnlyError("DevicePolicyManager.resetPassword() 仅在 Android 设备上可用")
-
- def lockNow(self):
- """立即锁定设备"""
- raise AndroidOnlyError("DevicePolicyManager.lockNow() 仅在 Android 设备上可用")
-
- def wipeData(self, flags: int = 0):
- """擦除设备数据"""
- raise AndroidOnlyError("DevicePolicyManager.wipeData() 仅在 Android 设备上可用")
-
- def setCameraDisabled(self, admin: "DeviceAdminInfo", disabled: bool):
- """设置相机禁用状态"""
- self._camera_disabled = disabled
-
- def setKeyguardDisabled(self, admin: "DeviceAdminInfo", disabled: bool) -> bool:
- """设置锁屏禁用状态"""
- self._keyguard_disabled = disabled
- return True
-
- def installCaCert(self, admin: "DeviceAdminInfo", certBuffer: bytes) -> bool:
- """安装 CA 证书 (桌面存根)"""
- raise AndroidOnlyError("DevicePolicyManager.installCaCert() 仅在 Android 设备上可用")
-
- def uninstallCaCert(self, admin: "DeviceAdminInfo", certBuffer: bytes):
- """卸载 CA 证书 (桌面存根)"""
- raise AndroidOnlyError("DevicePolicyManager.uninstallCaCert() 仅在 Android 设备上可用")
-
- def getActiveAdmins(self) -> Optional[List["DeviceAdminInfo"]]:
- """获取活跃的管理器列表"""
- return list(self._active_admins) if self._active_admins else None
-
- def createAdminProfileInfo(
- self,
- packageName: str,
- localizedName: str,
- parentComponent: Any = None,
- adminInfo: Any = None,
- profileOwner: bool = False,
- ) -> "DeviceAdminInfo":
- """创建管理员配置文件信息"""
- return DeviceAdminInfo(
- packageName=packageName,
- localizedName=localizedName,
- parentComponent=parentComponent,
- adminInfo=adminInfo,
- profileOwner=profileOwner,
- )
-
- def toString(self) -> str:
- return f"DevicePolicyManager@active_admins={len(self._active_admins)}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# DeviceAdminInfo
-# ═══════════════════════════════════════════════════════════════
-
-class DeviceAdminInfo(Stub):
- """DeviceAdminInfo — 设备管理员信息"""
-
- USES_POLICY_WATCH_LOG = "uses_policy_watch_log"
- USES_POLICY_DISABLE_KEYGUARD_FEATURES = "uses_policy_disable_keyguard_features"
- USES_POLICY_DISABLE_CAMERA = "uses_policy_disable_camera"
- USES_POLICY_RESET_PASSWORD = "uses_policy_reset_password"
- USES_POLICY_FORCE_LOCK = "uses_policy_force_lock"
- USES_POLICY_WIPE_DATA = "uses_policy_wipe_data"
- USES_POLICY_EXPIRE_PASSWORD = "uses_policy_expire_password"
- USES_POLICY_LIMIT_PASSWORD = "uses_policy_limit_password"
- USES_ENCRYPTED_STORAGE = "uses_encrypted_storage"
- USES_POLICY_SETS_DEVICE_OWNER = "uses_policy_sets_device_owner"
- USES_POLICY_SETS_PROFILE_OWNER = "uses_policy_sets_profile_owner"
- USES_POLICY_INSTALL_CERT = "uses_policy_install_cert"
- USES_POLICY_UNINSTALL_CERT = "uses_policy_uninstall_cert"
-
- def __init__(
- self,
- packageName: str = "",
- localizedName: str = "",
- parentComponent: Any = None,
- adminInfo: Any = None,
- profileOwner: bool = False,
- ):
- super().__init__()
- self._packageName = packageName
- self._localizedName = localizedName
- self._parentComponent = parentComponent
- self._adminInfo = adminInfo
- self._profileOwner = profileOwner
-
- def getComponent(self) -> Optional[str]:
- """获取组件标识"""
- return self._parentComponent
-
- def getPackageName(self) -> str:
- return self._packageName
-
- def isVisible(self) -> bool:
- return True
-
- def isProfileOwner(self) -> bool:
- return self._profileOwner
-
- def toString(self) -> str:
- return f"DeviceAdminInfo(package={self._packageName})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, DeviceAdminInfo):
- return False
- return self._packageName == other._packageName and self._parentComponent == other._parentComponent
-
- def hashCode(self) -> int:
- return hash(self._packageName) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# DeviceAdminReceiver
-# ═══════════════════════════════════════════════════════════════
-
-class DeviceAdminReceiver(Stub):
- """DeviceAdminReceiver — 设备管理员广播接收器"""
-
- ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED"
- ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED"
- ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED"
- ACTION_PASSWORD_CHANGED = "android.app.action.ACTION_PASSWORD_CHANGED"
- ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED"
- ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED"
- ACTION_PASSWORD_EXPIRING = "android.app.action.ACTION_PASSWORD_EXPIRING"
- ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE"
- ACTION_BUGREPORT_SHARING_ACCEPTED = "android.app.action.BUGREPORT_SHARING_ACCEPTED"
- ACTION_BUGREPORT_SHARING_DECLINED = "android.app.action.BUGREPORT_SHARING_DECLINED"
- ACTION_BUGREPORT_FAILED = "android.app.action.BUGREPORT_FAILED"
- ACTION_NOTIFY_PENDING_SYSTEM_UPDATE = "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE"
- ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"
- ACTION_NETWORK_LOGS_AVAILABLE = "android.app.action.NETWORK_LOGS_AVAILABLE"
- ACTION_SECURITY_LOGS_AVAILABLE = "android.app.action.SECURITY_LOGS_AVAILABLE"
- ACTION_USER_ADDED = "android.app.action.USER_ADDED"
- ACTION_USER_REMOVED = "android.app.action.USER_REMOVED"
- ACTION_USER_STARTED = "android.app.action.USER_STARTED"
- ACTION_USER_STOPPED = "android.app.action.USER_STOPPED"
- ACTION_USER_SWITCHED = "android.app.action.USER_SWITCHED"
- ACTION_LOCK_TASK_ENTERING = "android.app.action.LOCK_TASK_ENTERING"
- ACTION_LOCK_TASK_EXITING = "android.app.action.LOCK_TASK_EXITING"
-
- def __init__(self):
- super().__init__()
-
- def onEnabled(self, context: Any, intent: Any):
- """管理员启用回调"""
- pass
-
- def onDisabled(self, context: Any, intent: Any):
- """管理员禁用回调"""
- pass
-
- def onPasswordChanged(self, context: Any, intent: Any):
- """密码更改回调"""
- pass
-
- def onPasswordExpiring(self, context: Any, intent: Any):
- """密码过期回调"""
- pass
-
- def onPasswordFailed(self, context: Any, intent: Any):
- """密码失败回调"""
- pass
-
- def onPasswordSucceeded(self, context: Any, intent: Any):
- """密码成功回调"""
- pass
-
- def onProfileProvisioningComplete(self, context: Any, intent: Any):
- """配置文件配置完成回调"""
- pass
-
- def onBugreportSharingAccepted(self, context: Any, intent: Any, bugreportHash: bytes):
- """错误报告分享接受回调"""
- pass
-
- def onBugreportSharingDeclined(self, context: Any, intent: Any):
- """错误报告分享拒绝回调"""
- pass
-
- def onBugreportFailed(self, context: Any, intent: Any, bugreportHash: bytes):
- """错误报告失败回调"""
- pass
-
- def onNotifyPendingSystemUpdate(self, context: Any, intent: Any, updateReceivedTime: int):
- """系统更新待处理通知回调"""
- pass
-
- def onNetworkLogsAvailable(self, context: Any, intent: Any, batchToken: int, networkLogsCount: int):
- """网络日志可用回调"""
- pass
-
- def onSecurityLogsAvailable(self, context: Any, intent: Any):
- """安全日志可用回调"""
- pass
-
- def onUserAdded(self, context: Any, intent: Any, newUserHandle: Any):
- """用户添加回调"""
- pass
-
- def onUserRemoved(self, context: Any, intent: Any, removedUserHandle: Any):
- """用户移除回调"""
- pass
-
- def onUserStarted(self, context: Any, intent: Any, userHandle: Any):
- """用户启动回调"""
- pass
-
- def onUserStopped(self, context: Any, intent: Any, userHandle: Any):
- """用户停止回调"""
- pass
-
- def onUserSwitched(self, context: Any, intent: Any, switchedUserHandle: Any):
- """用户切换回调"""
- pass
-
- def onLockTaskModeEntering(self, context: Any, intent: Any, pkg: str):
- """锁任务模式进入回调"""
- pass
-
- def onLockTaskModeExiting(self, context: Any, intent: Any):
- """锁任务模式退出回调"""
- pass
-
- def toString(self) -> str:
- return f"DeviceAdminReceiver@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SystemUpdatePolicy
-# ═══════════════════════════════════════════════════════════════
-
-class SystemUpdatePolicy(Stub):
- """SystemUpdatePolicy — 系统更新策略"""
-
- TYPE_INSTALL_AUTOMATIC = 1
- TYPE_INSTALL_WINDOWED = 2
- TYPE_POSTPONE = 3
-
- def __init__(self, policyType: int = TYPE_INSTALL_AUTOMATIC):
- super().__init__()
- self._policyType = policyType
- self._startTime: Optional[str] = None
- self._endTime: Optional[str] = None
-
- def getPolicyType(self) -> int:
- return self._policyType
-
- def setPolicyType(self, policyType: int):
- self._policyType = policyType
-
- def setInstallWindow(self, startTime: str, endTime: str):
- """设置安装窗口时间段 (格式 HH:mm)"""
- self._startTime = startTime
- self._endTime = endTime
-
- def getStartTime(self) -> Optional[str]:
- return self._startTime
-
- def getEndTime(self) -> Optional[str]:
- return self._endTime
-
- @staticmethod
- def createPolicy(policyType: int) -> "SystemUpdatePolicy":
- return SystemUpdatePolicy(policyType=policyType)
-
- def toString(self) -> str:
- return f"SystemUpdatePolicy(type={self._policyType})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, SystemUpdatePolicy):
- return False
- return self._policyType == other._policyType
-
- def hashCode(self) -> int:
- return self._policyType & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/app_assist.py b/android_pyapi/android/app_assist.py
deleted file mode 100644
index 4bb15f4..0000000
--- a/android_pyapi/android/app_assist.py
+++ /dev/null
@@ -1,469 +0,0 @@
-"""
-Android app.assist 包 — AssistManager, AssistStructure, AssistContent
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "AssistManager",
- "AssistStructure",
- "AssistStructureWindowNode",
- "AssistStructureViewNode",
- "AssistContent",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# AssistManager
-# ═══════════════════════════════════════════════════════════════
-
-class AssistManager(Stub):
- """AssistManager — 辅助管理器 (桌面存根)"""
-
- EXTRA_ASSIST_STRUCTURE = "android.app.extra.ASSIST_STRUCTURE"
- EXTRA_ASSIST_CONTENT = "android.app.extra.ASSIST_CONTENT"
- EXTRA_ASSIST_INPUT_HINT = "android.app.extra.ASSIST_INPUT_HINT"
- EXTRA_ASSIST_PACKAGE = "android.app.extra.ASSIST_PACKAGE"
- EXTRA_ASSIST_UID = "android.app.extra.ASSIST_UID"
- KEY_RECEIVER_EXTRA = "receiver_extra"
- KEY_DATA = "data"
- KEY_STRUCTURE = "structure"
- KEY_CONTENT = "content"
- KEY_INPUT_HINT = "input_hint"
- KEY_URI = "uri"
- KEY_ACTIVITY_ID = "activity_id"
- KEY_TIMESTAMP = "timestamp"
- KEY_ACTIVITY_NAME = "activity_name"
- ASSIST_STATE_UNKNOWN = 0
- ASSIST_STATE_DISALLOWED = 1
- ASSIST_STATE_SUPPORTED = 2
- ASSIST_STATE_ALLOWED = 3
- ASSIST_STRUCTURE_EXTRA_ARGS = "android.app.extra.ASSIST_STRUCTURE_ARGS"
- ASSIST_CONTENT_EXTRA_ARGS = "android.app.extra.ASSIST_CONTENT_ARGS"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._assist_state = AssistManager.ASSIST_STATE_ALLOWED
- self._assist_content: Optional["AssistContent"] = None
-
- def showScreenshot(self, screenshot: Any) -> None:
- """显示截图"""
- raise AndroidOnlyError("showScreenshot 仅在 Android 设备上可用")
-
- def showContext(self, context_data: Any) -> None:
- """显示上下文"""
- pass
-
- def getAssistContent(self) -> Optional["AssistContent"]:
- """获取辅助内容"""
- return self._assist_content
-
- def getAssistState(self) -> int:
- """获取辅助状态"""
- return self._assist_state
-
- def setAssistContent(self, content: "AssistContent") -> None:
- """设置辅助内容"""
- self._assist_content = content
-
- def getAssistContentForIntent(self, intent: Any) -> Optional["AssistContent"]:
- """获取 Intent 的辅助内容"""
- return None
-
- def dispatchAssistStructure(self, structure: "AssistStructure") -> None:
- """分发辅助结构"""
- pass
-
- def isAssistAllowed(self) -> bool:
- """检查是否允许辅助"""
- return self._assist_state == AssistManager.ASSIST_STATE_ALLOWED
-
- def suggestAssistInput(self, input_data: Any) -> None:
- """建议辅助输入"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AssistStructure
-# ═══════════════════════════════════════════════════════════════
-
-class AssistStructure(Stub):
- """AssistStructure — 辅助结构 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
- self._activity_name = ""
- self._package_name = ""
- self._windows: List["AssistStructureWindowNode"] = []
- self._description = ""
- self._activity_id = 0
- self._is_home_activity = False
- self._global_state: Optional[Any] = None
- self._data_valid = True
-
- def getActivityName(self) -> str:
- """获取活动名称"""
- return self._activity_name
-
- def getPackageName(self) -> str:
- """获取包名"""
- return self._package_name
-
- def getWindowNodeCount(self) -> int:
- """获取窗口节点数量"""
- return len(self._windows)
-
- def getWindowNodeAt(self, index: int) -> Optional["AssistStructureWindowNode"]:
- """获取指定索引的窗口节点"""
- if 0 <= index < len(self._windows):
- return self._windows[index]
- return None
-
- def getDescription(self) -> str:
- """获取描述"""
- return self._description
-
- def getActivityId(self) -> int:
- """获取活动 ID"""
- return self._activity_id
-
- def getIsHomeActivity(self) -> bool:
- """检查是否为桌面活动"""
- return self._is_home_activity
-
- def getGlobalState(self) -> Optional[Any]:
- """获取全局状态"""
- return self._global_state
-
- def toString(self) -> str:
- return f"AssistStructure(package={self._package_name}, activity={self._activity_name})"
-
- @staticmethod
- def longHashCode(value: int) -> int:
- """长哈希码"""
- return value & 0x7FFFFFFF
-
- def ensureData(self) -> None:
- """确保数据有效"""
- self._data_valid = True
-
- def populateWindowNodes(self) -> None:
- """填充窗口节点"""
- pass
-
- def updateClearCallback(self, callback: Any) -> None:
- """更新清除回调"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AssistStructure.WindowNode
-# ═══════════════════════════════════════════════════════════════
-
-class AssistStructureWindowNode(Stub):
- """AssistStructure.WindowNode — 辅助结构窗口节点"""
-
- def __init__(self):
- super().__init__()
- self._title = ""
- self._left = 0
- self._top = 0
- self._width = 0
- self._height = 0
- self._display_frame = (0, 0, 0, 0)
- self._root_view_node: Optional["AssistStructureViewNode"] = None
-
- def getTitle(self) -> str:
- """获取标题"""
- return self._title
-
- def getLeft(self) -> int:
- """获取左坐标"""
- return self._left
-
- def getTop(self) -> int:
- """获取顶坐标"""
- return self._top
-
- def getWidth(self) -> int:
- """获取宽度"""
- return self._width
-
- def getHeight(self) -> int:
- """获取高度"""
- return self._height
-
- def getDisplayFrame(self) -> Tuple[int, int, int, int]:
- """获取显示框架"""
- return self._display_frame
-
- def getRootViewNode(self) -> Optional["AssistStructureViewNode"]:
- """获取根视图节点"""
- return self._root_view_node
-
- def toString(self) -> str:
- return f"WindowNode(title={self._title}, rect=({self._left},{self._top},{self._width}x{self._height}))"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AssistStructure.ViewNode
-# ═══════════════════════════════════════════════════════════════
-
-class AssistStructureViewNode(Stub):
- """AssistStructure.ViewNode — 辅助结构视图节点"""
-
- def __init__(self):
- super().__init__()
- self._class_name = ""
- self._text = ""
- self._text_size = 0.0
- self._text_color = 0
- self._text_background_color = 0
- self._content_description: Optional[str] = None
- self._input_type = 0
- self._enabled = True
- self._focusable = False
- self._focused = False
- self._accessibility_focused = False
- self._clickable = False
- self._long_clickable = False
- self._selected = False
- self._activated = False
- self._checkable = False
- self._checked = False
- self._context_clickable = False
- self._drawing_order = 0
- self._id = 0
- self._label_for = 0
- self._left = 0
- self._top = 0
- self._scroll_x = 0
- self._scroll_y = 0
- self._width = 0
- self._height = 0
- self._alpha = 1.0
- self._autofill_hints: Optional[List[str]] = None
- self._opaque = True
- self._visibility = 0
- self._assist_blocked = False
- self._important_for_accessibility = 1
- self._children: List["AssistStructureViewNode"] = []
-
- def getClassName(self) -> str:
- return self._class_name
-
- def getText(self) -> str:
- return self._text
-
- def getTextSize(self) -> float:
- return self._text_size
-
- def getTextColor(self) -> int:
- return self._text_color
-
- def getTextBackgroundColor(self) -> int:
- return self._text_background_color
-
- def getContentDescription(self) -> Optional[str]:
- return self._content_description
-
- def getInputType(self) -> int:
- return self._input_type
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def isFocusable(self) -> bool:
- return self._focusable
-
- def isFocused(self) -> bool:
- return self._focused
-
- def isAccessibilityFocused(self) -> bool:
- return self._accessibility_focused
-
- def isClickable(self) -> bool:
- return self._clickable
-
- def isLongClickable(self) -> bool:
- return self._long_clickable
-
- def isSelected(self) -> bool:
- return self._selected
-
- def isActivated(self) -> bool:
- return self._activated
-
- def isCheckable(self) -> bool:
- return self._checkable
-
- def isChecked(self) -> bool:
- return self._checked
-
- def isContextClickable(self) -> bool:
- return self._context_clickable
-
- def getDrawingOrder(self) -> int:
- return self._drawing_order
-
- def getId(self) -> int:
- return self._id
-
- def getLabelFor(self) -> int:
- return self._label_for
-
- def getLeft(self) -> int:
- return self._left
-
- def getTop(self) -> int:
- return self._top
-
- def getScrollX(self) -> int:
- return self._scroll_x
-
- def getScrollY(self) -> int:
- return self._scroll_y
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getAlpha(self) -> float:
- return self._alpha
-
- def getAutofillHints(self) -> Optional[List[str]]:
- return self._autofill_hints
-
- def isOpaque(self) -> bool:
- return self._opaque
-
- def getVisibility(self) -> int:
- return self._visibility
-
- def getAssistBlocked(self) -> bool:
- return self._assist_blocked
-
- def getImportantForAccessibility(self) -> int:
- return self._important_for_accessibility
-
- def getChildCount(self) -> int:
- return len(self._children)
-
- def getChildAt(self, index: int) -> Optional["AssistStructureViewNode"]:
- if 0 <= index < len(self._children):
- return self._children[index]
- return None
-
- def toString(self) -> str:
- return f"ViewNode(class={self._class_name}, text={self._text})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AssistContent
-# ═══════════════════════════════════════════════════════════════
-
-class AssistContent(Stub):
- """AssistContent — 辅助内容 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
- self._intent: Optional[Any] = None
- self._clip_data: Optional[Any] = None
- self._structured_data: Optional[str] = None
- self._provider_uri: Optional[str] = None
- self._extras: Optional[Any] = None
- self._is_app_provided_intent = False
- self._is_app_provided_web_uri = False
- self._web_uri: Optional[str] = None
- self._uri: Optional[str] = None
-
- def getIntent(self) -> Optional[Any]:
- """获取 Intent"""
- return self._intent
-
- def setIntent(self, intent: Any) -> None:
- """设置 Intent"""
- self._intent = intent
- self._is_app_provided_intent = True
-
- def setClipData(self, clip_data: Any) -> None:
- """设置剪贴数据"""
- self._clip_data = clip_data
-
- def getClipData(self) -> Optional[Any]:
- """获取剪贴数据"""
- return self._clip_data
-
- def getStructuredData(self) -> Optional[str]:
- """获取结构化数据"""
- return self._structured_data
-
- def setStructuredData(self, data: str) -> None:
- """设置结构化数据"""
- self._structured_data = data
-
- def getProviderUri(self) -> Optional[str]:
- """获取提供商 URI"""
- return self._provider_uri
-
- def setProviderUri(self, uri: str) -> None:
- """设置提供商 URI"""
- self._provider_uri = uri
-
- def getExtras(self) -> Optional[Any]:
- """获取附加信息"""
- return self._extras
-
- def setExtras(self, extras: Any) -> None:
- """设置附加信息"""
- self._extras = extras
-
- def isAppProvidedIntent(self) -> bool:
- """检查是否为应用提供的 Intent"""
- return self._is_app_provided_intent
-
- def isAppProvidedWebUri(self) -> bool:
- """检查是否为应用提供的 Web URI"""
- return self._is_app_provided_web_uri
-
- def getWebUri(self) -> Optional[str]:
- """获取 Web URI"""
- return self._web_uri
-
- def setWebUri(self, uri: str) -> None:
- """设置 Web URI"""
- self._web_uri = uri
- self._is_app_provided_web_uri = True
-
- def getUri(self) -> Optional[str]:
- """获取 URI"""
- return self._uri
-
- def getLaunchUri(self) -> Optional[str]:
- """获取启动 URI"""
- return self._uri
-
- def clone(self) -> "AssistContent":
- """克隆"""
- new = AssistContent()
- new._intent = self._intent
- new._structured_data = self._structured_data
- new._provider_uri = self._provider_uri
- new._uri = self._uri
- new._web_uri = self._web_uri
- return new
-
- def toString(self) -> str:
- return f"AssistContent(intent={self._intent})"
\ No newline at end of file
diff --git a/android_pyapi/android/app_backup.py b/android_pyapi/android/app_backup.py
deleted file mode 100644
index 5e23961..0000000
--- a/android_pyapi/android/app_backup.py
+++ /dev/null
@@ -1,477 +0,0 @@
-"""
-Android Backup API — BackupManager, BackupAgent, BackupDataInput/Output, RestoreObserver 等
-方法签名完全对齐 Android SDK
-"""
-
-import json
-import os as _os
-import sys
-import tempfile
-import shutil
-import time
-from datetime import datetime
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable, BinaryIO
-
-from .._core import Stub, AndroidOnlyError, resolve_android_path, _app_data_dir
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "BackupManager",
- "BackupAgent",
- "BackupDataInput",
- "BackupDataOutput",
- "FullBackupDataOutput",
- "BackupHelper",
- "FileBackupHelper",
- "SharedPreferencesBackupHelper",
- "RestoreObserver",
- "BackupDataInputStream",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 备份存储路径
-# ═══════════════════════════════════════════════════════════════
-
-_BACKUP_DIR = _os.path.join(_app_data_dir, "backups")
-
-
-def _ensure_backup_dir():
- _os.makedirs(_BACKUP_DIR, exist_ok=True)
-
-
-_ensure_backup_dir()
-
-
-# ═══════════════════════════════════════════════════════════════
-# BackupManager
-# ═══════════════════════════════════════════════════════════════
-
-class BackupManager(Stub):
- """BackupManager — 备份管理器 (桌面文件备份模拟)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._backup_enabled = True
-
- def dataChanged(self, packageName: str = None):
- """通知系统数据已更改,需要备份"""
- if packageName:
- flag_path = _os.path.join(_BACKUP_DIR, f"{packageName}.pending")
- elif self._context:
- flag_path = _os.path.join(_BACKUP_DIR, f"{self._context.getPackageName()}.pending")
- else:
- flag_path = _os.path.join(_BACKUP_DIR, "default.pending")
- with open(flag_path, "w") as f:
- f.write(time.time())
-
- def requestRestore(self, observer: "RestoreObserver") -> int:
- """请求恢复备份数据"""
- raise AndroidOnlyError("BackupManager.requestRestore() 仅在 Android 设备上可用")
-
- def getCurrentTransport(self) -> Optional[str]:
- """获取当前备份传输名称"""
- return "com.android.localtransport.LocalTransport"
-
- def listAllTransports(self) -> List[str]:
- """列出所有可用备份传输"""
- return ["com.android.localtransport.LocalTransport"]
-
- def isBackupEnabled(self) -> bool:
- """检查备份是否启用"""
- return self._backup_enabled
-
- def setBackupEnabled(self, isEnabled: bool):
- """设置备份启用状态"""
- self._backup_enabled = isEnabled
-
- def toString(self) -> str:
- return f"BackupManager(backup_enabled={self._backup_enabled})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# BackupAgent
-# ═══════════════════════════════════════════════════════════════
-
-class BackupAgent(Stub):
- """BackupAgent — 备份代理基类"""
-
- def __init__(self):
- super().__init__()
-
- def onCreate(self):
- """创建备份代理时调用"""
- pass
-
- def onBackup(
- self,
- oldState: "BackupDataInput",
- data: "BackupDataOutput",
- newState: "BackupDataOutput",
- ):
- """执行备份操作"""
- pass
-
- def onRestore(
- self,
- data: "BackupDataInput",
- appVersionCode: int,
- newState: "BackupDataOutput",
- ):
- """执行恢复操作"""
- pass
-
- def toString(self) -> str:
- return f"BackupAgent@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# BackupDataInput
-# ═══════════════════════════════════════════════════════════════
-
-class BackupDataInput(Stub):
- """BackupDataInput — 备份数据输入流"""
-
- def __init__(self, filepath: str = ""):
- super().__init__()
- self._filepath = filepath
- self._data: Dict[str, Any] = {}
- self._keys: List[str] = []
- self._index = 0
- if filepath and _os.path.exists(filepath):
- with open(filepath, "r") as f:
- self._data = json.load(f)
- self._keys = list(self._data.keys())
-
- def readNextHeader(self) -> bool:
- """读取下一个数据头"""
- if self._index < len(self._keys):
- return True
- return False
-
- def getKey(self) -> str:
- """获取当前键名"""
- if self._index < len(self._keys):
- return self._keys[self._index]
- return ""
-
- def getDataSize(self) -> int:
- """获取当前数据大小"""
- if self._index < len(self._keys):
- val = self._data[self._keys[self._index]]
- return len(str(val))
- return 0
-
- def readEntityData(self, data: bytearray, offset: int, size: int) -> int:
- """读取实体数据"""
- if self._index < len(self._keys):
- val = str(self._data[self._keys[self._index]])
- raw = val.encode("utf-8")
- copy_len = min(size, len(raw) - offset)
- for i in range(copy_len):
- data[offset + i] = raw[i]
- self._index += 1
- return copy_len
- return -1
-
- def skipEntityData(self):
- """跳过当前实体数据"""
- self._index += 1
-
- def toString(self) -> str:
- return f"BackupDataInput(file={self._filepath})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# BackupDataOutput
-# ═══════════════════════════════════════════════════════════════
-
-class BackupDataOutput(Stub):
- """BackupDataOutput — 备份数据输出流"""
-
- def __init__(self, filepath: str = ""):
- super().__init__()
- self._filepath = filepath
- self._data: Dict[str, str] = {}
-
- def writeEntityHeader(self, key: str, dataSize: int):
- """写入实体数据头"""
- pass
-
- def writeEntityData(self, data: bytes, size: int):
- """写入实体数据"""
- key = f"entity_{len(self._data)}"
- self._data[key] = data[:size].decode("utf-8", errors="replace")
- if self._filepath:
- _os.makedirs(_os.path.dirname(self._filepath), exist_ok=True)
- with open(self._filepath, "w") as f:
- json.dump(self._data, f)
-
- def toString(self) -> str:
- return f"BackupDataOutput(file={self._filepath})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# FullBackupDataOutput
-# ═══════════════════════════════════════════════════════════════
-
-class FullBackupDataOutput(Stub):
- """FullBackupDataOutput — 完整备份数据输出"""
-
- def __init__(self, quota: int = 0, transportFlags: int = 0):
- super().__init__()
- self._quota = quota
- self._transportFlags = transportFlags
-
- def getQuota(self) -> int:
- return self._quota
-
- def getTransportFlags(self) -> int:
- return self._transportFlags
-
- def toString(self) -> str:
- return f"FullBackupDataOutput(quota={self._quota})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# BackupHelper
-# ═══════════════════════════════════════════════════════════════
-
-class BackupHelper(Stub):
- """BackupHelper — 备份辅助接口"""
-
- def __init__(self):
- super().__init__()
-
- def performBackup(
- self,
- oldState: "BackupDataInput",
- data: "BackupDataOutput",
- newState: "BackupDataOutput",
- ):
- """执行备份"""
- raise AndroidOnlyError("BackupHelper.performBackup() 仅在 Android 设备上可用")
-
- def restoreEntity(self, data: "BackupDataInput", appVersionCode: int):
- """恢复实体"""
- raise AndroidOnlyError("BackupHelper.restoreEntity() 仅在 Android 设备上可用")
-
- def toString(self) -> str:
- return f"BackupHelper@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileBackupHelper
-# ═══════════════════════════════════════════════════════════════
-
-class FileBackupHelper(BackupHelper):
- """FileBackupHelper — 文件备份辅助"""
-
- def __init__(self, context: Any, files: List[str]):
- super().__init__()
- self._context = context
- self._files = list(files)
-
- def performBackup(
- self,
- oldState: "BackupDataInput",
- data: "BackupDataOutput",
- newState: "BackupDataOutput",
- ):
- """执行文件备份"""
- for fname in self._files:
- if self._context:
- filepath = _os.path.join(self._context.getFilesDir(), fname)
- if _os.path.exists(filepath):
- with open(filepath, "rb") as f:
- content = f.read()
- data.writeEntityHeader(fname, len(content))
- data.writeEntityData(content, len(content))
-
- def restoreEntity(self, data: "BackupDataInput", appVersionCode: int):
- """恢复文件实体"""
- key = data.getKey()
- if self._context and key in self._files:
- filepath = _os.path.join(self._context.getFilesDir(), key)
- size = data.getDataSize()
- buf = bytearray(size)
- data.readEntityData(buf, 0, size)
- _os.makedirs(_os.path.dirname(filepath), exist_ok=True)
- with open(filepath, "wb") as f:
- f.write(buf)
-
- def toString(self) -> str:
- return f"FileBackupHelper(files={self._files})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, FileBackupHelper):
- return False
- return self._files == other._files
-
- def hashCode(self) -> int:
- return hash(tuple(self._files)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SharedPreferencesBackupHelper
-# ═══════════════════════════════════════════════════════════════
-
-class SharedPreferencesBackupHelper(BackupHelper):
- """SharedPreferencesBackupHelper — SharedPreferences 备份辅助"""
-
- def __init__(self, context: Any, prefNames: List[str]):
- super().__init__()
- self._context = context
- self._prefNames = list(prefNames)
-
- def performBackup(
- self,
- oldState: "BackupDataInput",
- data: "BackupDataOutput",
- newState: "BackupDataOutput",
- ):
- """执行 SharedPreferences 备份"""
- if not self._context:
- return
- prefs_dir = _os.path.join(_app_data_dir, "shared_prefs")
- for name in self._prefNames:
- filepath = _os.path.join(prefs_dir, f"{name}.xml")
- if _os.path.exists(filepath):
- with open(filepath, "rb") as f:
- content = f.read()
- data.writeEntityHeader(name, len(content))
- data.writeEntityData(content, len(content))
-
- def restoreEntity(self, data: "BackupDataInput", appVersionCode: int):
- """恢复 SharedPreferences"""
- key = data.getKey()
- if self._context and key in self._prefNames:
- prefs_dir = _os.path.join(_app_data_dir, "shared_prefs")
- filepath = _os.path.join(prefs_dir, f"{key}.xml")
- size = data.getDataSize()
- buf = bytearray(size)
- data.readEntityData(buf, 0, size)
- _os.makedirs(prefs_dir, exist_ok=True)
- with open(filepath, "wb") as f:
- f.write(buf)
-
- def toString(self) -> str:
- return f"SharedPreferencesBackupHelper(prefs={self._prefNames})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, SharedPreferencesBackupHelper):
- return False
- return self._prefNames == other._prefNames
-
- def hashCode(self) -> int:
- return hash(tuple(self._prefNames)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RestoreObserver
-# ═══════════════════════════════════════════════════════════════
-
-class RestoreObserver(Stub):
- """RestoreObserver — 恢复过程观察者"""
-
- def __init__(self):
- super().__init__()
-
- def onUpdate(self, nowBeingRestored: int, currentPackage: str):
- """恢复进度更新回调"""
- pass
-
- def onRestoreStarting(self, numPackages: int):
- """恢复开始回调"""
- pass
-
- def onRestoreFinished(self, error: int):
- """恢复完成回调"""
- pass
-
- def toString(self) -> str:
- return f"RestoreObserver@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# BackupDataInputStream
-# ═══════════════════════════════════════════════════════════════
-
-class BackupDataInputStream(Stub):
- """BackupDataInputStream — 备份数据输入流包装器"""
-
- def __init__(self, dataInput: "BackupDataInput" = None):
- super().__init__()
- self._input = dataInput
- self._pos = 0
- self._size = 0
-
- def read(self) -> int:
- """读取一个字节"""
- if self._input and self._pos < self._size:
- self._pos += 1
- return 0
- return -1
-
- def readFully(self, data: bytearray, offset: int, length: int):
- """读取完整数据块"""
- if self._input:
- self._input.readEntityData(data, offset, length)
-
- def size(self) -> int:
- return self._size
-
- def toString(self) -> str:
- return f"BackupDataInputStream(size={self._size})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/app_dialog.py b/android_pyapi/android/app_dialog.py
deleted file mode 100644
index 3c70c50..0000000
--- a/android_pyapi/android/app_dialog.py
+++ /dev/null
@@ -1,874 +0,0 @@
-"""
-Android Dialog API — Dialog, AlertDialog, DatePickerDialog, TimePickerDialog, ProgressDialog, etc.
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import time
-from datetime import datetime
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# BUTTON_* 常量
-BUTTON_POSITIVE = -1
-BUTTON_NEGATIVE = -2
-BUTTON_NEUTRAL = -3
-
-# THEME_* 常量
-THEME_TRADITIONAL = 0
-THEME_DEVICE_DEFAULT_DARK = 1
-THEME_DEVICE_DEFAULT_LIGHT = 2
-THEME_HOLO_DARK = 3
-THEME_HOLO_LIGHT = 4
-THEME_MATERIAL_DARK = 5
-THEME_MATERIAL_LIGHT = 6
-
-# Dialog 常量
-DISMISS_OTHER = 0
-DISMISS_BUTTON_POSITIVE = 1
-DISMISS_BUTTON_NEGATIVE = 2
-DISMISS_BUTTON_NEUTRAL = 3
-
-
-# ═══════════════════════════════════════════════════════════════
-# DialogInterface
-# ═══════════════════════════════════════════════════════════════
-
-class DialogInterface(Stub):
- """DialogInterface — 对话框接口"""
-
- BUTTON_POSITIVE = BUTTON_POSITIVE
- BUTTON_NEGATIVE = BUTTON_NEGATIVE
- BUTTON_NEUTRAL = BUTTON_NEUTRAL
-
- def __init__(self):
- super().__init__()
-
- def cancel(self) -> None:
- pass
-
- def dismiss(self) -> None:
- pass
-
- class OnClickListener(Stub):
- """DialogInterface.OnClickListener — 点击监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onClick(self, dialog: Any, which: int) -> None:
- pass
-
- def toString(self) -> str:
- return "OnClickListener"
-
- class OnDismissListener(Stub):
- """DialogInterface.OnDismissListener — 消除监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onDismiss(self, dialog: Any) -> None:
- pass
-
- def toString(self) -> str:
- return "OnDismissListener"
-
- class OnCancelListener(Stub):
- """DialogInterface.OnCancelListener — 取消监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onCancel(self, dialog: Any) -> None:
- pass
-
- def toString(self) -> str:
- return "OnCancelListener"
-
- class OnMultiChoiceClickListener(Stub):
- """DialogInterface.OnMultiChoiceClickListener — 多选点击监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onClick(self, dialog: Any, which: int, isChecked: bool) -> None:
- pass
-
- def toString(self) -> str:
- return "OnMultiChoiceClickListener"
-
- class OnShowListener(Stub):
- """DialogInterface.OnShowListener — 显示监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onShow(self, dialog: Any) -> None:
- pass
-
- def toString(self) -> str:
- return "OnShowListener"
-
- class OnKeyListener(Stub):
- """DialogInterface.OnKeyListener — 按键监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onKey(self, dialog: Any, keyCode: int, event: Any) -> bool:
- return False
-
- def toString(self) -> str:
- return "OnKeyListener"
-
- def toString(self) -> str:
- return "DialogInterface"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Dialog
-# ═══════════════════════════════════════════════════════════════
-
-class Dialog(DialogInterface):
- """Dialog — 对话框基类 (桌面存根)"""
-
- def __init__(self, context: Any = None, themeResId: int = 0):
- super().__init__()
- self._context = context
- self._theme_res_id = themeResId
- self._mShowing = False
- self._mCancelable = True
- self._mCanceled = False
- self._mCancelMessage: Optional[Any] = None
- self._mDismissMessage: Optional[Any] = None
- self._mShowMessage: Optional[Any] = None
- self._mWindow: Optional[Any] = None
- self._mOwnerActivity: Optional[Any] = None
- self._mOnCancelListener: Optional[DialogInterface.OnCancelListener] = None
- self._mOnDismissListener: Optional[DialogInterface.OnDismissListener] = None
- self._mOnShowListener: Optional[DialogInterface.OnShowListener] = None
- self._mOnKeyListener: Optional[DialogInterface.OnKeyListener] = None
- self._mCancelListeners: List[DialogInterface.OnCancelListener] = []
- self._mDismissListeners: List[DialogInterface.OnDismissListener] = []
- self._mShowListeners: List[DialogInterface.OnShowListener] = []
- self._mCreated = False
- self._mDecor: Optional[Any] = None
- self._mActionMode: Optional[Any] = None
- self._mActionModeType: Optional[Any] = None
- self._mDismissRunnable: Optional[Any] = None
-
- def show(self) -> None:
- self._mShowing = True
- if self._mOnShowListener:
- self._mOnShowListener.onShow(self)
- for listener in self._mShowListeners:
- listener.onShow(self)
-
- def hide(self) -> None:
- self._mShowing = False
-
- def dismiss(self) -> None:
- self._mShowing = False
- if self._mOnDismissListener:
- self._mOnDismissListener.onDismiss(self)
- for listener in self._mDismissListeners:
- listener.onDismiss(self)
-
- def cancel(self) -> None:
- if not self._mCancelable:
- return
- self._mCanceled = True
- if self._mOnCancelListener:
- self._mOnCancelListener.onCancel(self)
- for listener in self._mCancelListeners:
- listener.onCancel(self)
- self.dismiss()
-
- def isShowing(self) -> bool:
- return self._mShowing
-
- def setCancelable(self, flag: bool) -> None:
- self._mCancelable = flag
-
- def setCanceledOnTouchOutside(self, cancel: bool) -> None:
- pass
-
- def isCancelable(self) -> bool:
- return self._mCancelable
-
- def getContext(self) -> Optional[Any]:
- return self._context
-
- def getWindow(self) -> Optional[Any]:
- return self._mWindow
-
- def getOwnerActivity(self) -> Optional[Any]:
- return self._mOwnerActivity
-
- def setOwnerActivity(self, activity: Any) -> None:
- self._mOwnerActivity = activity
-
- def setOnCancelListener(self, listener: Optional[DialogInterface.OnCancelListener]) -> None:
- self._mOnCancelListener = listener
-
- def setOnDismissListener(self, listener: Optional[DialogInterface.OnDismissListener]) -> None:
- self._mOnDismissListener = listener
-
- def setOnShowListener(self, listener: Optional[DialogInterface.OnShowListener]) -> None:
- self._mOnShowListener = listener
-
- def setOnKeyListener(self, listener: Optional[DialogInterface.OnKeyListener]) -> None:
- self._mOnKeyListener = listener
-
- def setCancelMessage(self, msg: Any) -> None:
- self._mCancelMessage = msg
-
- def setDismissMessage(self, msg: Any) -> None:
- self._mDismissMessage = msg
-
- def setTitle(self, title: str) -> None:
- pass
-
- def setVolumeControlStream(self, streamType: int) -> None:
- pass
-
- def getVolumeControlStream(self) -> int:
- return -1
-
- def onWindowFocusChanged(self, hasFocus: bool) -> None:
- pass
-
- def onBackPressed(self) -> None:
- self.cancel()
-
- def onAttachedToWindow(self) -> None:
- pass
-
- def onDetachedFromWindow(self) -> None:
- pass
-
- def onContentChanged(self) -> None:
- pass
-
- def onWindowAttributesChanged(self, attrs: Any) -> None:
- pass
-
- def stopManagingActionMode(self, actionMode: Any) -> None:
- pass
-
- def startManagingActionMode(self, actionMode: Any) -> None:
- pass
-
- def takeActionMode(self, actionMode: Any) -> None:
- pass
-
- def onActionModeStarted(self, actionMode: Any) -> None:
- pass
-
- def onActionModeFinished(self, actionMode: Any) -> None:
- pass
-
- def addContentView(self, view: Any, params: Any) -> None:
- pass
-
- def setContentView(self, viewOrRes: Any, params: Any = None) -> None:
- pass
-
- def requireViewById(self, id: int) -> Any:
- return None
-
- def requireViewById(self, id: int) -> Any:
- result = self.findViewById(id)
- if result is None:
- raise IllegalArgumentException(f"View id=0x{id:x} not found")
- return result
-
- def requestWindowFeature(self, featureId: int) -> bool:
- return True
-
- def getLayoutInflater(self) -> Any:
- return None
-
- def onRestoreInstanceState(self, savedInstanceState: Any) -> None:
- pass
-
- def onSaveInstanceState(self) -> Any:
- return None
-
- def toString(self) -> str:
- return f"Dialog(showing={self._mShowing}, cancelable={self._mCancelable})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AlertDialog
-# ═══════════════════════════════════════════════════════════════
-
-class AlertDialog(Dialog):
- """AlertDialog — 警示对话框"""
-
- THEME_DEVICE_DEFAULT_DARK = THEME_DEVICE_DEFAULT_DARK
- THEME_DEVICE_DEFAULT_LIGHT = THEME_DEVICE_DEFAULT_LIGHT
- THEME_HOLO_DARK = THEME_HOLO_DARK
- THEME_HOLO_LIGHT = THEME_HOLO_LIGHT
- THEME_MATERIAL_DARK = THEME_MATERIAL_DARK
- THEME_MATERIAL_LIGHT = THEME_MATERIAL_LIGHT
- THEME_TRADITIONAL = THEME_TRADITIONAL
-
- def __init__(self, context: Any, themeResId: int = 0):
- super().__init__(context, themeResId)
- self._mTitle: Optional[str] = None
- self._mMessage: Optional[str] = None
- self._mIcon: Optional[Any] = None
- self._mIconAttrId = 0
- self._mPositiveButtonText: Optional[str] = None
- self._mNegativeButtonText: Optional[str] = None
- self._mNeutralButtonText: Optional[str] = None
- self._mPositiveButtonListener: Optional[DialogInterface.OnClickListener] = None
- self._mNegativeButtonListener: Optional[DialogInterface.OnClickListener] = None
- self._mNeutralButtonListener: Optional[DialogInterface.OnClickListener] = None
- self._mItems: Optional[List[str]] = None
- self._mItemClickListener: Optional[DialogInterface.OnClickListener] = None
- self._mAdapter: Optional[Any] = None
- self._mMultiChoiceItems: Optional[List[str]] = None
- self._mMultiChoiceListener: Optional[DialogInterface.OnMultiChoiceClickListener] = None
- self._mCheckedItems: Optional[List[bool]] = None
- self._mView: Optional[Any] = None
- self._mViewSpacingLeft = 0
- self._mViewSpacingTop = 0
- self._mViewSpacingRight = 0
- self._mViewSpacingBottom = 0
- self._mViewSpacingSpecified = False
- self._mCancelable = True
- self._mCancelListener: Optional[DialogInterface.OnCancelListener] = None
- self._mDismissListener: Optional[DialogInterface.OnDismissListener] = None
- self._mKeyListener: Optional[DialogInterface.OnKeyListener] = None
- self._mCustomTitleView: Optional[Any] = None
- self._mMessageView: Optional[Any] = None
- self._mScrollView: Optional[Any] = None
- self._mListView: Optional[Any] = None
- self._mButtonPanelLayout: Optional[Any] = None
- self._mAlertDialogLayout = 0
- self._mButtonPanelSideLayout = 0
- self._mListLayout = 0
- self._mMultiChoiceLayout = 0
- self._mSingleChoiceLayout = 0
- self._mProgressLayout = 0
- self._mProgressNumber: Optional[str] = None
- self._mProgressPercent: Optional[str] = None
- self._mProgressStyle = 0
- self._mProgressValue = 0
- self._mProgressValueMax = 100
- self._mProgressIndeterminate = False
- self._mCheckedItem = -1
- self._mForceInverseBackground = False
- self._mRecycleOnMeasure = True
- self._mShowTitle = True
-
- def getButton(self, whichButton: int) -> Optional[Any]:
- return None
-
- def setTitle(self, title: str) -> None:
- self._mTitle = title
-
- def setMessage(self, message: str) -> None:
- self._mMessage = message
-
- def setIcon(self, icon: Any) -> None:
- self._mIcon = icon
-
- def setIconAttribute(self, attrId: int) -> None:
- self._mIconAttrId = attrId
-
- def setCustomTitle(self, customTitleView: Any) -> None:
- self._mCustomTitleView = customTitleView
-
- def setView(self, view: Any) -> None:
- self._mView = view
-
- def setView(self, view: Any, viewSpacingLeft: int, viewSpacingTop: int, viewSpacingRight: int, viewSpacingBottom: int) -> None:
- self._mView = view
- self._mViewSpacingLeft = viewSpacingLeft
- self._mViewSpacingTop = viewSpacingTop
- self._mViewSpacingRight = viewSpacingRight
- self._mViewSpacingBottom = viewSpacingBottom
- self._mViewSpacingSpecified = True
-
- def setButton(self, whichButton: int, text: Any, listenerOrMsg: Any = None) -> None:
- text_str = str(text) if not isinstance(text, str) else text
- if whichButton == BUTTON_POSITIVE:
- self._mPositiveButtonText = text_str
- if isinstance(listenerOrMsg, DialogInterface.OnClickListener):
- self._mPositiveButtonListener = listenerOrMsg
- elif whichButton == BUTTON_NEGATIVE:
- self._mNegativeButtonText = text_str
- if isinstance(listenerOrMsg, DialogInterface.OnClickListener):
- self._mNegativeButtonListener = listenerOrMsg
- elif whichButton == BUTTON_NEUTRAL:
- self._mNeutralButtonText = text_str
- if isinstance(listenerOrMsg, DialogInterface.OnClickListener):
- self._mNeutralButtonListener = listenerOrMsg
-
- def setIconAttribute(self, attrId: int) -> None:
- self._mIconAttrId = attrId
-
- def getListView(self) -> Optional[Any]:
- return self._mListView
-
- def show(self) -> None:
- super().show()
- # 模拟按钮点击触发
- if self._mPositiveButtonListener:
- pass
- if self._mNegativeButtonListener:
- pass
- if self._mNeutralButtonListener:
- pass
-
- def toString(self) -> str:
- return f"AlertDialog(title={self._mTitle}, message={self._mMessage})"
-
- # ═══════════════════════════════════════════════════════════
- # AlertDialog.Builder
- # ═══════════════════════════════════════════════════════════
-
- class Builder(Stub):
- """AlertDialog.Builder — 警示对话框构建器"""
-
- def __init__(self, context: Any):
- super().__init__()
- self._P = AlertDialog(context)
- self._context = context
-
- def setTitle(self, titleOrId: Any) -> "AlertDialog.Builder":
- if isinstance(titleOrId, int):
- self._P._mTitle = f"title_{titleOrId}"
- else:
- self._P._mTitle = str(titleOrId)
- return self
-
- def setCustomTitle(self, customTitleView: Any) -> "AlertDialog.Builder":
- self._P._mCustomTitleView = customTitleView
- return self
-
- def setMessage(self, messageOrId: Any) -> "AlertDialog.Builder":
- if isinstance(messageOrId, int):
- self._P._mMessage = f"msg_{messageOrId}"
- else:
- self._P._mMessage = str(messageOrId)
- return self
-
- def setIcon(self, iconOrId: Any) -> "AlertDialog.Builder":
- if isinstance(iconOrId, int):
- pass
- else:
- self._P._mIcon = iconOrId
- return self
-
- def setIconAttribute(self, attrId: int) -> "AlertDialog.Builder":
- self._P._mIconAttrId = attrId
- return self
-
- def setPositiveButton(
- self, textOrId: Any, listener: Optional[DialogInterface.OnClickListener] = None
- ) -> "AlertDialog.Builder":
- if isinstance(textOrId, int):
- self._P._mPositiveButtonText = f"positive_{textOrId}"
- else:
- self._P._mPositiveButtonText = str(textOrId)
- self._P._mPositiveButtonListener = listener
- return self
-
- def setNegativeButton(
- self, textOrId: Any, listener: Optional[DialogInterface.OnClickListener] = None
- ) -> "AlertDialog.Builder":
- if isinstance(textOrId, int):
- self._P._mNegativeButtonText = f"negative_{textOrId}"
- else:
- self._P._mNegativeButtonText = str(textOrId)
- self._P._mNegativeButtonListener = listener
- return self
-
- def setNeutralButton(
- self, textOrId: Any, listener: Optional[DialogInterface.OnClickListener] = None
- ) -> "AlertDialog.Builder":
- if isinstance(textOrId, int):
- self._P._mNeutralButtonText = f"neutral_{textOrId}"
- else:
- self._P._mNeutralButtonText = str(textOrId)
- self._P._mNeutralButtonListener = listener
- return self
-
- def setCancelable(self, cancelable: bool) -> "AlertDialog.Builder":
- self._P._mCancelable = cancelable
- return self
-
- def setOnCancelListener(self, listener: DialogInterface.OnCancelListener) -> "AlertDialog.Builder":
- self._P._mCancelListener = listener
- return self
-
- def setOnDismissListener(self, listener: DialogInterface.OnDismissListener) -> "AlertDialog.Builder":
- self._P._mDismissListener = listener
- return self
-
- def setOnKeyListener(self, listener: DialogInterface.OnKeyListener) -> "AlertDialog.Builder":
- self._P._mKeyListener = listener
- return self
-
- def setItems(
- self, itemsOrId: Any, listener: Optional[DialogInterface.OnClickListener] = None
- ) -> "AlertDialog.Builder":
- if isinstance(itemsOrId, int):
- self._P._mItems = [f"item_{itemsOrId}"]
- else:
- self._P._mItems = list(itemsOrId)
- self._P._mItemClickListener = listener
- return self
-
- def setAdapter(
- self, adapter: Any, listener: Optional[DialogInterface.OnClickListener] = None
- ) -> "AlertDialog.Builder":
- self._P._mAdapter = adapter
- self._P._mItemClickListener = listener
- return self
-
- def setSingleChoiceItems(
- self, itemsOrId: Any, checkedItem: int, listener: Optional[DialogInterface.OnClickListener] = None
- ) -> "AlertDialog.Builder":
- if isinstance(itemsOrId, int):
- self._P._mItems = [f"item_{itemsOrId}"]
- else:
- self._P._mItems = list(itemsOrId)
- self._P._mCheckedItem = checkedItem
- self._P._mItemClickListener = listener
- return self
-
- def setMultiChoiceItems(
- self, itemsOrId: Any, checkedItems: Optional[List[bool]],
- listener: Optional[DialogInterface.OnMultiChoiceClickListener] = None
- ) -> "AlertDialog.Builder":
- if isinstance(itemsOrId, int):
- self._P._mMultiChoiceItems = [f"item_{itemsOrId}"]
- self._P._mCheckedItems = [False]
- else:
- self._P._mMultiChoiceItems = list(itemsOrId)
- self._P._mCheckedItems = checkedItems or [False] * len(itemsOrId)
- self._P._mMultiChoiceListener = listener
- return self
-
- def setView(self, viewOrRes: Any) -> "AlertDialog.Builder":
- self._P._mView = viewOrRes
- return self
-
- def setInverseBackgroundForced(self, useInverse: bool) -> "AlertDialog.Builder":
- self._P._mForceInverseBackground = useInverse
- return self
-
- def setRecycleOnMeasureEnabled(self, enabled: bool) -> "AlertDialog.Builder":
- self._P._mRecycleOnMeasure = enabled
- return self
-
- def create(self) -> AlertDialog:
- return self._P
-
- def show(self) -> AlertDialog:
- dialog = self.create()
- dialog.show()
- return dialog
-
- def toString(self) -> str:
- return f"AlertDialog.Builder(title={self._P._mTitle})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CharacterPickerDialog
-# ═══════════════════════════════════════════════════════════════
-
-class CharacterPickerDialog(Dialog):
- """CharacterPickerDialog — 字符选择对话框"""
-
- def __init__(self, context: Any, view: Any, listener: Any, options: List[str], allowMultiple: bool):
- super().__init__(context)
- self._view = view
- self._listener = listener
- self._options = list(options)
- self._allow_multiple = allowMultiple
- self._selected_indices: List[int] = []
- self._selected_characters: List[str] = []
-
- def onClick(self, which: int) -> None:
- if 0 <= which < len(self._options):
- char = self._options[which]
- if self._allow_multiple:
- if which in self._selected_indices:
- self._selected_indices.remove(which)
- self._selected_characters.remove(char)
- else:
- self._selected_indices.append(which)
- self._selected_characters.append(char)
- else:
- self._selected_indices = [which]
- self._selected_characters = [char]
- if self._listener:
- self._listener(char)
-
- def getSelectedCharacters(self) -> List[str]:
- return list(self._selected_characters)
-
- def toString(self) -> str:
- return f"CharacterPickerDialog(options={len(self._options)}, multiple={self._allow_multiple})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DatePickerDialog
-# ═══════════════════════════════════════════════════════════════
-
-class DatePickerDialog(AlertDialog):
- """DatePickerDialog — 日期选择对话框"""
-
- class OnDateSetListener(Stub):
- """DatePickerDialog.OnDateSetListener — 日期设置监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onDateSet(self, view: Any, year: int, month: int, dayOfMonth: int) -> None:
- pass
-
- def toString(self) -> str:
- return "OnDateSetListener"
-
- def __init__(
- self,
- context: Any,
- listener: Optional["DatePickerDialog.OnDateSetListener"] = None,
- year: int = 2024,
- month: int = 0,
- dayOfMonth: int = 1,
- ):
- super().__init__(context)
- self._mListener = listener
- self._mYear = year
- self._mMonth = month
- self._mDay = dayOfMonth
- self._mMinDate: Optional[int] = None
- self._mMaxDate: Optional[int] = None
- self._mDatePicker: Optional[Any] = None
- self._mTitle: Optional[str] = None
- self._mInitialDate = datetime(year, month + 1, dayOfMonth)
-
- def onDateChanged(self, view: Any, year: int, month: int, dayOfMonth: int) -> None:
- self._mYear = year
- self._mMonth = month
- self._mDay = dayOfMonth
-
- def getDatePicker(self) -> Optional[Any]:
- return self._mDatePicker
-
- def setOnDateSetListener(self, listener: "DatePickerDialog.OnDateSetListener") -> None:
- self._mListener = listener
-
- def updateDate(self, year: int, month: int, dayOfMonth: int) -> None:
- self._mYear = year
- self._mMonth = month
- self._mDay = dayOfMonth
-
- def getYear(self) -> int:
- return self._mYear
-
- def getMonth(self) -> int:
- return self._mMonth
-
- def getDayOfMonth(self) -> int:
- return self._mDay
-
- def setMinDate(self, minDate: int) -> None:
- self._mMinDate = minDate
-
- def setMaxDate(self, maxDate: int) -> None:
- self._mMaxDate = maxDate
-
- def getMinDate(self) -> Optional[int]:
- return self._mMinDate
-
- def getMaxDate(self) -> Optional[int]:
- return self._mMaxDate
-
- def show(self) -> None:
- super().show()
- if self._mListener:
- self._mListener.onDateSet(None, self._mYear, self._mMonth, self._mDay)
-
- def toString(self) -> str:
- return f"DatePickerDialog({self._mYear}-{self._mMonth + 1:02d}-{self._mDay:02d})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TimePickerDialog
-# ═══════════════════════════════════════════════════════════════
-
-class TimePickerDialog(AlertDialog):
- """TimePickerDialog — 时间选择对话框"""
-
- class OnTimeSetListener(Stub):
- """TimePickerDialog.OnTimeSetListener — 时间设置监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onTimeSet(self, view: Any, hourOfDay: int, minute: int) -> None:
- pass
-
- def toString(self) -> str:
- return "OnTimeSetListener"
-
- def __init__(
- self,
- context: Any,
- listener: Optional["TimePickerDialog.OnTimeSetListener"] = None,
- hourOfDay: int = 0,
- minute: int = 0,
- is24HourView: bool = True,
- ):
- super().__init__(context)
- self._mListener = listener
- self._mHour = hourOfDay
- self._mMinute = minute
- self._mIs24HourView = is24HourView
- self._mTimePicker: Optional[Any] = None
- self._mTitle: Optional[str] = None
-
- def onTimeChanged(self, view: Any, hourOfDay: int, minute: int) -> None:
- self._mHour = hourOfDay
- self._mMinute = minute
-
- def getTimePicker(self) -> Optional[Any]:
- return self._mTimePicker
-
- def setOnTimeSetListener(self, listener: "TimePickerDialog.OnTimeSetListener") -> None:
- self._mListener = listener
-
- def updateTime(self, hourOfDay: int, minute: int) -> None:
- self._mHour = hourOfDay
- self._mMinute = minute
-
- def getHour(self) -> int:
- return self._mHour
-
- def getMinute(self) -> int:
- return self._mMinute
-
- def is24HourView(self) -> bool:
- return self._mIs24HourView
-
- def show(self) -> None:
- super().show()
- if self._mListener:
- self._mListener.onTimeSet(None, self._mHour, self._mMinute)
-
- def toString(self) -> str:
- return f"TimePickerDialog({self._mHour:02d}:{self._mMinute:02d})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ProgressDialog
-# ═══════════════════════════════════════════════════════════════
-
-class ProgressDialog(AlertDialog):
- """ProgressDialog — 进度对话框"""
-
- STYLE_SPINNER = 0
- STYLE_HORIZONTAL = 1
-
- def __init__(self, context: Any):
- super().__init__(context)
- self._mProgressStyle = ProgressDialog.STYLE_SPINNER
- self._mMax = 100
- self._mProgress = 0
- self._mSecondaryProgress = 0
- self._mIndeterminate = False
- self._mHasProgress = True
- self._mProgressDrawable: Optional[Any] = None
- self._mProgressNumber: Optional[str] = None
- self._mProgressPercent: Optional[str] = None
- self._mProgressNumberFormat = "%1d/%2d"
- self._mProgressPercentFormat = "%.0f%%"
- self._mCurrentProgressText: Optional[str] = None
- self._mProgressTextColor = 0
- self._mProgressBackgroundColor = 0
- self._mMessageViewUpdate: bool = False
-
- def getMax(self) -> int:
- return self._mMax
-
- def setMax(self, max: int) -> None:
- self._mMax = max
-
- def getProgress(self) -> int:
- return self._mProgress
-
- def setProgress(self, value: int) -> None:
- self._mProgress = value
-
- def getSecondaryProgress(self) -> int:
- return self._mSecondaryProgress
-
- def setSecondaryProgress(self, secondaryProgress: int) -> None:
- self._mSecondaryProgress = secondaryProgress
-
- def getProgressStyle(self) -> int:
- return self._mProgressStyle
-
- def setProgressStyle(self, style: int) -> None:
- self._mProgressStyle = style
-
- def isIndeterminate(self) -> bool:
- return self._mIndeterminate
-
- def setIndeterminate(self, indeterminate: bool) -> None:
- self._mIndeterminate = indeterminate
-
- def incrementProgressBy(self, diff: int) -> None:
- self._mProgress = min(self._mProgress + diff, self._mMax)
-
- def incrementSecondaryProgressBy(self, diff: int) -> None:
- self._mSecondaryProgress += diff
-
- def setProgressDrawable(self, drawable: Any) -> None:
- self._mProgressDrawable = drawable
-
- def setProgressNumberFormat(self, format: str) -> None:
- self._mProgressNumberFormat = format
-
- def setProgressPercentFormat(self, format: str) -> None:
- self._mProgressPercentFormat = format
-
- def onStart(self) -> None:
- pass
-
- def setMessage(self, message: str) -> None:
- super().setMessage(message)
-
- def show(
- cls, context: Any, title: str, message: str, indeterminate: bool = True, cancelable: bool = False
- ) -> "ProgressDialog":
- dialog = ProgressDialog(context)
- dialog.setTitle(title)
- dialog.setMessage(message)
- dialog.setIndeterminate(indeterminate)
- dialog.setCancelable(cancelable)
- dialog.show()
- return dialog
-
- def toString(self) -> str:
- return f"ProgressDialog(style={self._mProgressStyle}, progress={self._mProgress}/{self._mMax})"
\ No newline at end of file
diff --git a/android_pyapi/android/app_fragment.py b/android_pyapi/android/app_fragment.py
deleted file mode 100644
index 861d30e..0000000
--- a/android_pyapi/android/app_fragment.py
+++ /dev/null
@@ -1,1055 +0,0 @@
-"""
-Android Fragment API — Fragment, FragmentManager, FragmentTransaction, etc.
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import uuid
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-from enum import IntEnum
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException, IllegalArgumentException, IllegalStateException
-from .app import Fragment as _BaseFragment
-from .app import FragmentManager as _BaseFragmentManager
-from .app import FragmentTransaction as _BaseFragmentTransaction
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# TRANSIT_* 常量
-TRANSIT_NONE = 0
-TRANSIT_FRAGMENT_OPEN = 1
-TRANSIT_FRAGMENT_CLOSE = 2
-TRANSIT_FRAGMENT_FADE = 3
-TRANSIT_UNSET = -1
-TRANSIT_ENTER_MASK = 0x1000
-TRANSIT_EXIT_MASK = 0x2000
-
-# TRANSACTION_* 常量
-TRANSACTION_NONE = 0
-TRANSACTION_ADD = 1
-TRANSACTION_REMOVE = 2
-TRANSACTION_REPLACE = 3
-TRANSACTION_SHOW = 4
-TRANSACTION_HIDE = 5
-TRANSACTION_ATTACH = 6
-TRANSACTION_DETACH = 7
-TRANSACTION_SET_PRIMARY_NAV = 8
-
-# OP_* 操作常量 (内部)
-_OP_NONE = 0
-_OP_ADD = 1
-_OP_REPLACE = 2
-_OP_REMOVE = 3
-_OP_HIDE = 4
-_OP_SHOW = 5
-_OP_DETACH = 6
-_OP_ATTACH = 7
-_OP_SET_PRIMARY_NAV = 8
-
-# Fragment 常量
-Fragment_USE_DEFAULT_TRANSITION = 0
-FRAGMENT_RESULT_CANCELED = 0
-FRAGMENT_RESULT_OK = -1
-
-# FragmentManager 常量
-POP_BACK_STACK_INCLUSIVE = 1
-
-
-# ═══════════════════════════════════════════════════════════════
-# Fragment
-# ═══════════════════════════════════════════════════════════════
-
-class Fragment(_BaseFragment):
- """Fragment — 片段基类 (桌面存根,继承 app.Fragment 的所有方法)"""
-
- def __init__(self):
- super().__init__()
- self._mCalled = False
- self._mTag: Optional[str] = None
- self._mFragmentId = 0
- self._mContainerId = 0
- self._mView: Optional[Any] = None
- self._mArguments: Optional[Any] = None
- self._mHidden = False
- self._mDetached = False
- self._mRemoving = False
- self._mInLayout = False
- self._mMenuVisible = True
- self._mHasMenu = False
- self._mRetainInstance = False
- self._mUserVisibleHint = True
- self._mState = 0
- self._mSavedState: Optional[Any] = None
- self._mActivity: Optional["FragmentActivity"] = None
- self._mHost: Optional["FragmentHostCallback"] = None
- self._mFragmentManager: Optional["FragmentManager"] = None
- self._mChildFragmentManager: Optional["FragmentManager"] = None
- self._mParentFragment: Optional["Fragment"] = None
- self._mTargetFragment: Optional["Fragment"] = None
- self._mTargetRequestCode = 0
- self._mNextAnim = 0
- self._mEnterTransition: Optional[Any] = None
- self._mExitTransition: Optional[Any] = None
- self._mSharedElementEnterTransition: Optional[Any] = None
- self._mSharedElementExitTransition: Optional[Any] = None
- self._mAllowEnterTransitionOverlap: Optional[bool] = None
- self._mAllowReturnTransitionOverlap: Optional[bool] = None
- self._mReenterTransition: Optional[Any] = None
- self._mReturnTransition: Optional[Any] = None
- self._mSharedElementReturnTransition: Optional[Any] = None
- self._mSharedElementReenterTransition: Optional[Any] = None
- self._mLifecycleRegistry: Optional[Any] = None
- self._mViewModelStore: Optional[Any] = None
- self._mMaxState: Optional[str] = None
- self._mInitialLifecycleState: Optional[int] = None
- self._mPrimaryNavigationFragment = False
- self._mIsNewlyAdded = False
- self._mIsCreated = False
- self._mIsViewCreated = False
- self._mIsStateSaved = False
- self._mIsStateSavedBefore = False
- self._mFragmentTransitionState = 0
- self._mInTransition = False
- self._mPostponedHandler: Optional[Any] = None
- self._mAnimationInfo: Optional[Any] = None
- self._mDebug = False
- self._mCalledForTransition = False
- self._mHiddenChanged = False
- self._mAnimationResId = 0
- self._mContainer: Optional["FragmentContainer"] = None
- self._mFactory: Optional[Any] = None
- self._mRequestPermissionsResult: List[Tuple[int, List[str], List[int]]] = []
- self._mResultListeners: List[Any] = []
-
- def getActivity(self) -> Optional["FragmentActivity"]:
- return self._mActivity
-
- def getHost(self) -> Optional["FragmentHostCallback"]:
- return self._mHost
-
- def getFragmentManager(self) -> Optional["FragmentManager"]:
- return self._mFragmentManager
-
- def getChildFragmentManager(self) -> Optional["FragmentManager"]:
- if self._mChildFragmentManager is None:
- from .._core import Stub as _Stub
- self._mChildFragmentManager = FragmentManager()
- return self._mChildFragmentManager
-
- def getParentFragment(self) -> Optional["Fragment"]:
- return self._mParentFragment
-
- def getTag(self) -> Optional[str]:
- return self._mTag
-
- def getId(self) -> int:
- return self._mFragmentId
-
- def getView(self) -> Optional[Any]:
- return self._mView
-
- def getArguments(self) -> Optional[Any]:
- return self._mArguments
-
- def setArguments(self, args: Any) -> None:
- if self._mState > 0:
- raise IllegalStateException("Fragment already active")
- self._mArguments = args
-
- def isAdded(self) -> bool:
- return self._mActivity is not None and self._mState > 0
-
- def isDetached(self) -> bool:
- return self._mDetached
-
- def isRemoving(self) -> bool:
- return self._mRemoving
-
- def isInLayout(self) -> bool:
- return self._mInLayout
-
- def isResumed(self) -> bool:
- return self._mState >= 7
-
- def isVisible(self) -> bool:
- return (not self._mHidden) and self.isAdded() and self._mView is not None
-
- def isHidden(self) -> bool:
- return self._mHidden
-
- def isMenuVisible(self) -> bool:
- return self._mMenuVisible
-
- def getUserVisibleHint(self) -> bool:
- return self._mUserVisibleHint
-
- def setUserVisibleHint(self, isVisible: bool) -> None:
- self._mUserVisibleHint = isVisible
- self._mHiddenChanged = not isVisible
-
- def getRetainInstance(self) -> bool:
- return self._mRetainInstance
-
- def setRetainInstance(self, retain: bool) -> None:
- self._mRetainInstance = retain
-
- def hasOptionsMenu(self) -> bool:
- return self._mHasMenu
-
- def setHasOptionsMenu(self, hasMenu: bool) -> None:
- self._mHasMenu = hasMenu
-
- def setMenuVisibility(self, menuVisible: bool) -> None:
- self._mMenuVisible = menuVisible
-
- def getTargetFragment(self) -> Optional["Fragment"]:
- return self._mTargetFragment
-
- def setTargetFragment(self, fragment: Optional["Fragment"], requestCode: int) -> None:
- self._mTargetFragment = fragment
- self._mTargetRequestCode = requestCode
-
- def getTargetRequestCode(self) -> int:
- return self._mTargetRequestCode
-
- def getContext(self) -> Optional[Any]:
- return self._mActivity
-
- def getResources(self) -> Optional[Any]:
- if self._mActivity:
- return self._mActivity.getResources()
- return None
-
- def requireActivity(self) -> "FragmentActivity":
- if self._mActivity is None:
- raise IllegalStateException("Fragment not attached to Activity")
- return self._mActivity
-
- def requireFragmentManager(self) -> "FragmentManager":
- if self._mFragmentManager is None:
- raise IllegalStateException("Fragment not attached to FragmentManager")
- return self._mFragmentManager
-
- def requireContext(self) -> Any:
- ctx = self.getContext()
- if ctx is None:
- raise IllegalStateException("Fragment not attached to a context")
- return ctx
-
- def requireView(self) -> Any:
- view = self.getView()
- if view is None:
- raise IllegalStateException("Fragment does not have a view")
- return view
-
- def requireHost(self) -> "FragmentHostCallback":
- if self._mHost is None:
- raise IllegalStateException("Fragment not attached to host")
- return self._mHost
-
- def isStateSaved(self) -> bool:
- return self._mIsStateSaved
-
- def getLifecycle(self) -> Optional[Any]:
- return self._mLifecycleRegistry
-
- def getViewModelStore(self) -> Optional[Any]:
- return self._mViewModelStore
-
- def postponeEnterTransition(self) -> None:
- self._mPostponedHandler = True
-
- def startPostponedEnterTransition(self) -> None:
- self._mPostponedHandler = None
-
- def getEnterTransition(self) -> Optional[Any]:
- return self._mEnterTransition
-
- def setEnterTransition(self, transition: Any) -> None:
- self._mEnterTransition = transition
-
- def getExitTransition(self) -> Optional[Any]:
- return self._mExitTransition
-
- def setExitTransition(self, transition: Any) -> None:
- self._mExitTransition = transition
-
- def getSharedElementEnterTransition(self) -> Optional[Any]:
- return self._mSharedElementEnterTransition
-
- def setSharedElementEnterTransition(self, transition: Any) -> None:
- self._mSharedElementEnterTransition = transition
-
- def getSharedElementExitTransition(self) -> Optional[Any]:
- return self._mSharedElementExitTransition
-
- def setSharedElementExitTransition(self, transition: Any) -> None:
- self._mSharedElementExitTransition = transition
-
- def getReenterTransition(self) -> Optional[Any]:
- return self._mReenterTransition or self._mEnterTransition
-
- def setReenterTransition(self, transition: Any) -> None:
- self._mReenterTransition = transition
-
- def getReturnTransition(self) -> Optional[Any]:
- return self._mReturnTransition or self._mExitTransition
-
- def setReturnTransition(self, transition: Any) -> None:
- self._mReturnTransition = transition
-
- def getSharedElementReturnTransition(self) -> Optional[Any]:
- return self._mSharedElementReturnTransition or self._mSharedElementEnterTransition
-
- def setSharedElementReturnTransition(self, transition: Any) -> None:
- self._mSharedElementReturnTransition = transition
-
- def getSharedElementReenterTransition(self) -> Optional[Any]:
- return self._mSharedElementReenterTransition or self._mSharedElementExitTransition
-
- def setSharedElementReenterTransition(self, transition: Any) -> None:
- self._mSharedElementReenterTransition = transition
-
- def getAllowEnterTransitionOverlap(self) -> bool:
- return self._mAllowEnterTransitionOverlap is not False
-
- def setAllowEnterTransitionOverlap(self, allow: bool) -> None:
- self._mAllowEnterTransitionOverlap = allow
-
- def getAllowReturnTransitionOverlap(self) -> bool:
- return self._mAllowReturnTransitionOverlap is not False
-
- def setAllowReturnTransitionOverlap(self, allow: bool) -> None:
- self._mAllowReturnTransitionOverlap = allow
-
- def isInBackStack(self) -> bool:
- return self._mFragmentManager is not None
-
- def getString(self, resId: int, *formatArgs: Any) -> str:
- return f"string_{resId}"
-
- def getText(self, resId: int) -> str:
- return f"text_{resId}"
-
- def getInt(self, resId: int) -> int:
- return 0
-
- def getBoolean(self, resId: int) -> bool:
- return False
-
- def instantiate(self, context: Any, fname: str, args: Optional[Any] = None) -> "Fragment":
- return Fragment()
-
- # ── 生命周期 ──
- def onAttach(self, context: Any) -> None:
- self._mCalled = True
-
- def onCreate(self, savedInstanceState: Optional[Any]) -> None:
- self._mCalled = True
- self._mIsCreated = True
-
- def onCreateView(self, inflater: Any, container: Any, savedInstanceState: Optional[Any]) -> Optional[Any]:
- self._mCalled = True
- return None
-
- def onViewCreated(self, view: Any, savedInstanceState: Optional[Any]) -> None:
- self._mCalled = True
- self._mIsViewCreated = True
-
- def onActivityCreated(self, savedInstanceState: Optional[Any]) -> None:
- self._mCalled = True
-
- def onViewStateRestored(self, savedInstanceState: Optional[Any]) -> None:
- self._mCalled = True
-
- def onStart(self) -> None:
- self._mCalled = True
-
- def onResume(self) -> None:
- self._mCalled = True
-
- def onPause(self) -> None:
- self._mCalled = True
-
- def onStop(self) -> None:
- self._mCalled = True
-
- def onDestroyView(self) -> None:
- self._mCalled = True
- self._mIsViewCreated = False
-
- def onDestroy(self) -> None:
- self._mCalled = True
- self._mIsCreated = False
-
- def onDetach(self) -> None:
- self._mCalled = True
-
- def onSaveInstanceState(self, outState: Any) -> None:
- pass
-
- def onMultiWindowModeChanged(self, isInMultiWindowMode: bool, newConfig: Any) -> None:
- pass
-
- def onPictureInPictureModeChanged(self, isInPictureInPictureMode: bool, newConfig: Any) -> None:
- pass
-
- def onConfigurationChanged(self, newConfig: Any) -> None:
- pass
-
- def onLowMemory(self) -> None:
- pass
-
- def onHiddenChanged(self, hidden: bool) -> None:
- pass
-
- def onAttachFragment(self, childFragment: "Fragment") -> None:
- pass
-
- def dump(self, prefix: str, fd: Any, writer: Any, args: List[str]) -> None:
- pass
-
- def registerForActivityResult(self, contract: Any, callback: Any) -> Any:
- return None
-
- def unregisterForActivityResult(self, token: Any) -> None:
- pass
-
- def toString(self) -> str:
- return f"Fragment({self._mTag or hex(id(self))})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FragmentManager
-# ═══════════════════════════════════════════════════════════════
-
-class FragmentManager(_BaseFragmentManager):
- """FragmentManager — 片段管理器 (继承 app.FragmentManager 的所有方法)"""
-
- def __init__(self):
- super().__init__()
- self._lock = threading.Lock()
- self._fragments: Dict[str, Fragment] = {}
- self._back_stack: List["FragmentTransaction"] = []
- self._back_stack_indices: Dict[int, str] = {}
- self._next_index = 0
- self._primary_nav_fragment: Optional[Fragment] = None
- self._fragment_container: Optional["FragmentContainer"] = None
-
- def beginTransaction(self) -> "FragmentTransaction":
- return FragmentTransaction(self)
-
- def executePendingTransactions(self) -> bool:
- return True
-
- def findFragmentById(self, id: int) -> Optional[Fragment]:
- with self._lock:
- for frag in self._fragments.values():
- if frag.getId() == id:
- return frag
- return None
-
- def findFragmentByTag(self, tag: str) -> Optional[Fragment]:
- with self._lock:
- return self._fragments.get(tag)
-
- def popBackStack(self) -> None:
- with self._lock:
- if self._back_stack:
- trans = self._back_stack.pop()
- trans._reverse()
-
- def popBackStackImmediate(self, name: Optional[str] = None, flags: int = 0) -> bool:
- self.popBackStack()
- return True
-
- def popBackStack(
- self, name: Optional[str], flags: int
- ) -> None:
- with self._lock:
- if name is None:
- if self._back_stack:
- trans = self._back_stack.pop()
- trans._reverse()
- return
- idx = -1
- for i, t in enumerate(self._back_stack):
- if t._name == name:
- idx = i
- break
- if idx >= 0:
- inclusive = (flags & POP_BACK_STACK_INCLUSIVE) != 0
- start = idx if inclusive else idx + 1
- to_remove = self._back_stack[start:]
- self._back_stack = self._back_stack[:start]
- for t in reversed(to_remove):
- t._reverse()
-
- def getBackStackEntryCount(self) -> int:
- with self._lock:
- return len(self._back_stack)
-
- def getBackStackEntryAt(self, index: int) -> Optional[Any]:
- with self._lock:
- if 0 <= index < len(self._back_stack):
- return self._back_stack[index]
- return None
-
- def saveFragmentInstanceState(self, fragment: Fragment) -> Optional[Any]:
- return None
-
- def isDestroyed(self) -> bool:
- return False
-
- def isStateSaved(self) -> bool:
- return False
-
- def getFragments(self) -> List[Fragment]:
- with self._lock:
- return list(self._fragments.values())
-
- def getFragment(self, bundle: Any, key: str) -> Optional[Fragment]:
- return None
-
- def putFragment(self, bundle: Any, key: str, fragment: Fragment) -> None:
- pass
-
- def getPrimaryNavigationFragment(self) -> Optional[Fragment]:
- return self._primary_nav_fragment
-
- def registerFragmentLifecycleCallbacks(self, cb: Any, recursive: bool) -> None:
- pass
-
- def unregisterFragmentLifecycleCallbacks(self, cb: Any) -> None:
- pass
-
- def isPrimaryNavigation(self, fragment: Fragment) -> bool:
- return fragment == self._primary_nav_fragment
-
- def toString(self) -> str:
- with self._lock:
- return f"FragmentManager(fragments={len(self._fragments)}, backstack={len(self._back_stack)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FragmentTransaction
-# ═══════════════════════════════════════════════════════════════
-
-class FragmentTransaction(_BaseFragmentTransaction):
- """FragmentTransaction — 片段事务 (继承 app.FragmentTransaction 的所有方法)"""
-
- TRANSIT_ENTER_MASK = TRANSIT_ENTER_MASK
- TRANSIT_EXIT_MASK = TRANSIT_EXIT_MASK
- TRANSIT_UNSET = TRANSIT_UNSET
- TRANSIT_NONE = TRANSIT_NONE
- TRANSIT_FRAGMENT_OPEN = TRANSIT_FRAGMENT_OPEN
- TRANSIT_FRAGMENT_CLOSE = TRANSIT_FRAGMENT_CLOSE
- TRANSIT_FRAGMENT_FADE = TRANSIT_FRAGMENT_FADE
-
- def __init__(self, manager: "FragmentManager"):
- super().__init__()
- self._manager = manager
- self._ops: List[Dict[str, Any]] = []
- self._name: Optional[str] = None
- self._transition = TRANSIT_NONE
- self._transition_style = 0
- self._transition_shared = False
- self._allow_add_to_back_stack = True
- self._add_to_back_stack = False
- self._is_reordering_allowed = False
- self._bread_crumb_title_res = 0
- self._bread_crumb_title: Optional[str] = None
- self._mCommitListener: Optional[Any] = None
-
- def add(self, containerViewId: Any = 0, fragment: Optional[Any] = None, tag: Optional[str] = None) -> "FragmentTransaction":
- if fragment is None and not isinstance(containerViewId, int):
- fragment = containerViewId
- containerViewId = 0
- self._ops.append({
- "op": _OP_ADD,
- "fragment": fragment,
- "containerId": int(containerViewId) if isinstance(containerViewId, int) else 0,
- "tag": tag,
- })
- if tag:
- fragment._mTag = tag
- return self
-
- def replace(self, containerViewId: int, fragment: Fragment, tag: Optional[str] = None) -> "FragmentTransaction":
- self._ops.append({
- "op": _OP_REPLACE,
- "fragment": fragment,
- "containerId": containerViewId,
- "tag": tag,
- })
- if tag:
- fragment._mTag = tag
- return self
-
- def remove(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"op": _OP_REMOVE, "fragment": fragment})
- return self
-
- def hide(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"op": _OP_HIDE, "fragment": fragment})
- return self
-
- def show(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"op": _OP_SHOW, "fragment": fragment})
- return self
-
- def detach(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"op": _OP_DETACH, "fragment": fragment})
- return self
-
- def attach(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"op": _OP_ATTACH, "fragment": fragment})
- return self
-
- def setPrimaryNavigationFragment(self, fragment: Fragment) -> "FragmentTransaction":
- self._ops.append({"op": _OP_SET_PRIMARY_NAV, "fragment": fragment})
- return self
-
- def addToBackStack(self, name: Optional[str] = None) -> "FragmentTransaction":
- self._add_to_back_stack = True
- self._name = name
- return self
-
- def setTransition(self, transit: int) -> "FragmentTransaction":
- self._transition = transit
- return self
-
- def setTransitionStyle(self, styleRes: int) -> "FragmentTransaction":
- self._transition_style = styleRes
- return self
-
- def setAllowOptimization(self, allow: bool) -> "FragmentTransaction":
- self._is_reordering_allowed = allow
- return self
-
- def setReorderingAllowed(self, allowed: bool) -> "FragmentTransaction":
- self._is_reordering_allowed = allowed
- return self
-
- def setBreadCrumbTitle(self, titleOrRes: Any) -> "FragmentTransaction":
- if isinstance(titleOrRes, int):
- self._bread_crumb_title_res = titleOrRes
- else:
- self._bread_crumb_title = str(titleOrRes)
- return self
-
- def runOnCommit(self, runnable: Callable[[], None]) -> "FragmentTransaction":
- self._mCommitListener = runnable
- return self
-
- def commit(self) -> int:
- with self._manager._lock:
- entry_id = self._manager._next_index
- self._manager._next_index += 1
- self._commit_ops()
- if self._add_to_back_stack:
- self._manager._back_stack.append(self)
- return entry_id
-
- def commitNow(self) -> None:
- self.commit()
-
- def commitAllowingStateLoss(self) -> int:
- return self.commit()
-
- def _commit_ops(self) -> None:
- for op in self._ops:
- frag = op["fragment"]
- tag = op.get("tag") or frag._mTag
- if op["op"] == _OP_ADD or op["op"] == _OP_REPLACE:
- if tag:
- self._manager._fragments[tag] = frag
- frag._mFragmentManager = self._manager
- elif op["op"] == _OP_REMOVE:
- if tag and tag in self._manager._fragments:
- del self._manager._fragments[tag]
- elif op["op"] == _OP_SET_PRIMARY_NAV:
- self._manager._primary_nav_fragment = frag
-
- def _reverse(self) -> None:
- for op in reversed(self._ops):
- frag = op["fragment"]
- tag = frag._mTag
- if op["op"] == _OP_ADD:
- if tag and tag in self._manager._fragments:
- del self._manager._fragments[tag]
- elif op["op"] == _OP_REMOVE:
- if tag:
- self._manager._fragments[tag] = frag
-
- def toString(self) -> str:
- return f"FragmentTransaction(ops={len(self._ops)}, backstack={self._add_to_back_stack})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FragmentActivity
-# ═══════════════════════════════════════════════════════════════
-
-class FragmentActivity(Stub):
- """FragmentActivity — 支持 Fragment 的 Activity"""
-
- def __init__(self):
- super().__init__()
- self._mFragments: FragmentController = FragmentController(FragmentManager())
- self._mFragmentManager: FragmentManager = FragmentManager()
- self._mCreated = False
- self._mResumed = False
- self._mStarted = False
-
- def getSupportFragmentManager(self) -> FragmentManager:
- return self._mFragmentManager
-
- def getSupportFragmentManager(self) -> FragmentManager:
- return self._mFragments.getFragmentManager()
-
- def onAttachFragment(self, fragment: Fragment) -> None:
- pass
-
- def supportInvalidateOptionsMenu(self) -> None:
- pass
-
- def dump(self, prefix: str, fd: Any, writer: Any, args: List[str]) -> None:
- pass
-
- def getLifecycle(self) -> Optional[Any]:
- return None
-
- def getViewModelStore(self) -> Optional[Any]:
- return None
-
- def toString(self) -> str:
- return f"FragmentActivity@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FragmentController
-# ═══════════════════════════════════════════════════════════════
-
-class FragmentController(Stub):
- """FragmentController — 片段控制器"""
-
- def __init__(self, manager: FragmentManager):
- super().__init__()
- self._manager = manager
-
- def getFragmentManager(self) -> FragmentManager:
- return self._manager
-
- def execPendingActions(self) -> None:
- pass
-
- def doLoaderStart(self) -> None:
- pass
-
- def doLoaderStop(self, retain: bool) -> None:
- pass
-
- def doLoaderRetain(self) -> None:
- pass
-
- def doLoaderDestroy(self) -> None:
- pass
-
- def noteStateNotSaved(self) -> None:
- pass
-
- def saveAllState(self) -> Optional[Any]:
- return None
-
- def restoreAllState(self, state: Any) -> None:
- pass
-
- def createLoader(self, id: int, bundle: Any, callback: Any) -> Any:
- return None
-
- def dispatchCreate(self) -> None:
- pass
-
- def dispatchActivityCreated(self) -> None:
- pass
-
- def dispatchStart(self) -> None:
- pass
-
- def dispatchResume(self) -> None:
- pass
-
- def dispatchPause(self) -> None:
- pass
-
- def dispatchStop(self) -> None:
- pass
-
- def dispatchDestroy(self) -> None:
- pass
-
- def dispatchMultiWindowModeChanged(self, isInMultiWindowMode: bool, newConfig: Any) -> None:
- pass
-
- def dispatchPictureInPictureModeChanged(self, isInPictureInPictureMode: bool, newConfig: Any) -> None:
- pass
-
- def dispatchConfigurationChanged(self, newConfig: Any) -> None:
- pass
-
- def dispatchLowMemory(self) -> None:
- pass
-
- def toString(self) -> str:
- return f"FragmentController(manager={self._manager})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FragmentHostCallback
-# ═══════════════════════════════════════════════════════════════
-
-class FragmentHostCallback(Stub):
- """FragmentHostCallback — 片段宿主的回调基类"""
-
- def __init__(self, context: Any = None, fragmentManager: Any = None, loaderManager: Any = None):
- super().__init__()
- self._context = context
- self._fragmentManager = fragmentManager
- self._loaderManager = loaderManager
-
- def onStartLoadingFragment(self, fragment: Fragment) -> None:
- pass
-
- def onDump(self, prefix: str, fd: Any, writer: Any, args: List[str]) -> None:
- pass
-
- def onShouldShowRequestPermissionRationale(self, permission: str) -> bool:
- return True
-
- def onGetLayoutInflater(self) -> Any:
- return None
-
- def onFindViewById(self, id: int) -> Optional[Any]:
- return None
-
- def onHasView(self) -> bool:
- return False
-
- def onGetWindowAnimations(self) -> int:
- return 0
-
- def onHasWindowAnimations(self) -> bool:
- return False
-
- def onGetActivityResultRegistry(self) -> Any:
- return None
-
- def onAttachFragment(self, fragment: Fragment) -> None:
- pass
-
- def onGetHostIdentifier(self) -> Any:
- return None
-
- def onValidateRequestPermissionsRequestCode(self, requestCode: int) -> None:
- pass
-
- def toString(self) -> str:
- return f"FragmentHostCallback@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FragmentContainer
-# ═══════════════════════════════════════════════════════════════
-
-class FragmentContainer(Stub):
- """FragmentContainer — 片段容器接口"""
-
- def __init__(self):
- super().__init__()
-
- def instantiate(self, context: Any, className: str, arguments: Optional[Any] = None) -> Fragment:
- return Fragment()
-
- def onFindViewById(self, id: int) -> Optional[Any]:
- return None
-
- def onHasView(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"FragmentContainer@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DialogFragment
-# ═══════════════════════════════════════════════════════════════
-
-class DialogFragment(Fragment):
- """DialogFragment — 对话框片段"""
-
- STYLE_NORMAL = 0
- STYLE_NO_TITLE = 1
- STYLE_NO_FRAME = 2
- STYLE_NO_INPUT = 3
-
- def __init__(self):
- super().__init__()
- self._dialog: Optional[Any] = None
- self._style = DialogFragment.STYLE_NORMAL
- self._theme = 0
- self._cancelable = True
- self._showing = False
- self._dismissed = False
- self._dismissed_by_nav = False
- self._shows_dialog = True
- self._mBackStackId = -1
- self._mDialogCanceled = False
-
- def setStyle(self, style: int, theme: int = 0) -> None:
- self._style = style
- self._theme = theme
-
- def show(self, manager: FragmentManager, tag: str) -> None:
- self._showing = True
- manager.beginTransaction().add(self, tag).commit()
-
- def showNow(self, manager: FragmentManager, tag: str) -> None:
- self.show(manager, tag)
-
- def dismiss(self) -> None:
- self._dismissed = True
- fm = self.getFragmentManager()
- if fm:
- fm.beginTransaction().remove(self).commit()
-
- def dismissAllowingStateLoss(self) -> None:
- self.dismiss()
-
- def getDialog(self) -> Optional[Any]:
- return self._dialog
-
- def getTheme(self) -> int:
- return self._theme
-
- def setCancelable(self, cancelable: bool) -> None:
- self._cancelable = cancelable
-
- def isCancelable(self) -> bool:
- return self._cancelable
-
- def setShowsDialog(self, showsDialog: bool) -> None:
- self._shows_dialog = showsDialog
-
- def getShowsDialog(self) -> bool:
- return self._shows_dialog
-
- def onDismiss(self, dialog: Any) -> None:
- pass
-
- def onCancel(self, dialog: Any) -> None:
- pass
-
- def onCreateDialog(self, savedInstanceState: Optional[Any]) -> Any:
- return None
-
- def toString(self) -> str:
- return f"DialogFragment(style={self._style}, showing={self._showing})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ListFragment
-# ═══════════════════════════════════════════════════════════════
-
-class ListFragment(Fragment):
- """ListFragment — 列表片段"""
-
- def __init__(self):
- super().__init__()
- self._adapter: Optional[Any] = None
- self._list_view: Optional[Any] = None
- self._selected_position = -1
- self._empty_text: Optional[str] = None
- self._empty_view: Optional[Any] = None
- self._progress_container: Optional[Any] = None
- self._standard_empty_view = False
- self._list_shown = False
- self._list_shown_no_animation = True
-
- def getListAdapter(self) -> Optional[Any]:
- return self._adapter
-
- def setListAdapter(self, adapter: Any) -> None:
- self._adapter = adapter
-
- def getListView(self) -> Optional[Any]:
- return self._list_view
-
- def getSelectedItemPosition(self) -> int:
- return self._selected_position
-
- def getSelectedItemId(self) -> int:
- return 0
-
- def setSelection(self, position: int) -> None:
- self._selected_position = position
-
- def setEmptyText(self, text: str) -> None:
- self._empty_text = text
-
- def getEmptyText(self) -> Optional[str]:
- return self._empty_text
-
- def listViewScrollToTop(self) -> None:
- pass
-
- def isListShown(self) -> bool:
- return self._list_shown
-
- def setListShown(self, shown: bool) -> None:
- self._list_shown = shown
- self._list_shown_no_animation = True
-
- def setListShownNoAnimation(self, shown: bool) -> None:
- self._list_shown = shown
- self._list_shown_no_animation = True
-
- def onListItemClick(self, lv: Any, v: Any, position: int, id: int) -> None:
- pass
-
- def onListAdapterChanged(self, adapter: Any) -> None:
- pass
-
- def toString(self) -> str:
- return f"ListFragment(list_shown={self._list_shown})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FragmentManagerNonConfig
-# ═══════════════════════════════════════════════════════════════
-
-class FragmentManagerNonConfig(Stub):
- """FragmentManagerNonConfig — 非配置保留片段 (已弃用)"""
-
- def __init__(self):
- super().__init__()
- self._fragments: List[Fragment] = []
- self._child_non_configs: List["FragmentManagerNonConfig"] = []
- self._view_model_stores: List[Any] = []
-
- def getFragments(self) -> List[Fragment]:
- return list(self._fragments)
-
- def getChildNonConfigs(self) -> List["FragmentManagerNonConfig"]:
- return list(self._child_non_configs)
-
- def getViewModelStores(self) -> List[Any]:
- return list(self._view_model_stores)
-
- def toString(self) -> str:
- return f"FragmentManagerNonConfig(fragments={len(self._fragments)})"
\ No newline at end of file
diff --git a/android_pyapi/android/app_job.py b/android_pyapi/android/app_job.py
deleted file mode 100644
index 6422700..0000000
--- a/android_pyapi/android/app_job.py
+++ /dev/null
@@ -1,444 +0,0 @@
-"""
-Android Job Scheduler API — JobScheduler, JobInfo, JobService, JobParameters, JobWorkItem
-方法签名完全对齐 Android SDK
-"""
-
-import heapq
-import threading
-import time
-from datetime import datetime, timedelta
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "JobScheduler",
- "JobInfo",
- "JobService",
- "JobParameters",
- "JobWorkItem",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# JobScheduler
-# ═══════════════════════════════════════════════════════════════
-
-class JobScheduler(Stub):
- """JobScheduler — 作业调度器 (桌面线程模拟)"""
-
- def __init__(self):
- super().__init__()
- self._lock = threading.Lock()
- self._jobs: Dict[int, "JobInfo"] = {}
- self._next_id = 1
- self._worker_thread: Optional[threading.Thread] = None
- self._running = False
- self._start_worker()
-
- def _start_worker(self):
- """启动后台工作线程"""
- if self._worker_thread is None or not self._worker_thread.is_alive():
- self._running = True
- self._worker_thread = threading.Thread(target=self._run_loop, daemon=True)
- self._worker_thread.start()
-
- def _run_loop(self):
- """运行作业调度循环"""
- while self._running:
- with self._lock:
- now = time.time()
- for job_id, info in list(self._jobs.items()):
- if info._deadline and now >= info._deadline:
- self._jobs.pop(job_id, None)
-
- time.sleep(1.0)
-
- def schedule(self, job: "JobInfo") -> int:
- """调度一个作业"""
- with self._lock:
- job_id = self._next_id
- self._next_id += 1
- job._id = job_id
- if job._periodic:
- job._deadline = time.time() + job._period_ms / 1000.0
- elif job._deadline_ms:
- job._deadline = time.time() + job._deadline_ms / 1000.0
- else:
- job._deadline = None
- self._jobs[job_id] = job
- return job_id
-
- def enqueue(self, job: "JobInfo", workItem: "JobWorkItem") -> int:
- """将作业加入队列"""
- return self.schedule(job)
-
- def cancel(self, jobId: int):
- """取消指定作业"""
- with self._lock:
- self._jobs.pop(jobId, None)
-
- def cancelAll(self):
- """取消所有作业"""
- with self._lock:
- self._jobs.clear()
-
- def getAllPendingJobs(self) -> List["JobInfo"]:
- """获取所有待处理作业"""
- with self._lock:
- return list(self._jobs.values())
-
- def getPendingJob(self, jobId: int) -> Optional["JobInfo"]:
- """获取指定待处理作业"""
- with self._lock:
- return self._jobs.get(jobId)
-
- def getTransientNetwork(self) -> Optional[Any]:
- """获取瞬时网络"""
- return None
-
- def getStartedJobs(self) -> List["JobInfo"]:
- """获取已开始的作业"""
- return []
-
- def toString(self) -> str:
- with self._lock:
- return f"JobScheduler(pending={len(self._jobs)})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# JobInfo
-# ═══════════════════════════════════════════════════════════════
-
-class JobInfo(Stub):
- """JobInfo — 作业信息"""
-
- # --- NetworkType 常量 ---
- NETWORK_TYPE_NONE = 0
- NETWORK_TYPE_ANY = 1
- NETWORK_TYPE_UNMETERED = 2
- NETWORK_TYPE_NOT_ROAMING = 3
- NETWORK_TYPE_CELLULAR = 4
-
- # --- Backoff 策略 ---
- BACKOFF_POLICY_LINEAR = 0
- BACKOFF_POLICY_EXPONENTIAL = 1
-
- def __init__(self):
- super().__init__()
- self._id = 0
- self._service = None
- self._required_network_type = self.NETWORK_TYPE_NONE
- self._requires_charging = False
- self._requires_device_idle = False
- self._deadline_ms = 0
- self._min_latency_ms = 0
- self._period_ms = 0
- self._periodic = False
- self._backoff_policy = self.BACKOFF_POLICY_EXPONENTIAL
- self._backoff_delay_ms = 30000
- self._extras = None
- self._transient_network = False
- self._estimated_network_bytes = -1
- self._prefetch_network_bytes = -1
- self._requires_storage_not_low = False
-
- def getId(self) -> int:
- return self._id
-
- def getService(self) -> Optional[Any]:
- return self._service
-
- def getRequiredNetworkType(self) -> int:
- return self._required_network_type
-
- def isRequiresCharging(self) -> bool:
- return self._requires_charging
-
- def isRequiresDeviceIdle(self) -> bool:
- return self._requires_device_idle
-
- def isRequiresStorageNotLow(self) -> bool:
- return self._requires_storage_not_low
-
- def getMinLatencyMillis(self) -> int:
- return self._min_latency_ms
-
- def getMaxExecutionDelayMillis(self) -> int:
- return self._deadline_ms
-
- def isPeriodic(self) -> bool:
- return self._periodic
-
- def getBackoffPolicy(self) -> int:
- return self._backoff_policy
-
- def getInitialBackoffMillis(self) -> int:
- return self._backoff_delay_ms
-
- def getEstimatedNetworkBytes(self) -> int:
- return self._estimated_network_bytes
-
- def getPrefetchNetworkBytes(self) -> int:
- return self._prefetch_network_bytes
-
- def getTransientNetwork(self) -> Optional[Any]:
- return None
-
- def isPersisted(self) -> bool:
- return False
-
- def getExtras(self) -> Optional[Any]:
- return self._extras
-
- # ═══════════════════════════════════════════════════════════
- # Builder
- # ═══════════════════════════════════════════════════════════
-
- class Builder(Stub):
- """JobInfo.Builder — 作业构建器"""
-
- def __init__(self, jobId: int, jobService: Any):
- super().__init__()
- self._info = JobInfo()
- self._info._id = jobId
- self._info._service = jobService
-
- def setRequiredNetworkType(self, networkType: int) -> "JobInfo.Builder":
- self._info._required_network_type = networkType
- return self
-
- def setRequiresCharging(self, requiresCharging: bool) -> "JobInfo.Builder":
- self._info._requires_charging = requiresCharging
- return self
-
- def setRequiresDeviceIdle(self, requiresDeviceIdle: bool) -> "JobInfo.Builder":
- self._info._requires_device_idle = requiresDeviceIdle
- return self
-
- def setRequiresStorageNotLow(self, requiresStorageNotLow: bool) -> "JobInfo.Builder":
- self._info._requires_storage_not_low = requiresStorageNotLow
- return self
-
- def setOverrideDeadline(self, deadlineMillis: int) -> "JobInfo.Builder":
- self._info._deadline_ms = deadlineMillis
- return self
-
- def setMinimumLatency(self, minLatencyMillis: int) -> "JobInfo.Builder":
- self._info._min_latency_ms = minLatencyMillis
- return self
-
- def setBackoffCriteria(
- self, initialBackoffMillis: int, backoffPolicy: int
- ) -> "JobInfo.Builder":
- self._info._backoff_delay_ms = initialBackoffMillis
- self._info._backoff_policy = backoffPolicy
- return self
-
- def setPeriodic(self, intervalMillis: int) -> "JobInfo.Builder":
- self._info._periodic = True
- self._info._period_ms = intervalMillis
- return self
-
- def setTransientNetwork(self, transient: bool) -> "JobInfo.Builder":
- self._info._transient_network = transient
- return self
-
- def setEstimatedNetworkBytes(self, estimatedBytes: int) -> "JobInfo.Builder":
- self._info._estimated_network_bytes = estimatedBytes
- return self
-
- def setPrefetchNetworkBytes(self, prefetchBytes: int) -> "JobInfo.Builder":
- self._info._prefetch_network_bytes = prefetchBytes
- return self
-
- def setExtras(self, extras: Any) -> "JobInfo.Builder":
- self._info._extras = extras
- return self
-
- def build(self) -> "JobInfo":
- return self._info
-
- def toString(self) -> str:
- return f"Builder(jobId={self._info._id})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"JobInfo(id={self._id}, network={self._required_network_type})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, JobInfo):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# JobService
-# ═══════════════════════════════════════════════════════════════
-
-class JobService(Stub):
- """JobService — 作业服务基类"""
-
- def __init__(self):
- super().__init__()
-
- def onStartJob(self, params: "JobParameters") -> bool:
- """作业开始时调用。返回 True 表示需要后台线程处理。"""
- return False
-
- def onStopJob(self, params: "JobParameters") -> bool:
- """作业停止时调用。返回 True 表示应重试。"""
- return False
-
- def jobFinished(self, params: "JobParameters", needsReschedule: bool):
- """通知系统作业已完成"""
- pass
-
- def toString(self) -> str:
- return f"JobService@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# JobParameters
-# ═══════════════════════════════════════════════════════════════
-
-class JobParameters(Stub):
- """JobParameters — 作业参数"""
-
- # --- StopReason 常量 ---
- STOP_REASON_UNDEFINED = 0
- STOP_REASON_DATA_CLEARED = 1
- STOP_REASON_APP_BACKGROUND = 2
- STOP_REASON_APP_STANDBY = 3
- STOP_REASON_DEVICE_IDLE = 4
- STOP_REASON_PREEXISTING = 5
- STOP_REASON_ESTIMATED_NETWORK_BYTES_EXCEEDED = 6
- STOP_REASON_QUOTA = 7
- STOP_REASON_TAPPED_CANCEL = 8
- STOP_REASON_USER = 9
- STOP_REASON_CONSTRAINT_BATTERY_NOT_OK = 10
- STOP_REASON_CONSTRAINT_NETWORK_NOT_OK = 11
- STOP_REASON_CONSTRAINT_CONNECTIVITY_NOT_OK = 12
- STOP_REASON_CONSTRAINT_STORAGE_NOT_OK = 13
- STOP_REASON_CONSTRAINT_CHARGING_NOT_OK = 14
- STOP_REASON_CONSTRAINT_IDLE_NOT_OK = 15
- STOP_REASON_CANCELED = 16
- STOP_REASON_CANCELLED_BY_APP = 17
- STOP_REASON_DEVICE_STATE = 18
- STOP_REASON_SYSTEM_PROCESSING = 19
- STOP_REASON_WORK_POLICY = 20
- STOP_REASON_SYSTEM_EXECUTION = 21
- STOP_REASON_RESTRICTED_BACKGROUND = 22
- STOP_REASON_TIMEOUT = 23
-
- def __init__(self, jobId: int = 0):
- super().__init__()
- self._job_id = jobId
- self._extras = None
- self._network = None
- self._transient_network = None
- self._stop_reason = 0
- self._override_deadline_expired = False
- self._requires_charging = False
- self._requires_device_idle = False
- self._requires_storage_not_low = False
- self._required_network_type = JobInfo.NETWORK_TYPE_NONE
-
- def getJobId(self) -> int:
- return self._job_id
-
- def getExtras(self) -> Optional[Any]:
- return self._extras
-
- def getNetwork(self) -> Optional[Any]:
- return self._network
-
- def getTransientNetwork(self) -> Optional[Any]:
- return self._transient_network
-
- def getStopReason(self) -> int:
- return self._stop_reason
-
- def isOverrideDeadlineExpired(self) -> bool:
- return self._override_deadline_expired
-
- def isRequiresCharging(self) -> bool:
- return self._requires_charging
-
- def isRequiresDeviceIdle(self) -> bool:
- return self._requires_device_idle
-
- def isRequiresStorageNotLow(self) -> bool:
- return self._requires_storage_not_low
-
- def getRequiredNetworkType(self) -> int:
- return self._required_network_type
-
- def toString(self) -> str:
- return f"JobParameters(jobId={self._job_id})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, JobParameters):
- return False
- return self._job_id == other._job_id
-
- def hashCode(self) -> int:
- return self._job_id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# JobWorkItem
-# ═══════════════════════════════════════════════════════════════
-
-class JobWorkItem(Stub):
- """JobWorkItem — 作业工作项"""
-
- def __init__(self, intent: Any = None):
- super().__init__()
- self._intent = intent
- self._delivery_count = 0
- self._latest_delivery_intent = None
-
- def getIntent(self) -> Optional[Any]:
- return self._intent
-
- def getDeliveryCount(self) -> int:
- return self._delivery_count
-
- def getLatestDeliveryIntent(self) -> Optional[Any]:
- return self._latest_delivery_intent
-
- def toString(self) -> str:
- return f"JobWorkItem(deliveryCount={self._delivery_count})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, JobWorkItem):
- return False
- return self._intent == other._intent
-
- def hashCode(self) -> int:
- return hash(str(self._intent)) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/app_notification.py b/android_pyapi/android/app_notification.py
deleted file mode 100644
index 7024aa2..0000000
--- a/android_pyapi/android/app_notification.py
+++ /dev/null
@@ -1,1307 +0,0 @@
-"""
-Android Notification API — NotificationChannel, NotificationManager, NotificationCompat, etc.
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import json
-import os
-import time
-import threading
-from datetime import datetime
-from enum import IntEnum
-from typing import Any, Dict, List, Optional, Tuple, Callable, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量定义
-# ═══════════════════════════════════════════════════════════════
-
-# IMPORTANCE 常量
-IMPORTANCE_UNSPECIFIED = -1000
-IMPORTANCE_NONE = 0
-IMPORTANCE_MIN = 1
-IMPORTANCE_LOW = 2
-IMPORTANCE_DEFAULT = 3
-IMPORTANCE_HIGH = 4
-IMPORTANCE_MAX = 5
-
-# VISIBILITY 常量
-VISIBILITY_PRIVATE = 0
-VISIBILITY_PUBLIC = 1
-VISIBILITY_SECRET = -1
-
-# PRIORITY 常量
-PRIORITY_MIN = -2
-PRIORITY_LOW = -1
-PRIORITY_DEFAULT = 0
-PRIORITY_HIGH = 1
-PRIORITY_MAX = 2
-
-# FLAG 常量
-FLAG_SHOW_LIGHTS = 0x00000001
-FLAG_ONGOING_EVENT = 0x00000002
-FLAG_INSISTENT = 0x00000004
-FLAG_ONLY_ALERT_ONCE = 0x00000008
-FLAG_AUTO_CANCEL = 0x00000010
-FLAG_NO_CLEAR = 0x00000020
-FLAG_FOREGROUND_SERVICE = 0x00000040
-FLAG_HIGH_PRIORITY = 0x00000080
-FLAG_BUBBLE = 0x00000100
-FLAG_GROUP_SUMMARY = 0x00000200
-FLAG_LOCAL_ONLY = 0x00000400
-FLAG_CAN_COLORIZE = 0x00000800
-FLAG_ALERT_ONLY_ONCE = 0x00001000
-
-# DEFAULT 常量
-DEFAULT_ALL = -1
-DEFAULT_SOUND = 1
-DEFAULT_VIBRATE = 2
-DEFAULT_LIGHTS = 4
-
-# STREAM 常量 (deprecated)
-STREAM_DEFAULT = -1
-STREAM_VOICE_CALL = 0
-STREAM_SYSTEM = 1
-STREAM_RING = 2
-STREAM_MUSIC = 3
-STREAM_ALARM = 4
-STREAM_NOTIFICATION = 5
-STREAM_DTMF = 8
-
-# BADGE 常量
-BADGE_ICON_NONE = 0
-BADGE_ICON_SMALL = 1
-BADGE_ICON_LARGE = 2
-
-# INTERRUPTION_FILTER 常量
-INTERRUPTION_FILTER_UNKNOWN = 0
-INTERRUPTION_FILTER_ALL = 1
-INTERRUPTION_FILTER_PRIORITY = 2
-INTERRUPTION_FILTER_NONE = 3
-INTERRUPTION_FILTER_ALARMS = 4
-
-# CATEGORY 常量
-CATEGORY_CALL = "call"
-CATEGORY_ALARM = "alarm"
-CATEGORY_REMINDER = "reminder"
-CATEGORY_EVENT = "event"
-CATEGORY_MESSAGE = "msg"
-CATEGORY_EMAIL = "email"
-CATEGORY_SOCIAL = "social"
-CATEGORY_ERROR = "err"
-CATEGORY_PROGRESS = "progress"
-CATEGORY_PROMO = "promo"
-CATEGORY_RECOMMENDATION = "recommendation"
-CATEGORY_STATUS = "status"
-CATEGORY_SYSTEM = "sys"
-CATEGORY_SERVICE = "service"
-CATEGORY_TRANSPORT = "transport"
-CATEGORY_WORKOUT = "workout"
-CATEGORY_LOCATION_SHARING = "location_sharing"
-CATEGORY_STOPWATCH = "stopwatch"
-CATEGORY_ALERT = "alert"
-CATEGORY_MISSED_CALL = "missed_call"
-
-# GROUP_ALERT 常量
-GROUP_ALERT_ALL = 0
-GROUP_ALERT_SUMMARY = 1
-GROUP_ALERT_CHILDREN = 2
-
-# SEMANTIC_ACTION 常量
-SEMANTIC_ACTION_NONE = 0
-SEMANTIC_ACTION_REPLY = 1
-SEMANTIC_ACTION_MARK_AS_READ = 2
-SEMANTIC_ACTION_MARK_AS_IMPORTANT = 3
-SEMANTIC_ACTION_DELETE = 4
-SEMANTIC_ACTION_ARCHIVE = 5
-SEMANTIC_ACTION_MUTE = 6
-SEMANTIC_ACTION_UNMUTE = 7
-SEMANTIC_ACTION_CALL = 8
-SEMANTIC_ACTION_THUMBS_UP = 9
-SEMANTIC_ACTION_THUMBS_DOWN = 10
-
-
-# ═══════════════════════════════════════════════════════════════
-# NotificationChannel
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationChannel(Stub):
- """NotificationChannel — 通知渠道"""
-
- def __init__(
- self,
- channelId: str,
- channelName: str,
- importance: int = IMPORTANCE_DEFAULT,
- ):
- super().__init__()
- self._id = channelId
- self._name = channelName
- self._description: Optional[str] = None
- self._importance = importance
- self._bypass_dnd = False
- self._lockscreen_visibility = VISIBILITY_PRIVATE
- self._show_badge = True
- self._sound: Optional[str] = None
- self._vibration_enabled = False
- self._vibration_pattern: Optional[List[int]] = None
- self._light_color = 0
- self._light_enabled = False
- self._group: Optional[str] = None
- self._can_bubble = False
- self._allow_bubbles = False
- self._is_vibration = False
- self._original_importance = importance
- self._fbr_enabled = False
- self._conversation_id: Optional[str] = None
- self._is_conversation = False
- self._demoted = False
- self._deleted = False
- self._has_user_set = False
- self._audio_attributes = None
- self._can_show_badge = True
- self._is_important_conversation = False
- self._important_conversation_quota = 0
-
- def getId(self) -> str:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def setName(self, name: str) -> None:
- self._name = name
-
- def getDescription(self) -> Optional[str]:
- return self._description
-
- def setDescription(self, description: str) -> None:
- self._description = description
-
- def getImportance(self) -> int:
- return self._importance
-
- def setImportance(self, importance: int) -> None:
- self._importance = importance
-
- def canBypassDnd(self) -> bool:
- return self._bypass_dnd
-
- def setBypassDnd(self, bypassDnd: bool) -> None:
- self._bypass_dnd = bypassDnd
-
- def getLockscreenVisibility(self) -> int:
- return self._lockscreen_visibility
-
- def setLockscreenVisibility(self, visibility: int) -> None:
- self._lockscreen_visibility = visibility
-
- def canShowBadge(self) -> bool:
- return self._show_badge
-
- def setShowBadge(self, showBadge: bool) -> None:
- self._show_badge = showBadge
-
- def getSound(self) -> Optional[str]:
- return self._sound
-
- def setSound(self, sound: Optional[str], audioAttributes: Any = None) -> None:
- self._sound = sound
- self._audio_attributes = audioAttributes
-
- def shouldVibrate(self) -> bool:
- return self._vibration_enabled
-
- def enableVibration(self, vibrationPattern: Optional[List[int]] = None) -> None:
- self._vibration_enabled = True
- if vibrationPattern is not None:
- self._vibration_pattern = vibrationPattern
-
- def getVibrationPattern(self) -> Optional[List[int]]:
- return self._vibration_pattern
-
- def getLightColor(self) -> int:
- return self._light_color
-
- def setLightColor(self, color: int) -> None:
- self._light_color = color
- self._light_enabled = True
-
- def getGroup(self) -> Optional[str]:
- return self._group
-
- def setGroup(self, groupId: Optional[str]) -> None:
- self._group = groupId
-
- def canBubble(self) -> bool:
- return self._can_bubble
-
- def setAllowBubbles(self, allow: bool) -> None:
- self._allow_bubbles = allow
-
- def isConversation(self) -> bool:
- return self._is_conversation
-
- def setConversationId(self, conversationId: str, parentChannelId: str = "") -> None:
- self._conversation_id = conversationId
- self._is_conversation = True
-
- def isDeleted(self) -> bool:
- return self._deleted
-
- def isImportantConversation(self) -> bool:
- return self._is_important_conversation
-
- def toString(self) -> str:
- return f"NotificationChannel(id={self._id}, name={self._name}, importance={self._importance})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NotificationChannelGroup
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationChannelGroup(Stub):
- """NotificationChannelGroup — 通知渠道组"""
-
- def __init__(self, groupId: str, groupName: str):
- super().__init__()
- self._id = groupId
- self._name = groupName
- self._description: Optional[str] = None
- self._channels: List[NotificationChannel] = []
- self._blocked = False
-
- def getId(self) -> str:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getDescription(self) -> Optional[str]:
- return self._description
-
- def setDescription(self, description: str) -> None:
- self._description = description
-
- def getChannels(self) -> List[NotificationChannel]:
- return list(self._channels)
-
- def isBlocked(self) -> bool:
- return self._blocked
-
- def toString(self) -> str:
- return f"NotificationChannelGroup(id={self._id}, name={self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Notification.Action
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationAction(Stub):
- """Notification.Action — 通知操作"""
-
- def __init__(
- self,
- icon: Optional[int] = None,
- title: Optional[str] = None,
- pendingIntent: Any = None,
- ):
- super().__init__()
- self.icon = icon
- self.title = title
- self.actionIntent = pendingIntent
- self._extras: Optional[Any] = None
- self._remote_inputs: List[Any] = []
- self._semantic_action = SEMANTIC_ACTION_NONE
- self._contextual = False
- self._allow_generated_replies = False
- self._is_authentication_required = False
- self._is_bubble = False
-
- def getExtras(self) -> Optional[Any]:
- return self._extras
-
- def getRemoteInputs(self) -> List[Any]:
- return list(self._remote_inputs)
-
- def getSemanticAction(self) -> int:
- return self._semantic_action
-
- def isContextual(self) -> bool:
- return self._contextual
-
- def getAllowGeneratedReplies(self) -> bool:
- return self._allow_generated_replies
-
- def isAuthenticationRequired(self) -> bool:
- return self._is_authentication_required
-
- def toString(self) -> str:
- return f"Notification.Action(title={self.title}, icon={self.icon})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Notification.Style 基类
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationStyle(Stub):
- """Notification.Style — 通知样式基类"""
-
- def __init__(self):
- super().__init__()
- self._big_content_title: Optional[str] = None
- self._summary_text: Optional[str] = None
- self._colorized = False
-
- def setBigContentTitle(self, title: str) -> "NotificationStyle":
- self._big_content_title = title
- return self
-
- def setSummaryText(self, summary: str) -> "NotificationStyle":
- self._summary_text = summary
- return self
-
- def getBigContentTitle(self) -> Optional[str]:
- return self._big_content_title
-
- def getSummaryText(self) -> Optional[str]:
- return self._summary_text
-
-
-class BigPictureStyle(NotificationStyle):
- """Notification.BigPictureStyle — 大图通知样式"""
-
- def __init__(self):
- super().__init__()
- self._big_large_icon: Optional[Any] = None
- self._big_picture: Optional[Any] = None
- self._content_description: Optional[str] = None
- self._show_icon = False
-
- def bigPicture(self, picture: Any) -> "BigPictureStyle":
- self._big_picture = picture
- return self
-
- def bigLargeIcon(self, icon: Any) -> "BigPictureStyle":
- self._big_large_icon = icon
- return self
-
- def setContentDescription(self, description: str) -> "BigPictureStyle":
- self._content_description = description
- return self
-
- def showBigPictureWhenCollapsed(self, show: bool) -> "BigPictureStyle":
- self._show_icon = show
- return self
-
- def getBigPicture(self) -> Optional[Any]:
- return self._big_picture
-
- def toString(self) -> str:
- return f"BigPictureStyle(title={self._big_content_title})"
-
-
-class BigTextStyle(NotificationStyle):
- """Notification.BigTextStyle — 大文本通知样式"""
-
- def __init__(self):
- super().__init__()
- self._big_text: Optional[str] = None
- self._lines: List[str] = []
-
- def bigText(self, text: str) -> "BigTextStyle":
- self._big_text = text
- return self
-
- def setLines(self, lines: List[str]) -> "BigTextStyle":
- self._lines = list(lines)
- return self
-
- def getBigText(self) -> Optional[str]:
- return self._big_text
-
- def toString(self) -> str:
- return f"BigTextStyle(text_len={len(self._big_text) if self._big_text else 0})"
-
-
-class InboxStyle(NotificationStyle):
- """Notification.InboxStyle — 收件箱通知样式"""
-
- def __init__(self):
- super().__init__()
- self._lines: List[str] = []
-
- def addLine(self, line: str) -> "InboxStyle":
- self._lines.append(line)
- return self
-
- def setLines(self, lines: List[str]) -> "InboxStyle":
- self._lines = list(lines)
- return self
-
- def getLines(self) -> List[str]:
- return list(self._lines)
-
- def toString(self) -> str:
- return f"InboxStyle(lines={len(self._lines)})"
-
-
-class MessagingStyle(NotificationStyle):
- """Notification.MessagingStyle — 消息通知样式"""
-
- class Message(Stub):
- """Notification.MessagingStyle.Message — 单条消息"""
-
- def __init__(
- self,
- text: str,
- timestamp: int,
- sender: Optional[str] = None,
- bundle: Optional[Any] = None,
- ):
- super().__init__()
- self._text = text
- self._timestamp = timestamp
- self._sender = sender
- self._bundle = bundle
- self._data_mime_type: Optional[str] = None
- self._data_uri: Optional[str] = None
- self._remote_input_history: List[Any] = []
- self._extras: Optional[Any] = None
-
- def getText(self) -> str:
- return self._text
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def getSender(self) -> Optional[str]:
- return self._sender
-
- def getDataMimeType(self) -> Optional[str]:
- return self._data_mime_type
-
- def getDataUri(self) -> Optional[str]:
- return self._data_uri
-
- def setData(self, mimeType: str, uri: str) -> None:
- self._data_mime_type = mimeType
- self._data_uri = uri
-
- def getExtras(self) -> Optional[Any]:
- return self._extras
-
- def getRemoteInputHistory(self) -> List[Any]:
- return list(self._remote_input_history)
-
- def toString(self) -> str:
- return f"Message(sender={self._sender}, text={self._text})"
-
- def __init__(self, user_display_name: str, conversation_title: Optional[str] = None):
- super().__init__()
- self._user_display_name = user_display_name
- self._conversation_title = conversation_title
- self._messages: List[MessagingStyle.Message] = []
- self._group_conversation = False
- self._is_group_conversation = False
-
- def addMessage(self, message: "MessagingStyle.Message") -> "MessagingStyle":
- self._messages.append(message)
- return self
-
- def addHistoricMessage(self, message: "MessagingStyle.Message") -> "MessagingStyle":
- if message not in self._messages:
- self._messages.append(message)
- return self
-
- def setConversationTitle(self, title: str) -> "MessagingStyle":
- self._conversation_title = title
- return self
-
- def setGroupConversation(self, isGroup: bool) -> "MessagingStyle":
- self._is_group_conversation = isGroup
- return self
-
- def getUserDisplayName(self) -> str:
- return self._user_display_name
-
- def getConversationTitle(self) -> Optional[str]:
- return self._conversation_title
-
- def getMessages(self) -> List["MessagingStyle.Message"]:
- return list(self._messages)
-
- def isGroupConversation(self) -> bool:
- return self._is_group_conversation
-
- def toString(self) -> str:
- return f"MessagingStyle(user={self._user_display_name}, msgs={len(self._messages)})"
-
-
-class CarExtender(Stub):
- """Notification.CarExtender — 车载通知扩展"""
-
- class UnreadConversation(Stub):
- """Notification.CarExtender.UnreadConversation — 未读对话"""
-
- def __init__(self):
- super().__init__()
- self._name: Optional[str] = None
- self._latest_timestamp: Optional[int] = None
- self._messages: List[str] = []
- self._remote_input: Optional[Any] = None
- self._participants: List[str] = []
- self._pending_intent: Optional[Any] = None
-
- def getName(self) -> Optional[str]:
- return self._name
-
- def getLatestTimestamp(self) -> Optional[int]:
- return self._latest_timestamp
-
- def getMessages(self) -> List[str]:
- return list(self._messages)
-
- def getRemoteInput(self) -> Optional[Any]:
- return self._remote_input
-
- def getParticipants(self) -> List[str]:
- return list(self._participants)
-
- def getPendingIntent(self) -> Optional[Any]:
- return self._pending_intent
-
- def toString(self) -> str:
- return f"UnreadConversation(name={self._name})"
-
- def __init__(self):
- super().__init__()
- self._color = 0
- self._large_icon: Optional[Any] = None
- self._unread_conversation: Optional["CarExtender.UnreadConversation"] = None
-
- def setColor(self, color: int) -> "CarExtender":
- self._color = color
- return self
-
- def getColor(self) -> int:
- return self._color
-
- def setLargeIcon(self, icon: Any) -> "CarExtender":
- self._large_icon = icon
- return self
-
- def getLargeIcon(self) -> Optional[Any]:
- return self._large_icon
-
- def setUnreadConversation(
- self, conversation: "CarExtender.UnreadConversation"
- ) -> "CarExtender":
- self._unread_conversation = conversation
- return self
-
- def getUnreadConversation(self) -> Optional["CarExtender.UnreadConversation"]:
- return self._unread_conversation
-
- def toString(self) -> str:
- return "CarExtender"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NotificationCompat
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationCompat(Stub):
- """NotificationCompat — 兼容通知构建器"""
-
- class Builder(Stub):
- """NotificationCompat.Builder — 通知构建器"""
-
- def __init__(self, context: Any = None, channelId: Optional[str] = None):
- super().__init__()
- self._context = context
- self._channel_id = channelId or ""
- self._content_title: Optional[str] = None
- self._content_text: Optional[str] = None
- self._content_info: Optional[str] = None
- self._sub_text: Optional[str] = None
- self._ticker_text: Optional[str] = None
- self._small_icon: Optional[Any] = None
- self._large_icon: Optional[Any] = None
- self._priority = PRIORITY_DEFAULT
- self._flags = 0
- self._defaults = 0
- self._when: Optional[int] = None
- self._color = 0
- self._colorized = False
- self._category: Optional[str] = None
- self._group: Optional[str] = None
- self._group_summary = False
- self._group_alert_behavior = GROUP_ALERT_ALL
- self._number = 0
- self._content_intent: Optional[Any] = None
- self._delete_intent: Optional[Any] = None
- self._full_screen_intent: Optional[Any] = None
- self._actions: List[NotificationAction] = []
- self._style: Optional[NotificationStyle] = None
- self._extras: Dict[str, Any] = {}
- self._people: List[str] = []
- self._uses_chronometer = False
- self._auto_cancel = False
- self._local_only = False
- self._ongoing = False
- self._only_alert_once = False
- self._show_when = True
- self._sort_key: Optional[str] = None
- self._public_version: Optional[Any] = None
- self._notification_sound: Optional[str] = None
- self._notification_vibrate: Optional[List[int]] = None
- self._notification_led_color = 0
- self._notification_led_on_ms = 0
- self._notification_led_off_ms = 0
- self._timeout_ms: Optional[int] = None
- self._timeout_after_ms: Optional[int] = None
- self._shortcut_id: Optional[str] = None
- self._time: Optional[int] = None
- self._visibility = VISIBILITY_PRIVATE
- self._badge_icon_type = BADGE_ICON_NONE
- self._settings_text: Optional[str] = None
- self._time_zone: Optional[Any] = None
- self._contextual = False
- self._allow_system_generated_contextual_actions = True
- self._bubble_metadata: Optional[Any] = None
- self._is_bubble = False
- self._fgs_delegate: Optional[Any] = None
-
- def setChannelId(self, channelId: str) -> "NotificationCompat.Builder":
- self._channel_id = channelId
- return self
-
- def setContentTitle(self, title: str) -> "NotificationCompat.Builder":
- self._content_title = title
- return self
-
- def setContentText(self, text: str) -> "NotificationCompat.Builder":
- self._content_text = text
- return self
-
- def setSubText(self, text: str) -> "NotificationCompat.Builder":
- self._sub_text = text
- return self
-
- def setContentInfo(self, info: str) -> "NotificationCompat.Builder":
- self._content_info = info
- return self
-
- def setTicker(self, tickerText: str) -> "NotificationCompat.Builder":
- self._ticker_text = tickerText
- return self
-
- def setSmallIcon(self, icon: Any) -> "NotificationCompat.Builder":
- self._small_icon = icon
- return self
-
- def setLargeIcon(self, icon: Any) -> "NotificationCompat.Builder":
- self._large_icon = icon
- return self
-
- def setPriority(self, priority: int) -> "NotificationCompat.Builder":
- self._priority = priority
- return self
-
- def setDefaults(self, defaults: int) -> "NotificationCompat.Builder":
- self._defaults = defaults
- return self
-
- def setWhen(self, when: int) -> "NotificationCompat.Builder":
- self._when = when
- return self
-
- def setUsesChronometer(self, b: bool) -> "NotificationCompat.Builder":
- self._uses_chronometer = b
- return self
-
- def setColor(self, color: int) -> "NotificationCompat.Builder":
- self._color = color
- return self
-
- def setColorized(self, colorized: bool) -> "NotificationCompat.Builder":
- self._colorized = colorized
- return self
-
- def setCategory(self, category: str) -> "NotificationCompat.Builder":
- self._category = category
- return self
-
- def setGroup(self, groupKey: str) -> "NotificationCompat.Builder":
- self._group = groupKey
- return self
-
- def setGroupSummary(self, isGroupSummary: bool) -> "NotificationCompat.Builder":
- self._group_summary = isGroupSummary
- return self
-
- def setGroupAlertBehavior(self, behavior: int) -> "NotificationCompat.Builder":
- self._group_alert_behavior = behavior
- return self
-
- def setNumber(self, number: int) -> "NotificationCompat.Builder":
- self._number = number
- return self
-
- def setContentIntent(self, intent: Any) -> "NotificationCompat.Builder":
- self._content_intent = intent
- return self
-
- def setDeleteIntent(self, intent: Any) -> "NotificationCompat.Builder":
- self._delete_intent = intent
- return self
-
- def setFullScreenIntent(self, intent: Any, highPriority: bool) -> "NotificationCompat.Builder":
- self._full_screen_intent = intent
- if highPriority:
- self._flags |= FLAG_HIGH_PRIORITY
- return self
-
- def addAction(
- self, iconOrAction: Any, title: Optional[str] = None, pendingIntent: Any = None
- ) -> "NotificationCompat.Builder":
- if isinstance(iconOrAction, NotificationAction):
- self._actions.append(iconOrAction)
- elif isinstance(iconOrAction, int):
- self._actions.append(NotificationAction(iconOrAction, title, pendingIntent))
- else:
- self._actions.append(NotificationAction(None, str(iconOrAction), pendingIntent))
- return self
-
- def setStyle(self, style: NotificationStyle) -> "NotificationCompat.Builder":
- self._style = style
- return self
-
- def addPerson(self, uri: str) -> "NotificationCompat.Builder":
- self._people.append(uri)
- return self
-
- def setShowWhen(self, show: bool) -> "NotificationCompat.Builder":
- self._show_when = show
- return self
-
- def setLocalOnly(self, localOnly: bool) -> "NotificationCompat.Builder":
- self._local_only = localOnly
- return self
-
- def setOngoing(self, ongoing: bool) -> "NotificationCompat.Builder":
- self._ongoing = ongoing
- if ongoing:
- self._flags |= FLAG_ONGOING_EVENT
- else:
- self._flags &= ~FLAG_ONGOING_EVENT
- return self
-
- def setAutoCancel(self, autoCancel: bool) -> "NotificationCompat.Builder":
- self._auto_cancel = autoCancel
- if autoCancel:
- self._flags |= FLAG_AUTO_CANCEL
- else:
- self._flags &= ~FLAG_AUTO_CANCEL
- return self
-
- def setOnlyAlertOnce(self, onlyAlertOnce: bool) -> "NotificationCompat.Builder":
- self._only_alert_once = onlyAlertOnce
- if onlyAlertOnce:
- self._flags |= FLAG_ONLY_ALERT_ONCE
- else:
- self._flags &= ~FLAG_ONLY_ALERT_ONCE
- return self
-
- def setVisibility(self, visibility: int) -> "NotificationCompat.Builder":
- self._visibility = visibility
- return self
-
- def setBadgeIconType(self, iconType: int) -> "NotificationCompat.Builder":
- self._badge_icon_type = iconType
- return self
-
- def setSettingsText(self, text: str) -> "NotificationCompat.Builder":
- self._settings_text = text
- return self
-
- def setSortKey(self, sortKey: str) -> "NotificationCompat.Builder":
- self._sort_key = sortKey
- return self
-
- def setTimeout(self, durationMs: int) -> "NotificationCompat.Builder":
- self._timeout_ms = durationMs
- return self
-
- def setTimeoutAfter(self, durationMs: int) -> "NotificationCompat.Builder":
- self._timeout_after_ms = durationMs
- return self
-
- def setShortcutId(self, shortcutId: str) -> "NotificationCompat.Builder":
- self._shortcut_id = shortcutId
- return self
-
- def setPublicVersion(self, notification: Any) -> "NotificationCompat.Builder":
- self._public_version = notification
- return self
-
- def extend(self, extender: Any) -> "NotificationCompat.Builder":
- if extender:
- extender.extend(self)
- return self
-
- def setSound(self, sound: Optional[str]) -> "NotificationCompat.Builder":
- self._notification_sound = sound
- return self
-
- def setVibrate(self, pattern: Optional[List[int]]) -> "NotificationCompat.Builder":
- self._notification_vibrate = pattern
- return self
-
- def setLights(self, color: int, onMs: int, offMs: int) -> "NotificationCompat.Builder":
- self._notification_led_color = color
- self._notification_led_on_ms = onMs
- self._notification_led_off_ms = offMs
- return self
-
- def setFlag(self, flag: int, enabled: bool) -> "NotificationCompat.Builder":
- if enabled:
- self._flags |= flag
- else:
- self._flags &= ~flag
- return self
-
- def addExtras(self, extras: Dict[str, Any]) -> "NotificationCompat.Builder":
- self._extras.update(extras)
- return self
-
- def getExtras(self) -> Dict[str, Any]:
- return self._extras
-
- def build(self) -> "NotificationCompat":
- return NotificationCompat(self)
-
- def toString(self) -> str:
- return f"NotificationCompat.Builder(title={self._content_title})"
-
- def __init__(self, builder: "NotificationCompat.Builder"):
- super().__init__()
- self._channel_id = builder._channel_id
- self._content_title = builder._content_title
- self._content_text = builder._content_text
- self._sub_text = builder._sub_text
- self._priority = builder._priority
- self._flags = builder._flags
- self._defaults = builder._defaults
- self._when = builder._when
- self._small_icon = builder._small_icon
- self._large_icon = builder._large_icon
- self._actions = list(builder._actions)
- self._style = builder._style
- self._category = builder._category
- self._group = builder._group
- self._color = builder._color
- self._extras = dict(builder._extras)
- self._visibility = builder._visibility
-
- def getChannelId(self) -> Optional[str]:
- return self._channel_id
-
- def getContentTitle(self) -> Optional[str]:
- return self._content_title
-
- def getContentText(self) -> Optional[str]:
- return self._content_text
-
- def getSubText(self) -> Optional[str]:
- return self._sub_text
-
- def getPriority(self) -> int:
- return self._priority
-
- def getFlags(self) -> int:
- return self._flags
-
- def getDefaults(self) -> int:
- return self._defaults
-
- def getCategory(self) -> Optional[str]:
- return self._category
-
- def getGroup(self) -> Optional[str]:
- return self._group
-
- def getColor(self) -> int:
- return self._color
-
- def getVisibility(self) -> int:
- return self._visibility
-
- def getExtras(self) -> Dict[str, Any]:
- return dict(self._extras)
-
- def getActions(self) -> List[NotificationAction]:
- return list(self._actions)
-
- def getStyle(self) -> Optional[NotificationStyle]:
- return self._style
-
- def toString(self) -> str:
- return f"Notification(channel={self._channel_id}, title={self._content_title})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Notification (简化)
-# ═══════════════════════════════════════════════════════════════
-
-class Notification(Stub):
- """Notification — Android 通知"""
-
- Action = NotificationAction
- BigPictureStyle = BigPictureStyle
- BigTextStyle = BigTextStyle
- InboxStyle = InboxStyle
- MessagingStyle = MessagingStyle
- CarExtender = CarExtender
- Style = NotificationStyle
-
- def __init__(self):
- super().__init__()
- self._when: Optional[int] = None
- self._content_title: Optional[str] = None
- self._content_text: Optional[str] = None
- self._small_icon: Optional[Any] = None
- self._large_icon: Optional[Any] = None
- self._ticker_text: Optional[str] = None
- self._content_intent: Optional[Any] = None
- self._delete_intent: Optional[Any] = None
- self._full_screen_intent: Optional[Any] = None
- self._flags = 0
- self._defaults = 0
- self._sound: Optional[str] = None
- self._vibrate: Optional[List[int]] = None
- self._led_color = 0
- self._led_on_ms = 0
- self._led_off_ms = 0
- self._number = 0
- self._icon = 0
- self._icon_level = 0
- self._priority = PRIORITY_DEFAULT
- self._category: Optional[str] = None
- self._group: Optional[str] = None
- self._group_summary = False
- self._color = 0
- self._visibility = VISIBILITY_PRIVATE
- self._extras: Dict[str, Any] = {}
- self._actions: List[NotificationAction] = []
-
- def getWhen(self) -> Optional[int]:
- return self._when
-
- def getContentTitle(self) -> Optional[str]:
- return self._content_title
-
- def getContentText(self) -> Optional[str]:
- return self._content_text
-
- def getSmallIcon(self) -> Optional[Any]:
- return self._small_icon
-
- def getLargeIcon(self) -> Optional[Any]:
- return self._large_icon
-
- def getFlags(self) -> int:
- return self._flags
-
- def setFlags(self, flags: int) -> None:
- self._flags = flags
-
- def getDefaults(self) -> int:
- return self._defaults
-
- def getNumber(self) -> int:
- return self._number
-
- def getColor(self) -> int:
- return self._color
-
- def getCategory(self) -> Optional[str]:
- return self._category
-
- def getGroup(self) -> Optional[str]:
- return self._group
-
- def getPriority(self) -> int:
- return self._priority
-
- def getVisibility(self) -> int:
- return self._visibility
-
- def getExtras(self) -> Dict[str, Any]:
- return dict(self._extras)
-
- def getActions(self) -> List[NotificationAction]:
- return list(self._actions)
-
- def toString(self) -> str:
- return f"Notification(title={self._content_title})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NotificationManager
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationManager(Stub):
- """NotificationManager — 通知管理器 (桌面存根)"""
-
- # ImportErrorBehavior 常量
- IMPORTANCE_UNSPECIFIED = IMPORTANCE_UNSPECIFIED
- IMPORTANCE_NONE = IMPORTANCE_NONE
- IMPORTANCE_MIN = IMPORTANCE_MIN
- IMPORTANCE_LOW = IMPORTANCE_LOW
- IMPORTANCE_DEFAULT = IMPORTANCE_DEFAULT
- IMPORTANCE_HIGH = IMPORTANCE_HIGH
- IMPORTANCE_MAX = IMPORTANCE_MAX
-
- INTERRUPTION_FILTER_UNKNOWN = INTERRUPTION_FILTER_UNKNOWN
- INTERRUPTION_FILTER_ALL = INTERRUPTION_FILTER_ALL
- INTERRUPTION_FILTER_PRIORITY = INTERRUPTION_FILTER_PRIORITY
- INTERRUPTION_FILTER_NONE = INTERRUPTION_FILTER_NONE
- INTERRUPTION_FILTER_ALARMS = INTERRUPTION_FILTER_ALARMS
-
- BUBBLE_PREFERENCE_NONE = 0
- BUBBLE_PREFERENCE_SELECTED = 1
- BUBBLE_PREFERENCE_ALL = 2
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._lock = threading.Lock()
- self._notifications: Dict[str, List[Tuple[int, Any]]] = {}
- self._channels: Dict[str, NotificationChannel] = {}
- self._channel_groups: Dict[str, NotificationChannelGroup] = {}
- self._interruption_filter = INTERRUPTION_FILTER_ALL
- self._notification_delegate: Optional[str] = None
- self._notification_delegate_enabled = False
- self._are_notifications_enabled = True
- self._bubble_preference = NotificationManager.BUBBLE_PREFERENCE_SELECTED
- self._can_post_notifications = True
- self._auto_bundling_enabled = True
- self._notification_assist: Optional[str] = None
-
- def notify(self, tag: Optional[str], id: int, notification: Any) -> None:
- """发送通知"""
- with self._lock:
- key = tag or "__default__"
- if key not in self._notifications:
- self._notifications[key] = []
- self._notifications[key].append((id, notification))
-
- def cancel(self, tag: Optional[str], id: int) -> None:
- """取消指定通知"""
- with self._lock:
- key = tag or "__default__"
- if key in self._notifications:
- self._notifications[key] = [
- (nid, n) for nid, n in self._notifications[key] if nid != id
- ]
-
- def cancelAll(self) -> None:
- """取消所有通知"""
- with self._lock:
- self._notifications.clear()
-
- def getActiveNotifications(self) -> List[Any]:
- """获取活动通知列表"""
- with self._lock:
- result = []
- for entries in self._notifications.values():
- for _, notification in entries:
- result.append(notification)
- return result
-
- def createNotificationChannel(self, channel: NotificationChannel) -> None:
- """创建通知渠道"""
- with self._lock:
- self._channels[channel.getId()] = channel
-
- def createNotificationChannelGroup(self, group: NotificationChannelGroup) -> None:
- """创建通知渠道组"""
- with self._lock:
- self._channel_groups[group.getId()] = group
-
- def createNotificationChannels(self, channels: List[NotificationChannel]) -> None:
- """批量创建通知渠道"""
- with self._lock:
- for ch in channels:
- self._channels[ch.getId()] = ch
-
- def createNotificationChannelGroups(self, groups: List[NotificationChannelGroup]) -> None:
- """批量创建通知渠道组"""
- with self._lock:
- for g in groups:
- self._channel_groups[g.getId()] = g
-
- def getNotificationChannel(self, channelId: str) -> Optional[NotificationChannel]:
- """获取通知渠道"""
- with self._lock:
- return self._channels.get(channelId)
-
- def getNotificationChannels(self) -> List[NotificationChannel]:
- """获取所有通知渠道"""
- with self._lock:
- return list(self._channels.values())
-
- def getNotificationChannelGroups(self) -> List[NotificationChannelGroup]:
- """获取所有通知渠道组"""
- with self._lock:
- return list(self._channel_groups.values())
-
- def deleteNotificationChannel(self, channelId: str) -> None:
- """删除通知渠道"""
- with self._lock:
- if channelId in self._channels:
- channel = self._channels.pop(channelId)
- channel._deleted = True
-
- def getImportance(self) -> int:
- """获取当前通知重要性"""
- return IMPORTANCE_DEFAULT
-
- def areNotificationsEnabled(self) -> bool:
- """检查通知是否启用"""
- return self._are_notifications_enabled
-
- def isNotificationPolicyAccessGranted(self) -> bool:
- """检查是否授予通知策略访问权限"""
- return True
-
- def getCurrentInterruptionFilter(self) -> int:
- """获取当前中断过滤器"""
- return self._interruption_filter
-
- def setInterruptionFilter(self, filterType: int) -> None:
- """设置中断过滤器"""
- self._interruption_filter = filterType
-
- def getNotificationDelegate(self) -> Optional[str]:
- """获取通知代理"""
- return self._notification_delegate
-
- def isNotificationListenerAccessGranted(self, listener: Any) -> bool:
- """检查是否授予通知监听访问权限"""
- return True
-
- def matchesCallFilter(self, incomingAddress: Any) -> bool:
- """检查是否匹配来电过滤"""
- return True
-
- def getBubblePreference(self) -> int:
- """获取气泡偏好"""
- return self._bubble_preference
-
- def canNotifyAsPackage(self, pkg: str) -> bool:
- """检查能否以指定包名发送通知"""
- return True
-
- def setNotificationDelegate(self, delegate: str) -> None:
- """设置通知代理"""
- self._notification_delegate = delegate
-
- def areBubblesAllowed(self) -> bool:
- """检查是否允许气泡"""
- return True
-
- def getActiveNotificationCount(self) -> int:
- """获取活动通知数量"""
- with self._lock:
- count = 0
- for entries in self._notifications.values():
- count += len(entries)
- return count
-
- def isAutoBundlingEnabled(self) -> bool:
- """检查自动捆绑是否启用"""
- return self._auto_bundling_enabled
-
- def setAutoBundlingEnabled(self, enabled: bool) -> None:
- """设置自动捆绑"""
- self._auto_bundling_enabled = enabled
-
- def getNotificationAssist(self) -> Optional[str]:
- """获取通知助手"""
- return self._notification_assist
-
- def getConsolidatedNotificationPolicy(self) -> Optional[Any]:
- """获取合并通知策略"""
- return None
-
- def toString(self) -> str:
- with self._lock:
- return (
- f"NotificationManager(channels={len(self._channels)}, "
- f"groups={len(self._channel_groups)}, "
- f"active_notifications={self.getActiveNotificationCount()})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# NotificationManager.Policy
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationManagerPolicy(Stub):
- """NotificationManager.Policy — 通知策略"""
-
- PRIORITY_CATEGORY_UNKNOWN = 0
- PRIORITY_CATEGORY_CALLS = 1
- PRIORITY_CATEGORY_MESSAGES = 2
- PRIORITY_CATEGORY_CONVERSATIONS = 3
- PRIORITY_CATEGORY_REMINDERS = 4
- PRIORITY_CATEGORY_EVENTS = 5
- PRIORITY_CATEGORY_ALARMS = 6
- PRIORITY_CATEGORY_MEDIA = 7
- PRIORITY_CATEGORY_SYSTEM = 8
- PRIORITY_CATEGORY_ALERTS = 9
-
- PRIORITY_SENDERS_ANY = 0
- PRIORITY_SENDERS_CONTACTS = 1
- PRIORITY_SENDERS_STARRED = 2
-
- SUPPRESSED_EFFECT_SCREEN_OFF = 1
- SUPPRESSED_EFFECT_SCREEN_ON = 2
- SUPPRESSED_EFFECT_FULL_SCREEN_INTENT = 4
- SUPPRESSED_EFFECT_AMBIENT = 8
- SUPPRESSED_EFFECT_PEEK = 16
- SUPPRESSED_EFFECT_STATUS_BAR = 32
- SUPPRESSED_EFFECT_BADGE = 64
- SUPPRESSED_EFFECT_BANNER = 128
- SUPPRESSED_EFFECT_LIGHTS = 256
-
- def __init__(
- self,
- priorityCategories: int = 0,
- priorityCallSenders: int = PRIORITY_SENDERS_ANY,
- priorityMessageSenders: int = PRIORITY_SENDERS_ANY,
- suppressedEffects: int = 0,
- ):
- super().__init__()
- self.priorityCategories = priorityCategories
- self.priorityCallSenders = priorityCallSenders
- self.priorityMessageSenders = priorityMessageSenders
- self.suppressedEffects = suppressedEffects
-
- def toString(self) -> str:
- return (
- f"NotificationManager.Policy("
- f"priorityCategories={self.priorityCategories}, "
- f"priorityCallSenders={self.priorityCallSenders}, "
- f"priorityMessageSenders={self.priorityMessageSenders})"
- )
\ No newline at end of file
diff --git a/android_pyapi/android/app_people.py b/android_pyapi/android/app_people.py
deleted file mode 100644
index c139a83..0000000
--- a/android_pyapi/android/app_people.py
+++ /dev/null
@@ -1,268 +0,0 @@
-"""
-Android People API — PeopleManager, ConversationStatus, PeopleManager.Person, PeopleManager.Conversation
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "PeopleManager",
- "ConversationStatus",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# PeopleManager
-# ═══════════════════════════════════════════════════════════════
-
-class PeopleManager(Stub):
- """PeopleManager — 人物管理器 (桌面存根)"""
-
- ACTION_PEOPLE_CONVERSATION = "android.app.people.action.PEOPLE_CONVERSATION"
- ACTION_REMOVE_STATUS = "android.app.people.action.REMOVE_STATUS"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._statuses: Dict[str, "ConversationStatus"] = {}
- self._people: Dict[str, "PeopleManager.Person"] = {}
- self._conversations: Dict[str, "PeopleManager.Conversation"] = {}
- self._listeners: List[Callable] = []
-
- def getStatus(self, packageName: str, personUri: str) -> Optional["ConversationStatus"]:
- """获取指定人的状态"""
- key = f"{packageName}:{personUri}"
- return self._statuses.get(key)
-
- def getDataIdFromPhoneNumber(self, phoneNumber: str) -> Optional[str]:
- """根据电话号码获取数据 ID"""
- return None
-
- def addOrUpdateStatus(
- self, packageName: str, status: "ConversationStatus"
- ):
- """添加或更新状态"""
- key = f"{packageName}:{status.getPersonUri()}"
- self._statuses[key] = status
-
- def removeStatus(self, packageName: str, personUri: str):
- """移除状态"""
- key = f"{packageName}:{personUri}"
- self._statuses.pop(key, None)
-
- def getStoredPeople(self) -> List["PeopleManager.Person"]:
- """获取已存储的人物列表"""
- return list(self._people.values())
-
- def isConversation(self, packageName: str, personUri: str) -> bool:
- """检查是否为对话"""
- key = f"{packageName}:{personUri}"
- return key in self._conversations
-
- def getConversation(
- self, packageName: str, personUri: str
- ) -> Optional["PeopleManager.Conversation"]:
- """获取对话信息"""
- key = f"{packageName}:{personUri}"
- return self._conversations.get(key)
-
- # ═══════════════════════════════════════════════════════════
- # Status - 状态内部类
- # ═══════════════════════════════════════════════════════════
-
- class Status(Stub):
- """PeopleManager.Status — 状态基类"""
-
- def __init__(self):
- super().__init__()
-
- def toString(self) -> str:
- return f"Status@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- # ═══════════════════════════════════════════════════════════
- # Person - 人物内部类
- # ═══════════════════════════════════════════════════════════
-
- class Person(Stub):
- """PeopleManager.Person — 人物信息"""
-
- def __init__(
- self,
- name: str = "",
- key: str = "",
- uri: str = "",
- importantForPeople: bool = False,
- ):
- super().__init__()
- self._name = name
- self._key = key
- self._uri = uri
- self._important_for_people = importantForPeople
-
- def getName(self) -> str:
- return self._name
-
- def getKey(self) -> str:
- return self._key
-
- def getUri(self) -> str:
- return self._uri
-
- def getImportantForPeople(self) -> bool:
- return self._important_for_people
-
- def toString(self) -> str:
- return f"Person(name={self._name}, key={self._key})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, PeopleManager.Person):
- return False
- return self._key == other._key
-
- def hashCode(self) -> int:
- return hash(self._key) & 0x7FFFFFFF
-
- # ═══════════════════════════════════════════════════════════
- # Conversation - 对话内部类
- # ═══════════════════════════════════════════════════════════
-
- class Conversation(Stub):
- """PeopleManager.Conversation — 对话信息"""
-
- def __init__(
- self,
- conv_id: str = "",
- person: "PeopleManager.Person" = None,
- notificationChannelId: str = "",
- shortcutInfo: Any = None,
- parentUserHandle: Any = None,
- ):
- super().__init__()
- self._id = conv_id
- self._person = person
- self._notification_channel_id = notificationChannelId
- self._shortcut_info = shortcutInfo
- self._parent_user_handle = parentUserHandle
-
- def getId(self) -> str:
- return self._id
-
- def getPerson(self) -> Optional["PeopleManager.Person"]:
- return self._person
-
- def getNotificationChannelId(self) -> str:
- return self._notification_channel_id
-
- def getShortcutInfo(self) -> Optional[Any]:
- return self._shortcut_info
-
- def getParentUserHandle(self) -> Optional[Any]:
- return self._parent_user_handle
-
- def toString(self) -> str:
- return f"Conversation(id={self._id})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, PeopleManager.Conversation):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return hash(self._id) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"PeopleManager@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ConversationStatus
-# ═══════════════════════════════════════════════════════════════
-
-class ConversationStatus(Stub):
- """ConversationStatus — 对话状态"""
-
- def __init__(
- self,
- userId: int = 0,
- packageName: str = "",
- personUri: str = "",
- status: int = 0,
- statusIcon: int = 0,
- notificationKey: str = "",
- notificationContentDescription: str = "",
- ):
- super().__init__()
- self._user_id = userId
- self._package_name = packageName
- self._person_uri = personUri
- self._status = status
- self._status_icon = statusIcon
- self._notification_key = notificationKey
- self._notification_content_description = notificationContentDescription
- self._active = False
- self._muted = False
-
- def getUserId(self) -> int:
- return self._user_id
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def getPersonUri(self) -> str:
- return self._person_uri
-
- def getStatus(self) -> int:
- return self._status
-
- def getStatusIcon(self) -> int:
- return self._status_icon
-
- def getNotificationKey(self) -> str:
- return self._notification_key
-
- def getNotificationContentDescription(self) -> str:
- return self._notification_content_description
-
- def isActive(self) -> bool:
- return self._active
-
- def isMuted(self) -> bool:
- return self._muted
-
- def setActive(self, active: bool):
- self._active = active
-
- def setMuted(self, muted: bool):
- self._muted = muted
-
- def toString(self) -> str:
- return (f"ConversationStatus(pkg={self._package_name}, "
- f"uri={self._person_uri}, active={self._active})")
-
- def equals(self, other) -> bool:
- if not isinstance(other, ConversationStatus):
- return False
- return (self._package_name == other._package_name
- and self._person_uri == other._person_uri)
-
- def hashCode(self) -> int:
- return hash((self._package_name, self._person_uri)) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/app_role.py b/android_pyapi/android/app_role.py
deleted file mode 100644
index cb276a1..0000000
--- a/android_pyapi/android/app_role.py
+++ /dev/null
@@ -1,117 +0,0 @@
-"""
-Android Role API — RoleManager
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "RoleManager",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# RoleManager
-# ═══════════════════════════════════════════════════════════════
-
-class RoleManager(Stub):
- """RoleManager — 角色管理器 (桌面存根)"""
-
- ACTION_REQUEST_ROLE = "android.app.role.action.REQUEST_ROLE"
-
- # --- 角色常量 ---
- ROLE_ASSISTANT = "android.app.role.ASSISTANT"
- ROLE_BROWSER = "android.app.role.BROWSER"
- ROLE_DIALER = "android.app.role.DIALER"
- ROLE_SMS = "android.app.role.SMS"
- ROLE_HOME = "android.app.role.HOME"
- ROLE_EMERGENCY = "android.app.role.EMERGENCY"
- ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION"
- ROLE_SYSTEM_EXCLUSIVE = "android.app.role.SYSTEM_EXCLUSIVE"
- ROLE_WALLPAPER = "android.app.role.WALLPAPER"
- ROLE_NOTIFICATION_ACCESS = "android.app.role.NOTIFICATION_ACCESS"
- ROLE_FOREGROUND_SERVICE = "android.app.role.FOREGROUND_SERVICE"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- # 模拟桌面角色持有者 (key=角色名, value=持有者包名列表)
- self._role_holders: Dict[str, List[str]] = {
- self.ROLE_HOME: ["com.example.launcher"],
- self.ROLE_BROWSER: ["org.mozilla.firefox"],
- self.ROLE_DIALER: ["com.google.android.dialer"],
- self.ROLE_SMS: ["com.google.android.messaging"],
- }
- self._listeners: List[Callable] = []
-
- def isRoleAvailable(self, roleName: str) -> bool:
- """检查角色是否可用"""
- available_roles = [
- self.ROLE_ASSISTANT, self.ROLE_BROWSER, self.ROLE_DIALER,
- self.ROLE_SMS, self.ROLE_HOME, self.ROLE_EMERGENCY,
- self.ROLE_CALL_REDIRECTION, self.ROLE_SYSTEM_EXCLUSIVE,
- self.ROLE_WALLPAPER, self.ROLE_NOTIFICATION_ACCESS,
- self.ROLE_FOREGROUND_SERVICE,
- ]
- return roleName in available_roles
-
- def isRoleHeld(self, roleName: str) -> bool:
- """检查当前应用是否持有指定角色"""
- if not self._context:
- return False
- pkg = self._context.getPackageName() if hasattr(self._context, "getPackageName") else ""
- holders = self._role_holders.get(roleName, [])
- return pkg in holders
-
- def createRequestRoleIntent(self, roleName: str) -> Any:
- """创建请求角色的 Intent"""
- from .app import Intent
- intent = Intent(self.ACTION_REQUEST_ROLE)
- intent.putExtra("android.app.role.extra.ROLE_NAME", roleName)
- return intent
-
- def getRoleHolders(self, roleName: str) -> List[str]:
- """获取角色持有者列表"""
- return list(self._role_holders.get(roleName, []))
-
- def addOnRoleHoldersChangedListener(
- self, executor: Any, listener: Callable
- ):
- """添加角色持有者变更监听器"""
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeOnRoleHoldersChangedListener(self, listener: Callable):
- """移除角色持有者变更监听器"""
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def getRoleNamesFromController(self) -> List[str]:
- """获取控制器管理的角色名列表"""
- return [
- self.ROLE_ASSISTANT, self.ROLE_BROWSER, self.ROLE_DIALER,
- self.ROLE_SMS, self.ROLE_HOME, self.ROLE_EMERGENCY,
- self.ROLE_CALL_REDIRECTION, self.ROLE_SYSTEM_EXCLUSIVE,
- self.ROLE_WALLPAPER, self.ROLE_NOTIFICATION_ACCESS,
- self.ROLE_FOREGROUND_SERVICE,
- ]
-
- def getApplicationVisibleRoleNames(self) -> List[str]:
- """获取应用可见的角色名列表"""
- return self.getRoleNamesFromController()
-
- def toString(self) -> str:
- return f"RoleManager@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/app_search.py b/android_pyapi/android/app_search.py
deleted file mode 100644
index c69e34a..0000000
--- a/android_pyapi/android/app_search.py
+++ /dev/null
@@ -1,494 +0,0 @@
-"""
-Android app.search 包 — SearchManager, SearchableInfo, SearchView
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "SearchManager",
- "SearchableInfo",
- "SearchView",
- "SearchViewSearchAutoComplete",
- "OnQueryTextListener",
- "OnSuggestionListener",
- "OnCloseListener",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# SearchManager
-# ═══════════════════════════════════════════════════════════════
-
-class SearchManager(Stub):
- """SearchManager — 搜索管理器 (桌面存根)"""
-
- INTENT_ACTION_SEARCHABLES_CHANGED = "android.search.action.SEARCHABLES_CHANGED"
- INTENT_ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS"
- INTENT_ACTION_SEARCH_SETTINGS_CHANGED = "android.search.action.SEARCH_SETTINGS_CHANGED"
- APP_DATA_SEARCH_IS_GLOBAL_SEARCH = "search_is_global_search"
- EXTRA_DATA_KEY = "data_key"
- EXTRA_NEW_SEARCH = "new_search"
- EXTRA_SELECT_QUERY = "select_query"
- EXTRA_WEB_SEARCH_KEY = "web_search_key"
- FLAG_QUERY_REFINEMENT = 0x1
- MENU_KEY = "search"
- MENU_ORDER = 0
- QUERY = "query"
- SUGGEST_COLUMN_FORMAT = "suggest_format"
- SUGGEST_COLUMN_ICON_1 = "suggest_icon_1"
- SUGGEST_COLUMN_ICON_2 = "suggest_icon_2"
- SUGGEST_COLUMN_INTENT_ACTION = "suggest_intent_action"
- SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data"
- SUGGEST_COLUMN_INTENT_DATA_ID = "suggest_intent_data_id"
- SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data"
- SUGGEST_COLUMN_QUERY = "suggest_query"
- SUGGEST_COLUMN_SHORTCUT_ID = "suggest_shortcut_id"
- SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING = "suggest_spinner_while_refreshing"
- SUGGEST_COLUMN_TEXT_1 = "suggest_text_1"
- SUGGEST_COLUMN_TEXT_2 = "suggest_text_2"
- SUGGEST_COLUMN_TEXT_2_URL = "suggest_text_2_url"
- SUGGEST_MIME_TYPE = "vnd.android.cursor.dir/vnd.android.search.suggest"
- SUGGEST_NEVER_MAKE_SHORTCUT = "never_make_shortcut"
- SUGGEST_URI_PATH_QUERY = "/search_suggest_query"
- SUGGEST_URI_PATH_SHORTCUT = "/search_suggest_shortcut"
- SUGGEST_URI_PATH_SEARCH = "/search"
-
- _instance: Optional["SearchManager"] = None
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._searchable_info: Dict[str, "SearchableInfo"] = {}
- self._global_search_activity: Optional[Any] = None
- self._online_search_enabled = True
-
- @staticmethod
- def get(context: Any) -> "SearchManager":
- """获取搜索管理器"""
- if SearchManager._instance is None:
- SearchManager._instance = SearchManager(context)
- return SearchManager._instance
-
- def startSearch(self, initial_query: str, select_init_key: bool, app_search_activity: Any,
- global_search: bool, app_search_data: Any, extra_info: Any) -> None:
- """开始搜索"""
- pass
-
- def triggerSearch(self, query: str, app_search_activity: Any, app_search_data: Any) -> None:
- """触发搜索"""
- pass
-
- def stopSearch(self) -> None:
- """停止搜索"""
- pass
-
- def search(self, query: str) -> None:
- """执行搜索"""
- pass
-
- def setSearchableInfo(self, info: "SearchableInfo") -> None:
- """设置可搜索信息"""
- self._searchable_info[info.getSearchActivity() or ""] = info
-
- def getSearchableInfo(self, component_name: Any) -> Optional["SearchableInfo"]:
- """获取可搜索信息"""
- return self._searchable_info.get(str(component_name))
-
- def getSuggestions(self, query: str, limit: int = 5) -> List[str]:
- """获取建议"""
- return []
-
- def getSearchablesInGlobalSearch(self) -> List["SearchableInfo"]:
- """获取全局搜索中的可搜索项"""
- return list(self._searchable_info.values())
-
- def setGlobalSearch(self, component_name: Any) -> None:
- """设置全局搜索"""
- pass
-
- def getGlobalSearchActivity(self) -> Optional[Any]:
- """获取全局搜索活动"""
- return self._global_search_activity
-
- def launchAssist(self, intent: Any) -> None:
- """启动辅助"""
- pass
-
- def launchQuery(self, query: str, component_name: Any, bundle: Any) -> None:
- """启动查询"""
- pass
-
- def getOnlineSearchEnabled(self) -> bool:
- """检查在线搜索是否启用"""
- return self._online_search_enabled
-
- def setOnlineSearchEnabled(self, enabled: bool) -> None:
- """设置在线搜索启用"""
- self._online_search_enabled = enabled
-
- def onDestroy(self) -> None:
- """销毁"""
- pass
-
- def dismissSearch(self) -> None:
- """取消搜索"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# SearchableInfo
-# ═══════════════════════════════════════════════════════════════
-
-class SearchableInfo(Stub):
- """SearchableInfo — 可搜索信息 (桌面存根)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._suggest_authority = ""
- self._suggest_package = ""
- self._suggest_intent_action = ""
- self._suggest_intent_data = ""
- self._suggest_path = ""
- self._suggest_selection = ""
- self._suggest_threshold = 1
- self._input_type = 0x0001
- self._ime_options = 0
- self._action_key = 0
- self._action_key_text = ""
- self._action_key_id = 0
- self._voice_search_launch_web_search = False
- self._voice_search_launch_recognizer = False
- self._settings_description = ""
- self._search_activity = ""
- self._search_hint = ""
- self._search_label = ""
- self._search_hint_id = 0
- self._search_label_id = 0
- self._description_id = 0
- self._settings_description_id = 0
- self._icon_id = 0
- self._use_browser_link = False
- self._voice_search_enabled = True
- self._query_after_zero_results = True
- self._is_default = False
- self._search_permissions: List[str] = []
-
- def getSuggestAuthority(self) -> str:
- return self._suggest_authority
-
- def getSuggestPackage(self) -> str:
- return self._suggest_package
-
- def getSuggestIntentAction(self) -> str:
- return self._suggest_intent_action
-
- def getSuggestIntentData(self) -> str:
- return self._suggest_intent_data
-
- def getSuggestPath(self) -> str:
- return self._suggest_path
-
- def getSuggestSelection(self) -> str:
- return self._suggest_selection
-
- def getSuggestThreshold(self) -> int:
- return self._suggest_threshold
-
- def getInputType(self) -> int:
- return self._input_type
-
- def getImeOptions(self) -> int:
- return self._ime_options
-
- def getActionKey(self) -> int:
- return self._action_key
-
- def getActionKeyText(self) -> str:
- return self._action_key_text
-
- def getActionKeyId(self) -> int:
- return self._action_key_id
-
- def getVoiceSearchLaunchWebSearch(self) -> bool:
- return self._voice_search_launch_web_search
-
- def getVoiceSearchLaunchRecognizer(self) -> bool:
- return self._voice_search_launch_recognizer
-
- def getSettingsDescription(self) -> str:
- return self._settings_description
-
- def getSearchActivity(self) -> str:
- return self._search_activity
-
- def getSearchHint(self) -> str:
- return self._search_hint
-
- def getSearchLabel(self) -> str:
- return self._search_label
-
- def getSearchHintId(self) -> int:
- return self._search_hint_id
-
- def getSearchLabelId(self) -> int:
- return self._search_label_id
-
- def getDescriptionId(self) -> int:
- return self._description_id
-
- def getSettingsDescriptionId(self) -> int:
- return self._settings_description_id
-
- def getIconId(self) -> int:
- return self._icon_id
-
- def getUseBrowserLink(self) -> bool:
- return self._use_browser_link
-
- def isVoiceSearchEnabled(self) -> bool:
- return self._voice_search_enabled
-
- def isQueryAfterZeroResults(self) -> bool:
- return self._query_after_zero_results
-
- def isDefault(self) -> bool:
- return self._is_default
-
- def getSearchSuggestPermission(self) -> str:
- return "android.permission.SEARCH"
-
- def getSearchPermissions(self) -> List[str]:
- return self._search_permissions.copy()
-
- def getSearchPermission(self, index: int) -> str:
- if 0 <= index < len(self._search_permissions):
- return self._search_permissions[index]
- return ""
-
-
-# ═══════════════════════════════════════════════════════════════
-# SearchView (and inner interfaces / classes)
-# ═══════════════════════════════════════════════════════════════
-
-class OnQueryTextListener(Stub):
- """OnQueryTextListener — 查询文本监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onQueryTextSubmit(self, query: str) -> bool:
- """查询文本提交"""
- return False
-
- def onQueryTextChange(self, new_text: str) -> bool:
- """查询文本变化"""
- return False
-
-
-class OnSuggestionListener(Stub):
- """OnSuggestionListener — 建议监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onSuggestionSelect(self, position: int) -> bool:
- """建议选中"""
- return False
-
- def onSuggestionClick(self, position: int) -> bool:
- """建议点击"""
- return False
-
-
-class OnCloseListener(Stub):
- """OnCloseListener — 关闭监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onClose(self) -> bool:
- """关闭事件"""
- return False
-
-
-class SearchViewSearchAutoComplete(Stub):
- """SearchView.SearchAutoComplete — 搜索自动完成 (桌面存根)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._threshold = 1
- self._text = ""
-
- def setThreshold(self, threshold: int) -> None:
- """设置阈值"""
- self._threshold = threshold
-
- def getThreshold(self) -> int:
- """获取阈值"""
- return self._threshold
-
- def enoughToFilter(self) -> bool:
- """检查是否足够过滤"""
- return len(self._text) >= self._threshold
-
- def setText(self, text: str) -> None:
- self._text = text
-
-
-class SearchView(Stub):
- """SearchView — 搜索视图 (桌面存根)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._query_hint = ""
- self._query = ""
- self._iconified = True
- self._iconified_by_default = True
- self._submit_button_enabled = True
- self._query_refinement_enabled = True
- self._max_width = 0
- self._input_type = 0x0001
- self._ime_options = 0
- self._searchable_info: Optional[SearchableInfo] = None
- self._auto_complete = SearchViewSearchAutoComplete(context)
- self._query_text_listener: Optional[OnQueryTextListener] = None
- self._suggestion_listener: Optional[OnSuggestionListener] = None
- self._close_listener: Optional[OnCloseListener] = None
-
- def setQueryHint(self, hint: str) -> None:
- """设置查询提示"""
- self._query_hint = hint
- self._auto_complete.setText(hint)
-
- def setQuery(self, query: str, submit: bool) -> None:
- """设置查询"""
- self._query = query
- if self._query_text_listener:
- self._query_text_listener.onQueryTextChange(query)
- if submit and self._query_text_listener:
- self._query_text_listener.onQueryTextSubmit(query)
-
- def setIconified(self, iconified: bool) -> None:
- """设置图标化"""
- self._iconified = iconified
-
- def setIconifiedByDefault(self, iconified: bool) -> None:
- """设置默认图标化"""
- self._iconified_by_default = iconified
-
- def isIconifiedByDefault(self) -> bool:
- """检查是否默认图标化"""
- return self._iconified_by_default
-
- def setSubmitButtonEnabled(self, enabled: bool) -> None:
- """设置提交按钮启用"""
- self._submit_button_enabled = enabled
-
- def isSubmitButtonEnabled(self) -> bool:
- """检查提交按钮是否启用"""
- return self._submit_button_enabled
-
- def setQueryRefinementEnabled(self, enabled: bool) -> None:
- """设置查询细化启用"""
- self._query_refinement_enabled = enabled
-
- def isQueryRefinementEnabled(self) -> bool:
- """检查查询细化是否启用"""
- return self._query_refinement_enabled
-
- def setSearchableInfo(self, info: SearchableInfo) -> None:
- """设置可搜索信息"""
- self._searchable_info = info
-
- def onActionViewExpanded(self) -> None:
- """操作视图展开"""
- pass
-
- def onActionViewCollapsed(self) -> None:
- """操作视图折叠"""
- pass
-
- def onClose(self) -> None:
- """关闭"""
- if self._close_listener:
- self._close_listener.onClose()
-
- def onQueryRefine(self, query: str) -> bool:
- """查询细化"""
- return False
-
- def onQueryTextChange(self, new_text: str) -> bool:
- """查询文本变化"""
- if self._query_text_listener:
- return self._query_text_listener.onQueryTextChange(new_text)
- return False
-
- def onQueryTextSubmit(self, query: str) -> bool:
- """查询文本提交"""
- if self._query_text_listener:
- return self._query_text_listener.onQueryTextSubmit(query)
- return False
-
- def onSuggestionSelect(self, position: int) -> bool:
- """建议选中"""
- if self._suggestion_listener:
- return self._suggestion_listener.onSuggestionSelect(position)
- return False
-
- def onSuggestionClick(self, position: int) -> bool:
- """建议点击"""
- if self._suggestion_listener:
- return self._suggestion_listener.onSuggestionClick(position)
- return False
-
- def onSuggestionsDisplayed(self, display: bool) -> None:
- """建议显示"""
- pass
-
- def getQuery(self) -> str:
- """获取查询"""
- return self._query
-
- def getCurrentQuery(self) -> str:
- """获取当前查询"""
- return self._query
-
- def getIconified(self) -> bool:
- """获取图标化状态"""
- return self._iconified
-
- def getMaxWidth(self) -> int:
- """获取最大宽度"""
- return self._max_width
-
- def setMaxWidth(self, max_width: int) -> None:
- """设置最大宽度"""
- self._max_width = max_width
-
- def getInputType(self) -> int:
- """获取输入类型"""
- return self._input_type
-
- def setInputType(self, input_type: int) -> None:
- """设置输入类型"""
- self._input_type = input_type
-
- def getImeOptions(self) -> int:
- """获取 IME 选项"""
- return self._ime_options
-
- def setImeOptions(self, ime_options: int) -> None:
- """设置 IME 选项"""
- self._ime_options = ime_options
\ No newline at end of file
diff --git a/android_pyapi/android/app_slice.py b/android_pyapi/android/app_slice.py
deleted file mode 100644
index d61f780..0000000
--- a/android_pyapi/android/app_slice.py
+++ /dev/null
@@ -1,409 +0,0 @@
-"""
-Android app.slice 组件 — Slice, SliceManager, SliceProvider, SliceSpec 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import uuid
-from typing import Any, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# SliceSpec
-# ═══════════════════════════════════════════════════════════════
-
-class SliceSpec(Stub):
- """SliceSpec — Slice 规范"""
-
- def __init__(self, type_: str, revision: int = 1):
- super().__init__()
- self._type = type_
- self._revision = revision
-
- def getType(self) -> str:
- return self._type
-
- def getRevision(self) -> int:
- return self._revision
-
- def toString(self) -> str:
- return f"SliceSpec{{type={self._type}, revision={self._revision}}}"
-
- def hashCode(self) -> int:
- return hash((self._type, self._revision)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, SliceSpec):
- return False
- return self._type == other._type and self._revision == other._revision
-
-
-# ═══════════════════════════════════════════════════════════════
-# SliceItem
-# ═══════════════════════════════════════════════════════════════
-
-class SliceItem(Stub):
- """SliceItem — Slice 数据项"""
-
- FORMAT_TEXT = "text"
- FORMAT_IMAGE = "image"
- FORMAT_ACTION = "action"
- FORMAT_INT = "int"
- FORMAT_LONG = "long"
- FORMAT_REMOTE_INPUT = "remote_input"
- FORMAT_SLICE = "slice"
-
- def __init__(self, format_: str, hints: List[str], sub_type: str = ""):
- super().__init__()
- self._format = format_
- self._hints = list(hints)
- self._sub_type = sub_type
- self._text: Optional[str] = None
- self._icon: Any = None
- self._intent: Any = None
- self._slice: Optional["Slice"] = None
- self._remote_input: Any = None
- self._action: Any = None
- self._color: int = 0
-
- def getFormat(self) -> str:
- return self._format
-
- def getHints(self) -> List[str]:
- return list(self._hints)
-
- def getSubType(self) -> str:
- return self._sub_type
-
- def getText(self) -> Optional[str]:
- return self._text
-
- def getIcon(self) -> Any:
- return self._icon
-
- def getIntent(self) -> Any:
- return self._intent
-
- def getSlice(self) -> Optional["Slice"]:
- return self._slice
-
- def getRemoteInput(self) -> Any:
- return self._remote_input
-
- def getAction(self) -> Any:
- return self._action
-
- def getColor(self) -> int:
- return self._color
-
- def toString(self) -> str:
- return f"SliceItem{{format={self._format}, hints={self._hints}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Slice
-# ═══════════════════════════════════════════════════════════════
-
-class Slice(Stub):
- """Slice — 切片数据"""
-
- HINT_TITLE = "title"
- HINT_SUBTITLE = "subtitle"
- HINT_SUMMARY = "summary"
- HINT_KEYWORDS = "keywords"
- HINT_TTL = "ttl"
- HINT_LAST_UPDATED = "last_updated"
- HINT_PERMISSION = "permission"
- HINT_SHORTCUT = "shortcut"
- HINT_TOGGLE = "toggle"
- HINT_SLIDER = "slider"
- HINT_TINT = "tint"
- HINT_LIST = "list"
- HINT_GRID = "grid"
- HINT_VERTICAL = "vertical"
- HINT_HORIZONTAL = "horizontal"
- HINT_PARTIAL = "partial"
- HINT_SEE_MORE = "see_more"
- HINT_NO_TINT = "no_tint"
- HINT_SHOW_BACKGROUND = "show_background"
- HINT_LARGE = "large"
- HINT_ERROR = "error"
-
- def __init__(self, uri: str = "", hints: Optional[List[str]] = None,
- spec: Optional[SliceSpec] = None):
- super().__init__()
- self._uri = uri
- self._hints = hints or []
- self._items: List[SliceItem] = []
- self._spec = spec or SliceSpec("default")
- self._calling_uid: int = -1
- self._calling_package: Optional[str] = None
-
- def getUri(self) -> str:
- return self._uri
-
- def getHints(self) -> List[str]:
- return list(self._hints)
-
- def getItems(self) -> List[SliceItem]:
- return list(self._items)
-
- def getSpec(self) -> SliceSpec:
- return self._spec
-
- def getCallingUid(self) -> int:
- return self._calling_uid
-
- def getCallingPackage(self) -> Optional[str]:
- return self._calling_package
-
- def getItem(self, format_: str) -> Optional[SliceItem]:
- for item in self._items:
- if item.getFormat() == format_:
- return item
- return None
-
- def toString(self) -> str:
- return f"Slice{{uri={self._uri}, hints={self._hints}}}"
-
- class Builder(Stub):
- """Slice.Builder — 构建器"""
-
- def __init__(self, uri: str, spec: SliceSpec):
- super().__init__()
- self._uri = uri
- self._spec = spec
- self._hints: List[str] = []
- self._items: List[SliceItem] = []
- self._caller_needed: bool = False
-
- def setCallerNeeded(self, needed: bool) -> "Slice.Builder":
- self._caller_needed = needed
- return self
-
- def addHints(self, hints: List[str]) -> "Slice.Builder":
- self._hints.extend(hints)
- return self
-
- def addSubSlice(self, sub_slice: Slice, hints: List[str]) -> "Slice.Builder":
- item = SliceItem(SliceItem.FORMAT_SLICE, hints)
- item._slice = sub_slice
- self._items.append(item)
- return self
-
- def addIcon(self, icon: Any, hints: List[str], sub_type: str = "") -> "Slice.Builder":
- item = SliceItem(SliceItem.FORMAT_IMAGE, hints, sub_type)
- item._icon = icon
- self._items.append(item)
- return self
-
- def addText(self, text: str, hints: List[str], sub_type: str = "") -> "Slice.Builder":
- item = SliceItem(SliceItem.FORMAT_TEXT, hints, sub_type)
- item._text = text
- self._items.append(item)
- return self
-
- def addAction(self, action: Any, hints: List[str], sub_type: str = "") -> "Slice.Builder":
- item = SliceItem(SliceItem.FORMAT_ACTION, hints, sub_type)
- item._action = action
- self._items.append(item)
- return self
-
- def addInt(self, value: int, hints: List[str], sub_type: str = "") -> "Slice.Builder":
- item = SliceItem(SliceItem.FORMAT_INT, hints, sub_type)
- item._text = str(value)
- self._items.append(item)
- return self
-
- def addLong(self, value: int, hints: List[str], sub_type: str = "") -> "Slice.Builder":
- item = SliceItem(SliceItem.FORMAT_LONG, hints, sub_type)
- item._text = str(value)
- self._items.append(item)
- return self
-
- def addRemoteInput(self, remote_input: Any, hints: List[str],
- sub_type: str = "") -> "Slice.Builder":
- item = SliceItem(SliceItem.FORMAT_REMOTE_INPUT, hints, sub_type)
- item._remote_input = remote_input
- self._items.append(item)
- return self
-
- def build(self) -> "Slice":
- s = Slice(self._uri, self._hints, self._spec)
- s._items = list(self._items)
- return s
-
-
-# ═══════════════════════════════════════════════════════════════
-# ListBuilder
-# ═══════════════════════════════════════════════════════════════
-
-class ListBuilder(Stub):
- """ListBuilder — Slice 列表构建器"""
-
- def __init__(self, uri: str, spec: SliceSpec):
- super().__init__()
- self._uri = uri
- self._spec = spec
- self._header_slice: Optional[Slice] = None
- self._rows: List[Slice] = []
- self._grid_rows: List[Slice] = []
- self._input_ranges: List[Slice] = []
- self._sliders: List[Slice] = []
- self._ranges: List[Slice] = []
- self._select_toggles: List[Slice] = []
-
- def setHeader(self, slice_: Slice) -> "ListBuilder":
- self._header_slice = slice_
- return self
-
- def addRow(self, slice_: Slice) -> "ListBuilder":
- self._rows.append(slice_)
- return self
-
- def addGridRow(self, slice_: Slice) -> "ListBuilder":
- self._grid_rows.append(slice_)
- return self
-
- def addInputRange(self, slice_: Slice) -> "ListBuilder":
- self._input_ranges.append(slice_)
- return self
-
- def addSlider(self, slice_: Slice) -> "ListBuilder":
- self._sliders.append(slice_)
- return self
-
- def addRange(self, slice_: Slice) -> "ListBuilder":
- self._ranges.append(slice_)
- return self
-
- def addSelectToggle(self, slice_: Slice) -> "ListBuilder":
- self._select_toggles.append(slice_)
- return self
-
- def build(self) -> Slice:
- return Slice(self._uri, ["list"], self._spec)
-
- def toString(self) -> str:
- return f"ListBuilder{{uri={self._uri}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SliceManager
-# ═══════════════════════════════════════════════════════════════
-
-class SliceManager(Stub):
- """SliceManager — Slice 管理器"""
-
- def __init__(self):
- super().__init__()
- self._pinned_slices: Dict[str, Slice] = {}
- self._permissions: Dict[str, Set[str]] = {}
-
- def bindSlice(self, uri: str, specs: Set[SliceSpec]) -> Optional[Slice]:
- return self._pinned_slices.get(uri)
-
- def bindSliceForIntent(self, intent: Any, specs: Set[SliceSpec]) -> Optional[Slice]:
- return None
-
- def mapIntentToUri(self, intent: Any) -> Optional[str]:
- return None
-
- def grantSlicePermission(self, toPackage: str, uri: str):
- if uri not in self._permissions:
- self._permissions[uri] = set()
- self._permissions[uri].add(toPackage)
-
- def revokeSlicePermission(self, toPackage: str, uri: str):
- if uri in self._permissions:
- self._permissions[uri].discard(toPackage)
-
- def checkSlicePermission(self, uri: str, pid: int, uid: int) -> int:
- return 0 # PERMISSION_GRANTED
-
- def pinSlice(self, uri: str, specs: Set[SliceSpec]) -> Optional[Slice]:
- slice_ = self._pinned_slices.get(uri)
- if slice_:
- return slice_
- s = Slice(uri, spec=list(specs)[0] if specs else None)
- self._pinned_slices[uri] = s
- return s
-
- def unpinSlice(self, uri: str):
- self._pinned_slices.pop(uri, None)
-
- def getPinnedSlices(self) -> List[Slice]:
- return list(self._pinned_slices.values())
-
- def getSliceDescendants(self, uri: str) -> List[str]:
- return []
-
- def getSlice(self, uri: str) -> Optional[Slice]:
- return self._pinned_slices.get(uri)
-
- def getAllowedPackages(self) -> List[str]:
- return []
-
- def slicePinUser(self, uri: str) -> int:
- return 0
-
- def getPinnedSliceSpecs(self, uri: str) -> Set[SliceSpec]:
- return set()
-
- def toString(self) -> str:
- return f"SliceManager@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SliceProvider
-# ═══════════════════════════════════════════════════════════════
-
-class SliceProvider(Stub):
- """SliceProvider — Slice 提供者"""
-
- def __init__(self):
- super().__init__()
-
- def onCreateSliceProvider(self) -> bool:
- return True
-
- def onBindSlice(self, sliceUri: str, specs: Set[SliceSpec]) -> Optional[Slice]:
- return None
-
- def onSlicePinned(self, sliceUri: str):
- pass
-
- def onSliceUnpinned(self, sliceUri: str):
- pass
-
- def onMapIntentToUri(self, intent: Any) -> Optional[str]:
- return None
-
- def handleSliceRequest(self, uri: str, specs: Set[SliceSpec]) -> Optional[Slice]:
- return self.onBindSlice(uri, specs)
-
- def getCallingPackage(self) -> Optional[str]:
- return None
-
- def toString(self) -> str:
- return f"SliceProvider@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Slice",
- "SliceManager",
- "SliceProvider",
- "SliceSpec",
- "SliceItem",
- "ListBuilder",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/app_tasks.py b/android_pyapi/android/app_tasks.py
deleted file mode 100644
index eb8680a..0000000
--- a/android_pyapi/android/app_tasks.py
+++ /dev/null
@@ -1,969 +0,0 @@
-"""
-Android app.tasks 包 — TaskManager, TaskInfo, TaskStackListener,
-ActivityManager 任务/进程/内存信息等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import time
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-try:
- from .._linux_impl import IS_LINUX, LinuxProcess, LinuxPower
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-__all__ = [
- "TaskManager", "TaskInfo", "TaskStackListener", "TaskSnapshot",
- "TaskDescription", "ActivityManager",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-PROCESS_STATE_UNKNOWN = -1
-PROCESS_STATE_PERSISTENT = 0
-PROCESS_STATE_PERSISTENT_UI = 1
-PROCESS_STATE_TOP = 2
-PROCESS_STATE_BOUND_TOP = 3
-PROCESS_STATE_FOREGROUND_SERVICE = 4
-PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5
-PROCESS_STATE_IMPORTANT_FOREGROUND = 6
-PROCESS_STATE_IMPORTANT_BACKGROUND = 7
-PROCESS_STATE_TRANSIENT_BACKGROUND = 8
-PROCESS_STATE_BACKUP = 9
-PROCESS_STATE_SERVICE = 10
-PROCESS_STATE_RECEIVER = 11
-PROCESS_STATE_TOP_SLEEPING = 12
-PROCESS_STATE_HEAVY_WEIGHT = 13
-PROCESS_STATE_HOME = 14
-PROCESS_STATE_LAST_ACTIVITY = 15
-PROCESS_STATE_CACHED_ACTIVITY = 16
-PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17
-PROCESS_STATE_CACHED_EMPTY = 18
-
-IMPORTANCE_FOREGROUND = 100
-IMPORTANCE_FOREGROUND_SERVICE = 125
-IMPORTANCE_VISIBLE = 200
-IMPORTANCE_SERVICE = 300
-IMPORTANCE_CACHED = 400
-IMPORTANCE_CANT_SAVE_STATE = 170
-IMPORTANCE_GONE = 1000
-IMPORTANCE_BACKGROUND = 500
-IMPORTANCE_TOP_SLEEPING = 325
-IMPORTANCE_HAS_PREVIOUS = 650
-
-TASK_ID_NONE = -1
-TASK_LOCK_STATE_UNLOCKED = 0
-TASK_LOCK_STATE_LOCKED = 1
-TASK_LOCK_STATE_PINNED = 2
-
-TASK_NON_FULLSCREEN = 0
-TASK_FULLSCREEN = 1
-TASK_FLOATING = 2
-TASK_SPLIT_SCREEN_PRIMARY = 3
-TASK_SPLIT_SCREEN_SECONDARY = 4
-TASK_FREEFORM = 5
-
-
-# ═══════════════════════════════════════════════════════════════
-# TaskDescription
-# ═══════════════════════════════════════════════════════════════
-
-class TaskDescription(Stub):
- """TaskDescription — 任务描述"""
-
- def __init__(self, label: str = "", icon: Any = None, colorPrimary: int = 0,
- colorBackground: int = 0, statusBarColor: int = 0,
- navigationBarColor: int = 0):
- super().__init__()
- self._label = label
- self._icon = icon
- self._color_primary = colorPrimary
- self._color_background = colorBackground
- self._status_bar_color = statusBarColor
- self._navigation_bar_color = navigationBarColor
-
- def getLabel(self) -> str:
- return self._label
-
- def getIcon(self) -> Optional[Any]:
- return self._icon
-
- def getPrimaryColor(self) -> int:
- return self._color_primary
-
- def getBackgroundColor(self) -> int:
- return self._color_background
-
- def getStatusBarColor(self) -> int:
- return self._status_bar_color
-
- def getNavigationBarColor(self) -> int:
- return self._navigation_bar_color
-
- def toString(self) -> str:
- return f"TaskDescription(label={self._label})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, TaskDescription):
- return False
- return self._label == other._label
-
- def hashCode(self) -> int:
- return hash(self._label) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TaskSnapshot
-# ═══════════════════════════════════════════════════════════════
-
-class TaskSnapshot(Stub):
- """TaskSnapshot — 任务快照"""
-
- def __init__(self, taskId: int = 0, snapshot: Any = None,
- width: int = 0, height: int = 0,
- isRealSnapshot: bool = True,
- isTranslucent: bool = False,
- isPrivate: bool = False,
- topActivityComponent: str = "",
- snapshotScale: float = 1.0):
- super().__init__()
- self._task_id = taskId
- self._snapshot = snapshot
- self._width = width
- self._height = height
- self._is_real_snapshot = isRealSnapshot
- self._is_translucent = isTranslucent
- self._is_private = isPrivate
- self._top_activity = topActivityComponent
- self._snapshot_scale = snapshotScale
-
- def getTaskId(self) -> int:
- return self._task_id
-
- def getSnapshot(self) -> Any:
- return self._snapshot
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def isRealSnapshot(self) -> bool:
- return self._is_real_snapshot
-
- def isTranslucent(self) -> bool:
- return self._is_translucent
-
- def isPrivate(self) -> bool:
- return self._is_private
-
- def getTopActivityComponent(self) -> str:
- return self._top_activity
-
- def getSnapshotScale(self) -> float:
- return self._snapshot_scale
-
- def toString(self) -> str:
- return f"TaskSnapshot(task={self._task_id}, size={self._width}x{self._height})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, TaskSnapshot):
- return False
- return self._task_id == other._task_id
-
- def hashCode(self) -> int:
- return self._task_id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TaskInfo
-# ═══════════════════════════════════════════════════════════════
-
-class TaskInfo(Stub):
- """TaskInfo — 任务信息"""
-
- def __init__(self, taskId: int = 0, baseIntent: Any = None,
- baseActivity: Any = None, topActivity: Any = None,
- origActivity: Any = None, description: Any = None,
- numActivities: int = 0, numRunning: int = 0,
- isRunning: bool = False, supportsSplitScreen: bool = False,
- resizeMode: int = TASK_FULLSCREEN,
- userId: int = 0, displayId: int = 0,
- isVisible: bool = False, isPersistable: bool = True,
- lockState: int = TASK_LOCK_STATE_UNLOCKED,
- isRooted: bool = False,
- pictureInPictureEnabled: bool = False):
- super().__init__()
- self._task_id = taskId
- self._base_intent = baseIntent
- self._base_activity = baseActivity
- self._top_activity = topActivity
- self._orig_activity = origActivity
- self._description = description or TaskDescription()
- self._num_activities = numActivities
- self._num_running = numRunning
- self._is_running = isRunning
- self._supports_split_screen = supportsSplitScreen
- self._resize_mode = resizeMode
- self._user_id = userId
- self._display_id = displayId
- self._is_visible = isVisible
- self._is_persistable = isPersistable
- self._lock_state = lockState
- self._is_rooted = isRooted
- self._pip_enabled = pictureInPictureEnabled
-
- def getTaskId(self) -> int:
- return self._task_id
-
- def getBaseIntent(self) -> Any:
- return self._base_intent
-
- def getBaseActivity(self) -> Any:
- return self._base_activity
-
- def getTopActivity(self) -> Any:
- return self._top_activity
-
- def getOrigActivity(self) -> Any:
- return self._orig_activity
-
- def getDescription(self) -> Any:
- return self._description
-
- def getNumActivities(self) -> int:
- return self._num_activities
-
- def getNumRunning(self) -> int:
- return self._num_running
-
- def isRunning(self) -> bool:
- return self._is_running
-
- def supportsSplitScreen(self) -> bool:
- return self._supports_split_screen
-
- def getResizeMode(self) -> int:
- return self._resize_mode
-
- def getUserId(self) -> int:
- return self._user_id
-
- def getDisplayId(self) -> int:
- return self._display_id
-
- def isVisible(self) -> bool:
- return self._is_visible
-
- def isPersistable(self) -> bool:
- return self._is_persistable
-
- def getLockState(self) -> int:
- return self._lock_state
-
- def isRooted(self) -> bool:
- return self._is_rooted
-
- def isPictureInPictureEnabled(self) -> bool:
- return self._pip_enabled
-
- def toString(self) -> str:
- return (f"TaskInfo(id={self._task_id}, "
- f"activities={self._num_activities}, "
- f"running={self._is_running})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, TaskInfo):
- return False
- return self._task_id == other._task_id
-
- def hashCode(self) -> int:
- return self._task_id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TaskStackListener
-# ═══════════════════════════════════════════════════════════════
-
-class TaskStackListener(Stub):
- """TaskStackListener — 任务栈监听器"""
-
- def onTaskStackChanged(self):
- pass
-
- def onTaskCreated(self, taskId: int, componentName: Any):
- pass
-
- def onTaskRemoved(self, taskId: int):
- pass
-
- def onTaskMovedToFront(self, taskInfo: TaskInfo):
- pass
-
- def onTaskMovedToBack(self, taskInfo: TaskInfo):
- pass
-
- def onTaskDescriptionChanged(self, taskInfo: TaskInfo,
- taskDescription: TaskDescription):
- pass
-
- def onTaskSnapshotChanged(self, taskId: int, snapshot: TaskSnapshot):
- pass
-
- def onTaskDisplayChanged(self, taskId: int, newDisplayId: int):
- pass
-
- def onTaskProfileLocked(self, taskId: int, userId: int):
- pass
-
- def onRecentTaskListUpdated(self):
- pass
-
- def toString(self) -> str:
- return f"TaskStackListener@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TaskManager
-# ═══════════════════════════════════════════════════════════════
-
-class TaskManager(Stub):
- """TaskManager — 任务管理器"""
-
- def __init__(self):
- super().__init__()
- self._tasks: Dict[int, TaskInfo] = {}
- self._listeners: Dict[int, TaskStackListener] = {}
- self._snapshots: Dict[int, TaskSnapshot] = {}
- self._next_id = 100
-
- def getTasks(self, maxNum: int = 10) -> List[TaskInfo]:
- return list(self._tasks.values())[:maxNum]
-
- def getTaskInfo(self, taskId: int) -> Optional[TaskInfo]:
- return self._tasks.get(taskId)
-
- def getRecentTasks(self, maxNum: int = 10, flags: int = 0) -> List[TaskInfo]:
- return list(self._tasks.values())[:maxNum]
-
- def addTask(self, taskInfo: TaskInfo):
- self._tasks[taskInfo.getTaskId()] = taskInfo
-
- def removeTask(self, taskId: int):
- self._tasks.pop(taskId, None)
-
- def moveTaskToFront(self, taskId: int, flags: int = 0):
- pass
-
- def moveTaskToBack(self, taskId: int):
- pass
-
- def cancelTaskWindowTransition(self, taskId: int):
- pass
-
- def setTaskDescription(self, taskId: int, description: TaskDescription):
- task = self._tasks.get(taskId)
- if task:
- self._tasks[taskId] = task
-
- def takeTaskSnapshot(self, taskId: int) -> Optional[TaskSnapshot]:
- return self._snapshots.get(taskId)
-
- def registerTaskStackListener(self, listener: TaskStackListener):
- lid = id(listener)
- self._listeners[lid] = listener
-
- def unregisterTaskStackListener(self, listener: TaskStackListener):
- lid = id(listener)
- self._listeners.pop(lid, None)
-
- def createTask(self, componentName: str) -> int:
- task_id = self._next_id
- self._next_id += 1
- task = TaskInfo(taskId=task_id, baseActivity=componentName, isRunning=True)
- self._tasks[task_id] = task
- return task_id
-
- def getTaskCount(self) -> int:
- return len(self._tasks)
-
- def getRunningTaskCount(self) -> int:
- return sum(1 for t in self._tasks.values() if t.isRunning())
-
- def toString(self) -> str:
- return f"TaskManager(tasks={len(self._tasks)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ActivityManager 任务/进程/内存信息内部类
-# ═══════════════════════════════════════════════════════════════
-
-class ActivityManager(Stub):
- """ActivityManager — 活动管理器 (任务/进程/内存相关内部类)"""
-
- RECENT_IGNORE_UNAVAILABLE = 0x00000002
- RECENT_WITH_EXCLUDED = 0x00000001
- RECENT_INCLUDE_PROFILES = 0x00000004
- RECENT_INGORE_DOCKED_STACK_TOP = 0x00000008
- RECENT_INGORE_PINNED_STACK = 0x00000010
-
- START_SUCCESS = 0
- START_INTENT_NOT_RESOLVED = -1
- START_CLASS_NOT_FOUND = -2
- START_FORWARD_AND_REQUEST_CONFLICT = -3
- START_PERMISSION_DENIED = -4
- START_NOT_ACTIVITY = -5
- START_NOT_VOICE_COMPATIBLE = -6
- START_NOT_CURRENT_USER = -7
- START_RETURN_LOCK_ERROR = -8
- START_LOCK_ERROR = -9
- START_SWITCHES_CANCELED = -10
- START_ABORTED = -11
-
- MOVETASK_WITH_HOME = 0x00000001
- MOVETASK_NO_ANIMATION = 0x00000002
-
- # ═══════════════════════════════════════════════════════════
- # RecentTaskInfo
- # ═══════════════════════════════════════════════════════════
-
- class RecentTaskInfo(Stub):
- """ActivityManager.RecentTaskInfo — 最近任务信息"""
-
- def __init__(self, taskId: int = 0, baseIntent: Any = None,
- origActivity: Any = None, description: Any = None,
- userId: int = 0, persistentId: int = 0,
- affiliatedTaskId: int = 0, affiliatedTaskColor: int = 0,
- isExcluded: bool = False, isDockable: bool = True,
- resizeMode: int = TASK_FULLSCREEN,
- topActivity: Any = None, baseActivity: Any = None):
- super().__init__()
- self._task_id = taskId
- self._base_intent = baseIntent
- self._orig_activity = origActivity
- self._description = description
- self._user_id = userId
- self._persistent_id = persistentId
- self._affiliated_task_id = affiliatedTaskId
- self._affiliated_task_color = affiliatedTaskColor
- self._is_excluded = isExcluded
- self._is_dockable = isDockable
- self._resize_mode = resizeMode
- self._top_activity = topActivity
- self._base_activity = baseActivity
-
- def getTaskId(self) -> int:
- return self._task_id
-
- def getBaseIntent(self) -> Any:
- return self._base_intent
-
- def getOrigActivity(self) -> Any:
- return self._orig_activity
-
- def getDescription(self) -> Any:
- return self._description
-
- def getUserId(self) -> int:
- return self._user_id
-
- def getPersistentId(self) -> int:
- return self._persistent_id
-
- def getAffiliatedTaskId(self) -> int:
- return self._affiliated_task_id
-
- def getAffiliatedTaskColor(self) -> int:
- return self._affiliated_task_color
-
- def isExcluded(self) -> bool:
- return self._is_excluded
-
- def isDockable(self) -> bool:
- return self._is_dockable
-
- def getResizeMode(self) -> int:
- return self._resize_mode
-
- def getTopActivity(self) -> Any:
- return self._top_activity
-
- def getBaseActivity(self) -> Any:
- return self._base_activity
-
- def toString(self) -> str:
- return f"RecentTaskInfo(id={self._task_id})"
-
- # ═══════════════════════════════════════════════════════════
- # AppTask
- # ═══════════════════════════════════════════════════════════
-
- class AppTask(Stub):
- """ActivityManager.AppTask — 应用任务"""
-
- def __init__(self, taskInfo: Optional[RecentTaskInfo] = None):
- super().__init__()
- self._task_info = taskInfo
-
- def getTaskInfo(self) -> Optional["ActivityManager.RecentTaskInfo"]:
- return self._task_info
-
- def moveToFront(self):
- pass
-
- def startActivity(self, intent: Any, options: Any = None):
- pass
-
- def setExcludeFromRecents(self, exclude: bool):
- pass
-
- def finishAndRemoveTask(self):
- pass
-
- def setTaskDescription(self, description: TaskDescription):
- pass
-
- def toString(self) -> str:
- return f"AppTask(info={self._task_info})"
-
- # ═══════════════════════════════════════════════════════════
- # StackInfo
- # ═══════════════════════════════════════════════════════════
-
- class StackInfo(Stub):
- """ActivityManager.StackInfo — 栈信息"""
-
- def __init__(self, stackId: int = 0, bounds: Any = None,
- taskIds: List[int] = None, taskNames: List[str] = None,
- displayId: int = 0, topActivity: Any = None,
- visible: bool = False, position: int = 0,
- isWindowingMode: int = TASK_FULLSCREEN):
- super().__init__()
- self._stack_id = stackId
- self._bounds = bounds
- self._task_ids = taskIds or []
- self._task_names = taskNames or []
- self._display_id = displayId
- self._top_activity = topActivity
- self._visible = visible
- self._position = position
- self._windowing_mode = isWindowingMode
-
- def getStackId(self) -> int:
- return self._stack_id
-
- def getBounds(self) -> Any:
- return self._bounds
-
- def getTaskIds(self) -> List[int]:
- return list(self._task_ids)
-
- def getTaskNames(self) -> List[str]:
- return list(self._task_names)
-
- def getDisplayId(self) -> int:
- return self._display_id
-
- def getTopActivity(self) -> Any:
- return self._top_activity
-
- def isVisible(self) -> bool:
- return self._visible
-
- def getPosition(self) -> int:
- return self._position
-
- def getWindowingMode(self) -> int:
- return self._windowing_mode
-
- def toString(self) -> str:
- return f"StackInfo(id={self._stack_id}, tasks={len(self._task_ids)})"
-
- # ═══════════════════════════════════════════════════════════
- # RunningTaskInfo
- # ═══════════════════════════════════════════════════════════
-
- class RunningTaskInfo(Stub):
- """ActivityManager.RunningTaskInfo — 运行中任务信息"""
-
- def __init__(self, taskId: int = 0, baseActivity: Any = None,
- topActivity: Any = None, numActivities: int = 0,
- numRunning: int = 0, description: Any = None,
- thumbnail: Any = None, isRunning: bool = True):
- super().__init__()
- self._task_id = taskId
- self._base_activity = baseActivity
- self._top_activity = topActivity
- self._num_activities = numActivities
- self._num_running = numRunning
- self._description = description
- self._thumbnail = thumbnail
- self._is_running = isRunning
-
- def getTaskId(self) -> int:
- return self._task_id
-
- def getBaseActivity(self) -> Any:
- return self._base_activity
-
- def getTopActivity(self) -> Any:
- return self._top_activity
-
- def getNumActivities(self) -> int:
- return self._num_activities
-
- def getNumRunning(self) -> int:
- return self._num_running
-
- def getDescription(self) -> Any:
- return self._description
-
- def getThumbnail(self) -> Any:
- return self._thumbnail
-
- def isRunning(self) -> bool:
- return self._is_running
-
- def toString(self) -> str:
- return f"RunningTaskInfo(id={self._task_id}, activities={self._num_activities})"
-
- # ═══════════════════════════════════════════════════════════
- # RunningServiceInfo
- # ═══════════════════════════════════════════════════════════
-
- class RunningServiceInfo(Stub):
- """ActivityManager.RunningServiceInfo — 运行中服务信息"""
-
- def __init__(self, service: Any = None, process: str = "",
- uid: int = 0, pid: int = 0, clientCount: int = 0,
- clientLabel: int = 0, clientPackage: str = "",
- crashCount: int = 0, flags: int = 0,
- started: bool = False, foreground: bool = False,
- restarting: bool = False):
- super().__init__()
- self._service = service
- self._process = process
- self._uid = uid
- self._pid = pid
- self._client_count = clientCount
- self._client_label = clientLabel
- self._client_package = clientPackage
- self._crash_count = crashCount
- self._flags = flags
- self._started = started
- self._foreground = foreground
- self._restarting = restarting
-
- def getService(self) -> Any:
- return self._service
-
- def getProcess(self) -> str:
- return self._process
-
- def getUid(self) -> int:
- return self._uid
-
- def getPid(self) -> int:
- return self._pid
-
- def getClientCount(self) -> int:
- return self._client_count
-
- def getClientLabel(self) -> int:
- return self._client_label
-
- def getClientPackage(self) -> str:
- return self._client_package
-
- def getCrashCount(self) -> int:
- return self._crash_count
-
- def getFlags(self) -> int:
- return self._flags
-
- def isStarted(self) -> bool:
- return self._started
-
- def isForeground(self) -> bool:
- return self._foreground
-
- def isRestarting(self) -> bool:
- return self._restarting
-
- def toString(self) -> str:
- return f"RunningServiceInfo(service={self._service}, pid={self._pid})"
-
- # ═══════════════════════════════════════════════════════════
- # RunningAppProcessInfo
- # ═══════════════════════════════════════════════════════════
-
- class RunningAppProcessInfo(Stub):
- """ActivityManager.RunningAppProcessInfo — 运行中应用进程信息"""
-
- IMPORTANCE_FOREGROUND = IMPORTANCE_FOREGROUND
- IMPORTANCE_FOREGROUND_SERVICE = IMPORTANCE_FOREGROUND_SERVICE
- IMPORTANCE_VISIBLE = IMPORTANCE_VISIBLE
- IMPORTANCE_SERVICE = IMPORTANCE_SERVICE
- IMPORTANCE_CACHED = IMPORTANCE_CACHED
- IMPORTANCE_GONE = IMPORTANCE_GONE
- IMPORTANCE_BACKGROUND = IMPORTANCE_BACKGROUND
- IMPORTANCE_TOP_SLEEPING = IMPORTANCE_TOP_SLEEPING
-
- REASON_UNKNOWN = 0
- REASON_PROVIDER_IN_USE = 1
- REASON_SERVICE_IN_USE = 2
- REASON_BACKGROUND = 3
- REASON_CRASH = 4
- REASON_ANR = 5
- REASON_LOW_MEMORY = 6
- REASON_USER_STOPPED = 7
- REASON_PERMISSION_CHANGE = 8
- REASON_ABORTED = 9
-
- def __init__(self, processName: str = "", pid: int = 0,
- uid: int = 0, pkgList: List[str] = None,
- importance: int = IMPORTANCE_FOREGROUND,
- importanceReasonCode: int = REASON_UNKNOWN,
- importanceReasonPid: int = 0,
- importanceReasonComponent: Any = None,
- lastActivityTime: int = 0,
- lru: int = 0):
- super().__init__()
- self.processName = processName
- self.pid = pid
- self.uid = uid
- self.pkgList = pkgList or []
- self.importance = importance
- self.importanceReasonCode = importanceReasonCode
- self.importanceReasonPid = importanceReasonPid
- self.importanceReasonComponent = importanceReasonComponent
- self.lastActivityTime = lastActivityTime
- self.lru = lru
-
- def getProcessName(self) -> str:
- return self.processName
-
- def getPid(self) -> int:
- return self.pid
-
- def getUid(self) -> int:
- return self.uid
-
- def getPackageList(self) -> List[str]:
- return list(self.pkgList)
-
- def getImportance(self) -> int:
- return self.importance
-
- def getImportanceReasonCode(self) -> int:
- return self.importanceReasonCode
-
- def getImportanceReasonPid(self) -> int:
- return self.importanceReasonPid
-
- def getImportanceReasonComponent(self) -> Any:
- return self.importanceReasonComponent
-
- def toString(self) -> str:
- return (f"RunningAppProcessInfo(process={self.processName}, "
- f"pid={self.pid}, importance={self.importance})")
-
- # ═══════════════════════════════════════════════════════════
- # ProcessErrorStateInfo
- # ═══════════════════════════════════════════════════════════
-
- class ProcessErrorStateInfo(Stub):
- """ActivityManager.ProcessErrorStateInfo — 进程错误状态信息"""
-
- CRASHED = 1
- NOT_RESPONDING = 2
- NO_ERROR = 0
-
- def __init__(self, condition: int = NO_ERROR, processName: str = "",
- pid: int = 0, uid: int = 0, tag: str = "",
- shortMessage: str = "", longMessage: str = "",
- crashedApp: str = "",
- stackTrace: str = ""):
- super().__init__()
- self._condition = condition
- self._process_name = processName
- self._pid = pid
- self._uid = uid
- self._tag = tag
- self._short_message = shortMessage
- self._long_message = longMessage
- self._crash_app = crashedApp
- self._stack_trace = stackTrace
-
- def getCondition(self) -> int:
- return self._condition
-
- def getProcessName(self) -> str:
- return self._process_name
-
- def getPid(self) -> int:
- return self._pid
-
- def getUid(self) -> int:
- return self._uid
-
- def getTag(self) -> str:
- return self._tag
-
- def getShortMessage(self) -> str:
- return self._short_message
-
- def getLongMessage(self) -> str:
- return self._long_message
-
- def getCrashApp(self) -> str:
- return self._crash_app
-
- def getStackTrace(self) -> str:
- return self._stack_trace
-
- def toString(self) -> str:
- return (f"ProcessErrorStateInfo(condition={self._condition}, "
- f"process={self._process_name})")
-
- # ═══════════════════════════════════════════════════════════
- # MemoryInfo
- # ═══════════════════════════════════════════════════════════
-
- class MemoryInfo(Stub):
- """ActivityManager.MemoryInfo — 内存信息"""
-
- def __init__(self):
- super().__init__()
- self.availMem: int = 0
- self.totalMem: int = 0
- self.threshold: int = 0
- self.lowMemory: bool = False
- self.hiddenAppThreshold: int = 0
- self.secondaryServerThreshold: int = 0
- self.visibleAppThreshold: int = 0
- self.foregroundAppThreshold: int = 0
-
- def getAvailMem(self) -> int:
- return self.availMem
-
- def getTotalMem(self) -> int:
- return self.totalMem
-
- def getThreshold(self) -> int:
- return self.threshold
-
- def isLowMemory(self) -> bool:
- return self.lowMemory
-
- def getHiddenAppThreshold(self) -> int:
- return self.hiddenAppThreshold
-
- def getSecondaryServerThreshold(self) -> int:
- return self.secondaryServerThreshold
-
- def getVisibleAppThreshold(self) -> int:
- return self.visibleAppThreshold
-
- def getForegroundAppThreshold(self) -> int:
- return self.foregroundAppThreshold
-
- def toString(self) -> str:
- avail_mb = self.availMem / (1024 * 1024)
- total_mb = self.totalMem / (1024 * 1024)
- return (f"MemoryInfo(avail={avail_mb:.0f}MB, "
- f"total={total_mb:.0f}MB, "
- f"lowMemory={self.lowMemory})")
-
- def __init__(self):
- super().__init__()
- self._tasks: Dict[int, ActivityManager.RecentTaskInfo] = {}
- self._processes: Dict[int, ActivityManager.RunningAppProcessInfo] = {}
- self._services: Dict[int, ActivityManager.RunningServiceInfo] = {}
-
- def getRecentTasks(self, maxNum: int, flags: int) -> List[RecentTaskInfo]:
- return list(self._tasks.values())[:maxNum]
-
- def getRunningTasks(self, maxNum: int) -> List[RunningTaskInfo]:
- return []
-
- def getRunningServices(self, maxNum: int) -> List[RunningServiceInfo]:
- return list(self._services.values())[:maxNum]
-
- def getRunningAppProcesses(self) -> List[RunningAppProcessInfo]:
- if _USE_LINUX:
- return LinuxProcess.list_processes()
- return list(self._processes.values())
-
- def getMemoryInfo(self, outInfo: MemoryInfo):
- if _USE_LINUX:
- mem = LinuxPower.get_memory_info()
- outInfo.availMem = mem.get("available", 0)
- outInfo.totalMem = mem.get("total", 0)
- outInfo.threshold = int(mem.get("total", 0) * 0.1)
- outInfo.lowMemory = mem.get("percent", 0) > 90.0
- return outInfo
- import psutil
- try:
- import psutil
- mem = psutil.virtual_memory()
- outInfo.availMem = mem.available
- outInfo.totalMem = mem.total
- outInfo.threshold = int(mem.total * 0.1)
- outInfo.lowMemory = mem.percent > 90.0
- except ImportError:
- outInfo.totalMem = 8 * 1024 * 1024 * 1024
- outInfo.availMem = 4 * 1024 * 1024 * 1024
- outInfo.threshold = outInfo.totalMem // 10
-
- def getMyMemoryState(self, outInfo: RunningAppProcessInfo):
- outInfo.uid = os.getuid()
- outInfo.pid = os.getpid()
- outInfo.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
-
- def isLowRamDevice(self) -> bool:
- return False
-
- def clearApplicationUserData(self) -> bool:
- return False
-
- def killBackgroundProcesses(self, packageName: str):
- pass
-
- def restartPackage(self, packageName: str):
- pass
-
- def getProcessMemoryInfo(self, pids: List[int]) -> List[Any]:
- return []
-
- def toString(self) -> str:
- return f"ActivityManager(tasks={len(self._tasks)}, processes={len(self._processes)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/app_time.py b/android_pyapi/android/app_time.py
deleted file mode 100644
index e03cbf3..0000000
--- a/android_pyapi/android/app_time.py
+++ /dev/null
@@ -1,181 +0,0 @@
-"""
-Android app.time 组件 — TimeManager, TimeZoneCapabilities, TimeConfiguration 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import datetime
-import time as _time
-from typing import Any, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# TimeConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class TimeConfiguration(Stub):
- """TimeConfiguration — 时间配置"""
-
- def __init__(self):
- super().__init__()
- self._override_enabled: bool = False
- self._override_time_zone_ids: List[str] = []
-
- def setOverrideEnabled(self, enabled: bool):
- self._override_enabled = enabled
-
- def isOverrideEnabled(self) -> bool:
- return self._override_enabled
-
- def getOverrideTimeZoneIds(self) -> List[str]:
- return list(self._override_time_zone_ids)
-
- def setOverrideTimeZoneIds(self, ids: List[str]):
- self._override_time_zone_ids = list(ids)
-
- def toString(self) -> str:
- return f"TimeConfiguration{{overrideEnabled={self._override_enabled}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TimeZoneCapabilities
-# ═══════════════════════════════════════════════════════════════
-
-class TimeZoneCapabilities(Stub):
- """TimeZoneCapabilities — 时区能力"""
-
- CAPABILITY_NOT_SUPPORTED = 0
- CAPABILITY_NOT_ALLOWED = 1
- CAPABILITY_ALLOWED = 2
-
- def __init__(self):
- super().__init__()
- self._auto_detection_capability: int = self.CAPABILITY_ALLOWED
- self._manual_detection_capability: int = self.CAPABILITY_ALLOWED
- self._configure_auto_detection_capability: int = self.CAPABILITY_ALLOWED
-
- def getAutoDetectionCapability(self) -> int:
- return self._auto_detection_capability
-
- def getManualDetectionCapability(self) -> int:
- return self._manual_detection_capability
-
- def isAutoDetectionSupported(self) -> bool:
- return True
-
- def isManualDetectionSupported(self) -> bool:
- return True
-
- def toString(self) -> str:
- return (f"TimeZoneCapabilities{{autoDetection={self._auto_detection_capability}, "
- f"manualDetection={self._manual_detection_capability}}}")
-
-
-# ═══════════════════════════════════════════════════════════════
-# TimeZoneCapabilitiesAndConfig
-# ═══════════════════════════════════════════════════════════════
-
-class TimeZoneCapabilitiesAndConfig(Stub):
- """TimeZoneCapabilitiesAndConfig — 时区能力与配置"""
-
- def __init__(self):
- super().__init__()
- self._capabilities = TimeZoneCapabilities()
- self._configuration = TimeConfiguration()
-
- def getCapabilities(self) -> TimeZoneCapabilities:
- return self._capabilities
-
- def getConfiguration(self) -> TimeConfiguration:
- return self._configuration
-
- def toString(self) -> str:
- return (f"TimeZoneCapabilitiesAndConfig{{capabilities={self._capabilities}, "
- f"config={self._configuration}}}")
-
-
-# ═══════════════════════════════════════════════════════════════
-# TimeManager
-# ═══════════════════════════════════════════════════════════════
-
-class TimeManager(Stub):
- """TimeManager — 时间管理器"""
-
- EXTRA_SUGGESTION = "suggestion"
- EXTRA_RESULT = "result"
-
- RESULT_OK = 0
- RESULT_ERROR = -1
- RESULT_NOT_ALLOWED = -2
- RESULT_SKIPPED = -3
-
- def __init__(self):
- super().__init__()
-
- # ── Time zone ──
-
- def getTimeZoneCapabilitiesAndConfig(self) -> TimeZoneCapabilitiesAndConfig:
- return TimeZoneCapabilitiesAndConfig()
-
- def getDetectedTimeZoneSource(self) -> int:
- return 0
-
- def suggestExternalTimeZone(self, suggestion: Any) -> int:
- return self.RESULT_OK
-
- def suggestExternalTime(self, suggestion: Any) -> int:
- return self.RESULT_OK
-
- def confirmTimeChange(self, confirmation: Any) -> int:
- return self.RESULT_OK
-
- # ── Time / Time zone setting ──
-
- def isAutoTimeEnabled(self) -> bool:
- return True
-
- def isAutoTimeZoneEnabled(self) -> bool:
- return True
-
- def setAutoTimeEnabled(self, enabled: bool):
- pass
-
- def setAutoTimeZoneEnabled(self, enabled: bool):
- pass
-
- def setTime(self, millis: int):
- try:
- dt = datetime.datetime.fromtimestamp(millis / 1000.0)
- _time.mktime(dt.timetuple())
- except (OSError, ValueError):
- pass
-
- def setTimeZone(self, timeZone: str):
- pass
-
- def updateTime(self, time: Any):
- pass
-
- def updateTimeZone(self, timeZone: Any):
- pass
-
- def toString(self) -> str:
- return f"TimeManager@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "TimeManager",
- "TimeZoneCapabilities",
- "TimeZoneCapabilitiesAndConfig",
- "TimeConfiguration",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/app_usage.py b/android_pyapi/android/app_usage.py
deleted file mode 100644
index 8d6b150..0000000
--- a/android_pyapi/android/app_usage.py
+++ /dev/null
@@ -1,527 +0,0 @@
-"""
-Android Usage Stats API — UsageStatsManager, UsageStats, UsageEvents, ConfigurationStats, StorageStatsManager
-方法签名完全对齐 Android SDK
-"""
-
-import json
-import os as _os
-import sys
-import time
-from datetime import datetime, timedelta
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-from collections import defaultdict
-
-from .._core import Stub, AndroidOnlyError, resolve_android_path, _app_data_dir, _sdcard_root
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "UsageStatsManager",
- "UsageStats",
- "UsageEvents",
- "ConfigurationStats",
- "CacheUsageStats",
- "NetworkUsageStats",
- "UsageStatsManagerInternal",
- "StorageStatsManager",
- "StorageStats",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsageStatsManager
-# ═══════════════════════════════════════════════════════════════
-
-class UsageStatsManager(Stub):
- """UsageStatsManager — 使用统计管理器 (桌面模拟)"""
-
- INTERVAL_DAILY = 0
- INTERVAL_WEEKLY = 1
- INTERVAL_MONTHLY = 2
- INTERVAL_YEARLY = 3
- INTERVAL_BEST = 4
- INTERVAL_COUNT = 5
-
- USAGE_SOURCE_UNSPECIFIED = 0
- USAGE_SOURCE_CURRENT_ACTIVITY = 1
- USAGE_SOURCE_TASK_ROOT_ACTIVITY = 2
-
- def __init__(self):
- super().__init__()
- self._app_inactive: Dict[str, bool] = {}
-
- def queryUsageStats(
- self, intervalType: int, beginTime: int, endTime: int
- ) -> List["UsageStats"]:
- """查询使用统计信息"""
- result: List[UsageStats] = []
- stats_dir = _os.path.join(_app_data_dir, "usagestats")
- if _os.path.exists(stats_dir):
- for fname in _os.listdir(stats_dir):
- if fname.endswith(".json"):
- filepath = _os.path.join(stats_dir, fname)
- try:
- with open(filepath, "r") as f:
- data = json.load(f)
- stats = UsageStats()
- stats._package_name = data.get("package", fname[:-5])
- stats._first_time = data.get("first_time", beginTime)
- stats._last_time = data.get("last_time", endTime)
- stats._last_used = data.get("last_used", beginTime)
- stats._total_foreground = data.get("total_foreground", 0)
- stats._launch_count = data.get("launch_count", 0)
- if stats._last_time >= beginTime and stats._last_time <= endTime:
- result.append(stats)
- except (json.JSONDecodeError, IOError):
- pass
- return result
-
- def queryConfigurations(
- self, intervalType: int, beginTime: int, endTime: int
- ) -> List["ConfigurationStats"]:
- """查询配置统计"""
- return []
-
- def queryEvents(
- self, beginTime: int, endTime: int
- ) -> "UsageEvents":
- """查询使用事件"""
- return UsageEvents()
-
- def isAppInactive(self, packageName: str) -> bool:
- """检查应用是否处于非活跃状态"""
- return self._app_inactive.get(packageName, False)
-
- def setAppInactive(self, packageName: str, inactive: bool):
- """设置应用非活跃状态"""
- self._app_inactive[packageName] = inactive
-
- def onCarrierPrivilegedAppsChanged(self):
- """运营商特权应用变更 (桌面存根)"""
- pass
-
- def toString(self) -> str:
- return f"UsageStatsManager@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsageStats
-# ═══════════════════════════════════════════════════════════════
-
-class UsageStats(Stub):
- """UsageStats — 应用使用统计"""
-
- def __init__(self):
- super().__init__()
- self._package_name = ""
- self._first_time = 0
- self._last_time = 0
- self._last_used = 0
- self._total_foreground = 0
- self._launch_count = 0
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def getFirstTimeStamp(self) -> int:
- return self._first_time
-
- def getLastTimeStamp(self) -> int:
- return self._last_time
-
- def getLastUsedTime(self) -> int:
- return self._last_used
-
- def getTotalTimeInForeground(self) -> int:
- return self._total_foreground
-
- def getAppLaunchCount(self) -> int:
- return self._launch_count
-
- def toString(self) -> str:
- return (f"UsageStats(pkg={self._package_name}, "
- f"foreground={self._total_foreground}ms, "
- f"launches={self._launch_count})")
-
- def equals(self, other) -> bool:
- if not isinstance(other, UsageStats):
- return False
- return self._package_name == other._package_name
-
- def hashCode(self) -> int:
- return hash(self._package_name) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsageEvents
-# ═══════════════════════════════════════════════════════════════
-
-class UsageEvents(Stub):
- """UsageEvents — 使用事件列表"""
-
- def __init__(self):
- super().__init__()
- self._events: List["UsageEvents.Event"] = []
- self._index = 0
-
- def getNextEvent(self, eventOut: "UsageEvents.Event") -> bool:
- """获取下一个事件"""
- if self._index < len(self._events):
- ev = self._events[self._index]
- eventOut._package_name = ev._package_name
- eventOut._class_name = ev._class_name
- eventOut._action = ev._action
- eventOut._time_stamp = ev._time_stamp
- self._index += 1
- return True
- return False
-
- def hasNextEvent(self) -> bool:
- """检查是否还有下一个事件"""
- return self._index < len(self._events)
-
- def resetToStart(self):
- """重置到起始位置"""
- self._index = 0
-
- # ═══════════════════════════════════════════════════════════
- # Event — 内部事件类
- # ═══════════════════════════════════════════════════════════
-
- class Event(Stub):
- """UsageEvents.Event — 使用事件"""
-
- # --- Event action constants ---
- MOVE_TO_FOREGROUND = 1
- MOVE_TO_BACKGROUND = 2
- CONFIGURATION_CHANGE = 3
- SHORTCUT_INVOCATION = 4
- STANDBY_BUDGET_CHANGED = 5
- USER_INTERACTION = 6
- NOTIFICATION_SEEN = 7
- NOTIFICATION_INTERRUPTION = 8
- CHOOSER_ACTION = 9
- APP_COMPONENT_USED = 10
- ACTIVITY_STOPPED = 11
- SYSTEM_INTERACTION = 12
- FLAG_IS_PACKAGE_INSTALL = 13
- FLAG_NO_INTERRUPTION = 14
-
- def __init__(self):
- super().__init__()
- self._package_name = ""
- self._class_name = ""
- self._action = 0
- self._time_stamp = 0
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def getClassName(self) -> str:
- return self._class_name
-
- def getAction(self) -> int:
- return self._action
-
- def getTimeStamp(self) -> int:
- return self._time_stamp
-
- def toString(self) -> str:
- return (f"Event(pkg={self._package_name}, "
- f"action={self._action}, time={self._time_stamp})")
-
- def equals(self, other) -> bool:
- if not isinstance(other, UsageEvents.Event):
- return False
- return (self._package_name == other._package_name
- and self._action == other._action
- and self._time_stamp == other._time_stamp)
-
- def hashCode(self) -> int:
- return hash((self._package_name, self._action, self._time_stamp)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"UsageEvents(count={len(self._events)})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, UsageEvents):
- return False
- return self._events == other._events
-
- def hashCode(self) -> int:
- return hash(len(self._events)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ConfigurationStats
-# ═══════════════════════════════════════════════════════════════
-
-class ConfigurationStats(Stub):
- """ConfigurationStats — 配置统计"""
-
- def __init__(self):
- super().__init__()
- self._first_time = 0
- self._last_time = 0
- self._last_active = 0
- self._total_active = 0
- self._activation_count = 0
-
- def getFirstTimeStamp(self) -> int:
- return self._first_time
-
- def getLastTimeStamp(self) -> int:
- return self._last_time
-
- def getLastTimeActive(self) -> int:
- return self._last_active
-
- def getTotalTimeActive(self) -> int:
- return self._total_active
-
- def getActivationCount(self) -> int:
- return self._activation_count
-
- def toString(self) -> str:
- return f"ConfigurationStats(active={self._total_active}ms, count={self._activation_count})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, ConfigurationStats):
- return False
- return (self._first_time == other._first_time
- and self._last_time == other._last_time)
-
- def hashCode(self) -> int:
- return hash((self._first_time, self._last_time)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CacheUsageStats
-# ═══════════════════════════════════════════════════════════════
-
-class CacheUsageStats(Stub):
- """CacheUsageStats — 缓存使用统计"""
-
- def __init__(self):
- super().__init__()
- self._cache_size = 0
- self._total_size = 0
-
- def getCacheSize(self) -> int:
- return self._cache_size
-
- def getTotalSize(self) -> int:
- return self._total_size
-
- def toString(self) -> str:
- return f"CacheUsageStats(cache={self._cache_size}B)"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkUsageStats
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkUsageStats(Stub):
- """NetworkUsageStats — 网络使用统计"""
-
- def __init__(self):
- super().__init__()
- self._rx_bytes = 0
- self._tx_bytes = 0
- self._rx_packets = 0
- self._tx_packets = 0
-
- def getRxBytes(self) -> int:
- return self._rx_bytes
-
- def getTxBytes(self) -> int:
- return self._tx_bytes
-
- def getRxPackets(self) -> int:
- return self._rx_packets
-
- def getTxPackets(self) -> int:
- return self._tx_packets
-
- def toString(self) -> str:
- return f"NetworkUsageStats(rx={self._rx_bytes}B, tx={self._tx_bytes}B)"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsageStatsManagerInternal
-# ═══════════════════════════════════════════════════════════════
-
-class UsageStatsManagerInternal(Stub):
- """UsageStatsManagerInternal — 内部使用统计管理器"""
-
- def __init__(self):
- super().__init__()
-
- def reportEvent(self, event: Any):
- """报告使用事件"""
- pass
-
- def toString(self) -> str:
- return f"UsageStatsManagerInternal@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# StorageStatsManager
-# ═══════════════════════════════════════════════════════════════
-
-class StorageStatsManager(Stub):
- """StorageStatsManager — 存储统计管理器"""
-
- def __init__(self):
- super().__init__()
-
- def queryStatsForPackage(
- self, storageUuid: Any, packageName: str, userHandle: Any
- ) -> "StorageStats":
- """查询指定应用存储统计"""
- return self._query_stats(storageUuid, packageName)
-
- def queryStatsForUid(
- self, storageUuid: Any, uid: int
- ) -> "StorageStats":
- """查询指定 UID 存储统计"""
- return self._query_stats(storageUuid, f"uid_{uid}")
-
- def queryStatsForUser(
- self, storageUuid: Any, userHandle: Any
- ) -> "StorageStats":
- """查询指定用户存储统计"""
- return self._query_stats(storageUuid, f"user_{userHandle}")
-
- def queryExternalStatsForUser(
- self, storageUuid: Any, userHandle: Any
- ) -> "StorageStats":
- """查询外部用户存储统计"""
- return self._query_stats(storageUuid, f"external_user_{userHandle}")
-
- def getFreeBytes(self, storageUuid: Any) -> int:
- """获取空闲字节数"""
- try:
- st = _os.statvfs(_sdcard_root)
- return st.f_bavail * st.f_frsize
- except (OSError, AttributeError):
- return 1024 * 1024 * 1024 # 默认 1GB
-
- def getTotalBytes(self, storageUuid: Any) -> int:
- """获取总字节数"""
- try:
- st = _os.statvfs(_sdcard_root)
- return st.f_blocks * st.f_frsize
- except (OSError, AttributeError):
- return 64 * 1024 * 1024 * 1024 # 默认 64GB
-
- def _query_stats(self, storage_uuid: Any, tag: str) -> "StorageStats":
- """内部查询存储统计"""
- stats = StorageStats()
- pkg_dir = _os.path.join(_app_data_dir, "files")
- if _os.path.exists(pkg_dir):
- for dirpath, dirnames, filenames in _os.walk(pkg_dir):
- for fname in filenames:
- fpath = _os.path.join(dirpath, fname)
- try:
- fsize = _os.path.getsize(fpath)
- ext = _os.path.splitext(fname)[1].lower()
- if ext in (".jpg", ".png", ".gif", ".webp", ".bmp"):
- stats._image_bytes += fsize
- elif ext in (".mp3", ".wav", ".flac", ".ogg", ".aac"):
- stats._music_bytes += fsize
- elif ext in (".mp4", ".avi", ".mkv", ".mov", ".webm"):
- stats._video_bytes += fsize
- else:
- stats._data_bytes += fsize
- except OSError:
- pass
- return stats
-
- def toString(self) -> str:
- return f"StorageStatsManager@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# StorageStats
-# ═══════════════════════════════════════════════════════════════
-
-class StorageStats(Stub):
- """StorageStats — 存储统计"""
-
- def __init__(self):
- super().__init__()
- self._app_bytes = 0
- self._data_bytes = 0
- self._cache_bytes = 0
- self._music_bytes = 0
- self._video_bytes = 0
- self._image_bytes = 0
- self._game_bytes = 0
-
- def getAppBytes(self) -> int:
- return self._app_bytes
-
- def getDataBytes(self) -> int:
- return self._data_bytes
-
- def getCacheBytes(self) -> int:
- return self._cache_bytes
-
- def getMusicBytes(self) -> int:
- return self._music_bytes
-
- def getVideoBytes(self) -> int:
- return self._video_bytes
-
- def getImageBytes(self) -> int:
- return self._image_bytes
-
- def getGameBytes(self) -> int:
- return self._game_bytes
-
- def toString(self) -> str:
- return (f"StorageStats(app={self._app_bytes}B, data={self._data_bytes}B, "
- f"cache={self._cache_bytes}B, music={self._music_bytes}B, "
- f"video={self._video_bytes}B, image={self._image_bytes}B)")
-
- def equals(self, other) -> bool:
- if not isinstance(other, StorageStats):
- return False
- return (self._app_bytes == other._app_bytes
- and self._data_bytes == other._data_bytes)
-
- def hashCode(self) -> int:
- return hash((self._app_bytes, self._data_bytes)) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/app_voiceinteractor.py b/android_pyapi/android/app_voiceinteractor.py
deleted file mode 100644
index 924153d..0000000
--- a/android_pyapi/android/app_voiceinteractor.py
+++ /dev/null
@@ -1,590 +0,0 @@
-"""
-Android VoiceInteractor API — VoiceInteractor, Request, Prompt, etc.
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import uuid
-from typing import Any, Dict, List, Optional, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractor
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractor(Stub):
- """VoiceInteractor — 语音交互器 (桌面存根)"""
-
- # 结果码
- RESULT_CANCELED = 0
- RESULT_SUCCESS = -1
- RESULT_TIMEOUT = -2
- RESULT_ERROR = -3
- RESULT_NO_MATCH = -4
- RESULT_SKIPPED = -5
- RESULT_ABORTED = -6
- RESULT_UNSUPPORTED = -7
- RESULT_BUSY = -8
- RESULT_NOT_FOUND = -9
-
- # 语音活动状态
- SPEECH_ACTIVITY_UNKNOWN = 0
- SPEECH_ACTIVITY_STARTING = 1
- SPEECH_ACTIVITY_STARTED = 2
- SPEECH_ACTIVITY_STOPPING = 3
- SPEECH_ACTIVITY_STOPPED = 4
- SPEECH_ACTIVITY_IN_PROGRESS = 5
- SPEECH_ACTIVITY_INTERRUPTED = 6
- SPEECH_ACTIVITY_TIMED_OUT = 7
- SPEECH_ACTIVITY_COMPLETED = 8
- SPEECH_ACTIVITY_ERROR = 9
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._requests: Dict[str, "VoiceInteractor.Request"] = {}
- self._active_request: Optional["VoiceInteractor.Request"] = None
- self._speech_activity = VoiceInteractor.SPEECH_ACTIVITY_UNKNOWN
- self._available = True
- self._supported_actions: List[str] = []
- self._voice_activity_callback: Optional[Callable] = None
- self._interaction_callback: Optional[Callable] = None
- self._voice_interaction_service: Optional[Any] = None
- self._voice_interaction_session: Optional[Any] = None
- self._system_voice_interaction = False
-
- def isVoiceInteraction(self) -> bool:
- return True
-
- def isVoiceInteractionRoot(self) -> bool:
- return True
-
- def notifyVoiceActivity(self, state: int) -> None:
- self._speech_activity = state
- if self._voice_activity_callback:
- self._voice_activity_callback(state)
-
- def startVoiceActivity(self, voiceInteractionSession: Any) -> None:
- pass
-
- def setVoiceActivityCallback(self, callback: Callable) -> None:
- self._voice_activity_callback = callback
-
- def getVoiceActivityState(self) -> int:
- return self._speech_activity
-
- def submitRequest(self, request: "VoiceInteractor.Request") -> None:
- self._submitRequest(request)
-
- def submitRequest(self, request: "VoiceInteractor.Request", callback: Any) -> None:
- request._callback = callback
- self._submitRequest(request)
-
- def _submitRequest(self, request: "VoiceInteractor.Request") -> None:
- request_id = str(uuid.uuid4())
- request._request_id = request_id
- self._requests[request_id] = request
- self._active_request = request
- if request._callback:
- req = request
- # 模拟回调
-
- def getActiveRequest(self) -> Optional["VoiceInteractor.Request"]:
- return self._active_request
-
- def cancelRequest(self, request: "VoiceInteractor.Request") -> None:
- if request._request_id in self._requests:
- del self._requests[request._request_id]
- if self._active_request is request:
- self._active_request = None
-
- def cancelRequests(self, requestClass: type = None) -> None:
- if requestClass:
- to_remove = [
- rid for rid, req in self._requests.items()
- if isinstance(req, requestClass)
- ]
- for rid in to_remove:
- del self._requests[rid]
- else:
- self._requests.clear()
- if self._active_request and (not requestClass or isinstance(self._active_request, requestClass)):
- self._active_request = None
-
- def getCurrentRequest(self) -> Optional["VoiceInteractor.Request"]:
- return self._active_request
-
- def areNotificationsSupported(self, supportedActions: List[str]) -> bool:
- return True
-
- def startConfirmation(self, prompt: "VoiceInteractor.Prompt", callback: Any) -> None:
- request = VoiceInteractor.ConfirmationRequest(prompt, None)
- request._callback = callback
- self._submitRequest(request)
-
- def startPickOption(self, prompts: List["VoiceInteractor.Prompt"], options: List[Any], callback: Any) -> None:
- request = VoiceInteractor.PickOptionRequest(prompts, options, None)
- request._callback = callback
- self._submitRequest(request)
-
- def startCommand(self, command: str, callback: Any) -> None:
- request = VoiceInteractor.CommandRequest(command, None)
- request._callback = callback
- self._submitRequest(request)
-
- def startCompleteVoice(self, prompt: "VoiceInteractor.Prompt", callback: Any) -> None:
- request = VoiceInteractor.CompleteVoiceRequest(prompt, None)
- request._callback = callback
- self._submitRequest(request)
-
- def startAbortVoice(self, prompt: "VoiceInteractor.Prompt", callback: Any) -> None:
- request = VoiceInteractor.AbortVoiceRequest(prompt, None)
- request._callback = callback
- self._submitRequest(request)
-
- def getPackageName(self) -> str:
- return "com.android.voiceinteractor"
-
- def getVoiceInteractorService(self) -> Optional[Any]:
- return self._voice_interaction_service
-
- def destroy(self) -> None:
- self._requests.clear()
- self._active_request = None
- self._available = False
-
- def toString(self) -> str:
- return f"VoiceInteractor(active={self._active_request is not None}, requests={len(self._requests)})"
-
- # ═══════════════════════════════════════════════════════════
- # VoiceInteractor.Request
- # ═══════════════════════════════════════════════════════════
-
- class Request(Stub):
- """VoiceInteractor.Request — 请求基类"""
-
- def __init__(self):
- super().__init__()
- self._request_id: Optional[str] = None
- self._context: Optional[Any] = None
- self._callback: Optional[Any] = None
- self._cancelled = False
- self._result: Optional[Any] = None
- self._timeout_ms: Optional[int] = None
- self._start_time: Optional[float] = None
- self._activity: Optional[Any] = None
- self._interactor: Optional["VoiceInteractor"] = None
-
- def getRequestId(self) -> Optional[str]:
- return self._request_id
-
- def getActivity(self) -> Optional[Any]:
- return self._activity
-
- def onActivityResult(self, requestCode: int, resultCode: int, data: Any) -> None:
- pass
-
- def onCancel(self) -> None:
- self._cancelled = True
- if self._callback and hasattr(self._callback, "onCancel"):
- self._callback.onCancel(self)
-
- def onTimeout(self) -> None:
- if self._callback and hasattr(self._callback, "onTimeout"):
- self._callback.onTimeout(self)
-
- def isCancelled(self) -> bool:
- return self._cancelled
-
- def getResult(self) -> Optional[Any]:
- return self._result
-
- def cancel(self) -> None:
- self._cancelled = True
-
- def toString(self) -> str:
- return f"VoiceInteractor.Request(id={self._request_id})"
-
- # ═══════════════════════════════════════════════════════════
- # VoiceInteractor.Prompt
- # ═══════════════════════════════════════════════════════════
-
- class Prompt(Stub):
- """VoiceInteractor.Prompt — 语音提示"""
-
- def __init__(self, prompt: Any):
- super().__init__()
- if isinstance(prompt, str):
- self._voice_prompts: List[str] = [prompt]
- self._visual_prompt: Optional[str] = prompt
- elif isinstance(prompt, list):
- self._voice_prompts = list(prompt)
- self._visual_prompt = prompt[0] if prompt else None
- elif isinstance(prompt, tuple):
- self._voice_prompts = [str(p) for p in prompt]
- self._visual_prompt = str(prompt[0]) if prompt else None
- else:
- self._voice_prompts = [str(prompt)]
- self._visual_prompt = str(prompt)
- self._count = len(self._voice_prompts)
-
- def getVoicePromptAt(self, index: int) -> Optional[str]:
- if 0 <= index < self._count:
- return self._voice_prompts[index]
- return None
-
- def getVisualPrompt(self) -> Optional[str]:
- return self._visual_prompt
-
- def countVoicePrompts(self) -> int:
- return self._count
-
- def toString(self) -> str:
- return f"VoiceInteractor.Prompt(voice_prompts={self._count})"
-
- # ═══════════════════════════════════════════════════════════
- # VoiceInteractor.CompleteVoiceRequest
- # ═══════════════════════════════════════════════════════════
-
- class CompleteVoiceRequest(Request):
- """VoiceInteractor.CompleteVoiceRequest — 完成语音请求"""
-
- def __init__(self, prompt: "VoiceInteractor.Prompt", bundle: Any = None):
- super().__init__()
- self._prompt = prompt
- self._bundle = bundle
- self._result_code = VoiceInteractor.RESULT_SUCCESS
- self._result_data: Optional[Any] = None
-
- def getPrompt(self) -> Optional["VoiceInteractor.Prompt"]:
- return self._prompt
-
- def getBundle(self) -> Optional[Any]:
- return self._bundle
-
- def setResult(self, resultCode: int, result: Any) -> None:
- self._result_code = resultCode
- self._result_data = result
-
- def toString(self) -> str:
- return f"CompleteVoiceRequest(prompt={self._prompt})"
-
- # ═══════════════════════════════════════════════════════════
- # VoiceInteractor.AbortVoiceRequest
- # ═══════════════════════════════════════════════════════════
-
- class AbortVoiceRequest(Request):
- """VoiceInteractor.AbortVoiceRequest — 中止语音请求"""
-
- def __init__(self, prompt: "VoiceInteractor.Prompt", bundle: Any = None):
- super().__init__()
- self._prompt = prompt
- self._bundle = bundle
- self._result_code = VoiceInteractor.RESULT_ABORTED
- self._reason: Optional[str] = None
-
- def getPrompt(self) -> Optional["VoiceInteractor.Prompt"]:
- return self._prompt
-
- def getBundle(self) -> Optional[Any]:
- return self._bundle
-
- def getReason(self) -> Optional[str]:
- return self._reason
-
- def setAbortReason(self, reason: str) -> None:
- self._reason = reason
-
- def toString(self) -> str:
- return f"AbortVoiceRequest(prompt={self._prompt}, reason={self._reason})"
-
- # ═══════════════════════════════════════════════════════════
- # VoiceInteractor.CommandRequest
- # ═══════════════════════════════════════════════════════════
-
- class CommandRequest(Request):
- """VoiceInteractor.CommandRequest — 命令请求"""
-
- def __init__(self, command: str, bundle: Any = None):
- super().__init__()
- self._command = command
- self._bundle = bundle
- self._result_code = VoiceInteractor.RESULT_SUCCESS
- self._result_data: Optional[Any] = None
-
- def getCommand(self) -> str:
- return self._command
-
- def getBundle(self) -> Optional[Any]:
- return self._bundle
-
- def setResult(self, resultCode: int, result: Any) -> None:
- self._result_code = resultCode
- self._result_data = result
-
- def getResultCode(self) -> int:
- return self._result_code
-
- def getResultData(self) -> Optional[Any]:
- return self._result_data
-
- def onCommandResult(self, isCompleted: bool, result: Any) -> None:
- if self._callback and hasattr(self._callback, "onCommandResult"):
- self._callback.onCommandResult(isCompleted, result)
-
- def toString(self) -> str:
- return f"CommandRequest(command={self._command})"
-
- # ═══════════════════════════════════════════════════════════
- # VoiceInteractor.PickOptionRequest
- # ═══════════════════════════════════════════════════════════
-
- class PickOptionRequest(Request):
- """VoiceInteractor.PickOptionRequest — 选项选择请求"""
-
- class Option(Stub):
- """PickOptionRequest.Option — 选项"""
-
- def __init__(self, label: str, index: int = -1):
- super().__init__()
- self._label = label
- self._index = index
- self._synonyms: List[str] = []
- self._extras: Optional[Any] = None
- self._is_selected = False
-
- def getLabel(self) -> str:
- return self._label
-
- def getIndex(self) -> int:
- return self._index
-
- def setIndex(self, index: int) -> None:
- self._index = index
-
- def addSynonym(self, synonym: str) -> None:
- self._synonyms.append(synonym)
-
- def getSynonyms(self) -> List[str]:
- return list(self._synonyms)
-
- def setExtras(self, extras: Any) -> None:
- self._extras = extras
-
- def getExtras(self) -> Optional[Any]:
- return self._extras
-
- def isSelected(self) -> bool:
- return self._is_selected
-
- def toString(self) -> str:
- return f"Option(label={self._label}, index={self._index})"
-
- def __init__(self, prompts: Any, options: List[Any], bundle: Any = None):
- super().__init__()
- if isinstance(prompts, VoiceInteractor.Prompt):
- self._prompts = [prompts]
- elif isinstance(prompts, list):
- self._prompts = prompts
- else:
- self._prompts = [VoiceInteractor.Prompt(str(prompts))]
- self._options = options
- self._bundle = bundle
- self._selected_option: Optional[Any] = None
- self._result_code = VoiceInteractor.RESULT_SUCCESS
-
- def getPrompts(self) -> List["VoiceInteractor.Prompt"]:
- return list(self._prompts)
-
- def getOptions(self) -> List[Any]:
- return list(self._options)
-
- def getBundle(self) -> Optional[Any]:
- return self._bundle
-
- def getSelectedOption(self) -> Optional[Any]:
- return self._selected_option
-
- def setPickOptionResult(self, option: Any, result: Any) -> None:
- self._selected_option = option
- self._result_data = result
- self._result_code = VoiceInteractor.RESULT_SUCCESS
-
- def onPickOptionResult(self, completed: bool, option: Any, result: Any) -> None:
- if completed:
- self._selected_option = option
- if self._callback and hasattr(self._callback, "onPickOptionResult"):
- self._callback.onPickOptionResult(completed, option, result)
-
- def toString(self) -> str:
- return f"PickOptionRequest(options={len(self._options)})"
-
- # ═══════════════════════════════════════════════════════════
- # VoiceInteractor.ConfirmationRequest
- # ═══════════════════════════════════════════════════════════
-
- class ConfirmationRequest(Request):
- """VoiceInteractor.ConfirmationRequest — 确认请求"""
-
- def __init__(self, prompt: "VoiceInteractor.Prompt", bundle: Any = None):
- super().__init__()
- self._prompt = prompt
- self._bundle = bundle
- self._confirmed = False
- self._result_code = VoiceInteractor.RESULT_SUCCESS
- self._result_data: Optional[Any] = None
-
- def getPrompt(self) -> Optional["VoiceInteractor.Prompt"]:
- return self._prompt
-
- def getBundle(self) -> Optional[Any]:
- return self._bundle
-
- def isConfirmed(self) -> bool:
- return self._confirmed
-
- def setConfirmationResult(self, confirmed: bool, result: Any) -> None:
- self._confirmed = confirmed
- self._result_data = result
- self._result_code = VoiceInteractor.RESULT_SUCCESS if confirmed else VoiceInteractor.RESULT_CANCELED
-
- def onConfirmationResult(self, confirmed: bool, result: Any) -> None:
- self._confirmed = confirmed
- if self._callback and hasattr(self._callback, "onConfirmationResult"):
- self._callback.onConfirmationResult(confirmed, result)
-
- def toString(self) -> str:
- return f"ConfirmationRequest(confirmed={self._confirmed})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractor 扩展功能
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractorResult(Stub):
- """VoiceInteractor.Result — 语音交互结果"""
-
- def __init__(self, resultCode: int = VoiceInteractor.RESULT_SUCCESS, resultData: Any = None):
- super().__init__()
- self._result_code = resultCode
- self._result_data = resultData
- self._timed_out = False
- self._cancelled = False
- self._error_message: Optional[str] = None
-
- def getResultCode(self) -> int:
- return self._result_code
-
- def getResultData(self) -> Optional[Any]:
- return self._result_data
-
- def getErrorMessage(self) -> Optional[str]:
- return self._error_message
-
- def isTimedOut(self) -> bool:
- return self._timed_out
-
- def isCancelled(self) -> bool:
- return self._cancelled
-
- def isSuccess(self) -> bool:
- return self._result_code == VoiceInteractor.RESULT_SUCCESS
-
- def toString(self) -> str:
- return f"VoiceInteractorResult(code={self._result_code})"
-
-
-class VoiceInteractorCallback(Stub):
- """VoiceInteractor.Callback — 语音交互回调基类"""
-
- def __init__(self):
- super().__init__()
-
- def onRequestSuccess(self, request: VoiceInteractor.Request) -> None:
- pass
-
- def onRequestFailure(self, request: VoiceInteractor.Request) -> None:
- pass
-
- def onRequestCancelled(self, request: VoiceInteractor.Request) -> None:
- pass
-
- def onRequestTimeout(self, request: VoiceInteractor.Request) -> None:
- pass
-
- def toString(self) -> str:
- return "VoiceInteractor.Callback"
-
-
-class VoiceInteractorNotification(Stub):
- """VoiceInteractor.Notifications — 语音交互通知支持"""
-
- def __init__(self):
- super().__init__()
- self._supported_actions: List[str] = []
- self._notification_channel_id: Optional[str] = None
- self._notification_title: Optional[str] = None
- self._notification_text: Optional[str] = None
-
- def getSupportedActions(self) -> List[str]:
- return list(self._supported_actions)
-
- def isActionSupported(self, action: str) -> bool:
- return action in self._supported_actions
-
- def setNotificationChannel(self, channelId: str) -> None:
- self._notification_channel_id = channelId
-
- def getNotificationChannel(self) -> Optional[str]:
- return self._notification_channel_id
-
- def toString(self) -> str:
- return f"VoiceInteractorNotifications(actions={len(self._supported_actions)})"
-
-
-class VoiceInteractorSession(Stub):
- """VoiceInteractor.Session — 语音交互会话"""
-
- def __init__(self, interactor: "VoiceInteractor"):
- super().__init__()
- self._interactor = interactor
- self._session_id = str(uuid.uuid4())
- self._active = False
- self._start_time = time.time()
- self._requests: List[VoiceInteractor.Request] = []
- self._current_prompt: Optional[VoiceInteractor.Prompt] = None
- self._state = VoiceInteractor.SPEECH_ACTIVITY_UNKNOWN
-
- def getSessionId(self) -> str:
- return self._session_id
-
- def isActive(self) -> bool:
- return self._active
-
- def start(self) -> None:
- self._active = True
- self._state = VoiceInteractor.SPEECH_ACTIVITY_STARTING
-
- def stop(self) -> None:
- self._active = False
- self._state = VoiceInteractor.SPEECH_ACTIVITY_STOPPED
-
- def getDuration(self) -> float:
- if self._active:
- return time.time() - self._start_time
- return 0.0
-
- def getState(self) -> int:
- return self._state
-
- def getRequestCount(self) -> int:
- return len(self._requests)
-
- def toString(self) -> str:
- return f"VoiceInteractorSession(active={self._active}, state={self._state})"
\ No newline at end of file
diff --git a/android_pyapi/android/app_wallpaper.py b/android_pyapi/android/app_wallpaper.py
deleted file mode 100644
index ae59b8c..0000000
--- a/android_pyapi/android/app_wallpaper.py
+++ /dev/null
@@ -1,571 +0,0 @@
-"""
-Android Wallpaper API — WallpaperManager, WallpaperInfo, WallpaperService, WallpaperService.Engine
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import time
-import tempfile
-from typing import Any, Dict, List, Optional, Tuple, Callable, BinaryIO
-
-from .._core import Stub, AndroidOnlyError, resolve_android_path, _sdcard_root, _app_data_dir
-
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# FLAG_* 常量
-FLAG_SYSTEM = 0x00000001
-FLAG_LOCK = 0x00000002
-FLAG_SYSTEM_AND_LOCK = FLAG_SYSTEM | FLAG_LOCK
-FLAG_SET_BOTH = FLAG_SYSTEM | FLAG_LOCK
-
-# ACTION_* 常量
-ACTION_CHANGE_LIVE_WALLPAPER = "android.service.wallpaper.CHANGE_LIVE_WALLPAPER"
-ACTION_LIVE_WALLPAPER_CHOOSER = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER"
-ACTION_CROP_AND_SET_WALLPAPER = "android.service.wallpaper.CROP_AND_SET_WALLPAPER"
-ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED"
-ACTION_SET_WALLPAPER = "android.service.wallpaper.SET_WALLPAPER"
-
-# WALLPAPER_TYPE 常量
-WALLPAPER_TYPE_SYSTEM = 1
-WALLPAPER_TYPE_LOCK = 2
-WALLPAPER_TYPE_BOTH = 3
-WALLPAPER_TYPE_LIVE = 4
-
-# 其它常量
-WALLPAPER_HEIGHT = 1920
-WALLPAPER_WIDTH = 1080
-MIN_CROP_WIDTH = 320
-MIN_CROP_HEIGHT = 480
-
-
-# ═══════════════════════════════════════════════════════════════
-# WallpaperManager
-# ═══════════════════════════════════════════════════════════════
-
-class WallpaperManager(Stub):
- """WallpaperManager — 壁纸管理器 (桌面存根)"""
-
- ACTION_CHANGE_LIVE_WALLPAPER = ACTION_CHANGE_LIVE_WALLPAPER
- ACTION_LIVE_WALLPAPER_CHOOSER = ACTION_LIVE_WALLPAPER_CHOOSER
- ACTION_CROP_AND_SET_WALLPAPER = ACTION_CROP_AND_SET_WALLPAPER
- ACTION_WALLPAPER_CHANGED = ACTION_WALLPAPER_CHANGED
- ACTION_SET_WALLPAPER = ACTION_SET_WALLPAPER
-
- FLAG_SYSTEM = FLAG_SYSTEM
- FLAG_LOCK = FLAG_LOCK
- FLAG_SYSTEM_AND_LOCK = FLAG_SYSTEM_AND_LOCK
-
- WALLPAPER_TYPE_SYSTEM = WALLPAPER_TYPE_SYSTEM
- WALLPAPER_TYPE_LOCK = WALLPAPER_TYPE_LOCK
- WALLPAPER_TYPE_BOTH = WALLPAPER_TYPE_BOTH
- WALLPAPER_TYPE_LIVE = WALLPAPER_TYPE_LIVE
-
- _instance: Optional["WallpaperManager"] = None
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._wallpaper_dir = os.path.join(_app_data_dir, "wallpapers")
- os.makedirs(self._wallpaper_dir, exist_ok=True)
- self._system_wallpaper_path = os.path.join(self._wallpaper_dir, "system_wallpaper")
- self._lock_wallpaper_path = os.path.join(self._wallpaper_dir, "lock_wallpaper")
- self._wallpaper_info: Optional["WallpaperInfo"] = None
- self._is_wallpaper_supported = True
- self._wallpaper_offset = 0.5
- self._wallpaper_offsets = (0.0, 0.0, 0.0, 0.0)
- self._wallpaper_dimensions = (WALLPAPER_WIDTH, WALLPAPER_HEIGHT)
- self._wallpaper_zoom = 1.0
- self._suggest_wallpaper_dimensions = (WALLPAPER_WIDTH, WALLPAPER_HEIGHT)
- self._crop_hint = (0, 0, WALLPAPER_WIDTH, WALLPAPER_HEIGHT)
- self._padding = (0, 0, 0, 0)
- self._pre_wallpaper_components: List[Any] = []
- self._wallpaper_visibility = True
- self._wallpaper_callbacks: List[Callable] = []
- self._wallpaper_parallax_effect = True
- self._wallpaper_dimming = 0.0
-
- @staticmethod
- def getInstance(context: Any) -> "WallpaperManager":
- if WallpaperManager._instance is None:
- WallpaperManager._instance = WallpaperManager(context)
- return WallpaperManager._instance
-
- def getDrawable(self) -> Optional[Any]:
- """获取当前壁纸 Drawable"""
- if os.path.exists(self._system_wallpaper_path):
- from .._core import HAS_PIL
- if HAS_PIL:
- try:
- from PIL import Image as _PILImage
- return _PILImage.open(self._system_wallpaper_path)
- except Exception:
- pass
- return None
-
- def peekDrawable(self) -> Optional[Any]:
- """获取当前壁纸但不触发加载"""
- return self.getDrawable()
-
- def getFastDrawable(self) -> Optional[Any]:
- """快速获取壁纸"""
- return self.getDrawable()
-
- def peekFastDrawable(self) -> Optional[Any]:
- return self.peekDrawable()
-
- def getBitmap(self) -> Optional[Any]:
- """获取壁纸位图"""
- if os.path.exists(self._system_wallpaper_path):
- try:
- from PIL import Image as _PILImage
- return _PILImage.open(self._system_wallpaper_path)
- except ImportError:
- pass
- return None
-
- def peekBitmap(self) -> Optional[Any]:
- return self.getBitmap()
-
- def setBitmap(self, bitmap: Any) -> None:
- """设置壁纸位图"""
- self.setBitmap(bitmap, None, True, FLAG_SYSTEM)
-
- def setBitmap(self, bitmap: Any, hint: Any, allowBackup: bool = True, which: int = FLAG_SYSTEM) -> None:
- path = self._get_wallpaper_path(which)
- try:
- if hasattr(bitmap, "save"):
- bitmap.save(path)
- elif hasattr(bitmap, "tobytes"):
- with open(path, "wb") as f:
- f.write(bitmap.tobytes())
- else:
- with open(path, "w") as f:
- f.write(str(bitmap))
- except Exception as e:
- raise RuntimeException(f"Failed to set wallpaper: {e}")
-
- def setStream(self, data: BinaryIO) -> None:
- self.setStream(data, None, True, FLAG_SYSTEM)
-
- def setStream(self, data: BinaryIO, hint: Any, allowBackup: bool = True, which: int = FLAG_SYSTEM) -> None:
- path = self._get_wallpaper_path(which)
- with open(path, "wb") as f:
- f.write(data.read())
-
- def getResourceContext(self) -> Optional[Any]:
- return self._context
-
- def getWallpaperInfo(self) -> Optional["WallpaperInfo"]:
- return self._wallpaper_info
-
- def getWallpaperFile(self, which: int = FLAG_SYSTEM) -> Optional[Any]:
- path = self._get_wallpaper_path(which)
- if os.path.exists(path):
- return open(path, "rb")
- return None
-
- def getWallpaperId(self, which: int = FLAG_SYSTEM) -> int:
- path = self._get_wallpaper_path(which)
- if os.path.exists(path):
- return int(os.path.getmtime(path))
- return -1
-
- def hasResourceWallpaper(self, resid: int) -> bool:
- return False
-
- def suggestDesiredDimensions(self, minimumWidth: int, minimumHeight: int) -> None:
- self._suggest_wallpaper_dimensions = (minimumWidth, minimumHeight)
-
- def getDesiredMinimumWidth(self) -> int:
- return self._suggest_wallpaper_dimensions[0]
-
- def getDesiredMinimumHeight(self) -> int:
- return self._suggest_wallpaper_dimensions[1]
-
- def clearWallpaper(self) -> None:
- self.clear(FLAG_SYSTEM)
-
- def clear(self, which: int = FLAG_SYSTEM) -> None:
- if which & FLAG_SYSTEM:
- if os.path.exists(self._system_wallpaper_path):
- os.remove(self._system_wallpaper_path)
- if which & FLAG_LOCK:
- if os.path.exists(self._lock_wallpaper_path):
- os.remove(self._lock_wallpaper_path)
-
- def setWallpaperComponent(self, component: Any) -> None:
- pass
-
- def sendWallpaperCommand(self, window: Any, action: str, x: int, y: int, z: int, extras: Any) -> None:
- pass
-
- def setWallpaperOffsetSteps(self, xStep: float, yStep: float) -> None:
- pass
-
- def setWallpaperOffsets(self, window: Any, xOffset: float, yOffset: float) -> None:
- self._wallpaper_offset = xOffset
- self._wallpaper_offsets = (xOffset, yOffset, xOffset, yOffset)
-
- def getWallpaperOffsets(self, window: Any) -> Tuple[float, float, float, float]:
- return self._wallpaper_offsets
-
- def computeScrollRange(self, window: Any) -> int:
- return WALLPAPER_WIDTH
-
- def computeScrollXRange(self, window: Any) -> int:
- return WALLPAPER_WIDTH
-
- def computeScrollYRange(self, window: Any) -> int:
- return WALLPAPER_HEIGHT
-
- def isWallpaperSupported(self) -> bool:
- return self._is_wallpaper_supported
-
- def isSetWallpaperAllowed(self) -> bool:
- return True
-
- def isWallpaperBackupEligible(self, which: int = FLAG_SYSTEM) -> bool:
- return True
-
- def getWallpaperDimAmount(self) -> float:
- return self._wallpaper_dimming
-
- def setWallpaperDimAmount(self, dimAmount: float) -> None:
- self._wallpaper_dimming = max(0.0, min(1.0, dimAmount))
-
- def setWallpaperZoomOut(self, zoom: float) -> None:
- self._wallpaper_zoom = max(0.1, min(1.0, zoom))
-
- def getWallpaperZoomOut(self) -> float:
- return self._wallpaper_zoom
-
- def getCropHint(self) -> Tuple[int, int, int, int]:
- return self._crop_hint
-
- def setCropHint(self, cropHint: Tuple[int, int, int, int]) -> None:
- self._crop_hint = cropHint
-
- def getPadding(self) -> Tuple[int, int, int, int]:
- return self._padding
-
- def isParallaxEnabled(self) -> bool:
- return self._wallpaper_parallax_effect
-
- def setParallaxEnabled(self, enabled: bool) -> None:
- self._wallpaper_parallax_effect = enabled
-
- def addOnColorsChangedListener(self, listener: Any, handler: Any = None) -> None:
- if listener not in self._wallpaper_callbacks:
- self._wallpaper_callbacks.append(listener)
-
- def removeOnColorsChangedListener(self, listener: Any) -> None:
- if listener in self._wallpaper_callbacks:
- self._wallpaper_callbacks.remove(listener)
-
- def _get_wallpaper_path(self, which: int) -> str:
- if which & FLAG_SYSTEM:
- return self._system_wallpaper_path
- if which & FLAG_LOCK:
- return self._lock_wallpaper_path
- return self._system_wallpaper_path
-
- def toString(self) -> str:
- return (
- f"WallpaperManager(system_exists={os.path.exists(self._system_wallpaper_path)}, "
- f"lock_exists={os.path.exists(self._lock_wallpaper_path)})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# WallpaperInfo
-# ═══════════════════════════════════════════════════════════════
-
-class WallpaperInfo(Stub):
- """WallpaperInfo — 壁纸信息"""
-
- def __init__(self, context: Any = None, component: Any = None):
- super().__init__()
- self._context = context
- self._component = component
- self._package_name: Optional[str] = None
- self._service_name: Optional[str] = None
- self._label: Optional[str] = None
- self._description: Optional[str] = None
- self._author: Optional[str] = None
- self._context_description: Optional[str] = None
- self._settings_activity: Optional[str] = None
- self._settings_piece: Optional[str] = None
- self._thumbnail: Optional[Any] = None
- self._system_wallpaper = False
- self._supports_ambient_mode = False
- self._is_standalone = False
- self._show_metadata_in_preview = True
- self._shared_library = ""
- self._wallpaper_author: Optional[str] = None
- self._wallpaper_description: Optional[str] = None
- self._wallpaper_context_description: Optional[str] = None
- self._wallpaper_settings_activity: Optional[str] = None
- self._wallpaper_thumbnail: Optional[Any] = None
- self._wallpaper_show_metadata = True
- self._wallpaper_supports_ambient = False
-
- def getPackageName(self) -> Optional[str]:
- return self._package_name
-
- def getServiceName(self) -> Optional[str]:
- return self._service_name
-
- def getServiceInfo(self) -> Optional[Any]:
- return None
-
- def getComponent(self) -> Optional[Any]:
- return self._component
-
- def loadLabel(self, pm: Any) -> str:
- return self._label or "Wallpaper"
-
- def loadDescription(self, pm: Any) -> str:
- return self._description or ""
-
- def loadAuthor(self, pm: Any) -> str:
- return self._author or ""
-
- def loadContextDescription(self, pm: Any) -> str:
- return self._context_description or ""
-
- def loadIcon(self, pm: Any) -> Optional[Any]:
- return None
-
- def loadThumbnail(self, pm: Any) -> Optional[Any]:
- return self._thumbnail
-
- def getSettingsActivity(self) -> Optional[str]:
- return self._settings_activity
-
- def getSettingsSliceUri(self) -> Optional[str]:
- return None
-
- def getSharedLibrary(self) -> str:
- return self._shared_library
-
- def getShowMetadataInPreview(self) -> bool:
- return self._show_metadata_in_preview
-
- def isSystemWallpaper(self) -> bool:
- return self._system_wallpaper
-
- def supportsAmbientMode(self) -> bool:
- return self._supports_ambient_mode
-
- def toString(self) -> str:
- return f"WallpaperInfo(package={self._package_name}, service={self._service_name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WallpaperService
-# ═══════════════════════════════════════════════════════════════
-
-class WallpaperService(Stub):
- """WallpaperService — 动态壁纸服务基类"""
-
- SERVICE_INTERFACE = "android.service.wallpaper.WallpaperService"
- SERVICE_META_DATA = "android.service.wallpaper"
- WALLPAPER_HEIGHT = WALLPAPER_HEIGHT
- WALLPAPER_WIDTH = WALLPAPER_WIDTH
-
- def __init__(self):
- super().__init__()
- self._engine: Optional["WallpaperService.Engine"] = None
- self._created = False
- self._wallpaper_connected = False
-
- def onCreate(self) -> None:
- self._created = True
-
- def onDestroy(self) -> None:
- self._created = False
- self._wallpaper_connected = False
-
- def onCreateEngine(self) -> Optional["WallpaperService.Engine"]:
- return None
-
- def onCreateSurfaceHolder(self) -> Optional[Any]:
- return None
-
- def getWallpaperEngine(self) -> Optional["WallpaperService.Engine"]:
- return self._engine
-
- def toString(self) -> str:
- return f"WallpaperService(created={self._created})"
-
- # ═══════════════════════════════════════════════════════════
- # WallpaperService.Engine
- # ═══════════════════════════════════════════════════════════
-
- class Engine(Stub):
- """WallpaperService.Engine — 动态壁纸引擎"""
-
- def __init__(self, service: "WallpaperService"):
- super().__init__()
- self._service = service
- self._is_visible = False
- self._is_preview = False
- self._surface_holder: Optional[Any] = None
- self._surface_created = False
- self._surface_changed = False
- self._surface_destroyed = False
- self._offsets_changed = False
- self._desired_width = WALLPAPER_WIDTH
- self._desired_height = WALLPAPER_HEIGHT
- self._x_offset = 0.5
- self._y_offset = 0.5
- self._x_step = 0.0
- self._y_step = 0.0
- self._visible = True
- self._touch_events_enabled = True
- self._mSurfaceCreated = False
- self._mSurfaceValid = False
- self._mDrawingAllowed = False
- self._mOffsetMessageEnqueued = False
- self._mZoom = 1.0
- self._mZoomOut = 1.0
- self._mOffsetRequired = False
- self._mOffsetsChanged = False
- self._mSurfaceChanged = False
- self._mCreated = True
- self._mSurfaceDestroyed = False
-
- def getSurfaceHolder(self) -> Optional[Any]:
- return self._surface_holder
-
- def isVisible(self) -> bool:
- return self._is_visible
-
- def isPreview(self) -> bool:
- return self._is_preview
-
- def setTouchEventsEnabled(self, enabled: bool) -> None:
- self._touch_events_enabled = enabled
-
- def getTouchEventsEnabled(self) -> bool:
- return self._touch_events_enabled
-
- def setOffsetNotificationsEnabled(self, enabled: bool) -> None:
- pass
-
- def onCreate(self, surfaceHolder: Any) -> None:
- self._surface_holder = surfaceHolder
- self._surface_created = True
-
- def onDestroy(self) -> None:
- self._surface_destroyed = True
-
- def onVisibilityChanged(self, visible: bool) -> None:
- self._is_visible = visible
- self._visible = visible
-
- def onTouchEvent(self, event: Any) -> None:
- pass
-
- def onSurfaceChanged(self, holder: Any, format: int, width: int, height: int) -> None:
- self._desired_width = width
- self._desired_height = height
- self._surface_changed = True
-
- def onSurfaceCreated(self, holder: Any) -> None:
- self._surface_created = True
- self._mSurfaceCreated = True
- self._mSurfaceValid = True
-
- def onSurfaceDestroyed(self, holder: Any) -> None:
- self._surface_destroyed = True
- self._mSurfaceDestroyed = True
- self._mSurfaceValid = False
-
- def onSurfaceRedrawNeeded(self, holder: Any) -> None:
- pass
-
- def onOffsetsChanged(
- self,
- xOffset: float,
- yOffset: float,
- xOffsetStep: float,
- yOffsetStep: float,
- xPixelOffset: int,
- yPixelOffset: int,
- ) -> None:
- self._x_offset = xOffset
- self._y_offset = yOffset
- self._x_step = xOffsetStep
- self._y_step = yOffsetStep
-
- def onDesiredSizeChanged(self, desiredWidth: int, desiredHeight: int) -> None:
- self._desired_width = desiredWidth
- self._desired_height = desiredHeight
-
- def onZoomChanged(self, zoom: float) -> None:
- self._mZoom = zoom
-
- def setZoomOut(self, zoom: float) -> None:
- self._mZoomOut = zoom
-
- def getZoomOut(self) -> float:
- return self._mZoomOut
-
- def notifyZoomChanged(self) -> None:
- pass
-
- def notifyColorsChanged(self) -> None:
- pass
-
- def getDesiredMinimumWidth(self) -> int:
- return self._desired_width
-
- def getDesiredMinimumHeight(self) -> int:
- return self._desired_height
-
- def getXOffset(self) -> float:
- return self._x_offset
-
- def getYOffset(self) -> float:
- return self._y_offset
-
- def getXStep(self) -> float:
- return self._x_step
-
- def getYStep(self) -> float:
- return self._y_step
-
- def isCreated(self) -> bool:
- return self._mCreated
-
- def isSurfaceCreated(self) -> bool:
- return self._mSurfaceCreated
-
- def isSurfaceValid(self) -> bool:
- return self._mSurfaceValid
-
- def isVisible(self) -> bool:
- return self._visible
-
- def getSurfaceHolder(self) -> Optional[Any]:
- return self._surface_holder
-
- def getService(self) -> "WallpaperService":
- return self._service
-
- def toString(self) -> str:
- return (
- f"WallpaperService.Engine(visible={self._visible}, "
- f"surface_created={self._mSurfaceCreated}, "
- f"zoom={self._mZoom})"
- )
\ No newline at end of file
diff --git a/android_pyapi/android/appwidget.py b/android_pyapi/android/appwidget.py
deleted file mode 100644
index 91fda3e..0000000
--- a/android_pyapi/android/appwidget.py
+++ /dev/null
@@ -1,360 +0,0 @@
-"""
-Android App Widget API — AppWidgetProvider, AppWidgetManager, AppWidgetProviderInfo, AppWidgetHost, AppWidgetHostView
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "AppWidgetProvider",
- "AppWidgetManager",
- "AppWidgetProviderInfo",
- "AppWidgetHost",
- "AppWidgetHostView",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# AppWidgetProvider
-# ═══════════════════════════════════════════════════════════════
-
-class AppWidgetProvider(Stub):
- """AppWidgetProvider — 应用小部件提供者"""
-
- def __init__(self):
- super().__init__()
-
- def onUpdate(self, context: Any, appWidgetManager: "AppWidgetManager", appWidgetIds: List[int]):
- """小部件更新回调"""
- pass
-
- def onDeleted(self, context: Any, appWidgetIds: List[int]):
- """小部件删除回调"""
- pass
-
- def onEnabled(self, context: Any):
- """首个小部件启用回调"""
- pass
-
- def onDisabled(self, context: Any):
- """最后一个小部件禁用回调"""
- pass
-
- def onAppWidgetOptionsChanged(
- self, context: Any, appWidgetManager: "AppWidgetManager",
- appWidgetId: int, newOptions: Dict[str, Any]
- ):
- """小部件选项变更回调"""
- pass
-
- def onReceive(self, context: Any, intent: Any):
- """接收广播回调"""
- pass
-
- def onRestored(self, context: Any, oldWidgetIds: List[int], newWidgetId: int):
- """小部件恢复回调"""
- pass
-
- def onProviderChanged(
- self, context: Any, appWidgetManager: "AppWidgetManager",
- appWidgetId: int, newInfo: "AppWidgetProviderInfo"
- ):
- """提供者变更回调"""
- pass
-
- def toString(self) -> str:
- return f"AppWidgetProvider@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AppWidgetManager
-# ═══════════════════════════════════════════════════════════════
-
-class AppWidgetManager(Stub):
- """AppWidgetManager — 应用小部件管理器 (桌面存根)"""
-
- ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE"
- ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED"
- ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED"
- ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED"
- ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_OPTIONS_CHANGED"
- ACTION_APPWIDGET_RESTORED = "android.appwidget.action.APPWIDGET_RESTORED"
- ACTION_APPWIDGET_HOST_RESTORED = "android.appwidget.action.APPWIDGET_HOST_RESTORED"
- EXTRA_APPWIDGET_ID = "appWidgetId"
- EXTRA_APPWIDGET_IDS = "appWidgetIds"
- EXTRA_APPWIDGET_OLD_IDS = "appWidgetOldIds"
- EXTRA_APPWIDGET_OPTIONS = "appWidgetOptions"
- EXTRA_APPWIDGET_PROVIDER = "appWidgetProvider"
- EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile"
- WIDGET_CATEGORY_HOME_SCREEN = 1
- WIDGET_CATEGORY_KEYGUARD = 2
- WIDGET_CATEGORY_SEARCHBOX = 4
- OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth"
- OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight"
- OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth"
- OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._widget_views: Dict[int, Any] = {}
- self._widget_options: Dict[int, Dict[str, Any]] = {}
- self._providers: List["AppWidgetProviderInfo"] = []
- self._next_widget_id = 1
-
- @staticmethod
- def getInstance(context: Any) -> "AppWidgetManager":
- """获取 AppWidgetManager 实例"""
- return AppWidgetManager(context)
-
- def getAppWidgetIds(self, info: "AppWidgetProviderInfo") -> List[int]:
- """获取指定提供者的小部件 ID 列表"""
- return list(self._widget_views.keys())
-
- def updateAppWidget(self, appWidgetId: int, view: Any):
- """更新小部件视图"""
- self._widget_views[appWidgetId] = view
-
- def updateAppWidgetOptions(self, appWidgetId: int, options: Dict[str, Any]):
- """更新小部件选项"""
- if appWidgetId in self._widget_options:
- self._widget_options[appWidgetId].update(options)
- else:
- self._widget_options[appWidgetId] = dict(options)
-
- def getAppWidgetOptions(self, appWidgetId: int) -> Dict[str, Any]:
- """获取小部件选项"""
- return self._widget_options.get(appWidgetId, {})
-
- def bindAppWidgetIdIfAllowed(
- self, appWidgetId: int, info: "AppWidgetProviderInfo"
- ) -> bool:
- """绑定小部件 ID(如允许)"""
- return True
-
- def getAppWidgetInfo(self, appWidgetId: int) -> Optional["AppWidgetProviderInfo"]:
- """获取小部件信息"""
- if appWidgetId in self._widget_views:
- return self._providers[0] if self._providers else None
- return None
-
- def getInstalledProviders(self) -> List["AppWidgetProviderInfo"]:
- """获取已安装的提供者列表"""
- return list(self._providers)
-
- def isBindAppWidgetIdAllowed(self, appWidgetId: int, info: "AppWidgetProviderInfo") -> bool:
- """检查是否允许绑定小部件 ID"""
- return True
-
- def createAppWidgetConfigIntentSender(
- self, info: "AppWidgetProviderInfo", appWidgetId: int
- ) -> Optional[Any]:
- """创建小部件配置 IntentSender"""
- return None
-
- def requestPinAppWidget(
- self, info: "AppWidgetProviderInfo", successCallback: Any = None
- ) -> bool:
- """请求固定小部件"""
- return True
-
- def getAppWidgetHostViews(self, host: "AppWidgetHost") -> List["AppWidgetHostView"]:
- """获取主机视图列表"""
- return []
-
- def toString(self) -> str:
- return f"AppWidgetManager(widgets={len(self._widget_views)})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AppWidgetProviderInfo
-# ═══════════════════════════════════════════════════════════════
-
-class AppWidgetProviderInfo(Stub):
- """AppWidgetProviderInfo — 小部件提供者信息"""
-
- # --- ResizeMode ---
- RESIZE_MODE_NONE = 0
- RESIZE_MODE_HORIZONTAL = 1
- RESIZE_MODE_VERTICAL = 2
- RESIZE_MODE_RESIZE_ALL = 3
-
- # --- WidgetCategory ---
- WIDGET_CATEGORY_HOME_SCREEN = 1
- WIDGET_CATEGORY_KEYGUARD = 2
- WIDGET_CATEGORY_SEARCHBOX = 4
-
- # --- WidgetFeatures ---
- WIDGET_FEATURE_HIDE_FROM_PICKER = 1
- WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 2
- WIDGET_FEATURE_RECONFIGURABLE = 4
-
- def __init__(self):
- super().__init__()
- self.provider: Any = None
- self.configure: Any = None
- self.icon: int = 0
- self.label: str = ""
- self.previewImage: int = 0
- self.previewLayout: int = 0
- self.autoAdvanceViewId: int = -1
- self.resizeMode: int = self.RESIZE_MODE_NONE
- self.widgetCategory: int = self.WIDGET_CATEGORY_HOME_SCREEN
- self.widgetFeatures: int = 0
- self.description: str = ""
- self.targetCellWidth: int = 0
- self.targetCellHeight: int = 0
- self.minWidth: int = 0
- self.minHeight: int = 0
- self.maxWidth: int = 0
- self.maxHeight: int = 0
- self.minResizeWidth: int = 0
- self.minResizeHeight: int = 0
- self.updatePeriodMillis: int = 0
- self.initialLayout: int = 0
-
- def getProfile(self) -> Optional[Any]:
- """获取配置文件"""
- return None
-
- def getActivityInfo(self) -> Optional[Any]:
- """获取 Activity 信息"""
- return None
-
- def getIcon(self) -> int:
- return self.icon
-
- def getLabel(self) -> str:
- return self.label
-
- def loadPreviewImage(self, context: Any, density: int) -> Any:
- """加载预览图像"""
- return None
-
- def toString(self) -> str:
- return f"AppWidgetProviderInfo(label={self.label}, icon={self.icon})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, AppWidgetProviderInfo):
- return False
- return self.provider == other.provider and self.label == other.label
-
- def hashCode(self) -> int:
- return hash((str(self.provider), self.label)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AppWidgetHost
-# ═══════════════════════════════════════════════════════════════
-
-class AppWidgetHost(Stub):
- """AppWidgetHost — 小部件主机"""
-
- def __init__(self, context: Any, hostId: int):
- super().__init__()
- self._context = context
- self._host_id = hostId
- self._widget_ids: List[int] = []
- self._listening = False
-
- def createView(
- self, context: Any, appWidgetId: int, info: "AppWidgetProviderInfo"
- ) -> "AppWidgetHostView":
- """创建小部件视图"""
- view = AppWidgetHostView(context)
- view.setAppWidget(appWidgetId, info)
- return view
-
- def startListening(self):
- """开始监听"""
- self._listening = True
-
- def stopListening(self):
- """停止监听"""
- self._listening = False
-
- def allocateAppWidgetId(self) -> int:
- """分配小部件 ID"""
- widget_id = len(self._widget_ids) + 1000 + self._host_id
- self._widget_ids.append(widget_id)
- return widget_id
-
- def deleteAppWidgetId(self, appWidgetId: int):
- """删除小部件 ID"""
- if appWidgetId in self._widget_ids:
- self._widget_ids.remove(appWidgetId)
-
- def deleteHost(self):
- """删除主机"""
- self._widget_ids.clear()
-
- def clearViews(self):
- """清除所有视图"""
- self._widget_ids.clear()
-
- def toString(self) -> str:
- return f"AppWidgetHost(hostId={self._host_id}, widgets={len(self._widget_ids)})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, AppWidgetHost):
- return False
- return self._host_id == other._host_id
-
- def hashCode(self) -> int:
- return self._host_id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AppWidgetHostView
-# ═══════════════════════════════════════════════════════════════
-
-class AppWidgetHostView(Stub):
- """AppWidgetHostView — 小部件主机视图"""
-
- def __init__(self, context: Any):
- super().__init__()
- self._context = context
- self._app_widget_id = -1
- self._info: Optional["AppWidgetProviderInfo"] = None
-
- def setAppWidget(self, appWidgetId: int, info: "AppWidgetProviderInfo"):
- """设置小部件"""
- self._app_widget_id = appWidgetId
- self._info = info
-
- def updateAppWidget(self, info: "AppWidgetProviderInfo"):
- """更新小部件"""
- self._info = info
-
- def getAppWidgetInfo(self) -> Optional["AppWidgetProviderInfo"]:
- return self._info
-
- def toString(self) -> str:
- return f"AppWidgetHostView(widgetId={self._app_widget_id})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, AppWidgetHostView):
- return False
- return self._app_widget_id == other._app_widget_id
-
- def hashCode(self) -> int:
- return self._app_widget_id & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/bluetooth.py b/android_pyapi/android/bluetooth.py
deleted file mode 100644
index 6c75710..0000000
--- a/android_pyapi/android/bluetooth.py
+++ /dev/null
@@ -1,849 +0,0 @@
-"""
-Android Bluetooth 组件 — BluetoothAdapter, BluetoothDevice, BluetoothGatt 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-import uuid
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-# Linux 真实实现导入
-try:
- from .._linux_impl import IS_LINUX, LinuxBluetooth, HAS_BLUETOOTHCTL
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothProfile
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothProfile(Stub):
- """BluetoothProfile — 蓝牙配置档案"""
-
- A2DP = 2
- HEALTH = 3
- HEADSET = 1
- GATT = 7
- GATT_SERVER = 8
- A2DP_SINK = 11
- AVRC = 12
- HEARING_AID = 21
- LE_AUDIO = 22
- LE_AUDIO_BROADCAST = 26
-
- STATE_DISCONNECTED = 0
- STATE_CONNECTING = 1
- STATE_CONNECTED = 2
- STATE_DISCONNECTING = 3
-
- def getConnectedDevices(self) -> List[Any]:
- return []
-
- def getDevicesMatchingConnectionState(self, state: int) -> List[Any]:
- return []
-
- def getConnectionState(self, device: Any) -> int:
- return self.STATE_DISCONNECTED
-
-
-class BluetoothProfileServiceListener(Stub):
- """BluetoothProfile.ServiceListener"""
-
- def onServiceConnected(self, profile_id: int, proxy: Any):
- pass
-
- def onServiceDisconnected(self, profile_id: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothClass
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothClass(Stub):
- """BluetoothClass — 蓝牙设备类别"""
-
- class Device(Stub):
- COMPUTER_DESKTOP = 0x100
- COMPUTER_LAPTOP = 0x10C
- PHONE_SMART = 0x200
- PHONE_UNCATEGORIZED = 0x204
- AUDIO_VIDEO_WEARABLE_HEADSET = 0x404
- AUDIO_VIDEO_HANDSFREE = 0x408
-
- class Major(Stub):
- MISC = 0x0000
- COMPUTER = 0x0100
- PHONE = 0x0200
- NETWORKING = 0x0300
- AUDIO_VIDEO = 0x0400
- PERIPHERAL = 0x0500
- IMAGING = 0x0600
- WEARABLE = 0x0700
- TOY = 0x0800
- HEALTH = 0x0900
- UNCATEGORIZED = 0x1F00
-
- def __init__(self):
- super().__init__()
- self._device_class = 0
- self._major_class = 0
-
- def getDeviceClass(self) -> int:
- return self._device_class
-
- def getMajorDeviceClass(self) -> int:
- return self._major_class
-
- def hasService(self, service: int) -> bool:
- return False
-
- def toString(self) -> str:
- return f"BluetoothClass(device=0x{self._device_class:04X})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothSocket
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothSocket(Stub):
- """BluetoothSocket — 蓝牙套接字"""
-
- TYPE_RFCOMM = 1
- TYPE_L2CAP = 3
- TYPE_SCO = 2
-
- def __init__(self, type_: int = TYPE_RFCOMM):
- super().__init__()
- self._type = type_
- self._closed = False
- self._connected = False
- self._device: Optional["BluetoothDevice"] = None
-
- def connect(self):
- self._connected = True
-
- def bind(self):
- pass
-
- def getInputStream(self) -> Any:
- return None
-
- def getOutputStream(self) -> Any:
- return None
-
- def close(self):
- self._closed = True
- self._connected = False
-
- def getRemoteDevice(self) -> Optional["BluetoothDevice"]:
- return self._device
-
- def getMaxReceivePacketSize(self) -> int:
- return 0
-
- def isConnected(self) -> bool:
- return self._connected
-
- def isClosed(self) -> bool:
- return self._closed
-
-
-class BluetoothServerSocket(Stub):
- """BluetoothServerSocket — 蓝牙服务端套接字"""
-
- def __init__(self):
- super().__init__()
- self._closed = False
-
- def accept(self, timeout: int = 0) -> Optional[BluetoothSocket]:
- return None
-
- def close(self):
- self._closed = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothDevice
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothDevice(Stub):
- """BluetoothDevice — 蓝牙设备"""
-
- BOND_NONE = 10
- BOND_BONDING = 11
- BOND_BONDED = 12
-
- DEVICE_TYPE_DUAL = 3
- DEVICE_TYPE_LE = 2
- DEVICE_TYPE_BREDR = 1
- DEVICE_TYPE_UNKNOWN = 0
-
- ACTION_FOUND = "android.bluetooth.device.action.FOUND"
- ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED"
- ACTION_BOND_STATE_CHANGED = "android.bluetooth.device.action.BOND_STATE_CHANGED"
- EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE"
- EXTRA_NAME = "android.bluetooth.device.extra.NAME"
- EXTRA_RSSI = "android.bluetooth.device.extra.RSSI"
- EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE"
- EXTRA_PREVIOUS_BOND_STATE = "android.bluetooth.device.extra.PREVIOUS_BOND_STATE"
-
- def __init__(self, address: str = "00:00:00:00:00:00"):
- super().__init__()
- self._address = address
- self._name = "Unknown"
- self._bond_state = self.BOND_NONE
- self._device_type = self.DEVICE_TYPE_UNKNOWN
-
- def getAddress(self) -> str:
- return self._address
-
- def getName(self) -> str:
- return self._name
-
- def setName(self, name: str):
- self._name = name
-
- def getBondState(self) -> int:
- return self._bond_state
-
- def setBondState(self, state: int):
- self._bond_state = state
-
- def getType(self) -> int:
- return self._device_type
-
- def untergehende(self) -> bool:
- return self._bond_state == self.BOND_BONDED
-
- def createRfcommSocketToServiceRecord(self, uuid_str: str) -> BluetoothSocket:
- sock = BluetoothSocket(BluetoothSocket.TYPE_RFCOMM)
- sock._device = self
- return sock
-
- def createInsecureRfcommSocketToServiceRecord(self, uuid_str: str) -> BluetoothSocket:
- sock = BluetoothSocket(BluetoothSocket.TYPE_RFCOMM)
- sock._device = self
- return sock
-
- def createL2capChannel(self, psm: int) -> BluetoothSocket:
- sock = BluetoothSocket(BluetoothSocket.TYPE_L2CAP)
- sock._device = self
- return sock
-
- def createInsecureL2capChannel(self, psm: int) -> BluetoothSocket:
- sock = BluetoothSocket(BluetoothSocket.TYPE_L2CAP)
- sock._device = self
- return sock
-
- def fetchUuidsWithSdp(self) -> bool:
- return False
-
- def uuidEquals(self, uuid_str: str) -> bool:
- return False
-
- def setPairingConfirmation(self, accept: bool):
- pass
-
- def setPin(self, pin: bytes) -> bool:
- return True
-
- def toString(self) -> str:
- return f"BluetoothDevice(address={self._address}, name={self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothGattDescriptor
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothGattDescriptor(Stub):
- """BluetoothGattDescriptor — GATT 描述符"""
-
- ENABLE_NOTIFICATION_VALUE = bytes([0x01, 0x00])
- ENABLE_INDICATION_VALUE = bytes([0x02, 0x00])
- DISABLE_NOTIFICATION_VALUE = bytes([0x00, 0x00])
-
- def __init__(self, uuid_str: str, permissions: int = 0):
- super().__init__()
- self._uuid = uuid_str
- self._value: Optional[bytes] = None
- self._permissions = permissions
- self._characteristic: Optional["BluetoothGattCharacteristic"] = None
-
- def getUuid(self) -> str:
- return self._uuid
-
- def getValue(self) -> Optional[bytes]:
- return self._value
-
- def setValue(self, value: bytes):
- self._value = value
-
- def getCharacteristic(self) -> Optional["BluetoothGattCharacteristic"]:
- return self._characteristic
-
- def getPermissions(self) -> int:
- return self._permissions
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothGattCharacteristic
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothGattCharacteristic(Stub):
- """BluetoothGattCharacteristic — GATT 特征"""
-
- PROPERTY_BROADCAST = 1
- PROPERTY_READ = 2
- PROPERTY_WRITE_NO_RESPONSE = 4
- PROPERTY_WRITE = 8
- PROPERTY_NOTIFY = 16
- PROPERTY_INDICATE = 32
- PROPERTY_SIGNED_WRITE = 64
- PROPERTY_EXTENDED_PROPS = 128
-
- WRITE_TYPE_NO_RESPONSE = 1
- WRITE_TYPE_DEFAULT = 2
- WRITE_TYPE_SIGNED = 4
-
- PERMISSION_READ = 1
- PERMISSION_READ_ENCRYPTED = 2
- PERMISSION_READ_ENCRYPTED_MITM = 4
- PERMISSION_WRITE = 16
- PERMISSION_WRITE_ENCRYPTED = 32
- PERMISSION_WRITE_ENCRYPTED_MITM = 64
-
- FORMAT_FLOAT = 0x20
- FORMAT_SFLOAT = 0x10
- FORMAT_SINT16 = 0x02
- FORMAT_SINT32 = 0x04
- FORMAT_SINT8 = 0x01
- FORMAT_UINT16 = 0x12
- FORMAT_UINT32 = 0x14
- FORMAT_UINT8 = 0x11
-
- def __init__(self, uuid_str: str, properties: int = 0, permissions: int = 0):
- super().__init__()
- self._uuid = uuid_str
- self._properties = properties
- self._permissions = permissions
- self._write_type = self.WRITE_TYPE_DEFAULT
- self._value: Optional[bytes] = None
- self._service: Optional["BluetoothGattService"] = None
- self._descriptors: List[BluetoothGattDescriptor] = []
-
- def getUuid(self) -> str:
- return self._uuid
-
- def getService(self) -> Optional["BluetoothGattService"]:
- return self._service
-
- def getPermissions(self) -> int:
- return self._permissions
-
- def getProperties(self) -> int:
- return self._properties
-
- def getWriteType(self) -> int:
- return self._write_type
-
- def setWriteType(self, write_type: int):
- self._write_type = write_type
-
- def getValue(self) -> Optional[bytes]:
- return self._value
-
- def setValue(self, value: bytes):
- self._value = value
-
- def getDescriptors(self) -> List[BluetoothGattDescriptor]:
- return list(self._descriptors)
-
- def getDescriptor(self, uuid_str: str) -> Optional[BluetoothGattDescriptor]:
- for d in self._descriptors:
- if d.getUuid() == uuid_str:
- return d
- return None
-
- def addDescriptor(self, descriptor: BluetoothGattDescriptor):
- self._descriptors.append(descriptor)
- descriptor._characteristic = self
-
- def getIntValue(self, format_type: int, offset: int) -> Optional[int]:
- if self._value is None:
- return None
- import struct
- try:
- fmt_map = {
- self.FORMAT_UINT8: ("B", 1), self.FORMAT_SINT8: ("b", 1),
- self.FORMAT_UINT16: ("H", 2), self.FORMAT_SINT16: ("h", 2),
- self.FORMAT_UINT32: ("I", 4), self.FORMAT_SINT32: ("i", 4),
- self.FORMAT_FLOAT: ("f", 4), self.FORMAT_SFLOAT: ("e", 2),
- }
- fmt, size = fmt_map.get(format_type, ("B", 1))
- if offset + size > len(self._value):
- return None
- val = struct.unpack(fmt, self._value[offset:offset + size])[0]
- return int(val)
- except Exception:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothGattService
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothGattService(Stub):
- """BluetoothGattService — GATT 服务"""
-
- SERVICE_TYPE_PRIMARY = 0
- SERVICE_TYPE_SECONDARY = 1
-
- def __init__(self, uuid_str: str, service_type: int = SERVICE_TYPE_PRIMARY):
- super().__init__()
- self._uuid = uuid_str
- self._type = service_type
- self._characteristics: List[BluetoothGattCharacteristic] = []
- self._included_services: List["BluetoothGattService"] = []
- self._device: Optional[BluetoothDevice] = None
-
- def getUuid(self) -> str:
- return self._uuid
-
- def getType(self) -> int:
- return self._type
-
- def getCharacteristics(self) -> List[BluetoothGattCharacteristic]:
- return list(self._characteristics)
-
- def getCharacteristic(self, uuid_str: str) -> Optional[BluetoothGattCharacteristic]:
- for c in self._characteristics:
- if c.getUuid() == uuid_str:
- return c
- return None
-
- def addCharacteristic(self, characteristic: BluetoothGattCharacteristic):
- self._characteristics.append(characteristic)
- characteristic._service = self
-
- def getIncludedServices(self) -> List["BluetoothGattService"]:
- return list(self._included_services)
-
- def addIncludedService(self, service: "BluetoothGattService"):
- self._included_services.append(service)
-
- def getDevice(self) -> Optional[BluetoothDevice]:
- return self._device
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothGattCallback
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothGattCallback(Stub):
- """BluetoothGattCallback — GATT 回调"""
-
- def onConnectionStateChange(self, gatt: "BluetoothGatt", status: int, new_state: int):
- pass
-
- def onServicesDiscovered(self, gatt: "BluetoothGatt", status: int):
- pass
-
- def onCharacteristicRead(self, gatt: "BluetoothGatt",
- characteristic: BluetoothGattCharacteristic, value: bytes, status: int):
- pass
-
- def onCharacteristicWrite(self, gatt: "BluetoothGatt",
- characteristic: BluetoothGattCharacteristic, status: int):
- pass
-
- def onDescriptorRead(self, gatt: "BluetoothGatt",
- descriptor: BluetoothGattDescriptor, status: int):
- pass
-
- def onDescriptorWrite(self, gatt: "BluetoothGatt",
- descriptor: BluetoothGattDescriptor, status: int):
- pass
-
- def onCharacteristicChanged(self, gatt: "BluetoothGatt",
- characteristic: BluetoothGattCharacteristic, value: bytes):
- pass
-
- def onReadRemoteRssy(self, gatt: "BluetoothGatt", rssi: int, status: int):
- pass
-
- def onMtuChanged(self, gatt: "BluetoothGatt", mtu: int, status: int):
- pass
-
- def onPhyUpdate(self, gatt: "BluetoothGatt", tx_phy: int, rx_phy: int, status: int):
- pass
-
- def onPhyRead(self, gatt: "BluetoothGatt", tx_phy: int, rx_phy: int, status: int):
- pass
-
- def onServiceChanged(self, gatt: "BluetoothGatt"):
- pass
-
- def onNotificationSent(self, gatt: "BluetoothGatt", status: int):
- pass
-
- def onConnectionUpdated(self, gatt: "BluetoothGatt", interval: int,
- latency: int, timeout: int, status: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothGatt
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothGatt(Stub):
- """BluetoothGatt — GATT 客户端"""
-
- CONNECTION_STATE_DISCONNECTED = 0
- CONNECTION_STATE_CONNECTING = 1
- CONNECTION_STATE_CONNECTED = 2
- CONNECTION_STATE_DISCONNECTING = 3
-
- GATT_SUCCESS = 0
- GATT_FAILURE = 1
- GATT_CONNECTION_CONGESTED = 143
- GATT_INSUFFICIENT_AUTHENTICATION = 5
- GATT_INSUFFICIENT_ENCRYPTION = 15
- GATT_INSUFFICIENT_KEY_SIZE = 12
- GATT_INVALID_ATTRIBUTE_LENGTH = 13
- GATT_REQUEST_NOT_SUPPORTED = 6
- GATT_WRITE_NOT_PERMITTED = 3
- GATT_READ_NOT_PERMITTED = 2
- GATT_WRITE_NO_RESPONSE = 1
- GATT_WRITE_DEFAULT = 0
-
- def __init__(self, device: BluetoothDevice):
- super().__init__()
- self._device = device
- self._services: List[BluetoothGattService] = []
- self._connected = False
- self._mtu = 23
-
- def connect(self) -> bool:
- self._connected = True
- return True
-
- def disconnect(self):
- self._connected = False
-
- def close(self):
- self._connected = False
- self._services.clear()
-
- def discoverServices(self) -> bool:
- return True
-
- def getServices(self) -> List[BluetoothGattService]:
- return list(self._services)
-
- def getService(self, uuid_str: str) -> Optional[BluetoothGattService]:
- for s in self._services:
- if s.getUuid() == uuid_str:
- return s
- return None
-
- def getConnectedDevices(self) -> List[BluetoothDevice]:
- return [self._device] if self._connected else []
-
- def getDevicesMatchingConnectionState(self, state: int) -> List[BluetoothDevice]:
- if state == self.CONNECTION_STATE_CONNECTED and self._connected:
- return [self._device]
- return []
-
- def readCharacteristic(self, characteristic: BluetoothGattCharacteristic) -> bool:
- return True
-
- def writeCharacteristic(self, characteristic: BluetoothGattCharacteristic) -> bool:
- return True
-
- def readDescriptor(self, descriptor: BluetoothGattDescriptor) -> bool:
- return True
-
- def writeDescriptor(self, descriptor: BluetoothGattDescriptor) -> bool:
- return True
-
- def setCharacteristicNotification(self, characteristic: BluetoothGattCharacteristic,
- enable: bool) -> bool:
- return True
-
- def readRemoteRssy(self) -> bool:
- return True
-
- def requestMtu(self, mtu: int) -> bool:
- self._mtu = mtu
- return True
-
- def getMtu(self) -> int:
- return self._mtu
-
- def requestConnectionPriority(self, connection_priority: int) -> bool:
- return True
-
- def getDevice(self) -> BluetoothDevice:
- return self._device
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothManager
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothManager(Stub):
- """BluetoothManager — 蓝牙管理器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
-
- def getAdapter(self) -> Optional["BluetoothAdapter"]:
- return BluetoothAdapter.getDefaultAdapter()
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothAdapter(Stub):
- """BluetoothAdapter — 蓝牙适配器"""
-
- STATE_OFF = 10
- STATE_TURNING_ON = 11
- STATE_ON = 12
- STATE_TURNING_OFF = 13
-
- ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"
- ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"
- ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED"
- ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED"
- ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED"
-
- SCAN_MODE_NONE = 20
- SCAN_MODE_CONNECTABLE = 21
- SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23
-
- _default_adapter: Optional["BluetoothAdapter"] = None
-
- def __init__(self):
- super().__init__()
- self._enabled = True
- self._state = self.STATE_ON
- self._address = "00:1A:2B:3C:4D:5E"
- self._name = "MockBluetooth"
- self._discovering = False
- self._bonded_devices: List[BluetoothDevice] = []
-
- @staticmethod
- def getDefaultAdapter() -> Optional["BluetoothAdapter"]:
- if BluetoothAdapter._default_adapter is None:
- BluetoothAdapter._default_adapter = BluetoothAdapter()
- return BluetoothAdapter._default_adapter
-
- def isEnabled(self) -> bool:
- if _USE_LINUX:
- return LinuxBluetooth.get_state() == LinuxBluetooth.STATE_ON
- return self._enabled
-
- def enable(self) -> bool:
- if _USE_LINUX:
- return LinuxBluetooth.enable()
- self._enabled = True
- self._state = self.STATE_ON
- return True
-
- def disable(self) -> bool:
- if _USE_LINUX:
- return LinuxBluetooth.disable()
- self._enabled = False
- self._state = self.STATE_OFF
- return True
-
- def getAddress(self) -> str:
- if _USE_LINUX:
- addr = LinuxBluetooth.get_address()
- if addr:
- return addr
- return self._address
-
- def getName(self) -> str:
- if _USE_LINUX:
- name = LinuxBluetooth.get_name()
- if name:
- return name
- return self._name
-
- def setName(self, name: str) -> bool:
- self._name = name
- return True
-
- def getBondedDevices(self) -> Set[BluetoothDevice]:
- if _USE_LINUX:
- devices = set()
- for d in LinuxBluetooth.get_bonded_devices():
- dev = BluetoothDevice(d.get("address", "00:00:00:00:00:00"))
- dev._name = d.get("name", "Unknown")
- dev._bond_state = BluetoothDevice.BOND_BONDED
- devices.add(dev)
- return devices
- return set(self._bonded_devices)
-
- def getBondedDeviceAddresses(self) -> Set[str]:
- """获取已配对设备地址集合"""
- if _USE_LINUX:
- return {d.get("address", "") for d in LinuxBluetooth.get_bonded_devices()}
- return {d.getAddress() for d in self._bonded_devices}
-
- def startDiscovery(self) -> bool:
- if _USE_LINUX:
- try:
- LinuxBluetooth.scan(timeout=5)
- return True
- except Exception:
- return False
- self._discovering = True
- return True
-
- def cancelDiscovery(self) -> bool:
- if _USE_LINUX:
- # bluetoothctl scan off 在 LinuxBluetooth.scan 内部已处理
- return True
- self._discovering = False
- return True
-
- def isDiscovering(self) -> bool:
- return self._discovering
-
- @staticmethod
- def checkBluetoothAddress(address: str) -> bool:
- import re
- return bool(re.match(r"^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$", address))
-
- def getProfileProxy(self, context: Any, listener: BluetoothProfileServiceListener,
- profile_id: int) -> bool:
- return True
-
- def closeProfileProxy(self, profile_id: int, proxy: Any):
- pass
-
- def getState(self) -> int:
- if _USE_LINUX:
- return LinuxBluetooth.get_state()
- return self._state
-
- def listenUsingRfcommWithServiceRecord(self, name: str, uuid_str: str) -> BluetoothServerSocket:
- return BluetoothServerSocket()
-
- def listenUsingInsecureRfcommWithServiceRecord(self, name: str,
- uuid_str: str) -> BluetoothServerSocket:
- return BluetoothServerSocket()
-
- def getRemoteDevice(self, address: str) -> Optional[BluetoothDevice]:
- if _USE_LINUX:
- # 从已配对设备中查找
- for d in LinuxBluetooth.get_bonded_devices():
- if d.get("address", "").upper() == address.upper():
- dev = BluetoothDevice(d.get("address", address))
- dev._name = d.get("name", "Unknown")
- dev._bond_state = BluetoothDevice.BOND_BONDED
- return dev
- # 未配对但地址合法则返回一个设备对象
- if BluetoothAdapter.checkBluetoothAddress(address):
- return BluetoothDevice(address)
- return None
- if not BluetoothAdapter.checkBluetoothAddress(address):
- return None
- return BluetoothDevice(address)
-
- def getLeScanner(self) -> Any:
- from .bluetooth_le import BluetoothLeScanner
- return BluetoothLeScanner()
-
- def toString(self) -> str:
- return f"BluetoothAdapter(name={self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Additional profile stubs
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothHeadset(Stub):
- pass
-
-
-class BluetoothA2dp(Stub):
- pass
-
-
-class BluetoothHealth(Stub):
- pass
-
-
-class BluetoothHealthCallback(Stub):
- pass
-
-
-class BluetoothHealthAppConfiguration(Stub):
- pass
-
-
-class BluetoothCodecConfig(Stub):
- pass
-
-
-class BluetoothLeAudio(Stub):
- pass
-
-
-class BluetoothLeBroadcast(Stub):
- pass
-
-
-class BluetoothLeBroadcastMetadata(Stub):
- pass
-
-
-class BluetoothLeBroadcastSubgroup(Stub):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "BluetoothAdapter",
- "BluetoothDevice",
- "BluetoothServerSocket",
- "BluetoothSocket",
- "BluetoothClass",
- "BluetoothGatt",
- "BluetoothGattCallback",
- "BluetoothGattCharacteristic",
- "BluetoothGattDescriptor",
- "BluetoothGattService",
- "BluetoothHeadset",
- "BluetoothA2dp",
- "BluetoothHealth",
- "BluetoothHealthCallback",
- "BluetoothHealthAppConfiguration",
- "BluetoothProfile",
- "BluetoothProfileServiceListener",
- "BluetoothManager",
- "BluetoothCodecConfig",
- "BluetoothLeAudio",
- "BluetoothLeBroadcast",
- "BluetoothLeBroadcastMetadata",
- "BluetoothLeBroadcastSubgroup",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/bluetooth_le.py b/android_pyapi/android/bluetooth_le.py
deleted file mode 100644
index 0a8d311..0000000
--- a/android_pyapi/android/bluetooth_le.py
+++ /dev/null
@@ -1,512 +0,0 @@
-"""
-Android BLE 组件 — BluetoothLeScanner, ScanCallback, ScanFilter 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScanRecord
-# ═══════════════════════════════════════════════════════════════
-
-class ScanRecord(Stub):
- """ScanRecord — 扫描记录"""
-
- def __init__(self):
- super().__init__()
- self._service_uuids: List[str] = []
- self._service_solicitation_uuids: List[str] = []
- self._service_data: Dict[str, bytes] = {}
- self._manufacturer_specific_data: Dict[int, bytes] = {}
- self._tx_power_level: int = -127
- self._device_name: str = ""
- self._advertise_flags: int = 0
- self._bytes_data: bytes = b""
-
- def getServiceUuids(self) -> Optional[List[str]]:
- return list(self._service_uuids) if self._service_uuids else None
-
- def getServiceSolicitationUuids(self) -> Optional[List[str]]:
- return list(self._service_solicitation_uuids) if self._service_solicitation_uuids else None
-
- def getServiceData(self) -> Optional[Dict[str, bytes]]:
- return dict(self._service_data) if self._service_data else None
-
- def getServiceDataForService(self, uuid_str: str) -> Optional[bytes]:
- return self._service_data.get(uuid_str)
-
- def getManufacturerSpecificData(self) -> Optional[Dict[int, bytes]]:
- return dict(self._manufacturer_specific_data) if self._manufacturer_specific_data else None
-
- def getTxPowerLevel(self) -> int:
- return self._tx_power_level
-
- def getDeviceName(self) -> Optional[str]:
- return self._device_name or None
-
- def getAdvertiseFlags(self) -> int:
- return self._advertise_flags
-
- def getBytes(self) -> bytes:
- return self._bytes_data
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScanFilter
-# ═══════════════════════════════════════════════════════════════
-
-class ScanFilter(Stub):
- """ScanFilter — 扫描过滤器"""
-
- class Builder(Stub):
- def __init__(self):
- super().__init__()
- self._device_name: Optional[str] = None
- self._device_address: Optional[str] = None
- self._service_uuid: Optional[str] = None
- self._service_data: Optional[bytes] = None
- self._manufacturer_id: int = -1
- self._manufacturer_data: Optional[bytes] = None
-
- def setDeviceName(self, name: str) -> "ScanFilter.Builder":
- self._device_name = name
- return self
-
- def setDeviceAddress(self, address: str) -> "ScanFilter.Builder":
- self._device_address = address
- return self
-
- def setServiceUuid(self, uuid_str: str) -> "ScanFilter.Builder":
- self._service_uuid = uuid_str
- return self
-
- def setServiceData(self, data: bytes) -> "ScanFilter.Builder":
- self._service_data = data
- return self
-
- def setManufacturerData(self, manufacturer_id: int, data: bytes) -> "ScanFilter.Builder":
- self._manufacturer_id = manufacturer_id
- self._manufacturer_data = data
- return self
-
- def build(self) -> "ScanFilter":
- return ScanFilter(
- device_name=self._device_name,
- device_address=self._device_address,
- service_uuid=self._service_uuid,
- service_data=self._service_data,
- manufacturer_id=self._manufacturer_id,
- manufacturer_data=self._manufacturer_data,
- )
-
- def __init__(self, device_name: Optional[str] = None,
- device_address: Optional[str] = None,
- service_uuid: Optional[str] = None,
- service_data: Optional[bytes] = None,
- manufacturer_id: int = -1,
- manufacturer_data: Optional[bytes] = None):
- super().__init__()
- self._device_name = device_name
- self._device_address = device_address
- self._service_uuid = service_uuid
- self._service_data = service_data
- self._manufacturer_id = manufacturer_id
- self._manufacturer_data = manufacturer_data
-
-
-class ScanFilterBuilder(ScanFilter.Builder):
- """ScanFilter.Builder 别名"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScanSettings
-# ═══════════════════════════════════════════════════════════════
-
-class ScanSettings(Stub):
- """ScanSettings — 扫描设置"""
-
- SCAN_MODE_OPPORTUNISTIC = -1
- SCAN_MODE_LOW_POWER = 0
- SCAN_MODE_BALANCED = 1
- SCAN_MODE_LOW_LATENCY = 2
-
- CALLBACK_TYPE_ALL_MATCHES = 1
- CALLBACK_TYPE_FIRST_MATCH = 2
- CALLBACK_TYPE_MATCH_LOST = 4
-
- MATCH_NUM_FEW_CFG = 2
- MATCH_NUM_MAX_CFG = 1
- MATCH_MODE_AGGRESSIVE = 0
- MATCH_MODE_STICKY = 1
-
- class Builder(Stub):
- def __init__(self):
- super().__init__()
- self._scan_mode = ScanSettings.SCAN_MODE_LOW_POWER
- self._callback_type = ScanSettings.CALLBACK_TYPE_ALL_MATCHES
- self._legacy = True
- self._phy = 1
-
- def setScanMode(self, scan_mode: int) -> "ScanSettings.Builder":
- self._scan_mode = scan_mode
- return self
-
- def setCallbackType(self, callback_type: int) -> "ScanSettings.Builder":
- self._callback_type = callback_type
- return self
-
- def setLegacy(self, legacy: bool) -> "ScanSettings.Builder":
- self._legacy = legacy
- return self
-
- def setPhy(self, phy: int) -> "ScanSettings.Builder":
- self._phy = phy
- return self
-
- def build(self) -> "ScanSettings":
- return ScanSettings(
- scan_mode=self._scan_mode,
- callback_type=self._callback_type,
- legacy=self._legacy,
- phy=self._phy,
- )
-
- def __init__(self, scan_mode: int = SCAN_MODE_LOW_POWER,
- callback_type: int = CALLBACK_TYPE_ALL_MATCHES,
- legacy: bool = True, phy: int = 1):
- super().__init__()
- self._scan_mode = scan_mode
- self._callback_type = callback_type
- self._legacy = legacy
- self._phy = phy
-
- def getScanMode(self) -> int:
- return self._scan_mode
-
- def getCallbackType(self) -> int:
- return self._callback_type
-
- def getLegacy(self) -> bool:
- return self._legacy
-
- def getPhy(self) -> int:
- return self._phy
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScanResult
-# ═══════════════════════════════════════════════════════════════
-
-class ScanResult(Stub):
- """ScanResult — BLE 扫描结果"""
-
- DATA_COMPLETE = 0
- DATA_TRUNCATED = 2
- PHY_LE_1M = 1
- PHY_LE_2M = 2
- PHY_LE_CODED = 3
- PERIODIC_INTERVAL_NOT_PRESENT = 0
-
- def __init__(self, device: Any = None, scan_record: Optional[ScanRecord] = None,
- rssi: int = -127, timestamp_nanos: int = 0):
- super().__init__()
- self._device = device
- self._scan_record = scan_record or ScanRecord()
- self._rssi = rssi
- self._timestamp_nanos = timestamp_nanos
- self._primary_phy = self.PHY_LE_1M
- self._secondary_phy = 0
- self._advertising_sid = -1
- self._tx_power = -127
- self._periodic_interval = self.PERIODIC_INTERVAL_NOT_PRESENT
- self._data_status = self.DATA_COMPLETE
-
- def getDevice(self) -> Any:
- return self._device
-
- def getScanRecord(self) -> Optional[ScanRecord]:
- return self._scan_record
-
- def getRssi(self) -> int:
- return self._rssi
-
- def getTimestampNanos(self) -> int:
- return self._timestamp_nanos
-
- def getPrimaryPhy(self) -> int:
- return self._primary_phy
-
- def getSecondaryPhy(self) -> int:
- return self._secondary_phy
-
- def getAdvertisingSid(self) -> int:
- return self._advertising_sid
-
- def getTxPower(self) -> int:
- return self._tx_power
-
- def getPeriodicAdvertisingInterval(self) -> int:
- return self._periodic_interval
-
- def getDataStatus(self) -> int:
- return self._data_status
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScanCallback
-# ═══════════════════════════════════════════════════════════════
-
-class ScanCallback(Stub):
- """ScanCallback — 扫描回调"""
-
- SCAN_FAILED_ALREADY_STARTED = 1
- SCAN_FAILED_APPLICATION_REGISTRATION_FAILED = 2
- SCAN_FAILED_INTERNAL_ERROR = 3
- SCAN_FAILED_FEATURE_UNSUPPORTED = 4
- SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES = 5
- SCAN_FAILED_SCANNING_TOO_FREQUENTLY = 6
-
- def onScanResult(self, callback_type: int, result: ScanResult):
- pass
-
- def onBatchScanResults(self, results: List[ScanResult]):
- pass
-
- def onScanFailed(self, error_code: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothLeScanner
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothLeScanner(Stub):
- """BluetoothLeScanner — BLE 扫描器"""
-
- def __init__(self):
- super().__init__()
-
- def startScan(self, filters: Optional[List[ScanFilter]] = None,
- settings: Optional[ScanSettings] = None,
- callback: Optional[ScanCallback] = None):
- pass
-
- def startScanWithFilters(self, filters: List[ScanFilter],
- callback: ScanCallback):
- self.startScan(filters, None, callback)
-
- def stopScan(self, callback: Optional[ScanCallback] = None):
- pass
-
- def flushPendingScanResults(self, callback: ScanCallback):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AdvertiseData / AdvertiseSettings / AdvertiseCallback
-# ═══════════════════════════════════════════════════════════════
-
-class AdvertiseData(Stub):
- """AdvertiseData — 广播数据"""
-
- class Builder(Stub):
- def __init__(self):
- super().__init__()
- self._include_device_name = False
- self._include_tx_power_level = False
- self._service_uuids: List[str] = []
- self._service_data: Dict[str, bytes] = {}
- self._manufacturer_data: Dict[int, bytes] = {}
-
- def setIncludeDeviceName(self, include: bool) -> "AdvertiseData.Builder":
- self._include_device_name = include
- return self
-
- def setIncludeTxPowerLevel(self, include: bool) -> "AdvertiseData.Builder":
- self._include_tx_power_level = include
- return self
-
- def addServiceUuid(self, uuid_str: str) -> "AdvertiseData.Builder":
- self._service_uuids.append(uuid_str)
- return self
-
- def addServiceData(self, uuid_str: str, data: bytes) -> "AdvertiseData.Builder":
- self._service_data[uuid_str] = data
- return self
-
- def addManufacturerData(self, manufacturer_id: int, data: bytes) -> "AdvertiseData.Builder":
- self._manufacturer_data[manufacturer_id] = data
- return self
-
- def build(self) -> "AdvertiseData":
- return AdvertiseData(
- include_device_name=self._include_device_name,
- include_tx_power_level=self._include_tx_power_level,
- service_uuids=self._service_uuids,
- service_data=self._service_data,
- manufacturer_data=self._manufacturer_data,
- )
-
- def __init__(self, include_device_name: bool = False,
- include_tx_power_level: bool = False,
- service_uuids: Optional[List[str]] = None,
- service_data: Optional[Dict[str, bytes]] = None,
- manufacturer_data: Optional[Dict[int, bytes]] = None):
- super().__init__()
- self._include_device_name = include_device_name
- self._include_tx_power_level = include_tx_power_level
- self._service_uuids = service_uuids or []
- self._service_data = service_data or {}
- self._manufacturer_data = manufacturer_data or {}
-
-
-class AdvertiseDataBuilder(AdvertiseData.Builder):
- pass
-
-
-class AdvertiseSettings(Stub):
- """AdvertiseSettings — 广播设置"""
-
- ADVERTISE_MODE_LOW_POWER = 0
- ADVERTISE_MODE_BALANCED = 1
- ADVERTISE_MODE_LOW_LATENCY = 2
-
- ADVERTISE_TX_POWER_ULTRA_LOW = 0
- ADVERTISE_TX_POWER_LOW = 1
- ADVERTISE_TX_POWER_MEDIUM = 2
- ADVERTISE_TX_POWER_HIGH = 3
-
- class Builder(Stub):
- def __init__(self):
- super().__init__()
- self._advertise_mode = AdvertiseSettings.ADVERTISE_MODE_LOW_POWER
- self._tx_power_level = AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM
- self._connectable = True
- self._timeout = 0
-
- def setAdvertiseMode(self, mode: int) -> "AdvertiseSettings.Builder":
- self._advertise_mode = mode
- return self
-
- def setTxPowerLevel(self, power: int) -> "AdvertiseSettings.Builder":
- self._tx_power_level = power
- return self
-
- def setConnectable(self, connectable: bool) -> "AdvertiseSettings.Builder":
- self._connectable = connectable
- return self
-
- def setTimeout(self, timeout: int) -> "AdvertiseSettings.Builder":
- self._timeout = timeout
- return self
-
- def build(self) -> "AdvertiseSettings":
- return AdvertiseSettings(
- advertise_mode=self._advertise_mode,
- tx_power_level=self._tx_power_level,
- connectable=self._connectable,
- timeout=self._timeout,
- )
-
- def __init__(self, advertise_mode: int = ADVERTISE_MODE_LOW_POWER,
- tx_power_level: int = ADVERTISE_TX_POWER_MEDIUM,
- connectable: bool = True, timeout: int = 0):
- super().__init__()
- self._advertise_mode = advertise_mode
- self._tx_power_level = tx_power_level
- self._connectable = connectable
- self._timeout = timeout
-
- def getAdvertiseMode(self) -> int:
- return self._advertise_mode
-
- def getTxPowerLevel(self) -> int:
- return self._tx_power_level
-
- def isConnectable(self) -> bool:
- return self._connectable
-
- def getTimeout(self) -> int:
- return self._timeout
-
-
-class AdvertiseCallback(Stub):
- """AdvertiseCallback — 广播回调"""
-
- ADVERTISE_FAILED_DATA_TOO_LARGE = 1
- ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2
- ADVERTISE_FAILED_ALREADY_STARTED = 3
- ADVERTISE_FAILED_INTERNAL_ERROR = 4
- ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5
-
- def onStartSuccess(self, settings_in_effect: AdvertiseSettings):
- pass
-
- def onStartFailure(self, error_code: int):
- pass
-
-
-class BluetoothLeAdvertiser(Stub):
- """BluetoothLeAdvertiser — BLE 广播器"""
-
- def startAdvertising(self, settings: AdvertiseSettings,
- advertise_data: AdvertiseData,
- scan_response: Optional[AdvertiseData],
- callback: AdvertiseCallback):
- try:
- callback.onStartSuccess(settings)
- except Exception:
- pass
-
- def stopAdvertising(self, callback: AdvertiseCallback):
- pass
-
-
-class PeriodicAdvertisingManager(Stub):
- pass
-
-
-class PeriodicAdvertisingCallback(Stub):
- pass
-
-
-class DistanceMeasurementManager(Stub):
- pass
-
-
-class DistanceMeasurementResult(Stub):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "BluetoothLeScanner",
- "ScanCallback",
- "ScanResult",
- "ScanFilter",
- "ScanFilterBuilder",
- "ScanSettings",
- "ScanRecord",
- "BluetoothLeAdvertiser",
- "AdvertiseCallback",
- "AdvertiseData",
- "AdvertiseDataBuilder",
- "AdvertiseSettings",
- "PeriodicAdvertisingManager",
- "PeriodicAdvertisingCallback",
- "DistanceMeasurementManager",
- "DistanceMeasurementResult",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/companion.py b/android_pyapi/android/companion.py
deleted file mode 100644
index 569f8a3..0000000
--- a/android_pyapi/android/companion.py
+++ /dev/null
@@ -1,415 +0,0 @@
-"""
-Android Companion Device API — CompanionDeviceManager, AssociationInfo, DeviceFilters
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "CompanionDeviceManager",
- "AssociationInfo",
- "WifiDeviceFilter",
- "BluetoothDeviceFilter",
- "BluetoothLeDeviceFilter",
- "CommsDevice",
- "DeviceActivityCallback",
- "CompanionService",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionDeviceManager
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionDeviceManager(Stub):
- """CompanionDeviceManager — 配套设备管理器 (桌面存根)"""
-
- EXTRA_DEVICE = "android.companion.extra.DEVICE"
- EXTRA_ASSOCIATION = "android.companion.extra.ASSOCIATION"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._associations: Dict[str, "AssociationInfo"] = {}
- self._callbacks: List[Callable] = []
-
- def associate(
- self,
- request: Any,
- callback: "CompanionDeviceManager.Callback",
- handler: Any = None,
- ):
- """发起设备关联请求"""
- raise AndroidOnlyError("CompanionDeviceManager.associate() 仅在 Android 设备上可用")
-
- def associateCallback(
- self,
- request: Any,
- callback: Callable,
- executor: Any = None,
- ):
- """使用回调方式发起设备关联"""
- raise AndroidOnlyError("CompanionDeviceManager.associateCallback() 仅在 Android 设备上可用")
-
- def requestNotificationAccess(self, pairingDevice: "AssociationInfo"):
- """请求通知访问权限"""
- raise AndroidOnlyError("CompanionDeviceManager.requestNotificationAccess() 仅在 Android 设备上可用")
-
- def requestSystemAppStore(self, pairingDevice: "AssociationInfo"):
- """请求系统应用商店"""
- pass
-
- def startObservingDevicePresence(self, deviceAddress: str):
- """开始监听设备存在"""
- pass
-
- def stopObservingDevicePresence(self, deviceAddress: str):
- """停止监听设备存在"""
- pass
-
- def isDeviceAssociated(self, deviceAddress: str) -> bool:
- """检查设备是否已关联"""
- return deviceAddress in self._associations
-
- def getDeviceId(self, deviceAddress: str) -> Optional[str]:
- """获取设备 ID"""
- info = self._associations.get(deviceAddress)
- return info.getSelfManagedDeviceId() if info else None
-
- def getAssociations(self) -> List["AssociationInfo"]:
- """获取所有关联信息"""
- return list(self._associations.values())
-
- def removeAssociation(self, deviceAddress: str):
- """移除设备关联"""
- self._associations.pop(deviceAddress, None)
-
- # ═══════════════════════════════════════════════════════════
- # Callback - 回调类
- # ═══════════════════════════════════════════════════════════
-
- class Callback(Stub):
- """CompanionDeviceManager.Callback — 设备发现回调"""
-
- def __init__(self):
- super().__init__()
-
- def onDeviceFound(self, intent: Any):
- """设备找到回调"""
- pass
-
- def onFailure(self, error: str):
- """设备发现失败回调"""
- pass
-
- def toString(self) -> str:
- return f"Callback@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"CompanionDeviceManager(associations={len(self._associations)})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AssociationInfo
-# ═══════════════════════════════════════════════════════════════
-
-class AssociationInfo(Stub):
- """AssociationInfo — 设备关联信息"""
-
- def __init__(
- self,
- userId: int = 0,
- deviceProfile: str = "",
- selfManagedDeviceId: str = "",
- associatedDevice: Any = None,
- isSelfManaged: bool = False,
- isNotAssociated: bool = False,
- ):
- super().__init__()
- self._user_id = userId
- self._device_profile = deviceProfile
- self._self_managed_device_id = selfManagedDeviceId
- self._associated_device = associatedDevice
- self._self_managed = isSelfManaged
- self._not_associated = isNotAssociated
-
- def getUserId(self) -> int:
- return self._user_id
-
- def getDeviceProfile(self) -> str:
- return self._device_profile
-
- def getSelfManagedDeviceId(self) -> str:
- return self._self_managed_device_id
-
- def getAssociatedDevice(self) -> Optional[Any]:
- return self._associated_device
-
- def isSelfManaged(self) -> bool:
- return self._self_managed
-
- def isNotAssociated(self) -> bool:
- return self._not_associated
-
- def toString(self) -> str:
- return (f"AssociationInfo(deviceId={self._self_managed_device_id}, "
- f"profile={self._device_profile})")
-
- def equals(self, other) -> bool:
- if not isinstance(other, AssociationInfo):
- return False
- return self._self_managed_device_id == other._self_managed_device_id
-
- def hashCode(self) -> int:
- return hash(self._self_managed_device_id) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiDeviceFilter
-# ═══════════════════════════════════════════════════════════════
-
-class WifiDeviceFilter(Stub):
- """WifiDeviceFilter — WiFi 设备过滤器"""
-
- def __init__(self, namePattern: str = ""):
- super().__init__()
- self._name_pattern = namePattern
-
- def getNamePattern(self) -> str:
- return self._name_pattern
-
- def toString(self) -> str:
- return f"WifiDeviceFilter(pattern={self._name_pattern})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, WifiDeviceFilter):
- return False
- return self._name_pattern == other._name_pattern
-
- def hashCode(self) -> int:
- return hash(self._name_pattern) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothDeviceFilter
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothDeviceFilter(Stub):
- """BluetoothDeviceFilter — 蓝牙设备过滤器"""
-
- class Builder(Stub):
- """BluetoothDeviceFilter.Builder — 蓝牙过滤器构建器"""
-
- def __init__(self):
- super().__init__()
- self._name_pattern = ""
- self._address = ""
-
- def setNamePattern(self, pattern: str) -> "BluetoothDeviceFilter.Builder":
- self._name_pattern = pattern
- return self
-
- def setAddress(self, address: str) -> "BluetoothDeviceFilter.Builder":
- self._address = address
- return self
-
- def build(self) -> "BluetoothDeviceFilter":
- return BluetoothDeviceFilter(
- namePattern=self._name_pattern,
- address=self._address,
- )
-
- def toString(self) -> str:
- return f"Builder(pattern={self._name_pattern})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self, namePattern: str = "", address: str = ""):
- super().__init__()
- self._name_pattern = namePattern
- self._address = address
-
- def getNamePattern(self) -> str:
- return self._name_pattern
-
- def getAddress(self) -> str:
- return self._address
-
- def toString(self) -> str:
- return f"BluetoothDeviceFilter(address={self._address})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, BluetoothDeviceFilter):
- return False
- return self._address == other._address
-
- def hashCode(self) -> int:
- return hash(self._address) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# BluetoothLeDeviceFilter
-# ═══════════════════════════════════════════════════════════════
-
-class BluetoothLeDeviceFilter(Stub):
- """BluetoothLeDeviceFilter — BLE 设备过滤器"""
-
- class Builder(Stub):
- """BluetoothLeDeviceFilter.Builder — BLE 过滤器构建器"""
-
- def __init__(self):
- super().__init__()
- self._name_pattern = ""
- self._scan_filter = None
-
- def setNamePattern(self, pattern: str) -> "BluetoothLeDeviceFilter.Builder":
- self._name_pattern = pattern
- return self
-
- def setScanFilter(self, scanFilter: Any) -> "BluetoothLeDeviceFilter.Builder":
- self._scan_filter = scanFilter
- return self
-
- def build(self) -> "BluetoothLeDeviceFilter":
- return BluetoothLeDeviceFilter(
- namePattern=self._name_pattern,
- scanFilter=self._scan_filter,
- )
-
- def toString(self) -> str:
- return f"BLEBuilder(pattern={self._name_pattern})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self, namePattern: str = "", scanFilter: Any = None):
- super().__init__()
- self._name_pattern = namePattern
- self._scan_filter = scanFilter
-
- def getNamePattern(self) -> str:
- return self._name_pattern
-
- def getScanFilter(self) -> Optional[Any]:
- return self._scan_filter
-
- def toString(self) -> str:
- return f"BluetoothLeDeviceFilter(pattern={self._name_pattern})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, BluetoothLeDeviceFilter):
- return False
- return self._name_pattern == other._name_pattern
-
- def hashCode(self) -> int:
- return hash(self._name_pattern) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CommsDevice
-# ═══════════════════════════════════════════════════════════════
-
-class CommsDevice(Stub):
- """CommsDevice — 通信设备信息"""
-
- def __init__(self, deviceId: str = "", displayName: str = ""):
- super().__init__()
- self._device_id = deviceId
- self._display_name = displayName
-
- def getDeviceId(self) -> str:
- return self._device_id
-
- def getDisplayName(self) -> str:
- return self._display_name
-
- def toString(self) -> str:
- return f"CommsDevice(id={self._device_id}, name={self._display_name})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, CommsDevice):
- return False
- return self._device_id == other._device_id
-
- def hashCode(self) -> int:
- return hash(self._device_id) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# DeviceActivityCallback
-# ═══════════════════════════════════════════════════════════════
-
-class DeviceActivityCallback(Stub):
- """DeviceActivityCallback — 设备活动回调"""
-
- def __init__(self):
- super().__init__()
-
- def onDeviceActivityChanged(self, associationInfo: "AssociationInfo", active: bool):
- """设备活动状态变更回调"""
- pass
-
- def toString(self) -> str:
- return f"DeviceActivityCallback@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionService
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionService(Stub):
- """CompanionService — 配套服务"""
-
- SERVICE_INTERFACE = "android.companion.CompanionDeviceService"
-
- def __init__(self):
- super().__init__()
-
- def onConnected(self, deviceInfo: Any):
- """已连接回调"""
- pass
-
- def onDisconnected(self, deviceInfo: Any):
- """已断开回调"""
- pass
-
- def toString(self) -> str:
- return f"CompanionService@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/companion_ext.py b/android_pyapi/android/companion_ext.py
deleted file mode 100644
index 21ee6fd..0000000
--- a/android_pyapi/android/companion_ext.py
+++ /dev/null
@@ -1,716 +0,0 @@
-"""
-Android Companion Device API 扩展 — CompanionDeviceManager (扩展),
-AssociationRequest, DeviceFilter, DevicePresenceEvent,
-CompanionTransport, CompanionWireless, CompanionManager 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "CompanionDeviceManager",
- "AssociationRequest",
- "DeviceFilter",
- "DevicePresenceEvent",
- "DevicePresenceNotifier",
- "CompanionTransport",
- "CompanionWireless",
- "CompanionBluetooth",
- "CompanionWifi",
- "CompanionEthernet",
- "CompanionVendor",
- "CompanionManager",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-DEVICE_PRESENCE_ENTER = 0
-DEVICE_PRESENCE_EXIT = 1
-DEVICE_PRESENCE_PROXIMITY_NEAR = 2
-DEVICE_PRESENCE_PROXIMITY_FAR = 3
-DEVICE_PRESENCE_APPEAR = 4
-DEVICE_PRESENCE_DISAPPEAR = 5
-DEVICE_PRESENCE_AVAILABLE = 6
-DEVICE_PRESENCE_UNAVAILABLE = 7
-
-DEVICE_FLAG_NONE = 0
-DEVICE_FLAG_SELF_MANAGED = 1
-DEVICE_FLAG_NOT_ASSOCIATED = 2
-DEVICE_FLAG_SYSTEM_SERVICE = 4
-DEVICE_FLAG_DEBUG_ONLY = 8
-DEVICE_FLAG_VENDOR_SPECIFIC = 16
-
-COMPANION_TRANSPORT_BLUETOOTH = 0
-COMPANION_TRANSPORT_BLUETOOTH_LE = 1
-COMPANION_TRANSPORT_WIFI = 2
-COMPANION_TRANSPORT_ETHERNET = 3
-COMPANION_TRANSPORT_USB = 4
-COMPANION_TRANSPORT_NFC = 5
-COMPANION_TRANSPORT_VENDOR = 100
-
-ASSOCIATION_PENDING = 0
-ASSOCIATION_ESTABLISHED = 1
-ASSOCIATION_FAILED = 2
-ASSOCIATION_CANCELLED = 3
-ASSOCIATION_REVOKED = 4
-
-
-# ═══════════════════════════════════════════════════════════════
-# DeviceFilter
-# ═══════════════════════════════════════════════════════════════
-
-class DeviceFilter(Stub):
- """DeviceFilter — 设备过滤器基类"""
-
- def __init__(self, namePattern: str = "", address: str = "",
- isSelfManaged: bool = False):
- super().__init__()
- self._name_pattern = namePattern
- self._address = address
- self._is_self_managed = isSelfManaged
-
- def getNamePattern(self) -> str:
- return self._name_pattern
-
- def getAddress(self) -> str:
- return self._address
-
- def isSelfManaged(self) -> bool:
- return self._is_self_managed
-
- def matches(self, device: Any) -> bool:
- return True
-
- def toString(self) -> str:
- return f"DeviceFilter(pattern={self._name_pattern})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, DeviceFilter):
- return False
- return self._address == other._address
-
- def hashCode(self) -> int:
- return hash(self._address) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AssociationRequest
-# ═══════════════════════════════════════════════════════════════
-
-class AssociationRequest(Stub):
- """AssociationRequest — 关联请求"""
-
- def __init__(self, isSelfManaged: bool = False,
- deviceFilter: Optional[DeviceFilter] = None,
- displayName: str = "",
- transportTypes: List[int] = None,
- flags: int = DEVICE_FLAG_NONE,
- profile: str = ""):
- super().__init__()
- self._is_self_managed = isSelfManaged
- self._device_filter = deviceFilter
- self._display_name = displayName
- self._transport_types = transportTypes or []
- self._flags = flags
- self._profile = profile
-
- def isSelfManaged(self) -> bool:
- return self._is_self_managed
-
- def getDeviceFilter(self) -> Optional[DeviceFilter]:
- return self._device_filter
-
- def getDisplayName(self) -> str:
- return self._display_name
-
- def getTransportTypes(self) -> List[int]:
- return list(self._transport_types)
-
- def getFlags(self) -> int:
- return self._flags
-
- def getProfile(self) -> str:
- return self._profile
-
- class Builder(Stub):
- """AssociationRequest.Builder — 关联请求构建器"""
-
- def __init__(self):
- super().__init__()
- self._is_self_managed = False
- self._device_filter: Optional[DeviceFilter] = None
- self._display_name = ""
- self._transport_types: List[int] = []
- self._flags = DEVICE_FLAG_NONE
- self._profile = ""
-
- def setSelfManaged(self, selfManaged: bool) -> "AssociationRequest.Builder":
- self._is_self_managed = selfManaged
- return self
-
- def setDeviceFilter(self, filter_: DeviceFilter) -> "AssociationRequest.Builder":
- self._device_filter = filter_
- return self
-
- def setDisplayName(self, name: str) -> "AssociationRequest.Builder":
- self._display_name = name
- return self
-
- def addTransportType(self, transportType: int) -> "AssociationRequest.Builder":
- if transportType not in self._transport_types:
- self._transport_types.append(transportType)
- return self
-
- def setFlags(self, flags: int) -> "AssociationRequest.Builder":
- self._flags = flags
- return self
-
- def setProfile(self, profile: str) -> "AssociationRequest.Builder":
- self._profile = profile
- return self
-
- def build(self) -> "AssociationRequest":
- return AssociationRequest(
- isSelfManaged=self._is_self_managed,
- deviceFilter=self._device_filter,
- displayName=self._display_name,
- transportTypes=self._transport_types,
- flags=self._flags,
- profile=self._profile,
- )
-
- def toString(self) -> str:
- return (f"AssociationRequest(selfManaged={self._is_self_managed}, "
- f"name={self._display_name})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AssociationRequest):
- return False
- return (self._is_self_managed == other._is_self_managed and
- self._display_name == other._display_name)
-
- def hashCode(self) -> int:
- return hash((self._is_self_managed, self._display_name)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# DevicePresenceEvent
-# ═══════════════════════════════════════════════════════════════
-
-class DevicePresenceEvent(Stub):
- """DevicePresenceEvent — 设备存在事件"""
-
- def __init__(self, deviceAddress: str = "",
- eventType: int = DEVICE_PRESENCE_ENTER,
- timestamp: int = 0,
- rssi: int = 0, transportType: int = COMPANION_TRANSPORT_BLUETOOTH,
- deviceId: str = ""):
- super().__init__()
- self._device_address = deviceAddress
- self._event_type = eventType
- self._timestamp = timestamp
- self._rssi = rssi
- self._transport_type = transportType
- self._device_id = deviceId
-
- def getDeviceAddress(self) -> str:
- return self._device_address
-
- def getEventType(self) -> int:
- return self._event_type
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def getRssi(self) -> int:
- return self._rssi
-
- def getTransportType(self) -> int:
- return self._transport_type
-
- def getDeviceId(self) -> str:
- return self._device_id
-
- def toString(self) -> str:
- return (f"DevicePresenceEvent(addr={self._device_address}, "
- f"type={self._event_type})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, DevicePresenceEvent):
- return False
- return (self._device_address == other._device_address and
- self._event_type == other._event_type)
-
- def hashCode(self) -> int:
- return hash((self._device_address, self._event_type)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# DevicePresenceNotifier
-# ═══════════════════════════════════════════════════════════════
-
-class DevicePresenceNotifier(Stub):
- """DevicePresenceNotifier — 设备存在通知器"""
-
- def __init__(self):
- super().__init__()
- self._listeners: Dict[int, Callable] = {}
-
- def registerCallback(self, callback: Callable, handler: Any = None):
- lid = id(callback)
- self._listeners[lid] = callback
-
- def unregisterCallback(self, callback: Callable):
- lid = id(callback)
- self._listeners.pop(lid, None)
-
- def notifyPresence(self, event: DevicePresenceEvent):
- for cb in self._listeners.values():
- try:
- cb(event)
- except Exception:
- pass
-
- def toString(self) -> str:
- return f"DevicePresenceNotifier(listeners={len(self._listeners)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionTransport
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionTransport(Stub):
- """CompanionTransport — 配套设备传输基类"""
-
- def __init__(self, transportType: int = COMPANION_TRANSPORT_BLUETOOTH,
- name: str = ""):
- super().__init__()
- self._transport_type = transportType
- self._name = name
-
- def getTransportType(self) -> int:
- return self._transport_type
-
- def getName(self) -> str:
- return self._name
-
- def isAvailable(self) -> bool:
- return True
-
- def isEnabled(self) -> bool:
- return True
-
- def enable(self):
- pass
-
- def disable(self):
- pass
-
- def toString(self) -> str:
- return f"CompanionTransport(type={self._transport_type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionWireless (WiFi 传输)
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionWireless(CompanionTransport):
- """CompanionWireless — 无线传输 (WiFi Direct / WiFi Aware)"""
-
- SECURITY_NONE = 0
- SECURITY_WPA2 = 1
- SECURITY_WPA3 = 2
- SECURITY_WPA2_WPA3 = 3
-
- def __init__(self, ssid: str = "", bssid: str = "",
- frequency: int = 0, securityType: int = SECURITY_WPA2):
- super().__init__(transportType=COMPANION_TRANSPORT_WIFI, name="Wifi")
- self._ssid = ssid
- self._bssid = bssid
- self._frequency = frequency
- self._security_type = securityType
-
- def getSsid(self) -> str:
- return self._ssid
-
- def getBssid(self) -> str:
- return self._bssid
-
- def getFrequency(self) -> int:
- return self._frequency
-
- def getSecurityType(self) -> int:
- return self._security_type
-
- def toString(self) -> str:
- return f"CompanionWireless(ssid={self._ssid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionBluetooth
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionBluetooth(CompanionTransport):
- """CompanionBluetooth — 蓝牙传输"""
-
- TRANSPORT_BREDR = 0
- TRANSPORT_LE = 1
- TRANSPORT_DUAL = 2
-
- def __init__(self, address: str = "", name: str = "",
- transport: int = TRANSPORT_BREDR,
- isBonded: bool = False):
- super().__init__(transportType=COMPANION_TRANSPORT_BLUETOOTH, name="Bluetooth")
- self._address = address
- self._device_name = name
- self._transport = transport
- self._is_bonded = isBonded
-
- def getAddress(self) -> str:
- return self._address
-
- def getDeviceName(self) -> str:
- return self._device_name
-
- def getTransportMode(self) -> int:
- return self._transport
-
- def isBonded(self) -> bool:
- return self._is_bonded
-
- def toString(self) -> str:
- return f"CompanionBluetooth(addr={self._address}, name={self._device_name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionWifi
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionWifi(CompanionTransport):
- """CompanionWifi — WiFi 传输"""
-
- def __init__(self, ssid: str = "", bssid: str = "",
- ipAddress: str = "", port: int = 0,
- isDirect: bool = False, isAware: bool = False):
- super().__init__(transportType=COMPANION_TRANSPORT_WIFI, name="WiFi")
- self._ssid = ssid
- self._bssid = bssid
- self._ip_address = ipAddress
- self._port = port
- self._is_direct = isDirect
- self._is_aware = isAware
-
- def getSsid(self) -> str:
- return self._ssid
-
- def getBssid(self) -> str:
- return self._bssid
-
- def getIpAddress(self) -> str:
- return self._ip_address
-
- def getPort(self) -> int:
- return self._port
-
- def isDirect(self) -> bool:
- return self._is_direct
-
- def isAware(self) -> bool:
- return self._is_aware
-
- def toString(self) -> str:
- return f"CompanionWifi(ssid={self._ssid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionEthernet
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionEthernet(CompanionTransport):
- """CompanionEthernet — 以太网传输"""
-
- def __init__(self, interfaceName: str = "", macAddress: str = "",
- ipAddress: str = "", linkSpeed: int = 1000):
- super().__init__(transportType=COMPANION_TRANSPORT_ETHERNET, name="Ethernet")
- self._interface_name = interfaceName
- self._mac_address = macAddress
- self._ip_address = ipAddress
- self._link_speed = linkSpeed
-
- def getInterfaceName(self) -> str:
- return self._interface_name
-
- def getMacAddress(self) -> str:
- return self._mac_address
-
- def getIpAddress(self) -> str:
- return self._ip_address
-
- def getLinkSpeed(self) -> int:
- return self._link_speed
-
- def toString(self) -> str:
- return f"CompanionEthernet(iface={self._interface_name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionVendor
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionVendor(CompanionTransport):
- """CompanionVendor — 厂商自定义传输"""
-
- class RfcommEndpoint(Stub):
- """CompanionVendor.RfcommEndpoint — RFCOMM 端点"""
-
- def __init__(self, address: str = "", channel: int = 0,
- uuid: str = "", name: str = ""):
- super().__init__()
- self._address = address
- self._channel = channel
- self._uuid = uuid
- self._name = name
-
- def getAddress(self) -> str:
- return self._address
-
- def getChannel(self) -> int:
- return self._channel
-
- def getUuid(self) -> str:
- return self._uuid
-
- def getName(self) -> str:
- return self._name
-
- def toString(self) -> str:
- return f"RfcommEndpoint(addr={self._address}, channel={self._channel})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, CompanionVendor.RfcommEndpoint):
- return False
- return self._address == other._address and self._channel == other._channel
-
- def hashCode(self) -> int:
- return hash((self._address, self._channel)) & 0x7FFFFFFF
-
- class Transport(Stub):
- """CompanionVendor.Transport — 厂商传输层"""
-
- def __init__(self, name: str = "", vendorId: str = "",
- version: int = 1, endpoints: List["CompanionVendor.RfcommEndpoint"] = None):
- super().__init__()
- self._name = name
- self._vendor_id = vendorId
- self._version = version
- self._endpoints = endpoints or []
-
- def getName(self) -> str:
- return self._name
-
- def getVendorId(self) -> str:
- return self._vendor_id
-
- def getVersion(self) -> int:
- return self._version
-
- def getEndpoints(self) -> List["CompanionVendor.RfcommEndpoint"]:
- return list(self._endpoints)
-
- def addEndpoint(self, endpoint: "CompanionVendor.RfcommEndpoint"):
- self._endpoints.append(endpoint)
-
- def __init__(self, vendorName: str = "", vendorId: str = "",
- protocolVersion: int = 1,
- endpoints: List[RfcommEndpoint] = None,
- transport: Optional["CompanionVendor.Transport"] = None):
- super().__init__(transportType=COMPANION_TRANSPORT_VENDOR, name=vendorName)
- self._vendor_id = vendorId
- self._protocol_version = protocolVersion
- self._endpoints = endpoints or []
- self._transport_layer = transport
-
- def getVendorId(self) -> str:
- return self._vendor_id
-
- def getProtocolVersion(self) -> int:
- return self._protocol_version
-
- def getEndpoints(self) -> List["CompanionVendor.RfcommEndpoint"]:
- return list(self._endpoints)
-
- def getTransportLayer(self) -> Optional["CompanionVendor.Transport"]:
- return self._transport_layer
-
- def toString(self) -> str:
- return f"CompanionVendor(name={self._name}, vendorId={self._vendor_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionManager
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionManager(Stub):
- """CompanionManager — 配套设备管理器"""
-
- def __init__(self):
- super().__init__()
- self._associations: Dict[str, AssociationRequest] = {}
- self._transports: Dict[int, CompanionTransport] = {}
- self._presence_notifier = DevicePresenceNotifier()
- self._callbacks: Dict[int, Callable] = {}
-
- def associate(self, request: AssociationRequest, callback: Callable,
- handler: Any = None):
- raise AndroidOnlyError("CompanionManager.associate() is not available on desktop")
-
- def associateCallback(self, request: AssociationRequest, callback: Callable,
- executor: Any = None):
- raise AndroidOnlyError("CompanionManager.associateCallback() is not available on desktop")
-
- def revokeAssociation(self, deviceAddress: str):
- self._associations.pop(deviceAddress, None)
-
- def getAssociations(self) -> List[AssociationRequest]:
- return list(self._associations.values())
-
- def isDeviceAssociated(self, deviceAddress: str) -> bool:
- return deviceAddress in self._associations
-
- def registerTransport(self, transport: CompanionTransport):
- self._transports[transport.getTransportType()] = transport
-
- def unregisterTransport(self, transport: CompanionTransport):
- self._transports.pop(transport.getTransportType(), None)
-
- def getTransport(self, transportType: int) -> Optional[CompanionTransport]:
- return self._transports.get(transportType)
-
- def getPresenceNotifier(self) -> DevicePresenceNotifier:
- return self._presence_notifier
-
- def registerDevicePresenceCallback(self, callback: Callable):
- self._presence_notifier.registerCallback(callback)
-
- def unregisterDevicePresenceCallback(self, callback: Callable):
- self._presence_notifier.unregisterCallback(callback)
-
- def startObservingDevicePresence(self, deviceAddress: str):
- pass
-
- def stopObservingDevicePresence(self, deviceAddress: str):
- pass
-
- def toString(self) -> str:
- return (f"CompanionManager(associations={len(self._associations)}, "
- f"transports={len(self._transports)})")
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompanionDeviceManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class CompanionDeviceManager(Stub):
- """CompanionDeviceManager — 配套设备管理器 (扩展)"""
-
- EXTRA_DEVICE = "android.companion.extra.DEVICE"
- EXTRA_ASSOCIATION = "android.companion.extra.ASSOCIATION"
- EXTRA_EVENT = "android.companion.extra.EVENT"
- EXTRA_EVENT_TYPE = "android.companion.extra.EVENT_TYPE"
-
- FLAG_SELF_MANAGED = DEVICE_FLAG_SELF_MANAGED
- FLAG_NOT_ASSOCIATED = DEVICE_FLAG_NOT_ASSOCIATED
-
- def __init__(self):
- super().__init__()
- self._manager = CompanionManager()
-
- def associate(self, request: AssociationRequest, callback: Callable,
- handler: Any = None):
- raise AndroidOnlyError("CompanionDeviceManager.associate() is not available on desktop")
-
- def associateCallback(self, request: AssociationRequest, callback: Callable,
- executor: Any = None):
- raise AndroidOnlyError("CompanionDeviceManager.associateCallback() is not available on desktop")
-
- def requestNotificationAccess(self, pairingDevice: Any):
- raise AndroidOnlyError("CompanionDeviceManager.requestNotificationAccess() is not available on desktop")
-
- def requestSystemAppStore(self, pairingDevice: Any):
- pass
-
- def startObservingDevicePresence(self, deviceAddress: str):
- self._manager.startObservingDevicePresence(deviceAddress)
-
- def stopObservingDevicePresence(self, deviceAddress: str):
- self._manager.stopObservingDevicePresence(deviceAddress)
-
- def isDeviceAssociated(self, deviceAddress: str) -> bool:
- return self._manager.isDeviceAssociated(deviceAddress)
-
- def getDeviceId(self, deviceAddress: str) -> Optional[str]:
- return deviceAddress
-
- def getAssociations(self) -> List[Any]:
- return self._manager.getAssociations()
-
- def removeAssociation(self, deviceAddress: str):
- self._manager.revokeAssociation(deviceAddress)
-
- def registerDevicePresenceCallback(self, callback: Callable):
- self._manager.registerDevicePresenceCallback(callback)
-
- def unregisterDevicePresenceCallback(self, callback: Callable):
- self._manager.unregisterDevicePresenceCallback(callback)
-
- def getCompanionManager(self) -> CompanionManager:
- return self._manager
-
- class Callback(Stub):
- """CompanionDeviceManager.Callback — 设备发现回调"""
-
- def onDeviceFound(self, intent: Any):
- pass
-
- def onFailure(self, error: str):
- pass
-
- def toString(self) -> str:
- return f"Callback@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"CompanionDeviceManager(mgr={self._manager})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/content.py b/android_pyapi/android/content.py
deleted file mode 100644
index c3d3df7..0000000
--- a/android_pyapi/android/content.py
+++ /dev/null
@@ -1,2054 +0,0 @@
-"""
-Android Content 组件 — Context, ContentResolver, Uri, SharedPreferences 等
-方法签名完全对齐 Android SDK
-"""
-
-import json
-import mimetypes
-import os
-import sys
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-from urllib.parse import urlparse, urlunparse, urlencode, parse_qs, quote, unquote
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-try:
- from .._linux_impl import IS_LINUX, LinuxClipboard, LinuxNotify, LinuxLocation, LinuxProcess
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Uri
-# ═══════════════════════════════════════════════════════════════
-
-class Uri(Stub):
- """Android Uri — 统一资源标识符"""
-
- def __init__(self, scheme: str = "", authority: str = "", path: str = "",
- query: str = "", fragment: str = "", host: str = "", port: int = -1,
- ssp: str = "", user_info: str = ""):
- super().__init__()
- self._scheme = scheme
- self._authority = authority
- self._path = path
- self._query = query
- self._fragment = fragment
- self._host = host
- self._port = port
- self._ssp = ssp
- self._user_info = user_info
- self._opaque = bool(ssp)
- self._cached_string: Optional[str] = None
-
- @staticmethod
- def parse(uri_string: str) -> "Uri":
- parsed = urlparse(uri_string)
- host = parsed.hostname or ""
- port = parsed.port or -1
- return Uri(
- scheme=parsed.scheme,
- authority=parsed.netloc,
- path=parsed.path,
- query=parsed.query,
- fragment=parsed.fragment,
- host=host,
- port=port,
- user_info=parsed.username or "",
- )
-
- @staticmethod
- def fromParts(scheme: str, ssp: str, fragment: str) -> "Uri":
- uri = Uri(scheme=scheme, ssp=ssp, fragment=fragment)
- uri._opaque = True
- return uri
-
- @staticmethod
- def withAppendedPath(base_uri: "Uri", path_segment: str) -> "Uri":
- new_path = base_uri._path.rstrip("/") + "/" + path_segment
- return Uri(
- scheme=base_uri._scheme,
- authority=base_uri._authority,
- path=new_path,
- query=base_uri._query,
- fragment=base_uri._fragment,
- host=base_uri._host,
- port=base_uri._port,
- )
-
- @staticmethod
- def encode(s: str) -> str:
- return quote(s, safe=":/?#[]@!$&'()*+,;=-._~")
-
- @staticmethod
- def decode(s: str) -> str:
- return unquote(s)
-
- def buildUpon(self) -> "Uri.Builder":
- b = Uri.Builder()
- b._scheme = self._scheme
- b._authority = self._authority
- b._path = self._path
- b._query = self._query
- b._fragment = self._fragment
- return b
-
- def getScheme(self) -> Optional[str]:
- return self._scheme or None
-
- def getAuthority(self) -> Optional[str]:
- return self._authority or None
-
- def getPath(self) -> Optional[str]:
- return self._path or None
-
- def getQuery(self) -> Optional[str]:
- return self._query or None
-
- def getFragment(self) -> Optional[str]:
- return self._fragment or None
-
- def getHost(self) -> Optional[str]:
- return self._host or None
-
- def getPort(self) -> int:
- return self._port
-
- def getPathSegments(self) -> List[str]:
- return [s for s in self._path.split("/") if s] if self._path else []
-
- def getLastPathSegment(self) -> Optional[str]:
- segments = self.getPathSegments()
- return segments[-1] if segments else None
-
- def getUserInfo(self) -> Optional[str]:
- return self._user_info or None
-
- def isAbsolute(self) -> bool:
- return bool(self._scheme)
-
- def isOpaque(self) -> bool:
- return self._opaque
-
- def isHierarchical(self) -> bool:
- return not self._opaque
-
- def getSchemeSpecificPart(self) -> Optional[str]:
- return self._ssp or None
-
- def normalizeScheme(self) -> "Uri":
- if self._scheme:
- self._scheme = self._scheme.lower()
- return self
-
- def toString(self) -> str:
- if self._cached_string is not None:
- return self._cached_string
- if self._opaque and self._ssp:
- result = f"{self._scheme}:{self._ssp}"
- if self._fragment:
- result += f"#{self._fragment}"
- else:
- parts = []
- if self._scheme:
- parts.append(f"{self._scheme}:")
- if self._authority:
- parts.append(f"//{self._authority}")
- if self._path:
- parts.append(self._path)
- if self._query:
- parts.append(f"?{self._query}")
- if self._fragment:
- parts.append(f"#{self._fragment}")
- result = "".join(parts)
- self._cached_string = result
- return result
-
- def __repr__(self):
- return self.toString()
-
- def __str__(self):
- return self.toString()
-
- def __eq__(self, other):
- if isinstance(other, Uri):
- return self.toString() == other.toString()
- return NotImplemented
-
- def __hash__(self):
- return hash(self.toString())
-
- class Builder(Stub):
- """Uri builder pattern"""
-
- def __init__(self):
- super().__init__()
- self._scheme = ""
- self._authority = ""
- self._path = ""
- self._query = ""
- self._fragment = ""
- self._host = ""
- self._port = -1
- self._segments: List[str] = []
-
- def scheme(self, scheme: str) -> "Uri.Builder":
- self._scheme = scheme
- return self
-
- def authority(self, authority: str) -> "Uri.Builder":
- self._authority = authority
- return self
-
- def path(self, path: str) -> "Uri.Builder":
- self._path = path
- return self
-
- def appendPath(self, new_segment: str) -> "Uri.Builder":
- self._segments.append(new_segment)
- return self
-
- def query(self, query: str) -> "Uri.Builder":
- self._query = query
- return self
-
- def appendQueryParameter(self, key: str, value: str) -> "Uri.Builder":
- params = dict(parse_qs(self._query, keep_blank_values=True)) if self._query else {}
- if key in params:
- params[key].append(value)
- else:
- params[key] = [value]
- self._query = urlencode(params, doseq=True)
- return self
-
- def fragment(self, fragment: str) -> "Uri.Builder":
- self._fragment = fragment
- return self
-
- def opaquePart(self, opaque_part: str) -> "Uri.Builder":
- return self
-
- def build(self) -> "Uri":
- path = self._path
- if self._segments:
- path = (path.rstrip("/") if path else "") + "/" + "/".join(self._segments)
- return Uri(self._scheme, self._authority, path, self._query, self._fragment)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContentValues
-# ═══════════════════════════════════════════════════════════════
-
-class ContentValues(Stub):
- """ContentValues — 类似 dict 的内容值容器"""
-
- def __init__(self, from_dict: Optional[Dict[str, Any]] = None):
- super().__init__()
- self._values: Dict[str, Any] = dict(from_dict) if from_dict else {}
-
- def put(self, key: str, value: Any):
- self._values[key] = value
-
- def putNull(self, key: str):
- self._values[key] = None
-
- def get(self, key: str) -> Optional[Any]:
- return self._values.get(key)
-
- def getAsString(self, key: str) -> Optional[str]:
- v = self._values.get(key)
- return str(v) if v is not None else None
-
- def getAsInteger(self, key: str) -> Optional[int]:
- v = self._values.get(key)
- if v is None:
- return None
- try:
- return int(v)
- except (ValueError, TypeError):
- return None
-
- def getAsLong(self, key: str) -> Optional[int]:
- return self.getAsInteger(key)
-
- def getAsFloat(self, key: str) -> Optional[float]:
- v = self._values.get(key)
- if v is None:
- return None
- try:
- return float(v)
- except (ValueError, TypeError):
- return None
-
- def getAsDouble(self, key: str) -> Optional[float]:
- return self.getAsFloat(key)
-
- def getAsBoolean(self, key: str) -> Optional[bool]:
- v = self._values.get(key)
- if v is None:
- return None
- if isinstance(v, bool):
- return v
- if isinstance(v, str):
- return v.lower() in ("true", "1", "yes", "y")
- return bool(v)
-
- def getAsByteArray(self, key: str) -> Optional[bytes]:
- v = self._values.get(key)
- if isinstance(v, bytes):
- return v
- if isinstance(v, str):
- return v.encode("utf-8")
- return None
-
- def containsKey(self, key: str) -> bool:
- return key in self._values
-
- def valueSet(self) -> Set[str]:
- return set(self._values.keys())
-
- def keySet(self) -> Set[str]:
- return set(self._values.keys())
-
- def size(self) -> int:
- return len(self._values)
-
- def isEmpty(self) -> bool:
- return len(self._values) == 0
-
- def clear(self):
- self._values.clear()
-
- def remove(self, key: str):
- self._values.pop(key, None)
-
- def putAll(self, other: "ContentValues"):
- if other:
- self._values.update(other._values)
-
- def equals(self, other) -> bool:
- if isinstance(other, ContentValues):
- return self._values == other._values
- return False
-
- def hashCode(self) -> int:
- return hash(frozenset(self._values.items())) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"ContentValues({self._values})"
-
- def __getitem__(self, key: str):
- return self._values[key]
-
- def __setitem__(self, key: str, value: Any):
- self._values[key] = value
-
- def __contains__(self, key: str) -> bool:
- return key in self._values
-
- def __len__(self) -> int:
- return len(self._values)
-
- def __repr__(self):
- return self.toString()
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContentResolver
-# ═══════════════════════════════════════════════════════════════
-
-class ContentResolver(Stub):
- """ContentResolver — 内容解析器"""
-
- NOTIFY_SYNC_TO_NETWORK = 1
- NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2
-
- def __init__(self):
- super().__init__()
- self._observers: Dict[str, List[Any]] = {}
-
- @staticmethod
- def _uri_to_file_path(uri) -> Optional[str]:
- """将 file:// 或纯路径 Uri 转换为本地文件系统路径"""
- try:
- uri_str = str(uri)
- except Exception:
- return None
- # 处理字符串输入
- if isinstance(uri, str):
- if uri.startswith("file://"):
- return uri[7:]
- if "://" not in uri:
- return uri if uri else None
- return None
- scheme = getattr(uri, "_scheme", "") or ""
- path = getattr(uri, "_path", "") or ""
- if scheme == "file":
- return path if path else None
- if scheme == "" and path:
- return path
- return None
-
- def query(self, uri: Uri, projection: Optional[List[str]], selection: Optional[str],
- selection_args: Optional[List[str]], sort_order: Optional[str],
- cancellation_signal: Any = None) -> Any:
- """Query content provider. 对 file:// URI 返回基于目录列表的 Cursor。"""
- path = self._uri_to_file_path(uri)
- if path is not None and os.path.isdir(path):
- try:
- from .database import Cursor, MatrixCursor
- cols = projection or ["_id", "name", "size", "last_modified"]
- cursor = MatrixCursor(cols)
- for idx, name in enumerate(sorted(os.listdir(path))):
- full = os.path.join(path, name)
- try:
- st = os.stat(full)
- size = st.st_size
- mtime = int(st.st_mtime * 1000)
- except OSError:
- size = 0
- mtime = 0
- cursor.addRow([idx, name, size, mtime])
- return cursor
- except Exception:
- pass
- return None
-
- def insert(self, uri: Uri, values: ContentValues) -> Optional[Uri]:
- """Insert. 对 file:// URI 将 ContentValues 写为 JSON 文件。"""
- path = self._uri_to_file_path(uri)
- if path is not None and isinstance(values, ContentValues):
- try:
- os.makedirs(path if os.path.isdir(path) else os.path.dirname(path) or ".", exist_ok=True)
- target = path if not os.path.isdir(path) else os.path.join(path, "insert.json")
- data = values._values if hasattr(values, "_values") else {}
- with open(target, "w", encoding="utf-8") as f:
- json.dump(data, f, ensure_ascii=False, default=str)
- return Uri.withAppendedPath(uri, os.path.basename(target))
- except OSError:
- pass
- return uri
-
- def update(self, uri: Uri, values: ContentValues, selection: Optional[str],
- selection_args: Optional[List[str]]) -> int:
- """Update. 对 file:// URI 更新对应 JSON 文件。"""
- path = self._uri_to_file_path(uri)
- if path is not None and isinstance(values, ContentValues) and os.path.isfile(path):
- try:
- data = values._values if hasattr(values, "_values") else {}
- with open(path, "r", encoding="utf-8") as f:
- existing = json.load(f)
- if isinstance(existing, dict):
- existing.update(data)
- with open(path, "w", encoding="utf-8") as f:
- json.dump(existing, f, ensure_ascii=False, default=str)
- return 1
- except (OSError, ValueError):
- pass
- return 0
-
- def delete(self, uri: Uri, selection: Optional[str],
- selection_args: Optional[List[str]]) -> int:
- """Delete. 对 file:// URI 删除对应文件或目录。"""
- path = self._uri_to_file_path(uri)
- if path is not None:
- try:
- if os.path.isfile(path):
- os.remove(path)
- return 1
- if os.path.isdir(path):
- import shutil
- shutil.rmtree(path)
- return 1
- except OSError:
- pass
- return 0
-
- def applyBatch(self, authority: str, operations: List[Any]) -> List[Any]:
- """Apply batch operations, returning per-op results."""
- results: List[Any] = []
- for op in operations:
- try:
- op_type = getattr(op, "_type", None)
- uri = getattr(op, "_uri", None)
- values = getattr(op, "_values", None)
- if op_type == 1 and uri is not None: # INSERT
- results.append(ContentProviderResult(uri=self.insert(uri, values or ContentValues())))
- elif op_type == 2 and uri is not None: # UPDATE
- count = self.update(uri, values or ContentValues(),
- getattr(op, "_selection", None),
- getattr(op, "_selection_args", None))
- results.append(ContentProviderResult(count=count))
- elif op_type == 3 and uri is not None: # DELETE
- count = self.delete(uri, getattr(op, "_selection", None),
- getattr(op, "_selection_args", None))
- results.append(ContentProviderResult(count=count))
- else:
- results.append(ContentProviderResult(count=0))
- except Exception:
- results.append(ContentProviderResult(count=0))
- return results
-
- def bulkInsert(self, uri: Uri, values: List[ContentValues]) -> int:
- count = 0
- for v in values or []:
- if self.insert(uri, v) is not None:
- count += 1
- return count
-
- def call(self, uri: Uri, method: str, arg: Optional[str], extras: Optional[ContentValues]) -> Optional[ContentValues]:
- return None
-
- def notifyChange(self, uri: Uri, observer: Any, sync_to_network: bool = False):
- uri_str = str(uri)
- if uri_str in self._observers:
- for obs in list(self._observers[uri_str]):
- try:
- obs.onChange(True)
- except Exception:
- pass
-
- def registerContentObserver(self, uri: Uri, notify_for_descendants: bool, observer: Any):
- uri_str = str(uri)
- if uri_str not in self._observers:
- self._observers[uri_str] = []
- self._observers[uri_str].append(observer)
-
- def unregisterContentObserver(self, observer: Any):
- for uri_str in list(self._observers.keys()):
- if observer in self._observers[uri_str]:
- self._observers[uri_str].remove(observer)
- if not self._observers[uri_str]:
- del self._observers[uri_str]
-
- def getType(self, uri) -> Optional[str]:
- """返回 URI 指向资源的 MIME 类型。"""
- path = self._uri_to_file_path(uri)
- if path:
- mime, _ = mimetypes.guess_type(path)
- return mime or "application/octet-stream"
- scheme = getattr(uri, "_scheme", "") or ""
- if isinstance(uri, str) and "://" in uri:
- scheme = uri.split("://")[0]
- if scheme == "content":
- return "vnd.android.cursor.dir/vnd.android.content"
- return None
-
- def acquireContentProviderClient(self, uri: Uri) -> Optional["ContentProviderClient"]:
- return ContentProviderClient(uri)
-
- def acquireUnstableContentProviderClient(self, uri: Uri) -> Optional["ContentProviderClient"]:
- return ContentProviderClient(uri)
-
- def getStreamTypes(self, uri: Uri, mime_type_filter: str) -> Optional[List[str]]:
- """返回 URI 支持的流 MIME 类型列表。"""
- mime = self.getType(uri)
- if mime is None:
- return None
- if mime_type_filter and mime_type_filter.endswith("/*"):
- prefix = mime_type_filter[:-1]
- if mime.startswith(prefix):
- return [mime]
- return None
- if mime == mime_type_filter:
- return [mime]
- return [mime] if mime else None
-
- def openInputStream(self, uri: Uri) -> Any:
- """打开输入流。对 file:// URI 返回真实文件流。"""
- path = self._uri_to_file_path(uri)
- if path and os.path.isfile(path):
- try:
- return open(path, "rb")
- except OSError:
- return None
- return None
-
- def openOutputStream(self, uri: Uri) -> Any:
- """打开输出流。对 file:// URI 返回真实文件流。"""
- path = self._uri_to_file_path(uri)
- if path:
- try:
- d = os.path.dirname(path)
- if d:
- os.makedirs(d, exist_ok=True)
- return open(path, "wb")
- except OSError:
- return None
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# Context
-# ═══════════════════════════════════════════════════════════════
-
-class Context(Stub):
- """Android Context — 应用上下文"""
-
- # Service 常量
- POWER_SERVICE = "power"
- WINDOW_SERVICE = "window"
- LAYOUT_INFLATER_SERVICE = "layout_inflater"
- ACTIVITY_SERVICE = "activity"
- ALARM_SERVICE = "alarm"
- NOTIFICATION_SERVICE = "notification"
- ACCESSIBILITY_SERVICE = "accessibility"
- KEYGUARD_SERVICE = "keyguard"
- LOCATION_SERVICE = "location"
- SENSOR_SERVICE = "sensor"
- STORAGE_SERVICE = "storage"
- VIBRATOR_SERVICE = "vibrator"
- CONNECTIVITY_SERVICE = "connectivity"
- WIFI_SERVICE = "wifi"
- AUDIO_SERVICE = "audio"
- TELEPHONY_SERVICE = "telephony"
- INPUT_METHOD_SERVICE = "input_method"
- CAMERA_SERVICE = "camera"
- BATTERY_SERVICE = "battery"
- CLIPBOARD_SERVICE = "clipboard"
-
- # Mode 常量
- MODE_PRIVATE = 0x0000
- MODE_WORLD_READABLE = 0x0001
- MODE_WORLD_WRITEABLE = 0x0002
- MODE_APPEND = 0x8000
- MODE_MULTI_PROCESS = 0x0004
-
- # Flag 常量
- BIND_AUTO_CREATE = 0x0001
- BIND_DEBUG_UNBIND = 0x0002
- BIND_NOT_FOREGROUND = 0x0004
- BIND_ABOVE_CLIENT = 0x0008
- BIND_ALLOW_OOM_MANAGEMENT = 0x0010
- BIND_WAIVE_PRIORITY = 0x0020
- BIND_IMPORTANT = 0x0040
- BIND_ADJUST_WITH_ACTIVITY = 0x0080
-
- def __init__(self):
- super().__init__()
- self._package_name = _package_name
- self._services: Dict[str, Any] = {}
- self._shared_prefs: Dict[str, "SharedPreferences"] = {}
- self._registered_receivers: List[Dict] = []
- self._content_resolver = ContentResolver()
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def getFilesDir(self):
- return os.path.join(_app_data_dir, "files")
-
- def getCacheDir(self):
- return os.path.join(_app_data_dir, "cache")
-
- def getCodeCacheDir(self):
- return os.path.join(_app_data_dir, "code_cache")
-
- def getNoBackupFilesDir(self):
- return os.path.join(_app_data_dir, "no_backup")
-
- def getExternalFilesDir(self, type_: Optional[str] = None) -> str:
- base = os.path.join(_sdcard_root, "Android", "data", self._package_name, "files")
- if type_:
- base = os.path.join(base, type_)
- os.makedirs(base, exist_ok=True)
- return base
-
- def getExternalCacheDir(self):
- base = os.path.join(_sdcard_root, "Android", "data", self._package_name, "cache")
- os.makedirs(base, exist_ok=True)
- return base
-
- def getObbDir(self):
- base = os.path.join(_sdcard_root, "Android", "obb", self._package_name)
- os.makedirs(base, exist_ok=True)
- return base
-
- def getDataDir(self):
- return _app_data_dir
-
- def getPackageCodePath(self) -> str:
- return os.path.join(_app_data_dir, "base.apk")
-
- def getPackageResourcePath(self) -> str:
- return os.path.join(_app_data_dir, "base.apk")
-
- def startActivity(self, intent: Any):
- sys.stderr.write(f"[Context] startActivity: {intent}\n")
-
- def startActivities(self, intents: List[Any], options: Optional[Any] = None):
- for intent in intents:
- self.startActivity(intent)
-
- def sendBroadcast(self, intent: Any):
- sys.stderr.write(f"[Context] sendBroadcast: {intent}\n")
- for receiver in self._registered_receivers:
- if self._matches_intent_filter(intent, receiver.get("filter")):
- try:
- receiver["receiver"].onReceive(self, intent)
- except Exception as e:
- sys.stderr.write(f"[Context] broadcast error: {e}\n")
-
- def sendOrderedBroadcast(self, intent: Any, receiver_permission: Optional[str] = None):
- self.sendBroadcast(intent)
-
- def sendStickyBroadcast(self, intent: Any):
- self.sendBroadcast(intent)
-
- def registerReceiver(self, receiver: Optional[Any], filter: Any) -> Optional[Any]:
- if receiver:
- self._registered_receivers.append({"receiver": receiver, "filter": filter})
- return receiver
-
- def unregisterReceiver(self, receiver: Any):
- self._registered_receivers = [
- r for r in self._registered_receivers
- if r["receiver"] is not receiver
- ]
-
- def _matches_intent_filter(self, intent: Any, intent_filter: Any) -> bool:
- if intent_filter is None:
- return True
- action = getattr(intent, "getAction", lambda: None)()
- if intent_filter._action and action != intent_filter._action:
- return False
- return True
-
- def getContentResolver(self) -> ContentResolver:
- return self._content_resolver
-
- def getSharedPreferences(self, name: str, mode: int = MODE_PRIVATE) -> "SharedPreferences":
- if name not in self._shared_prefs:
- self._shared_prefs[name] = SharedPreferences(name)
- return self._shared_prefs[name]
-
- def getPackageManager(self):
- from .content_pm import PackageManager
- return PackageManager()
-
- def getResources(self):
- from .content_res import Resources, AssetManager
- if not hasattr(self, "_resources") or self._resources is None:
- self._resources = Resources(self.getAssets())
- return self._resources
-
- def getAssets(self):
- from .content_res import AssetManager
- if not hasattr(self, "_assets") or self._assets is None:
- self._assets = AssetManager()
- return self._assets
-
- def getMainLooper(self):
- from .os import Looper
- return Looper.getMainLooper()
-
- def getApplicationContext(self):
- return self
-
- def getSystemService(self, name: str) -> Any:
- if name == Context.ACTIVITY_SERVICE:
- from .app import ActivityManager
- return ActivityManager()
- if name == Context.ALARM_SERVICE:
- from .app import AlarmManager
- return AlarmManager()
- if name == Context.NOTIFICATION_SERVICE:
- from .app import NotificationManager
- return NotificationManager()
- if name == Context.VIBRATOR_SERVICE:
- from .os import Vibrator
- return Vibrator()
- if name == Context.POWER_SERVICE:
- from .os import PowerManager
- return PowerManager()
- if name == Context.LOCATION_SERVICE:
- from .location import LocationManager
- return LocationManager()
- if name == Context.SENSOR_SERVICE:
- from .hardware import SensorManager
- return SensorManager()
- if name == Context.CONNECTIVITY_SERVICE:
- from .net import ConnectivityManager
- return ConnectivityManager()
- if name == Context.WIFI_SERVICE:
- from .net_wifi import WifiManager
- return WifiManager()
- if name == Context.AUDIO_SERVICE:
- from .media import AudioManager
- return AudioManager()
- if name == Context.TELEPHONY_SERVICE:
- from .telephony import TelephonyManager
- return TelephonyManager()
- if name == Context.INPUT_METHOD_SERVICE:
- from .view_inputmethod import InputMethodManager
- return InputMethodManager()
- if name == Context.CAMERA_SERVICE:
- from .hardware_camera2 import CameraManager
- return CameraManager()
- if name == Context.BATTERY_SERVICE:
- from .os import BatteryManager
- return BatteryManager()
- if name == Context.CLIPBOARD_SERVICE:
- return ClipboardManager()
- return self._services.get(name)
-
- def startService(self, intent: Any) -> Optional[Any]:
- sys.stderr.write(f"[Context] startService: {intent}\n")
- return None
-
- def stopService(self, intent: Any) -> bool:
- return True
-
- def bindService(self, intent: Any, conn: Any, flags: int) -> bool:
- sys.stderr.write(f"[Context] bindService: {intent}\n")
- return True
-
- def unbindService(self, conn: Any):
- pass
-
- def getString(self, res_id: int, *args) -> str:
- """返回资源字符串。优先委托给 Resources,否则返回合理默认值。"""
- try:
- res = self.getResources()
- val = res.getString(res_id, *args)
- if val is not None:
- return val
- except Exception:
- pass
- return str(res_id)
-
- def getColor(self, color_id: int) -> int:
- """返回资源颜色。优先委托给 Resources,否则返回不透明黑色。"""
- try:
- res = self.getResources()
- return res.getColor(color_id)
- except Exception:
- return 0xFF000000
-
- def getDrawable(self, drawable_id: int):
- """返回 Drawable。优先委托给 Resources。"""
- try:
- res = self.getResources()
- return res.getDrawable(drawable_id)
- except Exception:
- return None
-
- def getWallpaper(self):
- """返回壁纸 Drawable。桌面端返回 None(无系统壁纸)。"""
- return None
-
- def getWallpaperDesiredMinimumWidth(self) -> int:
- return 1080
-
- def getWallpaperDesiredMinimumHeight(self) -> int:
- return 1920
-
- def checkCallingPermission(self, permission: str) -> int:
- from .content_pm import PackageManager
- return PackageManager.PERMISSION_GRANTED
-
- def checkSelfPermission(self, permission: str) -> int:
- from .content_pm import PackageManager
- return PackageManager.PERMISSION_GRANTED
-
- def shouldShowRequestPermissionRationale(self, permission: str) -> bool:
- return False
-
- def enforcePermission(self, permission: str, pid: int, uid: int, message: Optional[str]):
- pass
-
- def createPackageContext(self, package_name: str, flags: int) -> "Context":
- ctx = Context()
- ctx._package_name = package_name
- return ctx
-
- def isDeviceProtectedStorage(self) -> bool:
- return False
-
- def isCredentialProtectedStorage(self) -> bool:
- return False
-
- def deleteFile(self, name: str) -> bool:
- path = os.path.join(self.getFilesDir(), name)
- try:
- os.remove(path)
- return True
- except OSError:
- return False
-
- def fileList(self) -> List[str]:
- try:
- return os.listdir(self.getFilesDir())
- except OSError:
- return []
-
- def getDatabasePath(self, name: str):
- path = os.path.join(_app_data_dir, "databases", name)
- os.makedirs(os.path.dirname(path), exist_ok=True)
- return path
-
- def databaseList(self) -> List[str]:
- db_dir = os.path.join(_app_data_dir, "databases")
- try:
- return [f for f in os.listdir(db_dir) if f.endswith(".db")]
- except OSError:
- return []
-
- def deleteDatabase(self, name: str) -> bool:
- db_path = os.path.join(_app_data_dir, "databases", name)
- try:
- os.remove(db_path)
- return True
- except OSError:
- return False
-
- def getDir(self, name: str, mode: int) -> str:
- path = os.path.join(_app_data_dir, name)
- os.makedirs(path, exist_ok=True)
- return path
-
- def toString(self) -> str:
- return f"Context{{{self._package_name}}}"
-
- # ─── 文件流 / 权限 (扩展) ─────────────────────────────────
-
- def openFileInput(self, name):
- path = os.path.join(self.getFilesDir(), name)
- return open(path, 'rb')
-
- def openFileOutput(self, name, mode):
- path = os.path.join(self.getFilesDir(), name)
- os.makedirs(os.path.dirname(path), exist_ok=True)
- return open(path, 'wb')
-
- def getFileStreamPath(self, name):
- from ..java.io import File
- return File(self.getFilesDir(), name)
-
- def grantUriPermission(self, toPackage, uri, modeFlags):
- pass
-
- def revokeUriPermission(self, uri, modeFlags):
- pass
-
- def checkUriPermission(self, uri, pid, uid, modeFlags):
- return 0 # PERMISSION_GRANTED
-
- def checkPermission(self, permission, pid, uid):
- return 0 # PERMISSION_GRANTED
-
- def enforceUriPermission(self, uri, pid, uid, modeFlags, message):
- pass
-
- # ─── 资源 / 主题 (扩展) ───────────────────────────────────
-
- def getApplicationInfo(self):
- from .content_pm import ApplicationInfo
- return ApplicationInfo()
-
- def getTheme(self):
- return getattr(self, '_theme', 0)
-
- def setTheme(self, resid):
- self._theme = resid
-
- def getText(self, resId):
- """返回资源文本。优先委托给 Resources。"""
- try:
- res = self.getResources()
- val = res.getText(resId)
- if val is not None:
- return val
- except Exception:
- pass
- return str(resId)
-
- def getQuantityString(self, resId, quantity, *formatArgs):
- """返回复数字符串。优先委托给 Resources。"""
- try:
- res = self.getResources()
- return res.getQuantityString(resId, quantity, *formatArgs)
- except Exception:
- return str(resId)
-
- def getStringArray(self, resId):
- """返回字符串数组。优先委托给 Resources。"""
- try:
- res = self.getResources()
- val = res.getStringArray(resId)
- if val is not None:
- return val
- except Exception:
- pass
- return []
-
- def getTextArray(self, resId):
- """返回文本数组。优先委托给 Resources。"""
- try:
- res = self.getResources()
- val = res.getTextArray(resId)
- if val is not None:
- return val
- except Exception:
- pass
- return []
-
- def getIntArray(self, resId):
- """返回整型数组。优先委托给 Resources。"""
- try:
- res = self.getResources()
- val = res.getIntArray(resId)
- if val is not None:
- return val
- except Exception:
- pass
- return []
-
- # ─── Context 派生 / 回调 (扩展) ───────────────────────────
-
- def createConfigurationContext(self, overrideConfiguration):
- return Context()
-
- def createDisplayContext(self, display):
- return Context()
-
- def registerComponentCallbacks(self, callback):
- pass
-
- def unregisterComponentCallbacks(self, callback):
- pass
-
- def getExternalStoragePublicDirectory(self, type_):
- from ..java.io import File
- from .os import Environment
- return Environment.getExternalStoragePublicDirectory(type_)
-
- def getDisplayMetrics(self):
- from .util import DisplayMetrics
- return DisplayMetrics()
-
-
-class ContextWrapper(Context):
- """ContextWrapper — Context 的包装器"""
-
- def __init__(self, base: Context):
- super().__init__()
- self._base = base
-
- def getBaseContext(self) -> Context:
- return self._base
-
- def getPackageName(self) -> str:
- return self._base.getPackageName()
-
- def getFilesDir(self):
- return self._base.getFilesDir()
-
- def getCacheDir(self):
- return self._base.getCacheDir()
-
- def startActivity(self, intent: Any):
- self._base.startActivity(intent)
-
- def sendBroadcast(self, intent: Any):
- self._base.sendBroadcast(intent)
-
- def getContentResolver(self) -> ContentResolver:
- return self._base.getContentResolver()
-
- def getSharedPreferences(self, name: str, mode: int) -> "SharedPreferences":
- return self._base.getSharedPreferences(name, mode)
-
- def getSystemService(self, name: str) -> Any:
- return self._base.getSystemService(name)
-
- def startService(self, intent: Any) -> Optional[Any]:
- return self._base.startService(intent)
-
- def bindService(self, intent: Any, conn: Any, flags: int) -> bool:
- return self._base.bindService(intent, conn, flags)
-
- def registerReceiver(self, receiver: Optional[Any], filter: Any) -> Optional[Any]:
- return self._base.registerReceiver(receiver, filter)
-
- def unregisterReceiver(self, receiver: Any):
- self._base.unregisterReceiver(receiver)
-
-
-# ═══════════════════════════════════════════════════════════════
-# IntentFilter
-# ═══════════════════════════════════════════════════════════════
-
-class IntentFilter(Stub):
- """IntentFilter — 描述 Intent 匹配规则"""
-
- MATCH_CATEGORY_EMPTY = 0x100000
- MATCH_CATEGORY_HOST = 0x200000
- MATCH_CATEGORY_PORT = 0x400000
- MATCH_CATEGORY_PATH = 0x800000
- MATCH_CATEGORY_SCHEME = 0x1000000
- MATCH_CATEGORY_SCHEME_SPECIFIC_PART = 0x2000000
- MATCH_CATEGORY_TYPE = 0x4000000
- NO_MATCH_ACTION = -3
- NO_MATCH_CATEGORY = -4
- NO_MATCH_DATA = -5
- NO_MATCH_TYPE = -6
-
- def __init__(self, action: Optional[str] = None):
- super().__init__()
- self._action = action
- self._actions: List[str] = []
- self._categories: List[str] = []
- self._data_schemes: List[str] = []
- self._data_authorities: List[str] = []
- self._data_paths: List[str] = []
- self._data_types: List[str] = []
- self._priority = 0
- if action:
- self.addAction(action)
-
- def addAction(self, action: str):
- if action not in self._actions:
- self._actions.append(action)
-
- def addCategory(self, category: str):
- if category not in self._categories:
- self._categories.append(category)
-
- def addDataScheme(self, scheme: str):
- if scheme not in self._data_schemes:
- self._data_schemes.append(scheme)
-
- def addDataAuthority(self, host: str, port: int = -1):
- auth = f"{host}:{port}" if port >= 0 else host
- if auth not in self._data_authorities:
- self._data_authorities.append(auth)
-
- def addDataPath(self, path: str, pattern_type: int = 0):
- if path not in self._data_paths:
- self._data_paths.append(path)
-
- def addDataType(self, type_: str):
- if type_ not in self._data_types:
- self._data_types.append(type_)
-
- def hasAction(self, action: str) -> bool:
- return action in self._actions
-
- def hasCategory(self, category: str) -> bool:
- return category in self._categories
-
- def hasDataScheme(self, scheme: str) -> bool:
- return scheme in self._data_schemes
-
- def countActions(self) -> int:
- return len(self._actions)
-
- def getAction(self, index: int) -> str:
- return self._actions[index]
-
- def setPriority(self, priority: int):
- self._priority = priority
-
- def getPriority(self) -> int:
- return self._priority
-
- def match(self, action: str, type_: Optional[str], scheme: Optional[str],
- data: Optional[Any], categories: Optional[Set[str]], tag: str) -> int:
- if action and action not in self._actions:
- return self.NO_MATCH_ACTION
- return self.MATCH_CATEGORY_EMPTY
-
- def matchAction(self, action: str) -> bool:
- return action in self._actions
-
- def matchCategories(self, categories: Set[str]) -> Optional[str]:
- return None
-
- def matchData(self, type_: str, scheme: str, data: Any) -> int:
- return self.MATCH_CATEGORY_EMPTY
-
- def dump(self, du: Any, prefix: str):
- pass
-
- def describeContents(self) -> int:
- return 0
-
- def toString(self) -> str:
- return f"IntentFilter(actions={self._actions})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BroadcastReceiver
-# ═══════════════════════════════════════════════════════════════
-
-class BroadcastReceiver(Stub):
- """BroadcastReceiver — 广播接收器"""
-
- RESULT_OK = -1
- RESULT_CANCELED = 0
- RESULT_REDIRECT = 1
-
- def __init__(self):
- super().__init__()
- self._result_code = self.RESULT_OK
- self._result_data = ""
- self._result_extras: Optional[ContentValues] = None
- self._ordered = False
- self._initial_sticky = False
-
- def onReceive(self, context: Context, intent: Any):
- """Override this method to handle broadcasts"""
- pass
-
- def setResultCode(self, code: int):
- self._result_code = code
-
- def getResultCode(self) -> int:
- return self._result_code
-
- def setResultData(self, data: str):
- self._result_data = data
-
- def getResultData(self) -> str:
- return self._result_data
-
- def setResult(self, code: int, data: str, extras: Optional[ContentValues]):
- self._result_code = code
- self._result_data = data
- self._result_extras = extras
-
- def setResultExtras(self, extras: ContentValues):
- self._result_extras = extras
-
- def getResultExtras(self, make_map: bool) -> Optional[ContentValues]:
- return self._result_extras
-
- def abortBroadcast(self):
- self._result_code = self.RESULT_CANCELED
-
- def isOrderedBroadcast(self) -> bool:
- return self._ordered
-
- def isInitialStickyBroadcast(self) -> bool:
- return self._initial_sticky
-
- def getDebugUnregister(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"BroadcastReceiver@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SharedPreferences / SharedPreferencesEditor
-# ═══════════════════════════════════════════════════════════════
-
-_SHARED_PREFS_DIR = os.path.join(_app_data_dir, "shared_prefs")
-os.makedirs(_SHARED_PREFS_DIR, exist_ok=True)
-
-class SharedPreferences(Stub):
- """SharedPreferences — JSON 文件实现的持久化键值存储"""
-
- def __init__(self, name: str):
- super().__init__()
- self._name = name
- self._lock = threading.Lock()
- self._file_path = os.path.join(_SHARED_PREFS_DIR, f"{name}.json")
- self._data: Dict[str, Any] = {}
- self._load()
-
- def _load(self):
- try:
- if os.path.exists(self._file_path):
- with open(self._file_path, "r", encoding="utf-8") as f:
- self._data = json.load(f)
- else:
- self._data = {}
- except (json.JSONDecodeError, OSError):
- self._data = {}
-
- def _save(self):
- with self._lock:
- os.makedirs(os.path.dirname(self._file_path), exist_ok=True)
- with open(self._file_path, "w", encoding="utf-8") as f:
- json.dump(self._data, f, indent=2, ensure_ascii=False)
-
- def getString(self, key: str, def_value: Optional[str] = None) -> Optional[str]:
- v = self._data.get(key)
- return str(v) if v is not None else def_value
-
- def getInt(self, key: str, def_value: int = 0) -> int:
- v = self._data.get(key)
- if isinstance(v, int) or isinstance(v, float):
- return int(v)
- return def_value
-
- def getLong(self, key: str, def_value: int = 0) -> int:
- return self.getInt(key, def_value)
-
- def getFloat(self, key: str, def_value: float = 0.0) -> float:
- v = self._data.get(key)
- if isinstance(v, (int, float)):
- return float(v)
- return def_value
-
- def getBoolean(self, key: str, def_value: bool = False) -> bool:
- v = self._data.get(key)
- if isinstance(v, bool):
- return v
- if isinstance(v, str):
- return v.lower() in ("true", "1", "yes")
- return def_value
-
- def getAll(self) -> Dict[str, Any]:
- return dict(self._data)
-
- def contains(self, key: str) -> bool:
- return key in self._data
-
- def edit(self) -> "SharedPreferencesEditor":
- return SharedPreferencesEditor(self)
-
- def registerOnSharedPreferenceChangeListener(self, listener):
- if not hasattr(self, '_listeners'):
- self._listeners = []
- self._listeners.append(listener)
-
- def unregisterOnSharedPreferenceChangeListener(self, listener):
- if hasattr(self, '_listeners'):
- try:
- self._listeners.remove(listener)
- except ValueError:
- pass
-
- def getSharedPrefsFile(self):
- return self._file_path
-
- def toString(self) -> str:
- return f"SharedPreferences({self._name})"
-
-
-class SharedPreferencesEditor(Stub):
- """SharedPreferences Editor"""
-
- def __init__(self, prefs: SharedPreferences):
- super().__init__()
- self._prefs = prefs
- self._modified: Dict[str, Any] = {}
- self._removed: Set[str] = set()
- self._clear_all = False
-
- def putString(self, key: str, value: str) -> "SharedPreferencesEditor":
- self._modified[key] = value
- self._removed.discard(key)
- return self
-
- def putInt(self, key: str, value: int) -> "SharedPreferencesEditor":
- self._modified[key] = value
- self._removed.discard(key)
- return self
-
- def putLong(self, key: str, value: int) -> "SharedPreferencesEditor":
- self._modified[key] = value
- self._removed.discard(key)
- return self
-
- def putFloat(self, key: str, value: float) -> "SharedPreferencesEditor":
- self._modified[key] = value
- self._removed.discard(key)
- return self
-
- def putBoolean(self, key: str, value: bool) -> "SharedPreferencesEditor":
- self._modified[key] = value
- self._removed.discard(key)
- return self
-
- def remove(self, key: str) -> "SharedPreferencesEditor":
- self._removed.add(key)
- self._modified.pop(key, None)
- return self
-
- def clear(self) -> "SharedPreferencesEditor":
- self._clear_all = True
- self._modified.clear()
- self._removed.clear()
- return self
-
- def apply(self):
- """异步保存"""
- self.commit()
-
- def commit(self) -> bool:
- try:
- if self._clear_all:
- self._prefs._data.clear()
- for key in self._removed:
- self._prefs._data.pop(key, None)
- self._prefs._data.update(self._modified)
- self._prefs._save()
- # 触发监听器
- sp = getattr(self, '_prefs', None)
- if sp:
- for key in self._modified:
- for listener in getattr(sp, '_listeners', []):
- listener.onSharedPreferenceChanged(sp, key)
- self._modified.clear()
- self._removed.clear()
- self._clear_all = False
- return True
- except Exception:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# ComponentName
-# ═══════════════════════════════════════════════════════════════
-
-class ComponentName(Stub):
- """ComponentName — 标识包中的特定组件"""
-
- def __init__(self, pkg: str, cls: str):
- super().__init__()
- self._package = pkg
- self._classname = cls
-
- def getPackageName(self) -> str:
- return self._package
-
- def getClassName(self) -> str:
- return self._classname
-
- def getShortClassName(self) -> str:
- return self._classname.split(".")[-1] if "." in self._classname else self._classname
-
- def flattenToString(self) -> str:
- return f"{self._package}/{self._classname}"
-
- def flattenToShortString(self) -> str:
- return f"{self._package}/{self.getShortClassName()}"
-
- @staticmethod
- def unflattenFromString(str_: str) -> Optional["ComponentName"]:
- if "/" in str_:
- parts = str_.split("/", 1)
- return ComponentName(parts[0], parts[1])
- return None
-
- def toString(self) -> str:
- return f"ComponentInfo{{{self._package}/{self._classname}}}"
-
- def __repr__(self):
- return self.toString()
-
-
-# ═══════════════════════════════════════════════════════════════
-# ClipData / ClipDescription
-# ═══════════════════════════════════════════════════════════════
-
-class ClipDescription(Stub):
- """ClipDescription — 描述剪贴板数据"""
-
- MIMETYPE_TEXT_PLAIN = "text/plain"
- MIMETYPE_TEXT_HTML = "text/html"
- MIMETYPE_TEXT_URILIST = "text/uri-list"
- MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"
-
- def __init__(self, label: str, mime_types: List[str]):
- super().__init__()
- self._label = label
- self._mime_types = list(mime_types)
- self._timestamp = 0
-
- def getLabel(self) -> str:
- return self._label
-
- def getMimeType(self, index: int) -> str:
- if 0 <= index < len(self._mime_types):
- return self._mime_types[index]
- return ""
-
- def getMimeTypeCount(self) -> int:
- return len(self._mime_types)
-
- def filterMimeTypes(self, mime_type: str) -> bool:
- return mime_type in self._mime_types
-
- def compareMimeTypes(self, mime_type1: str, mime_type2: str) -> bool:
- return mime_type1 == mime_type2
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def toString(self) -> str:
- return f"ClipDescription({self._label}, {self._mime_types})"
-
-
-class ClipData(Stub):
- """ClipData — 剪贴板数据"""
-
- def __init__(self, description: ClipDescription, item: "ClipData.Item"):
- super().__init__()
- self._description = description
- self._items: List["ClipData.Item"] = [item] if item else []
-
- class Item(Stub):
- """单个剪贴板条目"""
- def __init__(self, text: Optional[str] = None, intent: Optional[Any] = None, uri: Optional[Uri] = None):
- super().__init__()
- self._text = text
- self._intent = intent
- self._uri = uri
- self._html_text = None
-
- def getText(self) -> Optional[str]:
- return self._text
-
- def getIntent(self):
- return self._intent
-
- def getUri(self) -> Optional[Uri]:
- return self._uri
-
- def getHtmlText(self) -> Optional[str]:
- return self._html_text
-
- def setHtmlText(self, html_text: str):
- self._html_text = html_text
-
- def coerceToText(self, context: Context) -> str:
- if self._text:
- return self._text
- if self._uri:
- return str(self._uri)
- if self._intent:
- return str(self._intent)
- return ""
-
- def coerceToHtmlText(self, context: Context) -> Optional[str]:
- return self._html_text
-
- def toString(self) -> str:
- return f"ClipData.Item({self._text})"
-
- @staticmethod
- def newPlainText(label: str, text: str) -> "ClipData":
- desc = ClipDescription(label, [ClipDescription.MIMETYPE_TEXT_PLAIN])
- return ClipData(desc, ClipData.Item(text=text))
-
- @staticmethod
- def newUri(cr: ContentResolver, label: str, uri: Uri) -> "ClipData":
- desc = ClipDescription(label, [ClipDescription.MIMETYPE_TEXT_URILIST])
- return ClipData(desc, ClipData.Item(uri=uri))
-
- @staticmethod
- def newIntent(label: str, intent: Any) -> "ClipData":
- desc = ClipDescription(label, [ClipDescription.MIMETYPE_TEXT_INTENT])
- return ClipData(desc, ClipData.Item(intent=intent))
-
- def getDescription(self) -> ClipDescription:
- return self._description
-
- def addItem(self, item: "ClipData.Item"):
- self._items.append(item)
-
- def getItemAt(self, index: int) -> Optional["ClipData.Item"]:
- if 0 <= index < len(self._items):
- return self._items[index]
- return None
-
- def getItemCount(self) -> int:
- return len(self._items)
-
- def toString(self) -> str:
- return f"ClipData({self._description})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContentProvider / ContentProviderClient
-# ═══════════════════════════════════════════════════════════════
-
-class ContentProvider(Stub):
- """ContentProvider — 内容提供者基类"""
-
- def __init__(self):
- super().__init__()
- self._context: Optional[Context] = None
- self._calling_package = ""
-
- def onCreate(self) -> bool:
- return True
-
- def query(self, uri: Uri, projection: Optional[List[str]], selection: Optional[str],
- selection_args: Optional[List[str]], sort_order: Optional[str]) -> Optional[Any]:
- """默认实现:委托给关联 Context 的 ContentResolver。"""
- if self._context is not None:
- return self._context.getContentResolver().query(
- uri, projection, selection, selection_args, sort_order)
- return None
-
- def insert(self, uri: Uri, values: ContentValues) -> Optional[Uri]:
- if self._context is not None:
- return self._context.getContentResolver().insert(uri, values)
- return None
-
- def update(self, uri: Uri, values: ContentValues, selection: Optional[str],
- selection_args: Optional[List[str]]) -> int:
- if self._context is not None:
- return self._context.getContentResolver().update(uri, values, selection, selection_args)
- return 0
-
- def delete(self, uri: Uri, selection: Optional[str], selection_args: Optional[List[str]]) -> int:
- if self._context is not None:
- return self._context.getContentResolver().delete(uri, selection, selection_args)
- return 0
-
- def getType(self, uri: Uri) -> Optional[str]:
- """返回 URI 的 MIME 类型。"""
- path = ContentResolver._uri_to_file_path(uri)
- if path:
- mime, _ = mimetypes.guess_type(path)
- return mime or "application/octet-stream"
- return None
-
- def getStreamTypes(self, uri: Uri, mime_type_filter: str) -> Optional[List[str]]:
- mime = self.getType(uri)
- if mime is None:
- return None
- return [mime]
-
- def openFile(self, uri: Uri, mode: str) -> Any:
- """打开文件。对 file:// URI 返回真实文件对象。"""
- path = ContentResolver._uri_to_file_path(uri)
- if path and os.path.exists(path):
- try:
- fmode = "rb" if "r" in mode else "wb"
- return open(path, fmode)
- except OSError:
- return None
- return None
-
- def openAssetFile(self, uri: Uri, mode: str) -> Any:
- return self.openFile(uri, mode)
-
- def attachInfo(self, context: Context, info: Any):
- self._context = context
-
- def getContext(self) -> Optional[Context]:
- return self._context
-
- def getCallingPackage(self) -> str:
- return self._calling_package
-
- def applyBatch(self, operations: List[Any]) -> List[Any]:
- return []
-
- def bulkInsert(self, uri: Uri, values: List[ContentValues]) -> int:
- return len(values) if values else 0
-
- def isTemporary(self) -> bool:
- return False
-
- def shutdown(self):
- pass
-
- def toString(self) -> str:
- return f"ContentProvider@{hex(id(self))}"
-
-
-class ContentProviderClient(Stub):
- """ContentProviderClient — 内容提供者客户端"""
-
- def __init__(self, uri: Optional[Uri] = None):
- super().__init__()
- self._uri = uri
-
- def query(self, uri: Uri, projection: Optional[List[str]], selection: Optional[str],
- selection_args: Optional[List[str]], sort_order: Optional[str]) -> Optional[Any]:
- """委托给 ContentResolver 处理 file:// URI。"""
- resolver = ContentResolver()
- return resolver.query(uri, projection, selection, selection_args, sort_order)
-
- def insert(self, uri: Uri, values: ContentValues) -> Optional[Uri]:
- resolver = ContentResolver()
- return resolver.insert(uri, values)
-
- def update(self, uri: Uri, values: ContentValues, selection: Optional[str],
- selection_args: Optional[List[str]]) -> int:
- resolver = ContentResolver()
- return resolver.update(uri, values, selection, selection_args)
-
- def delete(self, uri: Uri, selection: Optional[str], selection_args: Optional[List[str]]) -> int:
- resolver = ContentResolver()
- return resolver.delete(uri, selection, selection_args)
-
- def applyBatch(self, operations: List[Any]) -> List[Any]:
- resolver = ContentResolver()
- return resolver.applyBatch("", operations)
-
- def bulkInsert(self, uri: Uri, values: List[ContentValues]) -> int:
- resolver = ContentResolver()
- return resolver.bulkInsert(uri, values)
-
- def getType(self, uri: Uri) -> Optional[str]:
- """返回 URI 的 MIME 类型。"""
- path = ContentResolver._uri_to_file_path(uri)
- if path:
- mime, _ = mimetypes.guess_type(path)
- return mime or "application/octet-stream"
- return None
-
- def getStreamTypes(self, uri: Uri, mime_type_filter: str) -> Optional[List[str]]:
- mime = self.getType(uri)
- if mime is None:
- return None
- return [mime]
-
- def call(self, method: str, arg: Optional[str], extras: Optional[ContentValues]) -> Optional[ContentValues]:
- return None
-
- def release(self):
- pass
-
- def close(self):
- pass
-
- def openFile(self, uri: Uri, mode: str) -> Any:
- """打开文件。对 file:// URI 返回真实文件对象。"""
- path = ContentResolver._uri_to_file_path(uri)
- if path and os.path.exists(path):
- try:
- fmode = "rb" if "r" in mode else "wb"
- return open(path, fmode)
- except OSError:
- return None
- return None
-
- def openAssetFile(self, uri: Uri, mode: str) -> Any:
- return self.openFile(uri, mode)
-
- def openTypedAssetFile(self, uri: Uri, mime_type: str, opts: Optional[ContentValues]) -> Any:
- return self.openFile(uri, "r")
-
- def getLocalContentProvider(self) -> Optional[ContentProvider]:
- return None
-
-
-class ContentProviderOperation(Stub):
- """ContentProviderOperation — 批量操作"""
-
- TYPE_INSERT = 1
- TYPE_UPDATE = 2
- TYPE_DELETE = 3
- TYPE_ASSERT = 4
-
- class Builder(Stub):
- def __init__(self, type_: int, uri: Uri):
- super().__init__()
- self._type = type_
- self._uri = uri
- self._values: Optional[ContentValues] = None
- self._selection: Optional[str] = None
- self._selection_args: Optional[List[str]] = None
-
- def withValue(self, key: str, value: Any) -> "ContentProviderOperation.Builder":
- if self._values is None:
- self._values = ContentValues()
- self._values.put(key, value)
- return self
-
- def withValues(self, values: ContentValues) -> "ContentProviderOperation.Builder":
- self._values = values
- return self
-
- def withSelection(self, selection: str, selection_args: List[str]) -> "ContentProviderOperation.Builder":
- self._selection = selection
- self._selection_args = selection_args
- return self
-
- def build(self) -> "ContentProviderOperation":
- op = ContentProviderOperation()
- op._type = self._type
- op._uri = self._uri
- op._values = self._values
- op._selection = self._selection
- op._selection_args = self._selection_args
- return op
-
- @staticmethod
- def newInsert(uri: Uri) -> "ContentProviderOperation.Builder":
- return ContentProviderOperation.Builder(ContentProviderOperation.TYPE_INSERT, uri)
-
- @staticmethod
- def newUpdate(uri: Uri) -> "ContentProviderOperation.Builder":
- return ContentProviderOperation.Builder(ContentProviderOperation.TYPE_UPDATE, uri)
-
- @staticmethod
- def newDelete(uri: Uri) -> "ContentProviderOperation.Builder":
- return ContentProviderOperation.Builder(ContentProviderOperation.TYPE_DELETE, uri)
-
- @staticmethod
- def newAssert(uri: Uri) -> "ContentProviderOperation.Builder":
- return ContentProviderOperation.Builder(ContentProviderOperation.TYPE_ASSERT, uri)
-
-
-class ContentProviderResult(Stub):
- """ContentProviderResult — 操作结果"""
-
- def __init__(self, uri: Optional[Uri] = None, count: Optional[int] = None):
- super().__init__()
- self.uri = uri
- self.count = count
-
-
-# ═══════════════════════════════════════════════════════════════
-# Loader / CursorLoader / DialogInterface
-# ═══════════════════════════════════════════════════════════════
-
-class Loader(Stub):
- """Loader — 异步数据加载器基类"""
-
- def __init__(self, context: Context):
- super().__init__()
- self._context = context
- self._started = False
- self._abandoned = False
- self._listeners: List = []
-
- def deliverResult(self, data: Any):
- for listener in self._listeners:
- try:
- listener.onLoadFinished(self, data)
- except Exception:
- pass
-
- def startLoading(self):
- self._started = True
-
- def forceLoad(self):
- self.deliverResult(None)
-
- def stopLoading(self):
- self._started = False
-
- def abandon(self):
- self._abandoned = True
-
- def isStarted(self) -> bool:
- return self._started
-
- def isAbandoned(self) -> bool:
- return self._abandoned
-
- def reset(self):
- self._started = False
- self._abandoned = False
-
- def registerListener(self, listener):
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def unregisterListener(self, listener):
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def dataToString(self, data: Any) -> str:
- return str(data)
-
- def toString(self) -> str:
- return f"Loader@{hex(id(self))}"
-
-
-class CursorLoader(Loader):
- """CursorLoader — 游标加载器"""
-
- def __init__(self, context: Context, uri: Uri, projection: Optional[List[str]],
- selection: Optional[str], selection_args: Optional[List[str]], sort_order: Optional[str]):
- super().__init__(context)
- self._uri = uri
- self._projection = projection
- self._selection = selection
- self._selection_args = selection_args
- self._sort_order = sort_order
-
- def getUri(self) -> Uri:
- return self._uri
-
- def setUri(self, uri: Uri):
- self._uri = uri
-
- def getProjection(self) -> Optional[List[str]]:
- return self._projection
-
- def setProjection(self, projection: Optional[List[str]]):
- self._projection = projection
-
- def getSelection(self) -> Optional[str]:
- return self._selection
-
- def setSelection(self, selection: Optional[str]):
- self._selection = selection
-
- def getSelectionArgs(self) -> Optional[List[str]]:
- return self._selection_args
-
- def setSelectionArgs(self, args: Optional[List[str]]):
- self._selection_args = args
-
- def getSortOrder(self) -> Optional[str]:
- return self._sort_order
-
- def setSortOrder(self, sort_order: Optional[str]):
- self._sort_order = sort_order
-
- def loadInBackground(self):
- """在后台加载数据,委托给 ContentResolver.query。"""
- if self._context is not None:
- try:
- resolver = self._context.getContentResolver()
- return resolver.query(self._uri, self._projection, self._selection,
- self._selection_args, self._sort_order)
- except Exception:
- pass
- return None
-
-
-class DialogInterface(Stub):
- """DialogInterface — 对话框接口常量"""
-
- BUTTON_POSITIVE = -1
- BUTTON_NEGATIVE = -2
- BUTTON_NEUTRAL = -3
-
- def cancel(self):
- pass
-
- def dismiss(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncAdapter / SyncResult
-# ═══════════════════════════════════════════════════════════════
-
-class SyncAdapter(Stub):
- """SyncAdapter — 同步适配器"""
-
- def __init__(self, context: Context, auto_initialize: bool, allow_parallel_syncs: bool):
- super().__init__()
- self._context = context
-
- def onPerformSync(self, account: Any, extras: ContentValues, authority: str,
- provider: ContentProviderClient, sync_result: "SyncResult"):
- pass
-
- def onSecurityException(self, account: Any, extras: ContentValues,
- authority: str, sync_result: "SyncResult"):
- pass
-
-
-class SyncResult(Stub):
- """SyncResult — 同步结果"""
-
- def __init__(self):
- super().__init__()
- self.stats = self._Stats()
-
- class _Stats:
- def __init__(self):
- self.numEntries = 0
- self.numUpdates = 0
- self.numDeletes = 0
- self.numInserts = 0
- self.numSkippedEntries = 0
-
- def clear(self):
- self.stats = self._Stats()
-
- def hasError(self) -> bool:
- return False
-
- def hasSoftError(self) -> bool:
- return False
-
- def hasHardError(self) -> bool:
- return False
-
- def madeSomeProgress(self) -> bool:
- return self.stats.numEntries > 0
-
- def toString(self) -> str:
- return f"SyncResult({self.stats.numEntries} entries)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ClipboardManager
-# ═══════════════════════════════════════════════════════════════
-
-class ClipboardManager(Stub):
- """ClipboardManager — 剪贴板管理器"""
-
- def getText(self):
- if _USE_LINUX:
- return LinuxClipboard.read()
- return ""
-
- def setText(self, text):
- if _USE_LINUX:
- return LinuxClipboard.write(text)
- return False
-
- def hasText(self):
- if _USE_LINUX:
- return len(LinuxClipboard.read()) > 0
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# 替换 _core.py 中的 _GlobalContext
-# ═══════════════════════════════════════════════════════════════
-
-_real_context = Context()
-# 将 _core 中的 android_context 替换为真实 Context
-import importlib
-try:
- _core_mod = importlib.import_module(".._core", __package__)
- _core_mod.android_context.__class__ = Context
-except Exception:
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Uri",
- "ContentValues",
- "ContentResolver",
- "Context",
- "ContextWrapper",
- "IntentFilter",
- "BroadcastReceiver",
- "SharedPreferences",
- "SharedPreferencesEditor",
- "ComponentName",
- "ClipData",
- "ClipDescription",
- "ContentProvider",
- "ContentProviderClient",
- "ContentProviderOperation",
- "ContentProviderResult",
- "CursorLoader",
- "Loader",
- "DialogInterface",
- "SyncAdapter",
- "SyncResult",
- "ClipboardManager",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/content_intent.py b/android_pyapi/android/content_intent.py
deleted file mode 100644
index 31ef44c..0000000
--- a/android_pyapi/android/content_intent.py
+++ /dev/null
@@ -1,2087 +0,0 @@
-"""
-Android content Intent 完整扩展组件 — Intent (完整版), PendingIntent,
-IntentSender, IntentFilter (扩展), ShortcutInfo, ShortcutManager 等
-包含所有标准 ACTION_*, CATEGORY_*, EXTRA_*, FLAG_*, URI_*, SCHEME_*, MIME_* 常量
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import json
-import time
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-from .app import Intent as _BaseIntent
-from .app import PendingIntent as _BasePendingIntent
-from .content import IntentFilter as _BaseIntentFilter
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "Intent", "PendingIntent", "IntentSender",
- "IntentService",
- "IntentFilter", "MatchingFlags", "ShortcutInfo",
- "ShortcutManager",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# ACTION_* — 标准 Android Intent Action 常量
-# ═══════════════════════════════════════════════════════════════
-
-ACTION_MAIN = "android.intent.action.MAIN"
-ACTION_VIEW = "android.intent.action.VIEW"
-ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA"
-ACTION_EDIT = "android.intent.action.EDIT"
-ACTION_PICK = "android.intent.action.PICK"
-ACTION_CHOOSER = "android.intent.action.CHOOSER"
-ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT"
-ACTION_DIAL = "android.intent.action.DIAL"
-ACTION_CALL = "android.intent.action.CALL"
-ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON"
-ACTION_SEND = "android.intent.action.SEND"
-ACTION_SENDTO = "android.intent.action.SENDTO"
-ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE"
-ACTION_ANSWER = "android.intent.action.ANSWER"
-ACTION_INSERT = "android.intent.action.INSERT"
-ACTION_DELETE = "android.intent.action.DELETE"
-ACTION_RUN = "android.intent.action.RUN"
-ACTION_SYNC = "android.intent.action.SYNC"
-ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY"
-ACTION_SEARCH = "android.intent.action.SEARCH"
-ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH"
-ACTION_FACTORY_TEST = "android.intent.action.FACTORY_TEST"
-ACTION_TIME_TICK = "android.intent.action.TIME_TICK"
-ACTION_TIME_CHANGED = "android.intent.action.TIME_SET"
-ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED"
-ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"
-ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED"
-ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED"
-ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED"
-ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED"
-ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED"
-ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED"
-ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED"
-ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH"
-ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION"
-ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED"
-ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE"
-ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE"
-ACTION_APPLICATION_PREFERENCES = "android.intent.action.APPLICATION_PREFERENCES"
-ACTION_APPLICATION_LOCALE_CHANGED = "android.intent.action.APPLICATION_LOCALE_CHANGED"
-ACTION_APPLICATION_GRANT_URI_PERMISSION = "android.intent.action.APPLICATION_GRANT_URI_PERMISSION"
-ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED"
-ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON"
-ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED"
-ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT"
-ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED"
-ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED"
-ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG"
-ACTION_INPUT_METHOD_CHANGED = "android.intent.action.INPUT_METHOD_CHANGED"
-ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED"
-ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED"
-ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED"
-ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE"
-ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE"
-ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED"
-ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON"
-ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING"
-ACTION_MEDIA_EJECT = "android.intent.action.MEDIA_EJECT"
-ACTION_MEDIA_MOUNTED = "android.intent.action.MEDIA_MOUNTED"
-ACTION_MEDIA_NOFS = "android.intent.action.MEDIA_NOFS"
-ACTION_MEDIA_REMOVED = "android.intent.action.MEDIA_REMOVED"
-ACTION_MEDIA_SCANNER_FINISHED = "android.intent.action.MEDIA_SCANNER_FINISHED"
-ACTION_MEDIA_SCANNER_SCAN_FILE = "android.intent.action.MEDIA_SCANNER_SCAN_FILE"
-ACTION_MEDIA_SCANNER_STARTED = "android.intent.action.MEDIA_SCANNER_STARTED"
-ACTION_MEDIA_SHARED = "android.intent.action.MEDIA_SHARED"
-ACTION_MEDIA_UNMOUNTABLE = "android.intent.action.MEDIA_UNMOUNTABLE"
-ACTION_MEDIA_UNMOUNTED = "android.intent.action.MEDIA_UNMOUNTED"
-ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL"
-ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL"
-ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF"
-ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON"
-ACTION_USER_PRESENT = "android.intent.action.USER_PRESENT"
-ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED"
-ACTION_GTALK_SERVICE_CONNECTED = "android.intent.action.GTALK_CONNECTED"
-ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED"
-ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED"
-ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED"
-ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED"
-ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED"
-ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED"
-ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED"
-ACTION_WIFI_SCAN_AVAILABLE = "android.intent.action.WIFI_SCAN_AVAILABLE"
-ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW"
-ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK"
-ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED"
-ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW"
-ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY"
-ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED"
-ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED"
-ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN"
-ACTION_REBOOT = "android.intent.action.REBOOT"
-ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE"
-ACTION_NETWORK_SET_TIME = "android.intent.action.NETWORK_SET_TIME"
-ACTION_NETWORK_SET_TIMEZONE = "android.intent.action.NETWORK_SET_TIMEZONE"
-ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED"
-ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE"
-ACTION_SIGNAL_STRENGTH_CHANGED = "android.intent.action.SIG_STR"
-ACTION_DATA_CONNECTION_STATE_CHANGED = "android.intent.action.DATA_CONNECTION_STATE_CHANGED"
-ACTION_ANY_DATA_CONNECTION_STATE_CHANGED = "android.intent.action.ANY_DATA_STATE"
-ACTION_DATA_ACTIVITY = "android.intent.action.DATA_ACTIVITY"
-ACTION_DATA_STALL = "android.intent.action.DATA_STALL"
-ACTION_PROXY_CHANGE = "android.intent.action.PROXY_CHANGE"
-ACTION_WALLPAPER_SETTINGS = "android.intent.action.WALLPAPER_SETTINGS"
-ACTION_HDMI_AUDIO_PLUG = "android.intent.action.HDMI_AUDIO_PLUG"
-ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT"
-ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT"
-ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE"
-ACTION_VIEW_DOWNLOADS = "android.intent.action.VIEW_DOWNLOADS"
-ACTION_DOCUMENT_SETTINGS = "android.intent.action.DOCUMENT_SETTINGS"
-ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK"
-ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION"
-ACTION_MANAGED_ROAMING_INDICATION = "android.intent.action.MANAGED_ROAMING_INDICATION"
-ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND"
-ACTION_ASSIST = "android.intent.action.ASSIST"
-ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW"
-ACTION_CUSTOM_EVENT = "android.intent.action.CUSTOM_EVENT"
-ACTION_GET_RESTRICTION_ENTRIES = "android.intent.action.GET_RESTRICTION_ENTRIES"
-ACTION_SET_RESTRICTION = "android.intent.action.SET_RESTRICTION"
-ACTION_DEFAULT = "android.intent.action.DEFAULT"
-ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT"
-ACTION_INSTALL_SHORTCUT = "android.intent.action.INSTALL_SHORTCUT"
-ACTION_UNINSTALL_SHORTCUT = "com.android.launcher.action.UNINSTALL_SHORTCUT"
-ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE"
-ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE"
-ACTION_INSTALL_FAILURE = "android.intent.action.INSTALL_FAILURE"
-ACTION_UNINSTALL_FAILURE = "android.intent.action.UNINSTALL_FAILURE"
-ACTION_VIEW_SECURITY_POLICY = "android.intent.action.VIEW_SECURITY_POLICY"
-ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED"
-ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED"
-ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED"
-ACTION_LOCK_TASK_ENTERING = "android.intent.action.LOCK_TASK_ENTERING"
-ACTION_LOCK_TASK_EXITING = "android.intent.action.LOCK_TASK_EXITING"
-ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR"
-ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET"
-ACTION_GET_ACCOUNTS = "android.accounts.GET_ACCOUNTS"
-ACTION_ADD_ACCOUNT = "android.settings.ADD_ACCOUNT_SETTINGS"
-ACTION_SETTINGS = "android.settings.SETTINGS"
-ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS"
-ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS"
-ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS"
-ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS"
-ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS"
-ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS"
-ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS"
-ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"
-ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS"
-ACTION_NETWORK_OPERATOR_SETTINGS = "android.settings.NETWORK_OPERATOR_SETTINGS"
-ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS"
-ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS"
-ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS"
-ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS"
-ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS"
-ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS"
-ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS"
-ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS"
-ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS"
-ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS"
-ACTION_ADD_ACCOUNT_SETTINGS = "android.settings.ADD_ACCOUNT_SETTINGS"
-ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS"
-ACTION_APN_SETTINGS = "android.settings.APN_SETTINGS"
-ACTION_APPLICATION_SETTINGS_SHORT = "android.settings.APPLICATION_SETTINGS"
-ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"
-ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS"
-ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION"
-ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS"
-ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
-ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS"
-ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS"
-ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS"
-ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS"
-ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS"
-ACTION_WIFI_ADD_NETWORKS = "android.settings.WIFI_ADD_NETWORKS"
-ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"
-ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS"
-ACTION_ACCESSIBILITY_SETTINGS = "android.settings.ACCESSIBILITY_SETTINGS"
-ACTION_ACCOUNT_SYNC_SETTINGS = "android.settings.ACCOUNT_SYNC_SETTINGS"
-ACTION_APP_OPEN_BY_DEFAULT_SETTINGS = "android.settings.APP_OPEN_BY_DEFAULT_SETTINGS"
-ACTION_APP_LOCALE_SETTINGS = "android.settings.APP_LOCALE_SETTINGS"
-ACTION_APPLICATION_SETTINGS_SYSTEM = "android.settings.APPLICATION_SETTINGS_SYSTEM"
-ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS"
-ACTION_BIOMETRIC_ENROLL = "android.settings.BIOMETRIC_ENROLL"
-ACTION_BLUETOOTH_SCAN_SETTINGS = "android.settings.BLUETOOTH_SCAN_SETTINGS"
-ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS"
-ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS"
-ACTION_CONDITION_PROVIDER_SETTINGS = "android.settings.CONDITION_PROVIDER_SETTINGS"
-ACTION_DATA_USAGE_SETTINGS = "android.settings.DATA_USAGE_SETTINGS"
-ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS"
-ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS"
-ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"
-ACTION_END_KEY_LONG_PRESS = "android.settings.END_KEY_LONG_PRESS"
-ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL"
-ACTION_FINGERPRINT_SETTINGS = "android.settings.FINGERPRINT_SETTINGS"
-ACTION_HARD_KEY_ASSIST = "android.settings.HARD_KEY_ASSIST"
-ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS"
-ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS_SHORT = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"
-ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS"
-ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS"
-ACTION_INTERNAL_STORAGE_SETTINGS_SHORT = "android.settings.INTERNAL_STORAGE_SETTINGS"
-ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS"
-ACTION_MANAGE_APPLICATIONS_SETTINGS_SHORT = "android.settings.MANAGE_APPLICATIONS_SETTINGS"
-ACTION_MANAGE_SUPERVISOR_RESTRICTION = "android.settings.MANAGE_SUPERVISOR_RESTRICTION"
-ACTION_MOBILE_DATA_SETTINGS = "android.settings.MOBILE_DATA_SETTINGS"
-ACTION_PRINT_SETTINGS = "android.settings.PRINT_SETTINGS"
-ACTION_PROCESS_WIFI_CREDENTIAL = "android.settings.PROCESS_WIFI_CREDENTIAL"
-ACTION_QUICK_ACCESS_WALLET_SETTINGS = "android.settings.QUICK_ACCESS_WALLET_SETTINGS"
-ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS"
-ACTION_SEARCH_SETTINGS = "android.settings.SEARCH_SETTINGS"
-ACTION_STORAGE_VOLUME_ACCESS_SETTINGS = "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS"
-ACTION_SYSTEM_UPDATE_SETTINGS = "android.settings.SYSTEM_UPDATE_SETTINGS"
-ACTION_TEST_SETTINGS = "android.settings.TEST_SETTINGS"
-ACTION_TTS_SETTINGS = "android.settings.TTS_SETTINGS"
-ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS"
-ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE"
-ACTION_VOICE_CONTROL_BATTERY_SAVER = "android.settings.VOICE_CONTROL_BATTERY_SAVER"
-ACTION_VOICE_CONTROL_DO_NOT_DISTURB = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB"
-ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS"
-ACTION_WEBVIEW_SETTINGS = "android.settings.WEBVIEW_SETTINGS"
-ACTION_WIFI_AP_SETTINGS = "android.settings.WIFI_AP_SETTINGS"
-ACTION_WIFI_AP_SETTINGS_SHORT = "android.settings.WIFI_AP_SETTINGS"
-ACTION_WIFI_SCAN_SETTINGS = "android.settings.WIFI_SCAN_SETTINGS"
-ACTION_WIFI_SETUP = "android.settings.WIFI_SETUP"
-ACTION_WIRELESS_SETTINGS_SHORT = "android.settings.WIRELESS_SETTINGS"
-ACTION_ENTER_CAR_MODE = "android.intent.action.ENTER_CAR_MODE"
-ACTION_EXIT_CAR_MODE = "android.intent.action.EXIT_CAR_MODE"
-ACTION_CAR_MODE_SETTINGS = "android.settings.CAR_MODE_SETTINGS"
-ACTION_CAR_DOCK_CONNECT = "android.intent.action.CAR_DOCK"
-ACTION_DESK_DOCK_CONNECT = "android.intent.action.DESK_DOCK"
-ACTION_LE_DESK_DOCK_CONNECT = "android.intent.action.LE_DESK_DOCK"
-ACTION_HEADSET_PLUG_SHORT = "android.intent.action.HEADSET_PLUG"
-ACTION_USB_ANLG_HEADSET_PLUG = "android.intent.action.USB_ANLG_HEADSET_PLUG"
-ACTION_USB_DGTL_HEADSET_PLUG = "android.intent.action.USB_DGTL_HEADSET_PLUG"
-ACTION_HTC_CONNECTOR_PLUG = "android.intent.action.HTC_CONNECTOR_PLUG"
-ACTION_HTC_CONNECTOR_PLUG_SHORT = "android.intent.action.HTC_CONNECTOR_PLUG"
-ACTION_NFC_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED"
-ACTION_TAG_FOUND = "android.nfc.action.TAG_FOUND"
-ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED"
-ACTION_TAB_CHANGED = "android.intent.action.TAB_CHANGED"
-ACTION_TETHER_STATE_CHANGED = "android.net.wifi.WIFI_AP_STATE_CHANGED"
-ACTION_TRANSACTION_DETECTED = "android.nfc.action.TRANSACTION_DETECTED"
-ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"
-ACTION_ACCOUNT_REMOVED = "android.accounts.action.ACCOUNT_REMOVED"
-ACTION_ACCOUNT_VISIBLE = "android.accounts.action.ACCOUNT_VISIBLE"
-ACTION_VOICEMAIL_SMS_RECEIVED = "android.intent.action.VOICEMAIL_SMS_RECEIVED"
-ACTION_USER_ADDED = "android.intent.action.USER_ADDED"
-ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED"
-ACTION_USER_SWITCHED = "android.intent.action.USER_SWITCHED"
-ACTION_USER_STARTED = "android.intent.action.USER_STARTED"
-ACTION_USER_STOPPED = "android.intent.action.USER_STOPPED"
-ACTION_USER_BACKGROUND = "android.intent.action.USER_BACKGROUND"
-ACTION_USER_FOREGROUND = "android.intent.action.USER_FOREGROUND"
-ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE"
-ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED"
-ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"
-ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL"
-ACTION_APP_ERROR = "android.intent.action.APP_ERROR"
-ACTION_BUG_REPORT = "android.intent.action.BUG_REPORT"
-ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS"
-ACTION_PREFERRED_ACTIVITY_CHANGED = "android.intent.action.PREFERRED_ACTIVITY_CHANGED"
-ACTION_REBOOT_SHORT = "android.intent.action.REBOOT"
-ACTION_SCREEN_ON_LATE = "android.intent.action.SCREEN_ON_LATE"
-ACTION_SUBSCRIBER_FEATURES_CHANGED = "android.intent.action.SUBSCRIBER_FEATURES_CHANGED"
-ACTION_SYSTEM_OVERLAY = "android.intent.action.SYSTEM_OVERLAY"
-ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED"
-ACTION_CONTENT_CHANGED = "android.intent.action.CONTENT_CHANGED"
-ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE"
-ACTION_DOWNLOAD_NOTIFICATION_CLICKED = "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"
-ACTION_NOTIFICATION_CLICK = "android.intent.action.NOTIFICATION_CLICK"
-ACTION_DELETE_SHORT = "android.intent.action.DELETE"
-ACTION_INSERT_SHORT = "android.intent.action.INSERT"
-ACTION_REBOOT_2 = "android.intent.action.REBOOT"
-ACTION_PICK_ACTIVITY_SHORT = "android.intent.action.PICK_ACTIVITY"
-ACTION_GET_CONTENT_SHORT = "android.intent.action.GET_CONTENT"
-ACTION_SEND_SHORT = "android.intent.action.SEND"
-ACTION_ANSWER_SHORT = "android.intent.action.ANSWER"
-ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT"
-ACTION_PASTE = "android.intent.action.PASTE"
-ACTION_CLOSE = "android.intent.action.CLOSE"
-ACTION_SAVE = "android.intent.action.SAVE"
-ACTION_UNDO = "android.intent.action.UNDO"
-ACTION_REDO = "android.intent.action.REDO"
-ACTION_CUT = "android.intent.action.CUT"
-ACTION_COPY = "android.intent.action.COPY"
-ACTION_PRINT = "android.intent.action.PRINT"
-ACTION_PLAY = "android.intent.action.PLAY"
-ACTION_PAUSE = "android.intent.action.PAUSE"
-ACTION_STOP = "android.intent.action.STOP"
-ACTION_NEXT = "android.intent.action.NEXT"
-ACTION_PREVIOUS = "android.intent.action.PREVIOUS"
-ACTION_FAST_FORWARD = "android.intent.action.FAST_FORWARD"
-ACTION_REWIND = "android.intent.action.REWIND"
-ACTION_PLAY_PAUSE = "android.intent.action.PLAY_PAUSE"
-ACTION_MUTE = "android.intent.action.MUTE"
-ACTION_VOLUME_UP = "android.intent.action.VOLUME_UP"
-ACTION_VOLUME_DOWN = "android.intent.action.VOLUME_DOWN"
-ACTION_INFO = "android.intent.action.INFO"
-ACTION_REPLY = "android.intent.action.REPLY"
-ACTION_FORWARD = "android.intent.action.FORWARD"
-ACTION_COMPOSE = "android.intent.action.COMPOSE"
-ACTION_REFRESH = "android.intent.action.REFRESH"
-ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS"
-ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER"
-ACTION_ALARM_CHANGED = "android.intent.action.ALARM_CHANGED"
-ACTION_NEXT_ALARM_SET = "android.intent.action.NEXT_ALARM_SET"
-
-ACTION_ALL_APPS = "android.intent.action.ALL_APPS"
-ACTION_BOOKMARK = "android.intent.action.BOOKMARK"
-ACTION_CHROME_ICON = "android.intent.action.CHROME_ICON"
-ACTION_ERROR = "android.intent.action.ERROR"
-ACTION_GADGET = "android.intent.action.GADGET"
-ACTION_GOOGLE = "android.intent.action.GOOGLE"
-ACTION_HOTWORD = "android.intent.action.HOTWORD"
-ACTION_ICON = "android.intent.action.ICON"
-ACTION_LAUNCH = "android.intent.action.LAUNCH"
-ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE"
-ACTION_MEDIA_PLAY_FROM_SEARCH = "android.intent.action.MEDIA_PLAY_FROM_SEARCH"
-ACTION_MEDIA_PAUSED = "android.intent.action.MEDIA_PAUSED"
-ACTION_MEDIA_PLAYING = "android.intent.action.MEDIA_PLAYING"
-ACTION_MEDIA_UNPAUSED = "android.intent.action.MEDIA_UNPAUSED"
-ACTION_NAVIGATE = "android.intent.action.NAVIGATE"
-ACTION_NEW_APPLICATION = "android.intent.action.NEW_APPLICATION"
-ACTION_NO_DOWNLOAD = "android.intent.action.NO_DOWNLOAD"
-ACTION_NO_INSTALL = "android.intent.action.NO_INSTALL"
-ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL"
-ACTION_RADIO = "android.intent.action.RADIO"
-ACTION_RECORD = "android.intent.action.RECORD"
-ACTION_REMEMBER = "android.intent.action.REMEMBER"
-ACTION_RINGER_MODE_CHANGED = "android.media.RINGER_MODE_CHANGED"
-ACTION_SEND_REPORT = "android.intent.action.SEND_REPORT"
-ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER"
-ACTION_SHOW_ALARM = "android.intent.action.SHOW_ALARM"
-ACTION_SHORTCUT = "android.intent.action.SHORTCUT"
-ACTION_START = "android.intent.action.START"
-ACTION_STATISTICS = "android.intent.action.STATISTICS"
-ACTION_STOP_APPLICATION = "android.intent.action.STOP_APPLICATION"
-ACTION_STOP_SERVICE = "android.intent.action.STOP_SERVICE"
-ACTION_SYSTEM_DEVICE = "android.intent.action.SYSTEM_DEVICE"
-ACTION_SYSTEM_UPDATE = "android.intent.action.SYSTEM_UPDATE"
-ACTION_THEME = "android.intent.action.THEME"
-ACTION_UNINSTALL = "android.intent.action.UNINSTALL"
-ACTION_UNUSED = "android.intent.action.UNUSED"
-ACTION_UPDATE = "android.intent.action.UPDATE"
-ACTION_UPGRADE = "android.intent.action.UPGRADE"
-ACTION_VERIFY = "android.intent.action.VERIFY"
-ACTION_VIEW_APK = "android.intent.action.VIEW_APK"
-ACTION_VIEW_CONTACTS = "android.intent.action.VIEW_CONTACTS"
-ACTION_VIEW_URL = "android.intent.action.VIEW_URL"
-ACTION_VOICE_RECOGNIZE = "android.intent.action.VOICE_RECOGNIZE"
-ACTION_WEB_SEARCH_SHORT = "android.intent.action.WEB_SEARCH"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CATEGORY_* — 标准 Intent Category 常量
-# ═══════════════════════════════════════════════════════════════
-
-CATEGORY_DEFAULT = "android.intent.category.DEFAULT"
-CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE"
-CATEGORY_TAB = "android.intent.category.TAB"
-CATEGORY_ALTERNATIVE = "android.intent.category.ALTERNATIVE"
-CATEGORY_SELECTED_ALTERNATIVE = "android.intent.category.SELECTED_ALTERNATIVE"
-CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"
-CATEGORY_INFO = "android.intent.category.INFO"
-CATEGORY_HOME = "android.intent.category.HOME"
-CATEGORY_PREFERENCE = "android.intent.category.PREFERENCE"
-CATEGORY_TEST = "android.intent.category.TEST"
-CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK"
-CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK"
-CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK"
-CATEGORY_HE_DESK_DOCK = "android.intent.category.HE_DESK_DOCK"
-CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE"
-CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET"
-CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER"
-CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR"
-CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR"
-CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS"
-CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL"
-CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY"
-CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS"
-CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING"
-CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC"
-CATEGORY_APP_FILES = "android.intent.category.APP_FILES"
-CATEGORY_APP_CLOCK = "android.intent.category.APP_CLOCK"
-CATEGORY_APP_SETTINGS = "android.intent.category.APP_SETTINGS"
-CATEGORY_APP_WEATHER = "android.intent.category.APP_WEATHER"
-CATEGORY_APP_VIDEO = "android.intent.category.APP_VIDEO"
-CATEGORY_APP_CHAT = "android.intent.category.APP_CHAT"
-CATEGORY_APP_GAME = "android.intent.category.APP_GAME"
-CATEGORY_APP_FINANCE = "android.intent.category.APP_FINANCE"
-CATEGORY_APP_NEWS = "android.intent.category.APP_NEWS"
-CATEGORY_APP_SOCIAL = "android.intent.category.APP_SOCIAL"
-CATEGORY_APP_PHOTOGRAPHY = "android.intent.category.APP_PHOTOGRAPHY"
-CATEGORY_APP_PRODUCTIVITY = "android.intent.category.APP_PRODUCTIVITY"
-CATEGORY_APP_TRAVEL = "android.intent.category.APP_TRAVEL"
-CATEGORY_APP_WALLPAPER = "android.intent.category.APP_WALLPAPER"
-CATEGORY_APP_RECENTS = "android.intent.category.APP_RECENTS"
-CATEGORY_OPENABLE = "android.intent.category.OPENABLE"
-CATEGORY_TYPED_OPENABLE = "android.intent.category.TYPED_OPENABLE"
-CATEGORY_MONKEY = "android.intent.category.MONKEY"
-CATEGORY_DEVELOPMENT_PREFERENCE = "android.intent.category.DEVELOPMENT_PREFERENCE"
-CATEGORY_EMBED = "android.intent.category.EMBED"
-CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST = "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"
-CATEGORY_MASTER_CLEAR = "android.intent.category.MASTER_CLEAR"
-CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST"
-CATEGORY_SAMPLE_CODE = "android.intent.category.SAMPLE_CODE"
-CATEGORY_ACCESSIBILITY = "android.intent.category.ACCESSIBILITY"
-CATEGORY_VOICE = "android.intent.category.VOICE"
-CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES"
-CATEGORY_SEARCH_RESULT = "android.intent.category.SEARCH_RESULT"
-CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER"
-CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS"
-CATEGORY_LEANBACK_VIDEO = "android.intent.category.LEANBACK_VIDEO"
-CATEGORY_LEANBACK_DOCUMENT = "android.intent.category.LEANBACK_DOCUMENT"
-CATEGORY_LEANBACK_HOME = "android.intent.category.LEANBACK_HOME"
-CATEGORY_LEANBACK_SEARCH = "android.intent.category.LEANBACK_SEARCH"
-CATEGORY_SECONDARY_HOME = "android.intent.category.SECONDARY_HOME"
-CATEGORY_PREFERENCE_SHORT = "android.intent.category.PREFERENCE"
-CATEGORY_TEST_SHORT = "android.intent.category.TEST"
-CATEGORY_DESK_DOCK_SHORT = "android.intent.category.DESK_DOCK"
-CATEGORY_CAR_DOCK_SHORT = "android.intent.category.CAR_DOCK"
-CATEGORY_LE_DESK_DOCK_SHORT = "android.intent.category.LE_DESK_DOCK"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EXTRA_* — 标准 Intent Extra 常量
-# ═══════════════════════════════════════════════════════════════
-
-EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT"
-EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT"
-EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED"
-EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE"
-EXTRA_DOCK_STATE_HE_DESK = 4
-EXTRA_DOCK_STATE_LE_DESK = 3
-EXTRA_DOCK_STATE_CAR = 2
-EXTRA_DOCK_STATE_DESK = 1
-EXTRA_DOCK_STATE_UNDOCKED = 0
-EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP"
-EXTRA_EMAIL = "android.intent.extra.EMAIL"
-EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS"
-EXTRA_INTENT = "android.intent.extra.INTENT"
-EXTRA_KEY_EVENT = "android.intent.extra.KEY_EVENT"
-EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY"
-EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES"
-EXTRA_NOT_INITIALIZED = "android.intent.extra.NOT_INITIALIZED"
-EXTRA_PACKAGES = "android.intent.extra.PACKAGES"
-EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"
-EXTRA_REFERRER = "android.intent.extra.REFERRER"
-EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME"
-EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token"
-EXTRA_REPLACING = "android.intent.extra.REPLACING"
-EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON"
-EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE"
-EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT"
-EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME"
-EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY"
-EXTRA_STREAM = "android.intent.extra.STREAM"
-EXTRA_SUBJECT = "android.intent.extra.SUBJECT"
-EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE"
-EXTRA_TEXT = "android.intent.extra.TEXT"
-EXTRA_TITLE = "android.intent.extra.TITLE"
-EXTRA_UID = "android.intent.extra.UID"
-EXTRA_USER = "android.intent.extra.USER"
-EXTRA_USER_ID = "android.intent.extra.USER_ID"
-EXTRA_USER_HANDLE = "android.intent.extra.USER_HANDLE"
-EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE"
-EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT"
-EXTRA_CC = "android.intent.extra.CC"
-EXTRA_BCC = "android.intent.extra.BCC"
-EXTRA_FROM_STORAGE = "android.intent.extra.FROM_STORAGE"
-EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME"
-EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID"
-EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG"
-EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID"
-EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID"
-EXTRA_CONVERSATION_ID = "android.intent.extra.CONVERSATION_ID"
-EXTRA_IS_GROUP_CONVERSATION = "android.intent.extra.IS_GROUP_CONVERSATION"
-EXTRA_MESSAGES = "android.intent.extra.MESSAGES"
-EXTRA_PEOPLE = "android.intent.extra.PEOPLE"
-EXTRA_SELF_DISPLAY_NAME = "android.intent.extra.SELF_DISPLAY_NAME"
-EXTRA_TIME = "android.intent.extra.TIME"
-EXTRA_SIZE = "android.intent.extra.SIZE"
-EXTRA_COUNTRY = "android.intent.extra.COUNTRY"
-EXTRA_LOCATION = "android.intent.extra.LOCATION"
-EXTRA_LATITUDE = "android.intent.extra.LATITUDE"
-EXTRA_LONGITUDE = "android.intent.extra.LONGITUDE"
-EXTRA_ALTITUDE = "android.intent.extra.ALTITUDE"
-EXTRA_BEARING = "android.intent.extra.BEARING"
-EXTRA_SPEED = "android.intent.extra.SPEED"
-EXTRA_ACCURACY = "android.intent.extra.ACCURACY"
-EXTRA_POI_NAME = "android.intent.extra.POI_NAME"
-EXTRA_PHONE_NUMBER_SHORT = "android.intent.extra.PHONE_NUMBER"
-EXTRA_RINGER_MODE = "android.intent.extra.RINGER_MODE"
-EXTRA_VIBRATE_SETTING = "android.intent.extra.VIBRATE_SETTING"
-EXTRA_VOLUME_STREAM_TYPE = "android.intent.extra.VOLUME_STREAM_TYPE"
-EXTRA_VOLUME_STREAM_VALUE = "android.intent.extra.VOLUME_STREAM_VALUE"
-EXTRA_VOLUME_STREAM_VOLUME = "android.intent.extra.VOLUME_STREAM_VOLUME"
-EXTRA_FORCE_MASTER_VOLUME_MUTE = "android.intent.extra.FORCE_MASTER_VOLUME_MUTE"
-EXTRA_PREVIOUS_VOLUME_STREAM_VALUE = "android.intent.extra.PREVIOUS_VOLUME_STREAM_VALUE"
-EXTRA_VIBRATE_TYPE = "android.intent.extra.VIBRATE_TYPE"
-EXTRA_SCREEN_OFF_TIMEOUT = "android.intent.extra.SCREEN_OFF_TIMEOUT"
-EXTRA_TASK_ID = "android.intent.extra.TASK_ID"
-EXTRA_WINDOW_MINIMUM_SIZE_MAJOR = "android.intent.extra.WINDOW_MINIMUM_SIZE_MAJOR"
-EXTRA_WINDOW_MINIMUM_SIZE_MINOR = "android.intent.extra.WINDOW_MINIMUM_SIZE_MINOR"
-EXTRA_CHANGED_COMPONENT_NAME = "android.intent.extra.changed_component_name"
-EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list"
-EXTRA_CHANGED_UID = "android.intent.extra.changed_uid"
-EXTRA_DATA_REMOVED_SHORT = "android.intent.extra.DATA_REMOVED"
-EXTRA_DOCK_STATE_SHORT = "android.intent.extra.DOCK_STATE"
-EXTRA_REPLACING_SHORT = "android.intent.extra.REPLACING"
-EXTRA_SERVICE_INFO = "android.intent.extra.SERVICE_INFO"
-EXTRA_SERVICE_COMPONENT = "android.intent.extra.SERVICE_COMPONENT"
-EXTRA_REQUEST_QUALITY = "android.intent.extra.REQUEST_QUALITY"
-EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI"
-EXTRA_REFERRER_SHORT = "android.intent.extra.REFERRER"
-EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID"
-EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE"
-EXTRA_CALLING_UID = "android.intent.extra.CALLING_UID"
-EXTRA_CALLING_ACTIVITY = "android.intent.extra.CALLING_ACTIVITY"
-EXTRA_LAUNCHER_INTENT = "android.intent.extra.LAUNCHER_INTENT"
-EXTRA_WALLPAPER_OFFSET = "android.intent.extra.WALLPAPER_OFFSET"
-EXTRA_WALLPAPER_ID = "android.intent.extra.WALLPAPER_ID"
-EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS"
-EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER = "android.intent.extra.CHOOSER_REFINEMENT_INTENT_SENDER"
-EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER"
-EXTRA_ALARM_GROUP_ID = "android.intent.extra.ALARM_GROUP_ID"
-EXTRA_DELAY = "android.intent.extra.DELAY"
-EXTRA_HEADER = "android.intent.extra.HEADER"
-EXTRA_PROTOCOL = "android.intent.extra.PROTOCOL"
-EXTRA_FETCH_MODE = "android.intent.extra.FETCH_MODE"
-EXTRA_ID = "android.intent.extra.ID"
-EXTRA_NAME = "android.intent.extra.NAME"
-EXTRA_QUERY = "android.intent.extra.QUERY"
-EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION"
-EXTRA_ICON = "android.intent.extra.ICON"
-EXTRA_COLOR = "android.intent.extra.COLOR"
-EXTRA_ORIENTATION = "android.intent.extra.ORIENTATION"
-EXTRA_PRIORITY = "android.intent.extra.PRIORITY"
-EXTRA_STATE = "android.intent.extra.STATE"
-EXTRA_STATUS = "android.intent.extra.STATUS"
-EXTRA_TAG = "android.intent.extra.TAG"
-EXTRA_TARGET = "android.intent.extra.TARGET"
-EXTRA_TOKEN = "android.intent.extra.TOKEN"
-EXTRA_VERSION = "android.intent.extra.VERSION"
-EXTRA_URL = "android.intent.extra.URL"
-EXTRA_REQUEST_ID = "android.intent.extra.REQUEST_ID"
-EXTRA_RESPONSE_CODE = "android.intent.extra.RESPONSE_CODE"
-EXTRA_RESPONSE_MESSAGE = "android.intent.extra.RESPONSE_MESSAGE"
-EXTRA_AUTHENTICATOR_RESPONSE = "android.accounts.extra.AUTHENTICATOR_RESPONSE"
-EXTRA_AUTHENTICATOR_ACCOUNT = "android.accounts.extra.AUTHENTICATOR_ACCOUNT"
-EXTRA_AUTHENTICATOR_INTENT = "android.accounts.extra.AUTHENTICATOR_INTENT"
-EXTRA_ACCOUNT_TYPE = "android.accounts.extra.ACCOUNT_TYPE"
-EXTRA_ACCOUNT_LABEL = "android.accounts.extra.ACCOUNT_LABEL"
-EXTRA_ACCOUNT_AUTH_TOKEN_LABEL = "android.accounts.extra.AUTH_TOKEN_LABEL"
-EXTRA_PASSWORD = "android.accounts.extra.PASSWORD"
-EXTRA_AUTH_TOKEN_TYPE = "android.accounts.extra.AUTH_TOKEN_TYPE"
-EXTRA_CONFIRM_CREDENTIALS = "android.accounts.extra.CONFIRM_CREDENTIALS"
-EXTRA_UPDATE_CURRENT_ACCOUNT = "android.accounts.extra.UPDATE_CURRENT_ACCOUNT"
-EXTRA_ALLOW_ACCOUNT_REAUTH = "android.accounts.extra.ALLOW_ACCOUNT_REAUTH"
-EXTRA_UNKNOWN_USER = "android.accounts.extra.UNKNOWN_USER"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FLAG_* — Intent Flag 常量(Android SDK 实际数值)
-# ═══════════════════════════════════════════════════════════════
-
-FLAG_GRANT_READ_URI_PERMISSION = 0x00000001
-FLAG_GRANT_WRITE_URI_PERMISSION = 0x00000002
-FLAG_FROM_BACKGROUND = 0x00000004
-FLAG_DEBUG_LOG_RESOLUTION = 0x00000008
-FLAG_EXCLUDE_STOPPED_PACKAGES = 0x00000010
-FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020
-FLAG_GRANT_PERSISTABLE_URI_PERMISSION = 0x00000040
-FLAG_GRANT_PREFIX_URI_PERMISSION = 0x00000080
-FLAG_ACTIVITY_MATCH_EXTERNAL = 0x00001000
-FLAG_ACTIVITY_NO_HISTORY = 0x40000000
-FLAG_ACTIVITY_SINGLE_TOP = 0x20000000
-FLAG_ACTIVITY_NEW_TASK = 0x10000000
-FLAG_ACTIVITY_MULTIPLE_TASK = 0x08000000
-FLAG_ACTIVITY_CLEAR_TOP = 0x04000000
-FLAG_ACTIVITY_FORWARD_RESULT = 0x02000000
-FLAG_ACTIVITY_PREVIOUS_IS_TOP = 0x01000000
-FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 0x00800000
-FLAG_ACTIVITY_BROUGHT_TO_FRONT = 0x00400000
-FLAG_ACTIVITY_RESET_TASK_IF_NEEDED = 0x00200000
-FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 0x00100000
-FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000
-FLAG_ACTIVITY_NEW_DOCUMENT = 0x00080000
-FLAG_ACTIVITY_CLEAR_TASK = 0x00008000
-FLAG_ACTIVITY_TASK_ON_HOME = 0x00004000
-FLAG_ACTIVITY_RETAIN_IN_RECENTS = 0x00002000
-FLAG_ACTIVITY_LAUNCH_ADJACENT = 0x00001000
-FLAG_ACTIVITY_REORDER_TO_FRONT = 0x00020000
-FLAG_ACTIVITY_NO_USER_ACTION = 0x00010000
-FLAG_ACTIVITY_NO_ANIMATION = 0x00010000
-FLAG_RECEIVER_REGISTERED_ONLY = 0x40000000
-FLAG_RECEIVER_REPLACE_PENDING = 0x20000000
-FLAG_RECEIVER_FOREGROUND = 0x10000000
-FLAG_RECEIVER_NO_ABORT = 0x08000000
-FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x04000000
-FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000
-FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000
-FLAG_RECEIVER_EXCLUDE_BACKGROUND = 0x00800000
-FLAG_RECEIVER_FROM_SHELL = 0x00400000
-FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS = 0x00200000
-FLAG_RECEIVER_OFFLOAD = 0x00100000
-FLAG_SYSTEM_BROADCAST = 0x00000040
-
-
-# ═══════════════════════════════════════════════════════════════
-# URI_*, SCHEME_*, MIME_* 常量
-# ═══════════════════════════════════════════════════════════════
-
-URI_INTENT_SCHEME = "intent"
-SCHEME_FILE = "file"
-SCHEME_CONTENT = "content"
-SCHEME_ANDROID_RESOURCE = "android.resource"
-SCHEME_PACKAGE = "package"
-SCHEME_HTTP = "http"
-SCHEME_HTTPS = "https"
-SCHEME_TEL = "tel"
-SCHEME_SMSTO = "smsto"
-SCHEME_MAILTO = "mailto"
-SCHEME_GEO = "geo"
-SCHEME_MARKET = "market"
-SCHEME_ABOUT = "about"
-
-MIME_TYPE_TEXT_PLAIN = "text/plain"
-MIME_TYPE_TEXT_HTML = "text/html"
-MIME_TYPE_TEXT_CALENDAR = "text/calendar"
-MIME_TYPE_TEXT_XML = "text/xml"
-MIME_TYPE_IMAGE_JPEG = "image/jpeg"
-MIME_TYPE_IMAGE_PNG = "image/png"
-MIME_TYPE_IMAGE_GIF = "image/gif"
-MIME_TYPE_IMAGE_WEBP = "image/webp"
-MIME_TYPE_IMAGE_ALL = "image/*"
-MIME_TYPE_AUDIO_MPEG = "audio/mpeg"
-MIME_TYPE_AUDIO_MP4 = "audio/mp4"
-MIME_TYPE_AUDIO_ALL = "audio/*"
-MIME_TYPE_VIDEO_MP4 = "video/mp4"
-MIME_TYPE_VIDEO_ALL = "video/*"
-MIME_TYPE_APPLICATION_PDF = "application/pdf"
-MIME_TYPE_APPLICATION_ZIP = "application/zip"
-MIME_TYPE_APPLICATION_JSON = "application/json"
-MIME_TYPE_APPLICATION_XML = "application/xml"
-MIME_TYPE_APPLICATION_OCTET_STREAM = "application/octet-stream"
-MIME_TYPE_MULTIPART_MIXED = "multipart/mixed"
-MIME_TYPE_MULTIPART_FORM_DATA = "multipart/form-data"
-MIME_TYPE_ALL = "*/*"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Intent — 完整扩展
-# ═══════════════════════════════════════════════════════════════
-
-class Intent(_BaseIntent):
- """Android Intent — 完整扩展 (桌面存根,继承 app.Intent 的所有方法)"""
-
- # ── ShortcutIconResource inner class ──
-
- class ShortcutIconResource(Stub):
- """ShortcutIconResource — 快捷方式图标资源"""
-
- def __init__(self, packageName: str = "", resourceName: str = ""):
- super().__init__()
- self.packageName = packageName
- self.resourceName = resourceName
-
- @staticmethod
- def fromContext(context: Any, iconId: int) -> "Intent.ShortcutIconResource":
- return Intent.ShortcutIconResource(
- packageName=getattr(context, "getPackageName", lambda: "unknown")(),
- resourceName=str(iconId),
- )
-
- def toString(self) -> str:
- return f"ShortcutIconResource(packageName={self.packageName}, resourceName={self.resourceName})"
-
- # ── FilterComparison inner class ──
-
- class FilterComparison(Stub):
- """FilterComparison — Intent 过滤器比较"""
-
- def __init__(self, intent: "Intent"):
- super().__init__()
- self._intent = intent
-
- def getIntent(self) -> "Intent":
- return self._intent
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, Intent.FilterComparison):
- return False
- return self._intent.filterEquals(other._intent)
-
- def hashCode(self) -> int:
- return self._intent.filterHashCode()
-
- def toString(self) -> str:
- return f"FilterComparison({self._intent})"
-
- # ── Intent 主构造 ──
-
- def __init__(self, action: str = "", uri: Optional[str] = None,
- package: str = "", component: Optional[Any] = None):
- super().__init__()
- self._action = action
- self._data: Optional[str] = uri
- self._type: Optional[str] = None
- self._package = package
- self._component = component
- self._flags: int = 0
- self._categories: Set[str] = set()
- self._extras: Dict[str, Any] = {}
- self._scheme: str = ""
- self._authority: str = ""
- self._path: str = ""
- self._clip_data: Optional[Any] = None
- self._identifier: Optional[str] = None
- self._selector: Optional["Intent"] = None
- self._source_bounds: Optional[Tuple[int, int, int, int]] = None
-
- # ── Action ──
-
- def getAction(self) -> str:
- return self._action
-
- def setAction(self, action: str) -> "Intent":
- self._action = action
- return self
-
- # ── Data / URI ──
-
- def getData(self) -> Optional[str]:
- return self._data
-
- def setData(self, data) -> "Intent":
- self._data = data
- self._type = None
- # 从 Uri 提取 scheme
- if data is not None:
- if hasattr(data, 'getScheme'):
- self._scheme = data.getScheme() or ""
- elif isinstance(data, str):
- from urllib.parse import urlparse
- self._scheme = urlparse(data).scheme
- return self
-
- def getDataString(self) -> Optional[str]:
- if self._data is None:
- return None
- if isinstance(self._data, str):
- return self._data
- return str(self._data)
-
- def getScheme(self) -> str:
- if self._scheme:
- return self._scheme
- # 从 data 动态提取
- if self._data is not None:
- if hasattr(self._data, 'getScheme'):
- return self._data.getScheme() or ""
- elif isinstance(self._data, str):
- from urllib.parse import urlparse
- return urlparse(self._data).scheme
- return ""
-
- # ── Type ──
-
- def getType(self) -> Optional[str]:
- return self._type
-
- def setType(self, type_: str) -> "Intent":
- self._type = type_
- self._data = None
- return self
-
- def setDataAndType(self, data: str, type_: str) -> "Intent":
- self._data = data
- self._type = type_
- return self
-
- def resolveType(self, resolver: Any = None) -> Optional[str]:
- return self._type
-
- # ── Scheme ──
-
- def getSchemeSpecificPart(self) -> str:
- if self._data and ":" in self._data:
- return self._data.split(":", 1)[1]
- return ""
-
- # ── Package ──
-
- def getPackage(self) -> str:
- return self._package
-
- def setPackage(self, package: str) -> "Intent":
- self._package = package or ""
- return self
-
- # ── Component ──
-
- def getComponent(self) -> Optional[Any]:
- return self._component
-
- def setComponent(self, component: Any) -> "Intent":
- self._component = component
- return self
-
- def getClassName(self) -> str:
- if self._component:
- return getattr(self._component, "getClassName", lambda: str(self._component))()
- return ""
-
- # ── Flags ──
-
- def getFlags(self) -> int:
- return self._flags
-
- def setFlags(self, flags: int) -> "Intent":
- self._flags = flags
- return self
-
- def addFlags(self, flags: int) -> "Intent":
- self._flags |= flags
- return self
-
- def removeFlags(self, flags: int) -> None:
- self._flags &= ~flags
-
- # ── Categories ──
-
- def hasCategory(self, category: str) -> bool:
- return category in self._categories
-
- def getCategories(self) -> Set[str]:
- return self._categories.copy()
-
- def addCategory(self, category: str) -> "Intent":
- self._categories.add(category)
- return self
-
- def removeCategory(self, category: str) -> None:
- self._categories.discard(category)
-
- # ── Extras ──
-
- def getExtras(self) -> Dict[str, Any]:
- return dict(self._extras)
-
- def hasExtra(self, name: str) -> bool:
- return name in self._extras
-
- def getStringExtra(self, name: str) -> Optional[str]:
- val = self._extras.get(name)
- return str(val) if val is not None else None
-
- def getIntExtra(self, name: str, default: int = 0) -> int:
- val = self._extras.get(name)
- return int(val) if val is not None else default
-
- def getLongExtra(self, name: str, default: int = 0) -> int:
- val = self._extras.get(name)
- return int(val) if val is not None else default
-
- def getFloatExtra(self, name: str, default: float = 0.0) -> float:
- val = self._extras.get(name)
- return float(val) if val is not None else default
-
- def getDoubleExtra(self, name: str, default: float = 0.0) -> float:
- val = self._extras.get(name)
- return float(val) if val is not None else default
-
- def getBooleanExtra(self, name: str, default: bool = False) -> bool:
- val = self._extras.get(name)
- return bool(val) if val is not None else default
-
- def getCharExtra(self, name: str, default: str = "") -> str:
- val = self._extras.get(name)
- return str(val) if val is not None else default
-
- def getShortExtra(self, name: str, default: int = 0) -> int:
- val = self._extras.get(name)
- return int(val) if val is not None else default
-
- def getByteExtra(self, name: str, default: int = 0) -> int:
- val = self._extras.get(name)
- return int(val) if val is not None else default
-
- def getSerializableExtra(self, name: str) -> Optional[Any]:
- return self._extras.get(name)
-
- def getIntegerArrayListExtra(self, name: str) -> Optional[List[int]]:
- val = self._extras.get(name)
- if isinstance(val, list) and all(isinstance(v, int) for v in val):
- return val
- return None
-
- def getStringArrayListExtra(self, name: str) -> Optional[List[str]]:
- val = self._extras.get(name)
- if isinstance(val, list) and all(isinstance(v, str) for v in val):
- return val
- return None
-
- def getCharSequenceArrayListExtra(self, name: str) -> Optional[List[str]]:
- val = self._extras.get(name)
- if isinstance(val, list):
- return [str(v) for v in val]
- return None
-
- def getBundleExtra(self, name: str) -> Optional[Dict[str, Any]]:
- val = self._extras.get(name)
- return val if isinstance(val, dict) else None
-
- def putExtra(self, name: str, value: Any) -> "Intent":
- self._extras[name] = value
- return self
-
- def putExtras(self, extras: Dict[str, Any]) -> "Intent":
- self._extras.update(extras)
- return self
-
- def removeExtra(self, name: str) -> None:
- self._extras.pop(name, None)
-
- def replaceExtras(self, extras: Dict[str, Any]) -> "Intent":
- self._extras = dict(extras)
- return self
-
- def putIntegerArrayListExtra(self, name: str, values: List[int]) -> "Intent":
- self._extras[name] = list(values)
- return self
-
- def putStringArrayListExtra(self, name: str, values: List[str]) -> "Intent":
- self._extras[name] = list(values)
- return self
-
- def putCharSequenceArrayListExtra(self, name: str, values: List[str]) -> "Intent":
- self._extras[name] = [str(v) for v in values]
- return self
-
- # ── Selector ──
-
- def getSelector(self) -> Optional["Intent"]:
- return self._selector
-
- def setSelector(self, selector: "Intent") -> None:
- self._selector = selector
-
- # ── ClipData ──
-
- def getClipData(self) -> Optional[Any]:
- return self._clip_data
-
- def setClipData(self, clip: Optional[Any]) -> None:
- self._clip_data = clip
-
- # ── Identifier ──
-
- def getIdentifier(self) -> Optional[str]:
- return self._identifier
-
- def setIdentifier(self, identifier: str) -> None:
- self._identifier = identifier
-
- # ── SourceBounds ──
-
- def getSourceBounds(self) -> Optional[Tuple[int, int, int, int]]:
- return self._source_bounds
-
- def setSourceBounds(self, bounds: Optional[Tuple[int, int, int, int]]) -> None:
- self._source_bounds = bounds
-
- # ── FillIn ──
-
- def fillIn(self, other: "Intent", flags: int = 0) -> int:
- """将 other 的内容合并到当前 Intent"""
- changes = 0
- if not self._action and other._action:
- self._action = other._action
- changes |= 1
- if not self._data and other._data:
- self._data = other._data
- changes |= 2
- if not self._type and other._type:
- self._type = other._type
- changes |= 4
- if not self._package and other._package:
- self._package = other._package
- changes |= 8
- if not self._component and other._component:
- self._component = other._component
- changes |= 16
- if not self._scheme and other._scheme:
- self._scheme = other._scheme
- changes |= 32
- for cat in other._categories:
- if cat not in self._categories:
- self._categories.add(cat)
- changes |= 64
- self._flags |= other._flags
- for k, v in other._extras.items():
- if k not in self._extras:
- self._extras[k] = v
- changes |= 128
- return changes
-
- # ── FilterEquals (Intent resolution matching) ──
-
- def filterEquals(self, other: Any) -> bool:
- """判断两个 Intent 在 filter 匹配意义上是否相等"""
- if not isinstance(other, Intent):
- return False
- return (self._action == other._action
- and self._data == other._data
- and self._type == other._type
- and self._package == other._package
- and self._component == other._component
- and self._categories == other._categories)
-
- def filterHashCode(self) -> int:
- """计算 filter 哈希码"""
- h = hash(self._action) if self._action else 0
- h = h * 31 + (hash(self._data) if self._data else 0)
- h = h * 31 + (hash(self._type) if self._type else 0)
- h = h * 31 + (hash(self._package) if self._package else 0)
- h = h * 31 + (hash(str(self._component)) if self._component else 0)
- for cat in sorted(self._categories):
- h = h * 31 + hash(cat)
- return h & 0x7FFFFFFF
-
- # ── DescribeContents / WriteToParcel ──
-
- def describeContents(self) -> int:
- return 0
-
- def writeToParcel(self, dest: Any, flags: int = 0) -> None:
- """写入 Parcel (桌面存根)"""
- pass
-
- def readFromParcel(self, source: Any) -> None:
- """从 Parcel 读取 (桌面存根)"""
- pass
-
- # ── Create chooser ──
-
- @staticmethod
- def createChooser(target: "Intent", title: Optional[str] = None,
- sender: Optional[Any] = None) -> "Intent":
- intent = Intent(ACTION_CHOOSER)
- intent.putExtra(EXTRA_INTENT, target)
- if title:
- intent.putExtra(EXTRA_TITLE, title)
- if sender:
- intent.putExtra(EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER, sender)
- return intent
-
- @staticmethod
- def getIntentOld(action: str) -> "Intent":
- return Intent(action)
-
- @staticmethod
- def getIntent(uri: str) -> "Intent":
- return Intent(uri=uri)
-
- @staticmethod
- def parseUri(uri: str, flags: int = 0) -> "Intent":
- return Intent(uri=uri)
-
- def toURI(self) -> str:
- return f"{self._scheme}:{self._data or ''}#Intent;action={self._action};end"
-
- def toUri(self, flags: int = 0) -> str:
- return self.toURI()
-
- def toString(self) -> str:
- parts = [f"Intent {{ act={self._action}"]
- if self._data:
- parts.append(f" dat={self._data}")
- if self._type:
- parts.append(f" typ={self._type}")
- if self._package:
- parts.append(f" pkg={self._package}")
- if self._component:
- parts.append(f" cmp={self._component}")
- if self._flags:
- parts.append(f" flg=0x{self._flags:08x}")
- if self._categories:
- parts.append(f" cat={self._categories}")
- parts.append(" }")
- return "".join(parts)
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, Intent):
- return False
- return (self._action == other._action
- and self._data == other._data
- and self._type == other._type
- and self._package == other._package)
-
- def hashCode(self) -> int:
- h = hash(self._action) if self._action else 0
- h = h * 31 + (hash(self._data) if self._data else 0)
- h = h * 31 + (hash(self._type) if self._type else 0)
- h = h * 31 + (hash(self._package) if self._package else 0)
- return h & 0x7FFFFFFF
-
- def clone(self) -> "Intent":
- cloned = Intent(self._action, self._data, self._package, self._component)
- cloned._type = self._type
- cloned._flags = self._flags
- cloned._categories = set(self._categories)
- cloned._extras = dict(self._extras)
- cloned._scheme = self._scheme
- cloned._selector = self._selector
- cloned._clip_data = self._clip_data
- cloned._identifier = self._identifier
- cloned._source_bounds = self._source_bounds
- return cloned
-
- def toInsecureString(self) -> str:
- return self.toString()
-
- def toSecureString(self) -> str:
- return self.toString()
-
- def isDocument(self) -> bool:
- return bool(self._flags & FLAG_ACTIVITY_NEW_DOCUMENT)
-
- def isExcludingStopped(self) -> bool:
- return bool(self._flags & FLAG_EXCLUDE_STOPPED_PACKAGES)
-
- def isWebIntent(self) -> bool:
- return self._scheme in (SCHEME_HTTP, SCHEME_HTTPS)
-
- def getBooleanArrayExtra(self, name: str) -> Optional[List[bool]]:
- val = self._extras.get(name)
- if isinstance(val, list):
- return [bool(v) for v in val]
- return None
-
- def getIntArrayExtra(self, name: str) -> Optional[List[int]]:
- val = self._extras.get(name)
- if isinstance(val, list):
- return [int(v) for v in val]
- return None
-
- def getLongArrayExtra(self, name: str) -> Optional[List[int]]:
- val = self._extras.get(name)
- if isinstance(val, list):
- return [int(v) for v in val]
- return None
-
- def getFloatArrayExtra(self, name: str) -> Optional[List[float]]:
- val = self._extras.get(name)
- if isinstance(val, list):
- return [float(v) for v in val]
- return None
-
- def getDoubleArrayExtra(self, name: str) -> Optional[List[float]]:
- val = self._extras.get(name)
- if isinstance(val, list):
- return [float(v) for v in val]
- return None
-
- def getStringArrayExtra(self, name: str) -> Optional[List[str]]:
- val = self._extras.get(name)
- if isinstance(val, list):
- return [str(v) for v in val]
- return None
-
- def getCharSequenceArrayExtra(self, name: str) -> Optional[List[str]]:
- val = self._extras.get(name)
- if isinstance(val, list):
- return [str(v) for v in val]
- return None
-
- def getBundleArrayExtra(self, name: str) -> Optional[List[Dict[str, Any]]]:
- val = self._extras.get(name)
- if isinstance(val, list) and all(isinstance(v, dict) for v in val):
- return val
- return None
-
- def hasExtraSecret(self, name: str) -> bool:
- return name in self._extras
-
- def putExtraSecret(self, name: str, value: Any) -> "Intent":
- self._extras[name] = value
- return self
-
- def toShortString(self) -> str:
- return self.toString()[:80]
-
- def toShortUri(self) -> str:
- return self.toUri()[:80]
-
-
-# ═══════════════════════════════════════════════════════════════
-# IntentReceiver
-# ═══════════════════════════════════════════════════════════════
-
-class IntentReceiver(Stub):
- """IntentReceiver — Intent 接收器 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
- self._result_code = 0
- self._result_data: Optional[str] = None
- self._result_extras: Optional[Dict[str, Any]] = None
- self._abort = False
-
- def onReceive(self, context: Any, intent: Intent) -> None:
- """接收 Intent (桌面存根)"""
- pass
-
- def getResultCode(self) -> int:
- return self._result_code
-
- def setResultCode(self, code: int) -> None:
- self._result_code = code
-
- def getResultData(self) -> Optional[str]:
- return self._result_data
-
- def setResultData(self, data: str) -> None:
- self._result_data = data
-
- def getResultExtras(self) -> Optional[Dict[str, Any]]:
- return self._result_extras
-
- def setResultExtras(self, extras: Dict[str, Any]) -> None:
- self._result_extras = dict(extras)
-
- def abortBroadcast(self) -> None:
- self._abort = True
-
- def isAborted(self) -> bool:
- return self._abort
-
- def clearAbortBroadcast(self) -> None:
- self._abort = False
-
- def toString(self) -> str:
- return f"IntentReceiver(resultCode={self._result_code})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PendingIntent
-# ═══════════════════════════════════════════════════════════════
-
-class PendingIntent(_BasePendingIntent):
- """PendingIntent — 延迟 Intent (继承 app.PendingIntent 的所有方法)"""
-
- FLAG_ONE_SHOT = 1 << 30
- FLAG_NO_CREATE = 1 << 29
- FLAG_CANCEL_CURRENT = 1 << 28
- FLAG_UPDATE_CURRENT = 1 << 27
- FLAG_IMMUTABLE = 1 << 26
- FLAG_MUTABLE = 1 << 25
-
- def __init__(self, intent: Optional[Intent] = None, requestCode: int = 0,
- flags: int = 0):
- super().__init__(intent, requestCode, flags)
- self._intent = intent
- self._request_code = requestCode
- self._flags = flags
- self._canceled = False
-
- @staticmethod
- def getActivity(context: Any, requestCode: int, intent: Intent,
- flags: int) -> "PendingIntent":
- return PendingIntent(intent, requestCode, flags)
-
- @staticmethod
- def getActivities(context: Any, requestCode: int,
- intents: List[Intent], flags: int) -> "PendingIntent":
- return PendingIntent(intents[0] if intents else None, requestCode, flags)
-
- @staticmethod
- def getBroadcast(context: Any, requestCode: int, intent: Intent,
- flags: int) -> "PendingIntent":
- return PendingIntent(intent, requestCode, flags)
-
- @staticmethod
- def getService(context: Any, requestCode: int, intent: Intent,
- flags: int) -> "PendingIntent":
- return PendingIntent(intent, requestCode, flags)
-
- @staticmethod
- def getForegroundService(context: Any, requestCode: int, intent: Intent,
- flags: int) -> "PendingIntent":
- return PendingIntent(intent, requestCode, flags)
-
- def getIntent(self) -> Optional[Intent]:
- return self._intent
-
- def getCreatorPackage(self) -> str:
- return ""
-
- def getCreatorUid(self) -> int:
- return -1
-
- def getTargetPackage(self) -> str:
- return self._intent.getPackage() if self._intent else ""
-
- def getRequestCode(self) -> int:
- return self._request_code
-
- def isActivity(self) -> bool:
- return True
-
- def isForegroundService(self) -> bool:
- return False
-
- def isBroadcast(self) -> bool:
- return False
-
- def isService(self) -> bool:
- return not self.isActivity() and not self.isBroadcast()
-
- def send(self, code: int = 0, onFinished: Any = None,
- handler: Any = None, requiredPermission: Optional[str] = None,
- options: Optional[Dict[str, Any]] = None) -> None:
- """发送 PendingIntent (桌面存根)"""
- pass
-
- def cancel(self) -> None:
- self._canceled = True
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, PendingIntent):
- return False
- return (self._intent == other._intent
- and self._request_code == other._request_code)
-
- def hashCode(self) -> int:
- h = hash(self._intent) if self._intent else 0
- return (h * 31 + self._request_code) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"PendingIntent(requestCode={self._request_code}, flags=0x{self._flags:08x})"
-
- def getCreatorToken(self) -> Optional[Any]:
- return None
-
- def getTag(self, tagType: str) -> str:
- return ""
-
- def writeToParcel(self, dest: Any, flags: int = 0) -> None:
- pass
-
- def describeContents(self) -> int:
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# IntentSender
-# ═══════════════════════════════════════════════════════════════
-
-class IntentSender(Stub):
- """IntentSender — Intent 发送器"""
-
- class SendIntentException(Exception):
- """SendIntentException — Intent 发送异常"""
- pass
-
- def __init__(self, intent: Optional[Intent] = None):
- super().__init__()
- self._intent = intent
-
- @staticmethod
- def getActivity(context: Any, requestCode: int, intent: Intent,
- flags: int = 0) -> "IntentSender":
- return IntentSender(intent)
-
- def getTargetPackage(self) -> str:
- return self._intent.getPackage() if self._intent else ""
-
- def getCreatorUid(self) -> int:
- return -1
-
- def sendIntent(self, context: Any, code: int, onFinished: Any = None,
- handler: Any = None, requiredPermission: str = "") -> None:
- """发送 Intent (桌面存根)"""
- pass
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, IntentSender):
- return False
- return self._intent == other._intent
-
- def hashCode(self) -> int:
- return hash(self._intent) & 0x7FFFFFFF if self._intent else 0
-
- def toString(self) -> str:
- return f"IntentSender({self._intent})"
-
- def describeContents(self) -> int:
- return 0
-
- def writeToParcel(self, dest: Any, flags: int = 0) -> None:
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# IntentService
-# ═══════════════════════════════════════════════════════════════
-
-class IntentService(Stub):
- """IntentService — Intent 服务 (桌面存根)"""
-
- def __init__(self, name: str = "IntentService"):
- super().__init__()
- self._name = name
- self._started = False
- self._redelivery = False
-
- def onCreate(self) -> None:
- """服务创建"""
- self._started = True
-
- def onStartCommand(self, intent: Optional[Intent], flags: int, startId: int) -> int:
- """接收启动命令"""
- return 1 # START_REDELIVER_INTENT
-
- def onBind(self, intent: Intent) -> Optional[Any]:
- return None
-
- def onDestroy(self) -> None:
- self._started = False
-
- def setIntentRedelivery(self, enabled: bool) -> None:
- self._redelivery = enabled
-
- def stopSelf(self) -> None:
- self._started = False
-
- def stopSelfResult(self, startId: int) -> bool:
- self._started = False
- return True
-
- def toString(self) -> str:
- return f"IntentService(name={self._name}, started={self._started})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# IntentFilter
-# ═══════════════════════════════════════════════════════════════
-
-class IntentFilter(_BaseIntentFilter):
- """IntentFilter — Intent 过滤器 (桌面存根,继承 content.IntentFilter 的所有方法)"""
-
- class AuthorityEntry(Stub):
- """AuthorityEntry — 权限条目"""
-
- def __init__(self, host: str, port: int = -1):
- super().__init__()
- self._host = host
- self._port = port
-
- def getHost(self) -> str:
- return self._host
-
- def getPort(self) -> int:
- return self._port
-
- def match(self, data: Optional[str]) -> int:
- return IntentFilter.MATCH_CATEGORY_HOST if self._host else IntentFilter.NO_MATCH_DATA
-
- def toString(self) -> str:
- return f"AuthorityEntry(host={self._host}, port={self._port})"
-
- class MalformedMimeTypeException(Exception):
- """MalformedMimeTypeException — MIME 类型格式错误"""
- pass
-
- class PriorityGroup:
- """PriorityGroup — 优先级分组"""
- PRIORITY_GROUP_UNDEFINED = 0
- PRIORITY_GROUP_BACKGROUND = 0x1000
- PRIORITY_GROUP_FOREGROUND = 0x2000
- PRIORITY_GROUP_SYSTEM = 0x3000
-
- MATCH_CATEGORY_EMPTY = 0x00000000
- MATCH_CATEGORY_SCHEME = 0x00040000
- MATCH_CATEGORY_AUTHORITY = 0x00080000
- MATCH_CATEGORY_HOST = 0x00100000
- MATCH_CATEGORY_PORT = 0x00200000
- MATCH_CATEGORY_PATH = 0x00400000
- MATCH_CATEGORY_TYPE = 0x00800000
- MATCH_ADJUSTMENT_NORMAL = 0x00008000
- MATCH_ADJUSTMENT_MASK = 0x0000FFFF
- NO_MATCH_ACTION = -3
- NO_MATCH_CATEGORY = -4
- NO_MATCH_DATA = -2
- NO_MATCH_TYPE = -1
- MATCH_CATEGORY_MASK = 0xFFFF0000
-
- SYSTEM_HIGH_PRIORITY = 10000
- SYSTEM_LOW_PRIORITY = -10000
-
- def __init__(self, action: str = "", dataType: str = "",
- dataScheme: str = "", dataAuthority: str = "",
- dataPath: str = ""):
- super().__init__()
- self._actions: List[str] = [action] if action else []
- self._categories: List[str] = []
- self._data_types: List[str] = [dataType] if dataType else []
- self._data_schemes: List[str] = [dataScheme] if dataScheme else []
- self._data_authorities: List[IntentFilter.AuthorityEntry] = []
- if dataAuthority:
- self._data_authorities.append(
- IntentFilter.AuthorityEntry(dataAuthority))
- self._data_paths: List[str] = [dataPath] if dataPath else []
- self._priority: int = 0
- self._has_partial_types = False
- self._mime_group: Optional[str] = None
- self._scheme_specific_parts: List[str] = []
- self._data_scheme_specific_parts: List[str] = []
-
- def addAction(self, action: str) -> None:
- if action not in self._actions:
- self._actions.append(action)
-
- def addCategory(self, category: str) -> None:
- if category not in self._categories:
- self._categories.append(category)
-
- def addDataType(self, type_: str) -> None:
- self._data_types.append(type_)
-
- def addDataScheme(self, scheme: str) -> None:
- if scheme not in self._data_schemes:
- self._data_schemes.append(scheme)
-
- def addDataAuthority(self, host: str, port: int = -1) -> None:
- self._data_authorities.append(
- IntentFilter.AuthorityEntry(host, port))
-
- def addDataPath(self, path: str) -> None:
- self._data_paths.append(path)
-
- def addDataSchemeSpecificPart(self, ssp: str) -> None:
- self._scheme_specific_parts.append(ssp)
-
- def hasAction(self, action: str) -> bool:
- return action in self._actions
-
- def hasCategory(self, category: str) -> bool:
- return category in self._categories
-
- def hasDataType(self, type_: str) -> bool:
- return type_ in self._data_types
-
- def hasDataScheme(self, scheme: str) -> bool:
- return scheme in self._data_schemes
-
- def getAction(self, index: int) -> str:
- return self._actions[index] if 0 <= index < len(self._actions) else ""
-
- def getCategory(self, index: int) -> str:
- return self._categories[index] if 0 <= index < len(self._categories) else ""
-
- def getDataType(self, index: int) -> str:
- return self._data_types[index] if 0 <= index < len(self._data_types) else ""
-
- def getDataScheme(self, index: int) -> str:
- return self._data_schemes[index] if 0 <= index < len(self._data_schemes) else ""
-
- def getDataAuthority(self, index: int) -> Optional[AuthorityEntry]:
- if 0 <= index < len(self._data_authorities):
- return self._data_authorities[index]
- return None
-
- def countActions(self) -> int:
- return len(self._actions)
-
- def countCategories(self) -> int:
- return len(self._categories)
-
- def countDataTypes(self) -> int:
- return len(self._data_types)
-
- def countDataSchemes(self) -> int:
- return len(self._data_schemes)
-
- def countDataAuthorities(self) -> int:
- return len(self._data_authorities)
-
- def countDataPaths(self) -> int:
- return len(self._data_paths)
-
- def setPriority(self, priority: int) -> None:
- self._priority = priority
-
- def getPriority(self) -> int:
- return self._priority
-
- def match(self, action: str, type_: Optional[str], scheme: str,
- data: Optional[str], categories: Set[str], tag: str = "") -> int:
- """匹配 Intent (桌面存根)"""
- if self._actions and action not in self._actions:
- return IntentFilter.NO_MATCH_ACTION
- # 简化匹配逻辑
- return IntentFilter.MATCH_CATEGORY_EMPTY
-
- def matchAction(self, action: str) -> bool:
- return action in self._actions
-
- def matchCategories(self, categories: Set[str]) -> Optional[str]:
- for cat in categories:
- if cat not in self._categories:
- return cat
- return None
-
- def matchData(self, type_: str, scheme: str, data: str) -> int:
- """匹配数据 (桌面存根)"""
- return IntentFilter.MATCH_CATEGORY_EMPTY
-
- def matchDataAuthority(self, data: Optional[str]) -> int:
- for auth in self._data_authorities:
- if auth.match(data) >= 0:
- return IntentFilter.MATCH_CATEGORY_AUTHORITY
- return IntentFilter.NO_MATCH_DATA
-
- def describeContents(self) -> int:
- return 0
-
- def writeToParcel(self, dest: Any, flags: int = 0) -> None:
- pass
-
- def toString(self) -> str:
- return (f"IntentFilter(actions={self._actions}, "
- f"categories={self._categories}, "
- f"types={self._data_types}, "
- f"priority={self._priority})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, IntentFilter):
- return False
- return (self._actions == other._actions
- and self._categories == other._categories)
-
- def hashCode(self) -> int:
- h = 0
- for a in self._actions:
- h = h * 31 + hash(a)
- for c in self._categories:
- h = h * 31 + hash(c)
- return h & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# MatchingFlags
-# ═══════════════════════════════════════════════════════════════
-
-class MatchingFlags(Stub):
- """MatchingFlags — Intent 匹配标志"""
-
- MATCH_ALL = 0x00000000
- MATCH_DEFAULT_ONLY = 0x00010000
- MATCH_SYSTEM_ONLY = 0x00020000
- MATCH_DEBUG_TRIANGULATION = 0x00000010
- MATCH_INSTANT = 0x00000020
- MATCH_VISIBLE_TO_INSTANT_APP_ONLY = 0x00000040
- MATCH_DIRECT_BOOT_AUTO = 0x00000100
- MATCH_DIRECT_BOOT_AWARE = 0x00000200
- MATCH_DIRECT_BOOT_UNAWARE = 0x00000400
- MATCH_SYSTEM = 0x00010000
- MATCH_KNOWN_PACKAGES = 0x00080000
- MATCH_VERIFIED = 0x00100000
- MATCH_APEX = 0x01000000
-
- def __init__(self, flags: int = MATCH_ALL):
- super().__init__()
- self._flags = flags
-
- def getFlags(self) -> int:
- return self._flags
-
- def setFlags(self, flags: int) -> None:
- self._flags = flags
-
- def toString(self) -> str:
- return f"MatchingFlags(0x{self._flags:08x})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ShortcutInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ShortcutInfo(Stub):
- """ShortcutInfo — 快捷方式信息"""
-
- DISABLED_REASON_UNDEFINED = 0
- DISABLED_REASON_NOT_DISABLED = 1
- DISABLED_REASON_BY_APP = 2
- DISABLED_REASON_BY_USER = 3
- DISABLED_REASON_UNKNOWN = 4
- DISABLED_REASON_BACKUP_NOT_SUPPORTED = 5
- DISABLED_REASON_BLOCKED = 6
- DISABLED_REASON_EXCLUDED = 7
- DISABLED_REASON_APP_CHANGED = 8
- DISABLED_REASON_RESTORE_APP_REMOVED = 9
- DISABLED_REASON_RESTORE_BACKUP_NOT_AVAILABLE = 10
- DISABLED_REASON_RESTORE_VERSION_LOWER = 11
- DISABLED_REASON_RESTORE_SIGNATURE_MISMATCH = 12
- DISABLED_REASON_RESTORE_UID_MISMATCH = 13
- DISABLED_REASON_RESTORE_STALE = 14
- DISABLED_REASON_RESTORE_OTHER = 15
- SHORTCUT_TYPE_CLASSIC = 0
- SHORTCUT_TYPE_DYNAMIC = 1
- SHORTCUT_TYPE_PINNED = 2
-
- class Builder(Stub):
- """ShortcutInfo.Builder — ShortcutInfo 构建器"""
-
- def __init__(self, context: Any, id_: str):
- super().__init__()
- self._id = id_
- self._context = context
- self._short_label = ""
- self._long_label = ""
- self._disabled_message = ""
- self._intent: Optional[Intent] = None
- self._intents: List[Intent] = []
- self._icon: Optional[Any] = None
- self._rank = 0
- self._activity: Optional[Any] = None
- self._categories: Set[str] = set()
- self._is_enabled = True
- self._is_declared = False
- self._shortcut_type = ShortcutInfo.SHORTCUT_TYPE_CLASSIC
- self._icon_resource: Optional[Intent.ShortcutIconResource] = None
- self._long_lived = False
- self._person: Optional[Any] = None
- self._package_name = ""
-
- def setShortLabel(self, label: str) -> "ShortcutInfo.Builder":
- self._short_label = label
- return self
-
- def setLongLabel(self, label: str) -> "ShortcutInfo.Builder":
- self._long_label = label
- return self
-
- def setDisabledMessage(self, msg: str) -> "ShortcutInfo.Builder":
- self._disabled_message = msg
- return self
-
- def setIntent(self, intent: Intent) -> "ShortcutInfo.Builder":
- self._intent = intent
- return self
-
- def setIntents(self, intents: List[Intent]) -> "ShortcutInfo.Builder":
- self._intents = list(intents)
- return self
-
- def setIcon(self, icon: Any) -> "ShortcutInfo.Builder":
- self._icon = icon
- return self
-
- def setRank(self, rank: int) -> "ShortcutInfo.Builder":
- self._rank = rank
- return self
-
- def setActivity(self, activity: Any) -> "ShortcutInfo.Builder":
- self._activity = activity
- return self
-
- def setCategories(self, categories: Set[str]) -> "ShortcutInfo.Builder":
- self._categories = set(categories)
- return self
-
- def setLongLived(self, longLived: bool) -> "ShortcutInfo.Builder":
- self._long_lived = longLived
- return self
-
- def setShortcutType(self, shortcutType: int) -> "ShortcutInfo.Builder":
- self._shortcut_type = shortcutType
- return self
-
- def setIconResource(self, resource: Intent.ShortcutIconResource) -> "ShortcutInfo.Builder":
- self._icon_resource = resource
- return self
-
- def setPackageName(self, packageName: str) -> "ShortcutInfo.Builder":
- self._package_name = packageName
- return self
-
- def build(self) -> "ShortcutInfo":
- info = ShortcutInfo(self._id)
- info._short_label = self._short_label
- info._long_label = self._long_label
- info._disabled_message = self._disabled_message
- info._intent = self._intent
- info._intents = list(self._intents)
- info._icon = self._icon
- info._rank = self._rank
- info._activity = self._activity
- info._categories = set(self._categories)
- info._is_enabled = self._is_enabled
- info._shortcut_type = self._shortcut_type
- info._icon_resource = self._icon_resource
- info._long_lived = self._long_lived
- info._person = self._person
- info._package_name = self._package_name
- return info
-
- def __init__(self, id_: str = ""):
- super().__init__()
- self._id = id_
- self._package_name = ""
- self._short_label = ""
- self._long_label = ""
- self._disabled_message = ""
- self._intent: Optional[Intent] = None
- self._intents: List[Intent] = []
- self._icon: Optional[Any] = None
- self._rank = 0
- self._activity: Optional[Any] = None
- self._categories: Set[str] = set()
- self._is_enabled = True
- self._is_declared = False
- self._shortcut_type = ShortcutInfo.SHORTCUT_TYPE_CLASSIC
- self._icon_resource: Optional[Intent.ShortcutIconResource] = None
- self._last_changed_timestamp = 0
- self._long_lived = False
- self._person: Optional[Any] = None
- self._package_name = ""
-
- def getId(self) -> str:
- return self._id
-
- def getPackage(self) -> str:
- return self._package_name
-
- def getShortLabel(self) -> str:
- return self._short_label
-
- def getLongLabel(self) -> str:
- return self._long_label
-
- def getDisabledMessage(self) -> str:
- return self._disabled_message
-
- def getIntent(self) -> Optional[Intent]:
- return self._intent
-
- def getIntents(self) -> List[Intent]:
- return list(self._intents)
-
- def getIcon(self) -> Optional[Any]:
- return self._icon
-
- def getRank(self) -> int:
- return self._rank
-
- def getActivity(self) -> Optional[Any]:
- return self._activity
-
- def getCategories(self) -> Set[str]:
- return set(self._categories)
-
- def isEnabled(self) -> bool:
- return self._is_enabled
-
- def isDeclared(self) -> bool:
- return self._is_declared
-
- def getShortcutType(self) -> int:
- return self._shortcut_type
-
- def getLastChangedTimestamp(self) -> int:
- return self._last_changed_timestamp
-
- def isLongLived(self) -> bool:
- return self._long_lived
-
- def hasIconResource(self) -> bool:
- return self._icon_resource is not None
-
- def getIconResource(self) -> Optional[Intent.ShortcutIconResource]:
- return self._icon_resource
-
- def setRank(self, rank: int) -> None:
- self._rank = rank
-
- def setCategories(self, categories: Set[str]) -> None:
- self._categories = set(categories)
-
- def addCategory(self, category: str) -> None:
- self._categories.add(category)
-
- def toString(self) -> str:
- return (f"ShortcutInfo(id={self._id}, "
- f"shortLabel={self._short_label}, "
- f"rank={self._rank})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, ShortcutInfo):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return hash(self._id) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ShortcutManager
-# ═══════════════════════════════════════════════════════════════
-
-class ShortcutManager(Stub):
- """ShortcutManager — 快捷方式管理器 (扩展)"""
-
- FLAG_MATCH_CACHED = 0x00000001
- FLAG_MATCH_DYNAMIC = 0x00000002
- FLAG_MATCH_MANIFEST = 0x00000004
- FLAG_MATCH_PINNED = 0x00000008
- FLAG_GET_ALL = (FLAG_MATCH_DYNAMIC | FLAG_MATCH_MANIFEST | FLAG_MATCH_PINNED)
- RESULT_OK = 0
- RESULT_FAILURE = -1
- RESULT_DISABLED = -2
- RESULT_DUPLICATE = -3
- RESULT_MAX_SHORTCUTS_REACHED = -4
- RESULT_PINNED_MAX_SHORTCUTS_REACHED = -5
- RESULT_CALLER_NOT_ALLOWED = -6
- RESULT_PACKAGE_NOT_FOUND = -7
- RESULT_STORAGE_FULL = -8
-
- def __init__(self, context: Optional[Any] = None):
- super().__init__()
- self._context = context
- self._dynamic_shortcuts: Dict[str, ShortcutInfo] = {}
- self._pinned_shortcuts: Dict[str, ShortcutInfo] = {}
- self._manifest_shortcuts: Dict[str, ShortcutInfo] = {}
- self._cached_shortcuts: Dict[str, ShortcutInfo] = {}
- self._max_shortcut_count_per_activity = 5
- self._icon_max_width = -1
- self._icon_max_height = -1
- self._rate_limit_attempts = 0
- self._shortcuts_changed_listeners: List[Any] = []
-
- def setDynamicShortcuts(self, shortcutInfos: List[ShortcutInfo]) -> bool:
- self._dynamic_shortcuts.clear()
- for info in shortcutInfos:
- self._dynamic_shortcuts[info.getId()] = info
- return True
-
- def getDynamicShortcuts(self) -> List[ShortcutInfo]:
- return list(self._dynamic_shortcuts.values())
-
- def getManifestShortcuts(self) -> List[ShortcutInfo]:
- return list(self._manifest_shortcuts.values())
-
- def getPinnedShortcuts(self) -> List[ShortcutInfo]:
- return list(self._pinned_shortcuts.values())
-
- def getCachedShortcuts(self) -> List[ShortcutInfo]:
- return list(self._cached_shortcuts.values())
-
- def addDynamicShortcuts(self, shortcutInfos: List[ShortcutInfo]) -> bool:
- for info in shortcutInfos:
- self._dynamic_shortcuts[info.getId()] = info
- return True
-
- def removeDynamicShortcuts(self, shortcutIds: List[str]) -> None:
- for sid in shortcutIds:
- self._dynamic_shortcuts.pop(sid, None)
-
- def removeAllDynamicShortcuts(self) -> None:
- self._dynamic_shortcuts.clear()
-
- def disableShortcuts(self, shortcutIds: List[str],
- disabledMessage: str = "") -> None:
- for sid in shortcutIds:
- if sid in self._dynamic_shortcuts:
- self._dynamic_shortcuts[sid]._is_enabled = False
- if sid in self._pinned_shortcuts:
- self._pinned_shortcuts[sid]._is_enabled = False
-
- def enableShortcuts(self, shortcutIds: List[str]) -> None:
- for sid in shortcutIds:
- if sid in self._dynamic_shortcuts:
- self._dynamic_shortcuts[sid]._is_enabled = True
- if sid in self._pinned_shortcuts:
- self._pinned_shortcuts[sid]._is_enabled = True
-
- def getShortcuts(self, matchFlags: int = FLAG_GET_ALL) -> List[ShortcutInfo]:
- result: List[ShortcutInfo] = []
- if matchFlags & ShortcutManager.FLAG_MATCH_DYNAMIC:
- result.extend(self._dynamic_shortcuts.values())
- if matchFlags & ShortcutManager.FLAG_MATCH_PINNED:
- result.extend(self._pinned_shortcuts.values())
- if matchFlags & ShortcutManager.FLAG_MATCH_MANIFEST:
- result.extend(self._manifest_shortcuts.values())
- if matchFlags & ShortcutManager.FLAG_MATCH_CACHED:
- result.extend(self._cached_shortcuts.values())
- return result
-
- def updateShortcuts(self, shortcutInfos: List[ShortcutInfo]) -> bool:
- for info in shortcutInfos:
- sid = info.getId()
- if sid in self._dynamic_shortcuts:
- self._dynamic_shortcuts[sid] = info
- if sid in self._pinned_shortcuts:
- self._pinned_shortcuts[sid] = info
- return True
-
- def isRateLimitingActive(self) -> bool:
- return self._rate_limit_attempts > 5
-
- def getIconMaxWidth(self) -> int:
- return self._icon_max_width
-
- def getIconMaxHeight(self) -> int:
- return self._icon_max_height
-
- def pushDynamicShortcut(self, shortcut: ShortcutInfo) -> None:
- self._dynamic_shortcuts[shortcut.getId()] = shortcut
-
- def removeLongLivedShortcuts(self, shortcutIds: List[str]) -> None:
- for sid in shortcutIds:
- self._dynamic_shortcuts.pop(sid, None)
- self._pinned_shortcuts.pop(sid, None)
-
- def onApplicationActive(self, packageName: str, userId: int) -> None:
- """应用激活回调 (桌面存根)"""
- pass
-
- def registerShortcutsChangedListener(
- self, listener: Any, handler: Any = None) -> None:
- self._shortcuts_changed_listeners.append(listener)
-
- def unregisterShortcutsChangedListener(self, listener: Any) -> None:
- if listener in self._shortcuts_changed_listeners:
- self._shortcuts_changed_listeners.remove(listener)
-
- def reportShortcutUsed(self, shortcutId: str) -> None:
- """报告快捷方式被使用"""
- pass
-
- def setShareTargets(self, packageName: str, shareTargets: List[Any]) -> None:
- """设置分享目标 (桌面存根)"""
- pass
-
- def getShareTargets(self, packageName: str) -> List[Any]:
- """获取分享目标 (桌面存根)"""
- return []
-
- def getMaxShortcutCountPerActivity(self) -> int:
- return self._max_shortcut_count_per_activity
-
- def toString(self) -> str:
- return (f"ShortcutManager(dynamic={len(self._dynamic_shortcuts)}, "
- f"pinned={len(self._pinned_shortcuts)})")
\ No newline at end of file
diff --git a/android_pyapi/android/content_om.py b/android_pyapi/android/content_om.py
deleted file mode 100644
index cf6c030..0000000
--- a/android_pyapi/android/content_om.py
+++ /dev/null
@@ -1,551 +0,0 @@
-"""
-Android OverlayManager API — OverlayManager, OverlayInfo, OverlayManagerTransaction, OverlayStore
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import time
-import json
-import uuid
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# CATEGORY_* 常量
-CATEGORY_ALL = "android.overlay.category.ALL"
-CATEGORY_FONT = "android.overlay.category.FONT"
-CATEGORY_THEME = "android.overlay.category.THEME"
-CATEGORY_ICON = "android.overlay.category.ICON"
-CATEGORY_ICON_OVERLAY = "android.overlay.category.ICON_OVERLAY"
-CATEGORY_SOUND = "android.overlay.category.SOUND"
-CATEGORY_BOOT_ANIMATION = "android.overlay.category.BOOT_ANIMATION"
-CATEGORY_WALLPAPER = "android.overlay.category.WALLPAPER"
-CATEGORY_DYNAMIC = "android.overlay.category.DYNAMIC"
-CATEGORY_RRO = "android.overlay.category.RRO"
-CATEGORY_STATIC = "android.overlay.category.STATIC"
-
-# STATE_* 常量
-STATE_UNKNOWN = 0
-STATE_NOT_INSTALLED = 1
-STATE_INSTALLED = 2
-STATE_ENABLED = 3
-STATE_DISABLED = 4
-STATE_ENABLEMENT_DISABLED = 5
-STATE_ENABLEMENT_ENABLED = 6
-STATE_ENABLEMENT_UNKNOWN = 7
-STATE_OVERLAY_NOT_FOUND = 8
-STATE_OVERLAY_UPGRADING = 9
-STATE_OVERLAY_REMOVED = 10
-STATE_PACKAGE_INSTALLED = 11
-STATE_PACKAGE_UPDATED = 12
-STATE_PACKAGE_REMOVED = 13
-STATE_TARGET_PACKAGE_CHANGED = 14
-STATE_MISSING_TARGET_PACKAGE = 15
-STATE_UPGRADE_PENDING = 16
-
-# FLAG_* 常量
-FLAG_ENABLE = 0x00000001
-FLAG_DISABLE = 0x00000002
-FLAG_REMOVE = 0x00000004
-FLAG_UPGRADE = 0x00000008
-FLAG_INSTALL = 0x00000010
-FLAG_IMMUTABLE = 0x00000020
-FLAG_SYSTEM = 0x00000040
-FLAG_STATIC_OVERLAY = 0x00000080
-FLAG_DYNAMIC_OVERLAY = 0x00000100
-FLAG_FIRST_TARGET = 0x00000200
-FLAG_LAST_TARGET = 0x00000400
-FLAG_EXTERNAL = 0x00000800
-FLAG_PERSISTENT = 0x00001000
-
-# PRIORITY_ORDER 常量
-PRIORITY_ORDER_UNDEFINED = 0
-PRIORITY_ORDER_LOWEST = 1
-PRIORITY_ORDER_LOW = 2
-PRIORITY_ORDER_MEDIUM = 3
-PRIORITY_ORDER_HIGH = 4
-PRIORITY_ORDER_HIGHEST = 5
-
-
-# ═══════════════════════════════════════════════════════════════
-# OverlayInfo
-# ═══════════════════════════════════════════════════════════════
-
-class OverlayInfo(Stub):
- """OverlayInfo — 覆盖层信息"""
-
- CATEGORY_ALL = CATEGORY_ALL
- CATEGORY_FONT = CATEGORY_FONT
- CATEGORY_THEME = CATEGORY_THEME
- CATEGORY_ICON = CATEGORY_ICON
- CATEGORY_ICON_OVERLAY = CATEGORY_ICON_OVERLAY
- CATEGORY_SOUND = CATEGORY_SOUND
- CATEGORY_BOOT_ANIMATION = CATEGORY_BOOT_ANIMATION
- CATEGORY_WALLPAPER = CATEGORY_WALLPAPER
- CATEGORY_DYNAMIC = CATEGORY_DYNAMIC
-
- STATE_UNKNOWN = STATE_UNKNOWN
- STATE_NOT_INSTALLED = STATE_NOT_INSTALLED
- STATE_INSTALLED = STATE_INSTALLED
- STATE_ENABLED = STATE_ENABLED
- STATE_DISABLED = STATE_DISABLED
- STATE_ENABLEMENT_DISABLED = STATE_ENABLEMENT_DISABLED
- STATE_ENABLEMENT_ENABLED = STATE_ENABLEMENT_ENABLED
- STATE_ENABLEMENT_UNKNOWN = STATE_ENABLEMENT_UNKNOWN
- STATE_OVERLAY_NOT_FOUND = STATE_OVERLAY_NOT_FOUND
- STATE_OVERLAY_UPGRADING = STATE_OVERLAY_UPGRADING
- STATE_PACKAGE_INSTALLED = STATE_PACKAGE_INSTALLED
- STATE_PACKAGE_UPDATED = STATE_PACKAGE_UPDATED
- STATE_PACKAGE_REMOVED = STATE_PACKAGE_REMOVED
- STATE_TARGET_PACKAGE_CHANGED = STATE_TARGET_PACKAGE_CHANGED
- STATE_UPGRADE_PENDING = STATE_UPGRADE_PENDING
-
- def __init__(
- self,
- packageName: str = "",
- targetPackageName: str = "",
- category: str = CATEGORY_THEME,
- state: int = STATE_UNKNOWN,
- ):
- super().__init__()
- self._package_name = packageName
- self._target_package_name = targetPackageName
- self._category = category
- self._state = state
- self._is_enabled = (state == STATE_ENABLED or state == STATE_ENABLEMENT_ENABLED)
- self._priority = 0
- self._is_static = False
- self._is_upgradable = False
- self._is_system = False
- self._version = 0
- self._config: Optional[str] = None
- self._label: Optional[str] = None
- self._icon: Optional[Any] = None
- self._fabricated = False
- self._overlay_path: Optional[str] = None
- self._target_overlayable_name: Optional[str] = None
- self._require_all = False
- self._overlay_category: Optional[str] = category
- self._base_path: Optional[str] = None
- self._overlay_id = str(uuid.uuid4())
- self._install_time = time.time()
- self._mod_time = time.time()
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def getTargetPackageName(self) -> str:
- return self._target_package_name
-
- def getCategory(self) -> str:
- return self._category
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int) -> None:
- self._state = state
- self._is_enabled = (state == STATE_ENABLED)
-
- def isEnabled(self) -> bool:
- return self._is_enabled
-
- def getPriority(self) -> int:
- return self._priority
-
- def setPriority(self, priority: int) -> None:
- self._priority = priority
-
- def isStatic(self) -> bool:
- return self._is_static
-
- def isUpgradable(self) -> bool:
- return self._is_upgradable
-
- def isSystem(self) -> bool:
- return self._is_system
-
- def getVersion(self) -> int:
- return self._version
-
- def getLabel(self) -> Optional[str]:
- return self._label
-
- def getIcon(self) -> Optional[Any]:
- return self._icon
-
- def isFabricated(self) -> bool:
- return self._fabricated
-
- def getOverlayPath(self) -> Optional[str]:
- return self._overlay_path
-
- def getTargetOverlayableName(self) -> Optional[str]:
- return self._target_overlayable_name
-
- def getOverlayId(self) -> str:
- return self._overlay_id
-
- def getInstallTime(self) -> float:
- return self._install_time
-
- def getModTime(self) -> float:
- return self._mod_time
-
- def getConfig(self) -> Optional[str]:
- return self._config
-
- def requiresAll(self) -> bool:
- return self._require_all
-
- def toString(self) -> str:
- return (
- f"OverlayInfo(package={self._package_name}, "
- f"target={self._target_package_name}, "
- f"category={self._category}, "
- f"state={self._state})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# OverlayManagerTransaction
-# ═══════════════════════════════════════════════════════════════
-
-class OverlayManagerTransaction(Stub):
- """OverlayManagerTransaction — 覆盖层管理器事务"""
-
- TYPE_UNKNOWN = 0
- TYPE_SET_ENABLED = 1
- TYPE_SET_DISABLED = 2
- TYPE_REGISTER = 3
- TYPE_UNREGISTER = 4
- TYPE_SET_PRIORITY = 5
- TYPE_SET_CATEGORY = 6
- TYPE_SET_TARGET = 7
- TYPE_REMOVE = 8
- TYPE_SET_STATE = 9
-
- def __init__(self):
- super().__init__()
- self._operations: List[Dict[str, Any]] = []
- self._transaction_id = str(uuid.uuid4())
- self._created_at = time.time()
- self._committed = False
- self._rollback_on_failure = True
-
- def setEnabled(self, packageName: str, enabled: bool) -> "OverlayManagerTransaction":
- self._operations.append({
- "type": OverlayManagerTransaction.TYPE_SET_ENABLED,
- "packageName": packageName,
- "enabled": enabled,
- })
- return self
-
- def setDisabled(self, packageName: str) -> "OverlayManagerTransaction":
- self._operations.append({
- "type": OverlayManagerTransaction.TYPE_SET_DISABLED,
- "packageName": packageName,
- })
- return self
-
- def registerOverlay(self, packageName: str) -> "OverlayManagerTransaction":
- self._operations.append({
- "type": OverlayManagerTransaction.TYPE_REGISTER,
- "packageName": packageName,
- })
- return self
-
- def unregisterOverlay(self, packageName: str) -> "OverlayManagerTransaction":
- self._operations.append({
- "type": OverlayManagerTransaction.TYPE_UNREGISTER,
- "packageName": packageName,
- })
- return self
-
- def setPriority(self, packageName: str, priority: int) -> "OverlayManagerTransaction":
- self._operations.append({
- "type": OverlayManagerTransaction.TYPE_SET_PRIORITY,
- "packageName": packageName,
- "priority": priority,
- })
- return self
-
- def setCategory(self, packageName: str, category: str) -> "OverlayManagerTransaction":
- self._operations.append({
- "type": OverlayManagerTransaction.TYPE_SET_CATEGORY,
- "packageName": packageName,
- "category": category,
- })
- return self
-
- def setTarget(self, packageName: str, target: str) -> "OverlayManagerTransaction":
- self._operations.append({
- "type": OverlayManagerTransaction.TYPE_SET_TARGET,
- "packageName": packageName,
- "target": target,
- })
- return self
-
- def removeOverlay(self, packageName: str) -> "OverlayManagerTransaction":
- self._operations.append({
- "type": OverlayManagerTransaction.TYPE_REMOVE,
- "packageName": packageName,
- })
- return self
-
- def getOperations(self) -> List[Dict[str, Any]]:
- return list(self._operations)
-
- def getTransactionId(self) -> str:
- return self._transaction_id
-
- def isCommitted(self) -> bool:
- return self._committed
-
- def getOperationCount(self) -> int:
- return len(self._operations)
-
- def toString(self) -> str:
- return f"OverlayManagerTransaction(ops={len(self._operations)}, committed={self._committed})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# OverlayStore
-# ═══════════════════════════════════════════════════════════════
-
-class OverlayStore(Stub):
- """OverlayStore — 覆盖层存储"""
-
- def __init__(self):
- super().__init__()
- self._overlays: Dict[str, OverlayInfo] = {}
- self._lock = threading.Lock()
- self._store_path: Optional[str] = None
- self._max_overlays = 100
- self._persist_enabled = False
-
- def getOverlay(self, packageName: str) -> Optional[OverlayInfo]:
- with self._lock:
- return self._overlays.get(packageName)
-
- def getAllOverlays(self) -> List[OverlayInfo]:
- with self._lock:
- return list(self._overlays.values())
-
- def getOverlaysForTarget(self, targetPackage: str) -> List[OverlayInfo]:
- with self._lock:
- return [
- info for info in self._overlays.values()
- if info.getTargetPackageName() == targetPackage
- ]
-
- def getOverlaysByCategory(self, category: str) -> List[OverlayInfo]:
- with self._lock:
- return [
- info for info in self._overlays.values()
- if info.getCategory() == category
- ]
-
- def addOverlay(self, info: OverlayInfo) -> None:
- with self._lock:
- self._overlays[info.getPackageName()] = info
-
- def removeOverlay(self, packageName: str) -> Optional[OverlayInfo]:
- with self._lock:
- return self._overlays.pop(packageName, None)
-
- def updateOverlay(self, packageName: str, info: OverlayInfo) -> bool:
- with self._lock:
- if packageName in self._overlays:
- self._overlays[packageName] = info
- return True
- return False
-
- def contains(self, packageName: str) -> bool:
- with self._lock:
- return packageName in self._overlays
-
- def getEnabledOverlays(self) -> List[OverlayInfo]:
- with self._lock:
- return [info for info in self._overlays.values() if info.isEnabled()]
-
- def getDisabledOverlays(self) -> List[OverlayInfo]:
- with self._lock:
- return [info for info in self._overlays.values() if not info.isEnabled()]
-
- def getStaticOverlays(self) -> List[OverlayInfo]:
- with self._lock:
- return [info for info in self._overlays.values() if info.isStatic()]
-
- def getOverlayCount(self) -> int:
- with self._lock:
- return len(self._overlays)
-
- def clear(self) -> None:
- with self._lock:
- self._overlays.clear()
-
- def toString(self) -> str:
- with self._lock:
- return f"OverlayStore(overlays={len(self._overlays)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# OverlayManager
-# ═══════════════════════════════════════════════════════════════
-
-class OverlayManager(Stub):
- """OverlayManager — 覆盖层管理器 (桌面存根)"""
-
- CATEGORY_ALL = CATEGORY_ALL
- CATEGORY_FONT = CATEGORY_FONT
- CATEGORY_THEME = CATEGORY_THEME
- CATEGORY_ICON = CATEGORY_ICON
- CATEGORY_SOUND = CATEGORY_SOUND
-
- FLAG_ENABLE = FLAG_ENABLE
- FLAG_DISABLE = FLAG_DISABLE
- FLAG_REMOVE = FLAG_REMOVE
- FLAG_UPGRADE = FLAG_UPGRADE
- FLAG_INSTALL = FLAG_INSTALL
- FLAG_IMMUTABLE = FLAG_IMMUTABLE
- FLAG_SYSTEM = FLAG_SYSTEM
- FLAG_STATIC_OVERLAY = FLAG_STATIC_OVERLAY
- FLAG_DYNAMIC_OVERLAY = FLAG_DYNAMIC_OVERLAY
- FLAG_EXTERNAL = FLAG_EXTERNAL
- FLAG_PERSISTENT = FLAG_PERSISTENT
-
- STATE_UNKNOWN = STATE_UNKNOWN
- STATE_NOT_INSTALLED = STATE_NOT_INSTALLED
- STATE_INSTALLED = STATE_INSTALLED
- STATE_ENABLED = STATE_ENABLED
- STATE_DISABLED = STATE_DISABLED
- STATE_ENABLEMENT_DISABLED = STATE_ENABLEMENT_DISABLED
- STATE_ENABLEMENT_ENABLED = STATE_ENABLEMENT_ENABLED
- STATE_ENABLEMENT_UNKNOWN = STATE_ENABLEMENT_UNKNOWN
- STATE_OVERLAY_NOT_FOUND = STATE_OVERLAY_NOT_FOUND
- STATE_OVERLAY_UPGRADING = STATE_OVERLAY_UPGRADING
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._store = OverlayStore()
- self._lock = threading.Lock()
- self._transaction_history: List[OverlayManagerTransaction] = []
- self._callbacks: Dict[str, List[Callable]] = {}
- self._is_available = True
-
- def getOverlayInfo(self, packageName: str) -> Optional[OverlayInfo]:
- with self._lock:
- return self._store.getOverlay(packageName)
-
- def getAllOverlays(self) -> List[OverlayInfo]:
- with self._lock:
- return self._store.getAllOverlays()
-
- def getOverlaysForTarget(self, targetPackage: str) -> List[OverlayInfo]:
- with self._lock:
- return self._store.getOverlaysForTarget(targetPackage)
-
- def setEnabled(self, packageName: str, enabled: bool, userId: int = 0) -> None:
- with self._lock:
- info = self._store.getOverlay(packageName)
- if info:
- new_state = STATE_ENABLED if enabled else STATE_DISABLED
- info.setState(new_state)
-
- def setEnabledExclusive(
- self, packageName: str, withinCategory: bool, userId: int = 0
- ) -> None:
- with self._lock:
- info = self._store.getOverlay(packageName)
- if info:
- info.setState(STATE_ENABLED)
- category = info.getCategory()
- for overlay in self._store.getAllOverlays():
- if overlay.getPackageName() != packageName:
- if withinCategory and overlay.getCategory() == category:
- overlay.setState(STATE_DISABLED)
- elif not withinCategory:
- overlay.setState(STATE_DISABLED)
-
- def isEnabled(self, packageName: str) -> bool:
- with self._lock:
- info = self._store.getOverlay(packageName)
- return info is not None and info.isEnabled()
-
- def commit(
- self, transaction: OverlayManagerTransaction
- ) -> None:
- with self._lock:
- for op in transaction.getOperations():
- op_type = op.get("type")
- pkg = op.get("packageName", "")
- if op_type == OverlayManagerTransaction.TYPE_SET_ENABLED:
- self.setEnabled(pkg, op.get("enabled", True))
- elif op_type == OverlayManagerTransaction.TYPE_SET_DISABLED:
- self.setEnabled(pkg, False)
- elif op_type == OverlayManagerTransaction.TYPE_REGISTER:
- info = OverlayInfo(packageName=pkg)
- self._store.addOverlay(info)
- elif op_type == OverlayManagerTransaction.TYPE_UNREGISTER:
- self._store.removeOverlay(pkg)
- elif op_type == OverlayManagerTransaction.TYPE_SET_PRIORITY:
- info = self._store.getOverlay(pkg)
- if info:
- info.setPriority(op.get("priority", 0))
- elif op_type == OverlayManagerTransaction.TYPE_REMOVE:
- self._store.removeOverlay(pkg)
- self._transaction_history.append(transaction)
-
- def getDefaultOverlayPackages(self) -> List[str]:
- return []
-
- def getOverlayInfosForTarget(self, targetPackage: str, userId: int = 0) -> List[OverlayInfo]:
- return self.getOverlaysForTarget(targetPackage)
-
- def getOverlayStore(self) -> OverlayStore:
- return self._store
-
- def registerCallback(self, callback: Any) -> None:
- pass
-
- def unregisterCallback(self, callback: Any) -> None:
- pass
-
- def onOverlayChanged(self, packageName: str) -> None:
- pass
-
- def onOverlayStateChanged(self, packageName: str, newState: int) -> None:
- pass
-
- def isUpgradePending(self, packageName: str) -> bool:
- return False
-
- def getCategoryForOverlay(self, packageName: str) -> Optional[str]:
- with self._lock:
- info = self._store.getOverlay(packageName)
- return info.getCategory() if info else None
-
- def getPriority(self, packageName: str) -> int:
- with self._lock:
- info = self._store.getOverlay(packageName)
- return info.getPriority() if info else 0
-
- def toString(self) -> str:
- with self._lock:
- return (
- f"OverlayManager(overlays={self._store.getOverlayCount()}, "
- f"transactions={len(self._transaction_history)})"
- )
\ No newline at end of file
diff --git a/android_pyapi/android/content_pm.py b/android_pyapi/android/content_pm.py
deleted file mode 100644
index 1f2283e..0000000
--- a/android_pyapi/android/content_pm.py
+++ /dev/null
@@ -1,801 +0,0 @@
-"""
-Android PackageManager 组件 — PackageManager, PackageInfo, ApplicationInfo 等
-方法签名完全对齐 Android SDK
-"""
-
-import json
-import os
-import sys
-from typing import Any, Dict, List, Optional, Set
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# 数据存储路径
-# ═══════════════════════════════════════════════════════════════
-
-_PACKAGE_DATA_DIR = os.path.join(_app_data_dir, "package_data")
-os.makedirs(_PACKAGE_DATA_DIR, exist_ok=True)
-
-_DEFAULT_PACKAGE_INFO_PATH = os.path.join(_PACKAGE_DATA_DIR, f"{_package_name}.json")
-
-
-def _get_default_package_info() -> Dict[str, Any]:
- """获取默认包信息"""
- return {
- "packageName": _package_name,
- "versionName": "1.0.0",
- "versionCode": 1,
- "applicationInfo": {
- "name": _package_name,
- "packageName": _package_name,
- "className": f"{_package_name}.MainApplication",
- "icon": 0,
- "targetSdkVersion": 34,
- "sourceDir": os.path.join(_app_data_dir, "base.apk"),
- "dataDir": _app_data_dir,
- "enabled": True,
- "flags": 0,
- "theme": 0,
- "labelRes": 0,
- "descriptionRes": 0,
- "logo": 0,
- "banner": 0,
- "processName": _package_name,
- "uid": 10001,
- "manageSpaceActivityName": "",
- "taskAffinity": "",
- "permission": "",
- },
- "activities": [],
- "services": [],
- "receivers": [],
- "providers": [],
- "permissions": [],
- "requestedPermissions": [
- "android.permission.INTERNET",
- "android.permission.ACCESS_NETWORK_STATE",
- ],
- "features": {
- "android.hardware.camera": True,
- "android.hardware.wifi": True,
- "android.hardware.bluetooth": True,
- "android.hardware.location": True,
- "android.hardware.sensor.accelerometer": True,
- "android.hardware.sensor.gyroscope": True,
- "android.hardware.touchscreen": True,
- "android.hardware.microphone": True,
- "android.hardware.nfc": False,
- "android.hardware.telephony": True,
- "android.software.picture_in_picture": True,
- "android.hardware.usb.host": False,
- }
- }
-
-
-# ═══════════════════════════════════════════════════════════════
-# PackageItemInfo (基类)
-# ═══════════════════════════════════════════════════════════════
-
-class PackageItemInfo(Stub):
- """PackageItemInfo — 包条目信息基类"""
-
- def __init__(self, data: Optional[Dict[str, Any]] = None):
- super().__init__()
- data = data or {}
- self.name = data.get("name", "")
- self.packageName = data.get("packageName", "")
- self.labelRes = data.get("labelRes", 0)
- self.nonLocalizedLabel = data.get("nonLocalizedLabel", None)
- self.icon = data.get("icon", 0)
- self.banner = data.get("banner", 0)
- self.logo = data.get("logo", 0)
-
- def loadLabel(self, pm: "PackageManager") -> str:
- return self.nonLocalizedLabel or self.name.split(".")[-1] if self.name else ""
-
- def loadIcon(self, pm: "PackageManager") -> Any:
- return None
-
- def loadLogo(self, pm: "PackageManager") -> Any:
- return None
-
- def loadBanner(self, pm: "PackageManager") -> Any:
- return None
-
- def toString(self) -> str:
- return f"{self.__class__.__name__}({self.packageName}:{self.name})"
-
-
-class ComponentInfo(PackageItemInfo):
- """ComponentInfo — 组件信息基类"""
-
- def __init__(self, data: Optional[Dict[str, Any]] = None):
- super().__init__(data)
- data = data or {}
- self.processName = data.get("processName", self.packageName)
- self.splitName = data.get("splitName", None)
- self.enabled = data.get("enabled", True)
- self.exported = data.get("exported", False)
- self.directBootAware = data.get("directBootAware", False)
-
- def getComponentName(self) -> Any:
- from .content import ComponentName
- return ComponentName(self.packageName, self.name)
-
- def isEnabled(self) -> bool:
- return self.enabled
-
-
-# ═══════════════════════════════════════════════════════════════
-# ApplicationInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ApplicationInfo(ComponentInfo):
- """ApplicationInfo — 应用信息"""
-
- FLAG_SYSTEM = 1
- FLAG_DEBUGGABLE = 2
- FLAG_HAS_CODE = 4
- FLAG_ALLOW_CLEAR_USER_DATA = 0x00400000
- FLAG_ALLOW_BACKUP = 0x00008000
- FLAG_EXTERNAL_STORAGE = 0x00100000
- FLAG_LARGE_HEAP = 0x00100000
- FLAG_MULTIPROCESS = 0x00010000
- FLAG_TEST_ONLY = 0x00000100
- FLAG_STOPPED = 0x00200000
- FLAG_RESTART_ON_UPGRADE = 0x00000020
-
- def __init__(self, data: Optional[Dict[str, Any]] = None):
- super().__init__(data)
- data = data or {}
- self.taskAffinity = data.get("taskAffinity", "")
- self.permission = data.get("permission", "")
- self.processName = data.get("processName", self.packageName)
- self.className = data.get("className", "")
- self.descriptionRes = data.get("descriptionRes", 0)
- self.theme = data.get("theme", 0)
- self.flags = data.get("flags", 0)
- self.sourceDir = data.get("sourceDir", "")
- self.publicSourceDir = data.get("publicSourceDir", self.sourceDir)
- self.dataDir = data.get("dataDir", "")
- self.nativeLibraryDir = data.get("nativeLibraryDir", "")
- self.metaData = data.get("metaData", None)
- self.manageSpaceActivityName = data.get("manageSpaceActivityName", "")
- self.targetSdkVersion = data.get("targetSdkVersion", 34)
- self.uid = data.get("uid", 10001)
- self.backupAgentName = data.get("backupAgentName", "")
- self.enabled = data.get("enabled", True)
-
- def loadDescription(self, pm: "PackageManager") -> Optional[str]:
- return None
-
- def toString(self) -> str:
- return f"ApplicationInfo({self.packageName}, targetSdk={self.targetSdkVersion})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ActivityInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ActivityInfo(ComponentInfo):
- """ActivityInfo — Activity 组件信息"""
-
- CONFIG_MCC = 0x0001
- CONFIG_MNC = 0x0002
- CONFIG_LOCALE = 0x0004
- CONFIG_TOUCHSCREEN = 0x0008
- CONFIG_KEYBOARD = 0x0010
- CONFIG_KEYBOARD_HIDDEN = 0x0020
- CONFIG_NAVIGATION = 0x0040
- CONFIG_ORIENTATION = 0x0080
- CONFIG_SCREEN_LAYOUT = 0x0100
- CONFIG_UI_MODE = 0x0200
- CONFIG_SCREEN_SIZE = 0x0400
- CONFIG_SMALLEST_SCREEN_SIZE = 0x0800
- CONFIG_DENSITY = 0x1000
- CONFIG_LAYOUT_DIRECTION = 0x2000
- CONFIG_COLOR_MODE = 0x4000
-
- LAUNCH_MULTIPLE = 0
- LAUNCH_SINGLE_TOP = 1
- LAUNCH_SINGLE_TASK = 2
- LAUNCH_SINGLE_INSTANCE = 3
- LAUNCH_SINGLE_INSTANCE_PER_TASK = 4
-
- SCREEN_ORIENTATION_UNSPECIFIED = -1
- SCREEN_ORIENTATION_LANDSCAPE = 0
- SCREEN_ORIENTATION_PORTRAIT = 1
- SCREEN_ORIENTATION_USER = 2
- SCREEN_ORIENTATION_BEHIND = 3
- SCREEN_ORIENTATION_SENSOR = 4
- SCREEN_ORIENTATION_NOSENSOR = 5
- SCREEN_ORIENTATION_SENSOR_LANDSCAPE = 6
- SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7
- SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8
- SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9
- SCREEN_ORIENTATION_FULL_SENSOR = 10
- SCREEN_ORIENTATION_USER_LANDSCAPE = 11
- SCREEN_ORIENTATION_USER_PORTRAIT = 12
- SCREEN_ORIENTATION_FULL_USER = 13
- SCREEN_ORIENTATION_LOCKED = 14
-
- def __init__(self, data: Optional[Dict[str, Any]] = None):
- super().__init__(data)
- data = data or {}
- self.launchMode = data.get("launchMode", self.LAUNCH_MULTIPLE)
- self.screenOrientation = data.get("screenOrientation", self.SCREEN_ORIENTATION_UNSPECIFIED)
- self.configChanges = data.get("configChanges", 0)
- self.softInputMode = data.get("softInputMode", 0)
- self.theme = data.get("theme", 0)
- self.parentActivityName = data.get("parentActivityName", "")
- self.permission = data.get("permission", "")
- self.taskAffinity = data.get("taskAffinity", "")
- self.targetActivity = data.get("targetActivity", "")
-
- def toString(self) -> str:
- return f"ActivityInfo({self.name}, launchMode={self.launchMode})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ServiceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ServiceInfo(ComponentInfo):
- """ServiceInfo — Service 组件信息"""
-
- FLAG_STOP_WITH_TASK = 0x01
- FLAG_ISOLATED_PROCESS = 0x02
- FLAG_EXTERNAL_SERVICE = 0x04
- FLAG_SINGLE_USER = 0x40000000
- FLAG_USE_APP_OP = 0x08
-
- def __init__(self, data: Optional[Dict[str, Any]] = None):
- super().__init__(data)
- data = data or {}
- self.flags = data.get("flags", 0)
- self.permission = data.get("permission", "")
- self.foregroundServiceType = data.get("foregroundServiceType", 0)
-
- def toString(self) -> str:
- return f"ServiceInfo({self.name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ProviderInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ProviderInfo(ComponentInfo):
- """ProviderInfo — ContentProvider 组件信息"""
-
- def __init__(self, data: Optional[Dict[str, Any]] = None):
- super().__init__(data)
- data = data or {}
- self.authority = data.get("authority", "")
- self.readPermission = data.get("readPermission", "")
- self.writePermission = data.get("writePermission", "")
- self.grantUriPermissions = data.get("grantUriPermissions", False)
- self.multiprocess = data.get("multiprocess", False)
- self.initOrder = data.get("initOrder", 0)
- self.flags = data.get("flags", 0)
-
- def toString(self) -> str:
- return f"ProviderInfo({self.name}, authority={self.authority})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PermissionInfo
-# ═══════════════════════════════════════════════════════════════
-
-class PermissionInfo(PackageItemInfo):
- """PermissionInfo — 权限信息"""
-
- PROTECTION_NORMAL = 0
- PROTECTION_DANGEROUS = 1
- PROTECTION_SIGNATURE = 2
- PROTECTION_SIGNATURE_OR_SYSTEM = 3
- PROTECTION_INTERNAL = 4
-
- FLAG_COSTS_MONEY = 0x01
- FLAG_HARDWARE_RESTRICTED = 0x04
- FLAG_IMMUTABLY_RESTRICTED = 0x08
- FLAG_INSTALLED = 0x10
-
- def __init__(self, data: Optional[Dict[str, Any]] = None):
- super().__init__(data)
- data = data or {}
- self.group = data.get("group", "")
- self.descriptionRes = data.get("descriptionRes", 0)
- self.protectionLevel = data.get("protectionLevel", self.PROTECTION_NORMAL)
- self.flags = data.get("flags", 0)
-
- def loadDescription(self, pm: "PackageManager") -> Optional[str]:
- return None
-
- def toString(self) -> str:
- return f"PermissionInfo({self.name}, protectionLevel={self.protectionLevel})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ResolveInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ResolveInfo(Stub):
- """ResolveInfo — 解析意图的结果"""
-
- def __init__(self):
- super().__init__()
- self.activityInfo: Optional[ActivityInfo] = None
- self.serviceInfo: Optional[ServiceInfo] = None
- self.providerInfo: Optional[ProviderInfo] = None
- self.filter: Optional[Any] = None
- self.priority = 0
- self.match = 0
- self.preferredOrder = 0
- self.isDefault = False
- self.labelRes = 0
- self.nonLocalizedLabel = None
- self.icon = 0
- self.resolvePackageName = ""
- self.specificIndex = -1
- self.system = False
-
- def loadLabel(self, pm: "PackageManager") -> str:
- if self.activityInfo:
- return self.activityInfo.name.split(".")[-1]
- if self.serviceInfo:
- return self.serviceInfo.name.split(".")[-1]
- return ""
-
- def loadIcon(self, pm: "PackageManager"):
- return None
-
- def getIconResource(self) -> int:
- return self.icon
-
- def toString(self) -> str:
- return f"ResolveInfo(priority={self.priority})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PackageInfo
-# ═══════════════════════════════════════════════════════════════
-
-class PackageInfo(Stub):
- """PackageInfo — 包信息"""
-
- INSTALL_LOCATION_AUTO = 0
- INSTALL_LOCATION_INTERNAL_ONLY = 1
- INSTALL_LOCATION_PREFER_EXTERNAL = 2
- REQUESTED_PERMISSION_REQUIRED = 0x00100000
- REQUESTED_PERMISSION_GRANTED = 0x01000000
- REQUESTED_PERMISSION_DENIED = 0x02000000
-
- def __init__(self):
- super().__init__()
- self.packageName = ""
- self.versionName = ""
- self.versionCode = 0
- self.applicationInfo: Optional[ApplicationInfo] = None
- self.activities: List[ActivityInfo] = []
- self.services: List[ServiceInfo] = []
- self.receivers: List[ActivityInfo] = []
- self.providers: List[ProviderInfo] = []
- self.permissions: List[PermissionInfo] = []
- self.requestedPermissions: List[str] = []
- self.requestedPermissionsFlags: List[int] = []
- self.sharedUserId = ""
- self.sharedUserLabel = 0
- self.firstInstallTime = 0
- self.lastUpdateTime = 0
- self.gids: List[int] = []
- self.installLocation = self.INSTALL_LOCATION_AUTO
- self.configPreferences: List = []
- self.featureGroups: List = []
- self.packageName_ = ""
-
- def toString(self) -> str:
- return (f"PackageInfo({self.packageName} v{self.versionName} "
- f"code={self.versionCode})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# Signature
-# ═══════════════════════════════════════════════════════════════
-
-class Signature(Stub):
- """Signature — APK 签名"""
-
- def __init__(self, signature: str = ""):
- super().__init__()
- self._signature = signature
-
- def toCharsString(self) -> str:
- return self._signature
-
- def toByteArray(self) -> bytes:
- return self._signature.encode("utf-8") if self._signature else b""
-
- def equals(self, other) -> bool:
- if isinstance(other, Signature):
- return self._signature == other._signature
- return False
-
- def hashCode(self) -> int:
- return hash(self._signature) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return self._signature[:64] if len(self._signature) > 64 else self._signature
-
-
-# ═══════════════════════════════════════════════════════════════
-# PackageStats
-# ═══════════════════════════════════════════════════════════════
-
-class PackageStats(Stub):
- """PackageStats — 包存储统计"""
-
- def __init__(self, package_name: str = ""):
- super().__init__()
- self.packageName = package_name
- self.codeSize = 0
- self.dataSize = 0
- self.cacheSize = 0
- self.externalCodeSize = 0
- self.externalDataSize = 0
- self.externalCacheSize = 0
- self.externalMediaSize = 0
- self.externalObbSize = 0
-
- def toString(self) -> str:
- return (f"PackageStats({self.packageName}, "
- f"code={self.codeSize}, data={self.dataSize})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# PackageManager
-# ═══════════════════════════════════════════════════════════════
-
-class PackageManager(Stub):
- """PackageManager — 包管理器"""
-
- # Flag 常量
- GET_ACTIVITIES = 1
- GET_CONFIGURATIONS = 2
- GET_GIDS = 4
- GET_INSTRUMENTATION = 8
- GET_INTENT_FILTERS = 16
- GET_META_DATA = 128
- GET_PERMISSIONS = 4096
- GET_PROVIDERS = 8
- GET_RECEIVERS = 4
- GET_SERVICES = 2
- GET_SHARED_LIBRARY_FILES = 32
- GET_SIGNATURES = 64
- GET_UNINSTALLED_PACKAGES = 512
- GET_URI_PERMISSION_PATTERNS = 256
- MATCH_ALL = 0x10000
- MATCH_DISABLED_COMPONENTS = 0x200
- MATCH_DISABLED_UNTIL_USED_COMPONENTS = 0x8000
- MATCH_DEFAULT_ONLY = 0x10000
- MATCH_SYSTEM_ONLY = 0x800000
- MATCH_UNINSTALLED_PACKAGES = 0x2000000
- PERMISSION_DENIED = -1
- PERMISSION_GRANTED = 0
-
- # 特性常量
- FEATURE_CAMERA = "android.hardware.camera"
- FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus"
- FEATURE_CAMERA_FLASH = "android.hardware.camera.flash"
- FEATURE_CAMERA_FRONT = "android.hardware.camera.front"
- FEATURE_LOCATION = "android.hardware.location"
- FEATURE_LOCATION_GPS = "android.hardware.location.gps"
- FEATURE_LOCATION_NETWORK = "android.hardware.location.network"
- FEATURE_MICROPHONE = "android.hardware.microphone"
- FEATURE_NFC = "android.hardware.nfc"
- FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer"
- FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer"
- FEATURE_SENSOR_COMPASS = "android.hardware.sensor.compass"
- FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope"
- FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light"
- FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity"
- FEATURE_TELEPHONY = "android.hardware.telephony"
- FEATURE_TOUCHSCREEN = "android.hardware.touchscreen"
- FEATURE_USB_HOST = "android.hardware.usb.host"
- FEATURE_WIFI = "android.hardware.wifi"
- FEATURE_BLUETOOTH = "android.hardware.bluetooth"
-
- def __init__(self):
- super().__init__()
- self._packages: Dict[str, Dict[str, Any]] = {}
- self._load_packages()
-
- def _load_packages(self):
- """从 JSON 文件加载包信息"""
- try:
- if os.path.exists(_DEFAULT_PACKAGE_INFO_PATH):
- with open(_DEFAULT_PACKAGE_INFO_PATH, "r", encoding="utf-8") as f:
- data = json.load(f)
- if data.get("packageName"):
- self._packages[data["packageName"]] = data
- else:
- # 创建默认信息
- default_info = _get_default_package_info()
- self._packages[_package_name] = default_info
- os.makedirs(os.path.dirname(_DEFAULT_PACKAGE_INFO_PATH), exist_ok=True)
- with open(_DEFAULT_PACKAGE_INFO_PATH, "w", encoding="utf-8") as f:
- json.dump(default_info, f, indent=2, ensure_ascii=False)
- except (json.JSONDecodeError, OSError):
- self._packages[_package_name] = _get_default_package_info()
-
- def _make_app_info(self, data: Dict) -> ApplicationInfo:
- ai_data = data.get("applicationInfo", data)
- return ApplicationInfo(ai_data)
-
- def _make_activity_info(self, data: Dict) -> ActivityInfo:
- return ActivityInfo(data)
-
- def _make_service_info(self, data: Dict) -> ServiceInfo:
- return ServiceInfo(data)
-
- def _make_provider_info(self, data: Dict) -> ProviderInfo:
- return ProviderInfo(data)
-
- def getPackageInfo(self, package_name: str, flags: int) -> Optional[PackageInfo]:
- if package_name not in self._packages:
- return None
- raw = self._packages[package_name]
- pi = PackageInfo()
- pi.packageName = raw.get("packageName", package_name)
- pi.versionName = raw.get("versionName", "1.0.0")
- pi.versionCode = raw.get("versionCode", 1)
- pi.applicationInfo = self._make_app_info(raw)
-
- if flags & self.GET_ACTIVITIES:
- pi.activities = [self._make_activity_info(a) for a in raw.get("activities", [])]
- if flags & self.GET_SERVICES:
- pi.services = [self._make_service_info(s) for s in raw.get("services", [])]
- if flags & self.GET_RECEIVERS:
- pi.receivers = [self._make_activity_info(r) for r in raw.get("receivers", [])]
- if flags & self.GET_PROVIDERS:
- pi.providers = [self._make_provider_info(p) for p in raw.get("providers", [])]
- if flags & self.GET_PERMISSIONS:
- pi.permissions = [PermissionInfo(p) for p in raw.get("permissions", [])]
-
- pi.requestedPermissions = raw.get("requestedPermissions", [])
- return pi
-
- def getApplicationInfo(self, package_name: str, flags: int) -> Optional[ApplicationInfo]:
- if package_name not in self._packages:
- return None
- return self._make_app_info(self._packages[package_name])
-
- def getActivityInfo(self, component: Any, flags: int) -> Optional[ActivityInfo]:
- cn = component
- pkg = getattr(cn, "getPackageName", lambda: "")()
- cls = getattr(cn, "getClassName", lambda: "")()
- if pkg in self._packages:
- for a in self._packages[pkg].get("activities", []):
- if a.get("name") == cls:
- return ActivityInfo(a)
- return ActivityInfo({"name": cls, "packageName": pkg})
-
- def getServiceInfo(self, component: Any, flags: int) -> Optional[ServiceInfo]:
- cn = component
- pkg = getattr(cn, "getPackageName", lambda: "")()
- cls = getattr(cn, "getClassName", lambda: "")()
- if pkg in self._packages:
- for s in self._packages[pkg].get("services", []):
- if s.get("name") == cls:
- return ServiceInfo(s)
- return ServiceInfo({"name": cls, "packageName": pkg})
-
- def getInstalledPackages(self, flags: int) -> List[PackageInfo]:
- result = []
- for pkg_name in self._packages:
- pi = self.getPackageInfo(pkg_name, flags)
- if pi:
- result.append(pi)
- return result
-
- def getInstalledApplications(self, flags: int) -> List[ApplicationInfo]:
- result = []
- for pkg_name in self._packages:
- ai = self.getApplicationInfo(pkg_name, flags)
- if ai:
- result.append(ai)
- return result
-
- def queryIntentActivities(self, intent: Any, flags: int) -> List[ResolveInfo]:
- """查询匹配 Intent 的 Activity 列表"""
- results = []
- action = getattr(intent, "getAction", lambda: None)()
- for pkg_name, raw in self._packages.items():
- for a in raw.get("activities", []):
- ri = ResolveInfo()
- ri.activityInfo = ActivityInfo(a)
- ri.priority = 0
- ri.match = 0
- results.append(ri)
- return results
-
- def queryBroadcastReceivers(self, intent: Any, flags: int) -> List[ResolveInfo]:
- results = []
- for pkg_name, raw in self._packages.items():
- for r in raw.get("receivers", []):
- ri = ResolveInfo()
- ri.activityInfo = ActivityInfo(r)
- results.append(ri)
- return results
-
- def queryIntentServices(self, intent: Any, flags: int) -> List[ResolveInfo]:
- results = []
- for pkg_name, raw in self._packages.items():
- for s in raw.get("services", []):
- ri = ResolveInfo()
- ri.serviceInfo = ServiceInfo(s)
- results.append(ri)
- return results
-
- def queryIntentContentProviders(self, intent: Any, flags: int) -> List[ResolveInfo]:
- results = []
- for pkg_name, raw in self._packages.items():
- for p in raw.get("providers", []):
- ri = ResolveInfo()
- ri.providerInfo = ProviderInfo(p)
- results.append(ri)
- return results
-
- def resolveActivity(self, intent: Any, flags: int) -> Optional[ResolveInfo]:
- activities = self.queryIntentActivities(intent, flags)
- return activities[0] if activities else None
-
- def resolveService(self, intent: Any, flags: int) -> Optional[ResolveInfo]:
- services = self.queryIntentServices(intent, flags)
- return services[0] if services else None
-
- def checkPermission(self, permission: str, package_name: str) -> int:
- if package_name in self._packages:
- perms = self._packages[package_name].get("requestedPermissions", [])
- if permission in perms:
- return self.PERMISSION_GRANTED
- return self.PERMISSION_DENIED if permission else self.PERMISSION_GRANTED
-
- def getPermissionInfo(self, name: str, flags: int) -> Optional[PermissionInfo]:
- return PermissionInfo({"name": name, "packageName": "android"})
-
- def getDefaultActivityIcon(self) -> Any:
- return None
-
- def getApplicationLabel(self, info: ApplicationInfo) -> str:
- return info.name.split(".")[-1] if info.name else ""
-
- def getApplicationIcon(self, package_name: str) -> Any:
- return None
-
- def hasSystemFeature(self, feature: str) -> bool:
- for pkg_name, raw in self._packages.items():
- features = raw.get("features", {})
- if feature in features:
- return features[feature]
- return False
-
- def getLaunchIntentForPackage(self, package_name: str) -> Any:
- from .app import Intent
- if package_name in self._packages:
- intent = Intent(Intent.ACTION_MAIN)
- intent.setPackage(package_name)
- return intent
- return None
-
- def getLeanbackLaunchIntentForPackage(self, package_name: str) -> Any:
- return self.getLaunchIntentForPackage(package_name)
-
- def getPackageSizeInfo(self, package_name: str, observer: Any):
- pass
-
- def getPackageGids(self, package_name: str) -> Optional[List[int]]:
- return []
-
- def getPackageUid(self, package_name: str, flags: int) -> int:
- return 10001
-
- def getNameForUid(self, uid: int) -> Optional[str]:
- return _package_name
-
- def getPackagesForUid(self, uid: int) -> Optional[List[str]]:
- return [_package_name]
-
- def getResourcesForActivity(self, component: Any) -> Any:
- return None
-
- def getResourcesForApplication(self, app_info: ApplicationInfo) -> Any:
- return None
-
- def isSafeMode(self) -> bool:
- return False
-
- def addPackageToPreferred(self, package_name: str):
- pass
-
- def removePackageFromPreferred(self, package_name: str):
- pass
-
- def getPreferredPackages(self, flags: int) -> List[PackageInfo]:
- return []
-
- def setApplicationEnabledSetting(self, package_name: str, new_state: int, flags: int):
- pass
-
- def getApplicationEnabledSetting(self, package_name: str) -> int:
- return 0
-
- def getComponentEnabledSetting(self, component_name: Any) -> int:
- return 1
-
- def setComponentEnabledSetting(self, component_name: Any, new_state: int, flags: int):
- pass
-
- def clearInstantAppCookie(self):
- pass
-
- def getInstantAppCookie(self) -> bytes:
- return b""
-
- def getInstantAppCookieMaxSize(self) -> int:
- return 4096
-
- def getMimeGroup(self, mime_group: str) -> List[str]:
- return []
-
- def isInstantApp(self) -> bool:
- return False
-
- def isInstantAppPackageName(self, package_name: str) -> bool:
- return False
-
- def getSyntheticAppDetailsActivityEnabled(self, package_name: str) -> int:
- return 1
-
- def setSyntheticAppDetailsActivityEnabled(self, package_name: str, enabled: int):
- pass
-
- def canRequestPackageInstalls(self) -> bool:
- return True
-
- def currentToCanonicalPackageNames(self, names: List[str]) -> List[str]:
- return list(names)
-
- def canonicalToCurrentPackageNames(self, names: List[str]) -> List[str]:
- return list(names)
-
- def getInstallerPackageName(self, package_name: str) -> Optional[str]:
- return None
-
- def toString(self) -> str:
- return f"PackageManager(packages={len(self._packages)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "PackageManager",
- "PackageInfo",
- "ApplicationInfo",
- "ActivityInfo",
- "ServiceInfo",
- "ProviderInfo",
- "PermissionInfo",
- "ResolveInfo",
- "PackageItemInfo",
- "ComponentInfo",
- "Signature",
- "PackageStats",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/content_res.py b/android_pyapi/android/content_res.py
deleted file mode 100644
index 857b0f2..0000000
--- a/android_pyapi/android/content_res.py
+++ /dev/null
@@ -1,587 +0,0 @@
-"""
-Android content.res 组件 — Resources, AssetManager, Configuration 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import io
-import os
-import struct
-import sys
-from pathlib import Path
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-from xml.etree import ElementTree
-
-from .._core import Stub, AndroidOnlyError, android_context, resolve_android_path
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# Resources
-# ═══════════════════════════════════════════════════════════════
-
-class Resources(Stub):
- """Resources — 资源访问"""
-
- def __init__(self, assets: Optional["AssetManager"] = None):
- super().__init__()
- self._assets = assets or AssetManager()
- self._strings: Dict[str, str] = {}
- self._colors: Dict[str, int] = {}
- self._dimens: Dict[str, float] = {}
- self._drawables: Dict[str, Any] = {}
- self._booleans: Dict[str, bool] = {}
- self._integers: Dict[str, int] = {}
- self._string_arrays: Dict[str, List[str]] = {}
- self._int_arrays: Dict[str, List[int]] = {}
- self._identifiers: Dict[str, int] = {}
- self._next_id = 0x7f010000
- self._configuration = Configuration()
- self._display_metrics = DisplayMetrics()
-
- # ── String ──
-
- def getString(self, id: Union[int, str], *format_args: Any) -> Optional[str]:
- if isinstance(id, str):
- return self._strings.get(id)
- for key, val in self._strings.items():
- if self._identifiers.get(key) == id:
- return val.format(*format_args) if format_args else val
- return None
-
- def getText(self, id: Union[int, str]) -> Optional[str]:
- return self.getString(id)
-
- def getQuantityString(self, id: Union[int, str], quantity: int, *format_args: Any) -> str:
- base = self.getString(id) or ""
- return base.format(quantity, *format_args)
-
- # ── Color ──
-
- def getColor(self, id: Union[int, str], theme: Optional["Resources.Theme"] = None) -> int:
- if isinstance(id, str):
- return self._colors.get(id, 0xFF000000)
- for key, val in self._colors.items():
- if self._identifiers.get(key) == id:
- return val
- return 0xFF000000
-
- def getColorStateList(self, id: Union[int, str], theme: Optional["Resources.Theme"] = None) -> Any:
- return self.getColor(id, theme)
-
- # ── Dimension ──
-
- def getDimension(self, id: Union[int, str]) -> float:
- if isinstance(id, str):
- return self._dimens.get(id, 0.0)
- for key, val in self._dimens.items():
- if self._identifiers.get(key) == id:
- return val
- return 0.0
-
- def getDimensionPixelSize(self, id: Union[int, str]) -> int:
- return int(self.getDimension(id))
-
- def getDimensionPixelOffset(self, id: Union[int, str]) -> int:
- return int(self.getDimension(id))
-
- # ── Drawable ──
-
- def getDrawable(self, id: Union[int, str], theme: Optional["Resources.Theme"] = None) -> Any:
- if isinstance(id, str):
- return self._drawables.get(id)
- for key, val in self._drawables.items():
- if self._identifiers.get(key) == id:
- return val
- return None
-
- # ── Identifier ──
-
- def getIdentifier(self, name: str, defType: Optional[str] = None,
- defPackage: Optional[str] = None) -> int:
- key = f"{defPackage}:{defType}/{name}" if defType else name
- if key not in self._identifiers:
- self._next_id += 1
- self._identifiers[key] = self._next_id
- return self._identifiers[key]
-
- # ── Boolean / Integer ──
-
- def getBoolean(self, id: Union[int, str]) -> bool:
- if isinstance(id, str):
- return self._booleans.get(id, False)
- for key, val in self._booleans.items():
- if self._identifiers.get(key) == id:
- return val
- return False
-
- def getInteger(self, id: Union[int, str]) -> int:
- if isinstance(id, str):
- return self._integers.get(id, 0)
- for key, val in self._integers.items():
- if self._identifiers.get(key) == id:
- return val
- return 0
-
- # ── Arrays ──
-
- def getStringArray(self, id: Union[int, str]) -> List[str]:
- if isinstance(id, str):
- return self._string_arrays.get(id, [])
- for key, val in self._string_arrays.items():
- if self._identifiers.get(key) == id:
- return val
- return []
-
- def getTextArray(self, id: Union[int, str]) -> List[str]:
- return self.getStringArray(id)
-
- def getIntArray(self, id: Union[int, str]) -> List[int]:
- if isinstance(id, str):
- return self._int_arrays.get(id, [])
- for key, val in self._int_arrays.items():
- if self._identifiers.get(key) == id:
- return val
- return []
-
- # ── Layout / Animation / Xml ──
-
- def getLayout(self, id: Union[int, str]) -> Any:
- return self.getDrawable(id)
-
- def getAnimation(self, id: Union[int, str]) -> Any:
- return self.getDrawable(id)
-
- def getXml(self, id: Union[int, str]) -> "XmlResourceParser":
- return XmlResourceParser()
-
- # ── Assets ──
-
- def getAssets(self) -> "AssetManager":
- return self._assets
-
- # ── Config / Metrics ──
-
- def getConfiguration(self) -> "Configuration":
- return self._configuration
-
- def getDisplayMetrics(self) -> "DisplayMetrics":
- return self._display_metrics
-
- def getSystem(self) -> "Resources":
- return self
-
- # ── Resource names ──
-
- def getResourceEntryName(self, resid: int) -> str:
- for key, val in self._identifiers.items():
- if val == resid:
- return key.split("/")[-1] if "/" in key else key
- return "unknown"
-
- def getResourceName(self, resid: int) -> str:
- for key, val in self._identifiers.items():
- if val == resid:
- return key
- return "unknown"
-
- def getResourcePackageName(self, resid: int) -> str:
- for key, val in self._identifiers.items():
- if val == resid:
- parts = key.split(":")
- return parts[0] if len(parts) > 1 else ""
- return ""
-
- def getResourceTypeName(self, resid: int) -> str:
- for key, val in self._identifiers.items():
- if val == resid:
- parts = key.split("/")
- if len(parts) > 1:
- type_part = parts[0]
- if ":" in type_part:
- return type_part.split(":")[1]
- return type_part
- return ""
- return ""
-
- # ── Raw resources ──
-
- def openRawResource(self, id: int) -> io.BytesIO:
- return io.BytesIO(b"")
-
- def openRawResourceFd(self, id: int) -> Any:
- return None
-
- # ── Mutation helpers ──
-
- def _put_string(self, name: str, value: str):
- self._strings[name] = value
-
- def _put_color(self, name: str, value: int):
- self._colors[name] = value
-
- def _put_dimension(self, name: str, value: float):
- self._dimens[name] = value
-
- def _put_drawable(self, name: str, value: Any):
- self._drawables[name] = value
-
- def _put_boolean(self, name: str, value: bool):
- self._booleans[name] = value
-
- def _put_integer(self, name: str, value: int):
- self._integers[name] = value
-
- # ── Theme ──
-
- class Theme(Stub):
- """Resources.Theme — 主题"""
-
- def __init__(self, resources: "Resources"):
- super().__init__()
- self._resources = resources
- self._styles: Dict[int, Any] = {}
-
- def applyStyle(self, resid: int, force: bool = False):
- pass
-
- def setTo(self, other: "Resources.Theme"):
- self._styles = dict(other._styles)
-
- def getDrawable(self, id: int) -> Any:
- return self._resources.getDrawable(id)
-
- def getColor(self, id: int) -> int:
- return self._resources.getColor(id)
-
- def getResources(self) -> "Resources":
- return self._resources
-
- def toString(self) -> str:
- return f"Resources.Theme@{hex(id(self))}"
-
- def hashCode(self) -> int:
- return hash(id(self)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# AssetManager
-# ═══════════════════════════════════════════════════════════════
-
-class AssetManager(Stub):
- """AssetManager — 资源资产管理"""
-
- ACCESS_UNKNOWN = 0
- ACCESS_STREAMING = 1
- ACCESS_BUFFER = 2
- ACCESS_RANDOM = 3
-
- def __init__(self):
- super().__init__()
- self._assets_dir = os.path.join(
- os.path.expanduser("~"), "Android-compat", "assets"
- )
- os.makedirs(self._assets_dir, exist_ok=True)
- self._open: bool = True
-
- def open(self, fileName: str, access: int = ACCESS_STREAMING) -> io.BytesIO:
- path = os.path.join(self._assets_dir, fileName)
- if os.path.isfile(path):
- with open(path, "rb") as f:
- return io.BytesIO(f.read())
- return io.BytesIO(b"")
-
- def openFd(self, fileName: str) -> Any:
- path = os.path.join(self._assets_dir, fileName)
- if os.path.isfile(path):
- return open(path, "rb")
- return None
-
- def openNonAssetFd(self, fileName: str) -> Any:
- return self.openFd(fileName)
-
- def list(self, path: str = "") -> List[str]:
- dir_path = os.path.join(self._assets_dir, path)
- if os.path.isdir(dir_path):
- return os.listdir(dir_path)
- return []
-
- def close(self):
- self._open = False
-
- def toString(self) -> str:
- return f"AssetManager@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Configuration
-# ═══════════════════════════════════════════════════════════════
-
-class Configuration(Stub):
- """Configuration — 设备配置"""
-
- # Color mode constants
- COLOR_MODE_DEFAULT = 0
- COLOR_MODE_WIDE_COLOR_GAMUT = 1
- COLOR_MODE_HDR = 2
-
- # Density constants
- DENSITY_DPI_UNDEFINED = 0
- DENSITY_DPI_LOW = 120
- DENSITY_DPI_MEDIUM = 160
- DENSITY_DPI_HIGH = 240
- DENSITY_DPI_XHIGH = 320
- DENSITY_DPI_XXHIGH = 480
- DENSITY_DPI_XXXHIGH = 640
- DENSITY_DPI_TV = 213
-
- # Screen layout size
- SCREENLAYOUT_SIZE_SMALL = 1
- SCREENLAYOUT_SIZE_NORMAL = 2
- SCREENLAYOUT_SIZE_LARGE = 3
- SCREENLAYOUT_SIZE_XLARGE = 4
-
- # Orientation
- ORIENTATION_LANDSCAPE = 2
- ORIENTATION_PORTRAIT = 1
- ORIENTATION_SQUARE = 3
- ORIENTATION_UNDEFINED = 0
-
- # UI mode
- UI_MODE_TYPE_NORMAL = 1
- UI_MODE_TYPE_DESK = 2
- UI_MODE_TYPE_CAR = 3
- UI_MODE_TYPE_TELEVISION = 4
- UI_MODE_TYPE_APPLIANCE = 5
- UI_MODE_TYPE_WATCH = 6
- UI_MODE_TYPE_VR_HEADSET = 7
-
- UI_MODE_NIGHT_UNDEFINED = 0
- UI_MODE_NIGHT_NO = 1
- UI_MODE_NIGHT_YES = 2
-
- # Touchscreen
- TOUCHSCREEN_UNDEFINED = 0
- TOUCHSCREEN_NOTOUCH = 1
- TOUCHSCREEN_FINGER = 3
-
- # Keyboard
- KEYBOARD_UNDEFINED = 0
- KEYBOARD_NOKEYS = 1
- KEYBOARD_QWERTY = 2
- KEYBOARD_12KEY = 3
-
- # Keyboard hidden
- KEYBOARDHIDDEN_UNDEFINED = 0
- KEYBOARDHIDDEN_NO = 1
- KEYBOARDHIDDEN_YES = 2
-
- # Hard keyboard hidden
- HARDKEYBOARDHIDDEN_UNDEFINED = 0
- HARDKEYBOARDHIDDEN_NO = 1
- HARDKEYBOARDHIDDEN_YES = 2
-
- # Navigation
- NAVIGATION_UNDEFINED = 0
- NAVIGATION_NONAV = 1
- NAVIGATION_DPAD = 2
- NAVIGATION_TRACKBALL = 3
- NAVIGATION_WHEEL = 4
-
- # Navigation hidden
- NAVIGATIONHIDDEN_UNDEFINED = 0
- NAVIGATIONHIDDEN_NO = 1
- NAVIGATIONHIDDEN_YES = 2
-
- def __init__(self):
- super().__init__()
- self.fontScale: float = 1.0
- self.mcc: int = 310
- self.mnc: int = 260
- self.locale: Optional[str] = "en-US"
- self.screenLayout: int = self.SCREENLAYOUT_SIZE_NORMAL
- self.touchscreen: int = self.TOUCHSCREEN_FINGER
- self.keyboard: int = self.KEYBOARD_QWERTY
- self.keyboardHidden: int = self.KEYBOARDHIDDEN_NO
- self.hardKeyboardHidden: int = self.HARDKEYBOARDHIDDEN_NO
- self.navigation: int = self.NAVIGATION_NONAV
- self.navigationHidden: int = self.NAVIGATIONHIDDEN_NO
- self.orientation: int = self.ORIENTATION_PORTRAIT
- self.screenWidthDp: int = 360
- self.screenHeightDp: int = 640
- self.smallestScreenWidthDp: int = 360
- self.densityDpi: int = self.DENSITY_DPI_MEDIUM
- self.uiMode: int = self.UI_MODE_TYPE_NORMAL | self.UI_MODE_NIGHT_NO
-
- def toString(self) -> str:
- return (f"Configuration{{fontScale={self.fontScale}, mcc={self.mcc}, "
- f"mnc={self.mnc}, locale={self.locale}, "
- f"screenLayout={self.screenLayout}, orientation={self.orientation}, "
- f"screenWidthDp={self.screenWidthDp}, screenHeightDp={self.screenHeightDp}}}")
-
-
-# ═══════════════════════════════════════════════════════════════
-# DisplayMetrics
-# ═══════════════════════════════════════════════════════════════
-
-class DisplayMetrics(Stub):
- """DisplayMetrics — 显示指标"""
-
- DENSITY_DEFAULT = 160
- DENSITY_LOW = 120
- DENSITY_MEDIUM = 160
- DENSITY_HIGH = 240
- DENSITY_XHIGH = 320
- DENSITY_XXHIGH = 480
- DENSITY_XXXHIGH = 640
- DENSITY_TV = 213
-
- def __init__(self):
- super().__init__()
- self.widthPixels: int = 1080
- self.heightPixels: int = 1920
- self.densityDpi: int = self.DENSITY_DEFAULT
- self.density: float = 1.0
- self.scaledDensity: float = 1.0
- self.xdpi: float = 160.0
- self.ydpi: float = 160.0
- self.noncompatWidthPixels: int = 1080
- self.noncompatHeightPixels: int = 1920
- self.noncompatDensityDpi: int = self.DENSITY_DEFAULT
- self.noncompatDensity: float = 1.0
- self.noncompatScaledDensity: float = 1.0
- self.noncompatXdpi: float = 160.0
- self.noncompatYdpi: float = 160.0
- self.densityDpi: int = self.DENSITY_DEFAULT
-
- def toString(self) -> str:
- return (f"DisplayMetrics{{width={self.widthPixels}, height={self.heightPixels}, "
- f"densityDpi={self.densityDpi}, density={self.density:.2f}}}")
-
-
-# ═══════════════════════════════════════════════════════════════
-# TypedArray
-# ═══════════════════════════════════════════════════════════════
-
-class TypedArray(Stub):
- """TypedArray — 类型化数组"""
-
- def __init__(self):
- super().__init__()
- self._data: Dict[int, Any] = {}
-
- def getString(self, index: int) -> Optional[str]:
- val = self._data.get(index)
- return str(val) if val is not None else None
-
- def getInt(self, index: int, defValue: int = 0) -> int:
- val = self._data.get(index)
- return int(val) if val is not None else defValue
-
- def getFloat(self, index: int, defValue: float = 0.0) -> float:
- val = self._data.get(index)
- return float(val) if val is not None else defValue
-
- def getBoolean(self, index: int, defValue: bool = False) -> bool:
- val = self._data.get(index)
- return bool(val) if val is not None else defValue
-
- def getColor(self, index: int, defValue: int = 0) -> int:
- val = self._data.get(index)
- return int(val) if val is not None else defValue
-
- def getDimension(self, index: int, defValue: float = 0.0) -> float:
- val = self._data.get(index)
- return float(val) if val is not None else defValue
-
- def getDrawable(self, index: int) -> Any:
- return self._data.get(index)
-
- def getResourceId(self, index: int, defValue: int = 0) -> int:
- val = self._data.get(index)
- return int(val) if val is not None else defValue
-
- def getText(self, index: int) -> Optional[str]:
- return self.getString(index)
-
- def hasValue(self, index: int) -> bool:
- return index in self._data
-
- def length(self) -> int:
- return len(self._data)
-
- def recycle(self):
- self._data.clear()
-
- def toString(self) -> str:
- return f"TypedArray@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# XmlResourceParser
-# ═══════════════════════════════════════════════════════════════
-
-class XmlResourceParser(Stub):
- """XmlResourceParser — XML 资源解析器"""
-
- START_DOCUMENT = 0
- END_DOCUMENT = 1
- START_TAG = 2
- END_TAG = 3
- TEXT = 4
-
- def __init__(self):
- super().__init__()
- self._root: Optional[ElementTree.Element] = None
- self._event_type = self.START_DOCUMENT
-
- def next(self) -> int:
- return self.END_DOCUMENT
-
- def getEventType(self) -> int:
- return self._event_type
-
- def getName(self) -> Optional[str]:
- return None
-
- def getText(self) -> Optional[str]:
- return None
-
- def getAttributeCount(self) -> int:
- return 0
-
- def getAttributeName(self, index: int) -> Optional[str]:
- return None
-
- def getAttributeValue(self, index: int) -> Optional[str]:
- return None
-
- def getAttributeValue(self, namespace: Optional[str], name: str) -> Optional[str]:
- return None
-
- def close(self):
- pass
-
- def toString(self) -> str:
- return f"XmlResourceParser@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Resources",
- "AssetManager",
- "Configuration",
- "DisplayMetrics",
- "TypedArray",
- "XmlResourceParser",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/content_sync.py b/android_pyapi/android/content_sync.py
deleted file mode 100644
index 5d8e747..0000000
--- a/android_pyapi/android/content_sync.py
+++ /dev/null
@@ -1,915 +0,0 @@
-"""
-Android Content Sync API — SyncManager, SyncAdapter, SyncResult, SyncRequest, ContentResolver, etc.
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import time
-import json
-import uuid
-import threading
-from datetime import datetime, timedelta
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# SYNC_* 常量
-SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging"
-SYNC_EXTRAS_UPLOAD = "upload"
-SYNC_EXTRAS_MANUAL = "force"
-SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff"
-SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry"
-SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_local_deletions"
-SYNC_EXTRAS_EXPEDITED = "expedited"
-SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED = "schedule_as_expedited"
-SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "override_too_many_deletions"
-SYNC_EXTRAS_ALLOW_METERED = "allow_metered"
-SYNC_EXTRAS_INITIALIZE = "initialize"
-SYNC_EXTRAS_VIRTUAL_EXTRAS = "virtual_extras"
-SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings"
-SYNC_EXTRAS_IS_EXPEDITED = "is_expedited"
-SYNC_EXTRAS_IS_RETRY = "is_retry"
-
-# SYNC_ERROR 常量
-SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1
-SYNC_ERROR_AUTHENTICATION = 2
-SYNC_ERROR_IO = 3
-SYNC_ERROR_PARSE = 4
-SYNC_ERROR_CONFLICT = 5
-SYNC_ERROR_TOO_MANY_DELETIONS = 6
-SYNC_ERROR_TOO_MANY_RETRIES = 7
-SYNC_ERROR_INTERNAL = 8
-SYNC_ERROR_SYNC_EXTRAS_INVALID = 9
-SYNC_ERROR_REMOTE_SERVER_ERROR = 10
-SYNC_ERROR_MISMATCHED_UID = 11
-SYNC_ERROR_USER_CANCELED = 12
-
-# 通知码
-NOTIFY_SYNC_RESULT = 0
-NOTIFY_SETTINGS_CHANGE = 1
-NOTIFY_SYNC_START = 2
-NOTIFY_SYNC_STOP = 3
-
-# 同步触发器
-SYNC_TRIGGER_MANUAL = 0
-SYNC_TRIGGER_AUTO = 1
-SYNC_TRIGGER_EXPEDITED = 2
-SYNC_TRIGGER_SCHEDULED = 3
-
-# 同步状态
-SYNC_STATUS_PENDING = 0
-SYNC_STATUS_IN_PROGRESS = 1
-SYNC_STATUS_SUCCESS = 2
-SYNC_STATUS_ERROR = 3
-SYNC_STATUS_CANCELLED = 4
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncResult
-# ═══════════════════════════════════════════════════════════════
-
-class SyncResult(Stub):
- """SyncResult — 同步结果"""
-
- def __init__(self):
- super().__init__()
- self.syncAlreadlyInProgress = False
- self.tooManyDeletions = False
- self.tooManyRetries = False
- self.databaseError = False
- self.fullSyncRequested = False
- self.partialSyncUnavailable = False
- self.moreRecordsToGet = False
- self.delayUntil = 0
- self.stats: "SyncStats" = SyncStats()
- self._sync_error = 0
- self._sync_exception: Optional[Exception] = None
- self._sync_start_time: Optional[float] = None
- self._sync_end_time: Optional[float] = None
- self._sync_duration_ms: Optional[int] = None
- self._num_conflicts = 0
- self._num_auth_exceptions = 0
- self._num_io_exceptions = 0
- self._num_parse_exceptions = 0
- self._num_skipped_entries = 0
- self._num_inserted_entries = 0
- self._num_updated_entries = 0
- self._num_deleted_entries = 0
- self._has_error = False
- self._has_hard_error = False
- self._has_soft_error = False
-
- def hasError(self) -> bool:
- return (
- self.syncAlreadlyInProgress
- or self.tooManyDeletions
- or self.tooManyRetries
- or self.databaseError
- or self.stats.numAuthExceptions > 0
- or self.stats.numIoExceptions > 0
- or self.stats.numParseExceptions > 0
- or self._has_error
- )
-
- def hasHardError(self) -> bool:
- return (
- self.tooManyDeletions
- or self.databaseError
- or self.stats.numAuthExceptions > 0
- or self.stats.numParseExceptions > 0
- )
-
- def hasSoftError(self) -> bool:
- return (
- self.syncAlreadlyInProgress
- or self.tooManyRetries
- or self.stats.numIoExceptions > 0
- )
-
- def clear(self) -> None:
- self.syncAlreadlyInProgress = False
- self.tooManyDeletions = False
- self.tooManyRetries = False
- self.databaseError = False
- self.fullSyncRequested = False
- self.partialSyncUnavailable = False
- self.moreRecordsToGet = False
- self.delayUntil = 0
- self.stats.clear()
- self._has_error = False
- self._has_hard_error = False
- self._has_soft_error = False
-
- def getStats(self) -> "SyncStats":
- return self.stats
-
- def toString(self) -> str:
- return (
- f"SyncResult(hasError={self.hasError()}, "
- f"fullSyncRequested={self.fullSyncRequested}, "
- f"moreRecordsToGet={self.moreRecordsToGet}, "
- f"stats={self.stats})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncStats
-# ═══════════════════════════════════════════════════════════════
-
-class SyncStats(Stub):
- """SyncStats — 同步统计"""
-
- def __init__(self):
- super().__init__()
- self.numAuthExceptions = 0
- self.numIoExceptions = 0
- self.numParseExceptions = 0
- self.numConflictDetectedExceptions = 0
- self.numSkippedEntries = 0
- self.numInserts = 0
- self.numUpdates = 0
- self.numDeletes = 0
- self.numEntries = 0
- self._total_entries = 0
- self._total_errors = 0
- self._total_bytes_downloaded = 0
- self._total_bytes_uploaded = 0
- self._sync_duration_ms = 0
-
- def clear(self) -> None:
- self.numAuthExceptions = 0
- self.numIoExceptions = 0
- self.numParseExceptions = 0
- self.numConflictDetectedExceptions = 0
- self.numSkippedEntries = 0
- self.numInserts = 0
- self.numUpdates = 0
- self.numDeletes = 0
- self.numEntries = 0
- self._total_bytes_downloaded = 0
- self._total_bytes_uploaded = 0
- self._sync_duration_ms = 0
-
- def getTotalBytesDownloaded(self) -> int:
- return self._total_bytes_downloaded
-
- def setTotalBytesDownloaded(self, bytes_: int) -> None:
- self._total_bytes_downloaded = bytes_
-
- def getTotalBytesUploaded(self) -> int:
- return self._total_bytes_uploaded
-
- def setTotalBytesUploaded(self, bytes_: int) -> None:
- self._total_bytes_uploaded = bytes_
-
- def getSyncDurationMs(self) -> int:
- return self._sync_duration_ms
-
- def setSyncDurationMs(self, ms: int) -> None:
- self._sync_duration_ms = ms
-
- def toString(self) -> str:
- return (
- f"SyncStats(inserts={self.numInserts}, updates={self.numUpdates}, "
- f"deletes={self.numDeletes}, errors={self._total_errors})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncInfo
-# ═══════════════════════════════════════════════════════════════
-
-class SyncInfo(Stub):
- """SyncInfo — 同步信息"""
-
- def __init__(self, authority: str, account: Any, userId: int):
- super().__init__()
- self._authority = authority
- self._account = account
- self._user_id = userId
- self._start_time = time.time()
- self._status = SYNC_STATUS_PENDING
- self._sync_id = str(uuid.uuid4())
- self._elapsed_time_ms = 0
- self._result: Optional[SyncResult] = None
- self._description: Optional[str] = None
- self._is_manual = False
- self._is_expedited = False
- self._trigger = SYNC_TRIGGER_AUTO
- self._sync_request: Optional["SyncRequest"] = None
-
- def getAuthority(self) -> str:
- return self._authority
-
- def getAccount(self) -> Any:
- return self._account
-
- def getUserId(self) -> int:
- return self._user_id
-
- def getStartTime(self) -> float:
- return self._start_time
-
- def getStatus(self) -> int:
- return self._status
-
- def setStatus(self, status: int) -> None:
- self._status = status
-
- def getSyncId(self) -> str:
- return self._sync_id
-
- def getElapsedTimeMs(self) -> int:
- return self._elapsed_time_ms
-
- def getResult(self) -> Optional[SyncResult]:
- return self._result
-
- def isManual(self) -> bool:
- return self._is_manual
-
- def isExpedited(self) -> bool:
- return self._is_expedited
-
- def getTriggerSource(self) -> int:
- return self._trigger
-
- def toString(self) -> str:
- return f"SyncInfo(authority={self._authority}, status={self._status})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncStatusObserver
-# ═══════════════════════════════════════════════════════════════
-
-class SyncStatusObserver(Stub):
- """SyncStatusObserver — 同步状态观察者"""
-
- def __init__(self):
- super().__init__()
-
- def onStatusChanged(self, which: int) -> None:
- pass
-
- def toString(self) -> str:
- return "SyncStatusObserver"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class SyncAdapter(Stub):
- """SyncAdapter — 同步适配器基类"""
-
- def __init__(self, context: Any, autoInitialize: bool, allowParallelSyncs: bool):
- super().__init__()
- self._context = context
- self._auto_initialize = autoInitialize
- self._allow_parallel_syncs = allowParallelSyncs
- self._sync_auto_initialized = False
- self._is_initialized = False
- self._options: Dict[str, Any] = {}
-
- def onPerformSync(
- self,
- account: Any,
- extras: Any,
- authority: str,
- provider: Any,
- syncResult: SyncResult,
- ) -> None:
- pass
-
- def onSyncCanceled(self) -> None:
- pass
-
- def onSecurityException(self, account: Any, authority: str, exception: Any) -> None:
- pass
-
- def onUnsyncableAccount(self) -> bool:
- return True
-
- def getAutoInitialize(self) -> bool:
- return self._auto_initialize
-
- def getAllowParallelSyncs(self) -> bool:
- return self._allow_parallel_syncs
-
- def isSyncAdapterInitialized(self) -> bool:
- return self._is_initialized
-
- def toString(self) -> str:
- return f"SyncAdapter(auto_init={self._auto_initialize}, parallel={self._allow_parallel_syncs})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncRequest
-# ═══════════════════════════════════════════════════════════════
-
-class SyncRequest(Stub):
- """SyncRequest — 同步请求"""
-
- def __init__(self):
- super().__init__()
- self._account: Optional[Any] = None
- self._authority: Optional[str] = None
- self._extras: Dict[str, Any] = {}
- self._sync_flexibility_time = 0
- self._sync_run_time = 0
- self._is_expedited = False
- self._is_manual = False
- self._is_periodic = False
- self._ignore_backoff = False
- self._ignore_settings = False
- self._do_not_retry = False
- self._require_charging = False
- self._is_initialized = False
- self._schedule_as_expedited = False
- self._allow_metered = False
- self._discard_local_deletions = False
- self._override_too_many_deletions = False
-
- def getAccount(self) -> Optional[Any]:
- return self._account
-
- def getAuthority(self) -> Optional[str]:
- return self._authority
-
- def getExtras(self) -> Dict[str, Any]:
- return dict(self._extras)
-
- def isExpedited(self) -> bool:
- return self._is_expedited
-
- def isPeriodic(self) -> bool:
- return self._is_periodic
-
- def getSyncFlexibilityTime(self) -> int:
- return self._sync_flexibility_time
-
- def getSyncRunTime(self) -> int:
- return self._sync_run_time
-
- def toString(self) -> str:
- return f"SyncRequest(authority={self._authority}, periodic={self._is_periodic})"
-
- # ═══════════════════════════════════════════════════════════
- # SyncRequest.Builder
- # ═══════════════════════════════════════════════════════════
-
- class Builder(Stub):
- """SyncRequest.Builder — 同步请求构建器"""
-
- def __init__(self):
- super().__init__()
- self._request = SyncRequest()
-
- def sync(self) -> "SyncRequest.Builder":
- return self
-
- def setExpedited(self, expedited: bool) -> "SyncRequest.Builder":
- self._request._is_expedited = expedited
- return self
-
- def setManual(self, manual: bool) -> "SyncRequest.Builder":
- self._request._is_manual = manual
- return self
-
- def setExtras(self, extras: Dict[str, Any]) -> "SyncRequest.Builder":
- self._request._extras = dict(extras)
- return self
-
- def setIgnoreBackoff(self, ignoreBackoff: bool) -> "SyncRequest.Builder":
- self._request._ignore_backoff = ignoreBackoff
- return self
-
- def setIgnoreSettings(self, ignoreSettings: bool) -> "SyncRequest.Builder":
- self._request._ignore_settings = ignoreSettings
- return self
-
- def setDoNotRetry(self, doNotRetry: bool) -> "SyncRequest.Builder":
- self._request._do_not_retry = doNotRetry
- return self
-
- def setRequireCharging(self, requireCharging: bool) -> "SyncRequest.Builder":
- self._request._require_charging = requireCharging
- return self
-
- def setScheduleAsExpedited(self, expedited: bool) -> "SyncRequest.Builder":
- self._request._schedule_as_expedited = expedited
- return self
-
- def setAllowMetered(self, allowMetered: bool) -> "SyncRequest.Builder":
- self._request._allow_metered = allowMetered
- return self
-
- def setDiscardLocalDeletions(self, discard: bool) -> "SyncRequest.Builder":
- self._request._discard_local_deletions = discard
- return self
-
- def setOverrideTooManyDeletions(self, override: bool) -> "SyncRequest.Builder":
- self._request._override_too_many_deletions = override
- return self
-
- def setSyncAdapter(self, account: Any, authority: str) -> "SyncRequest.Builder":
- self._request._account = account
- self._request._authority = authority
- return self
-
- def setPeriodic(self, pollFrequency: int, flexTime: int = 0) -> "SyncRequest.Builder":
- self._request._is_periodic = True
- self._request._sync_run_time = time.time() + pollFrequency
- self._request._sync_flexibility_time = flexTime
- return self
-
- def build(self) -> SyncRequest:
- return self._request
-
- def toString(self) -> str:
- return f"SyncRequest.Builder(existing={self._request})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class SyncConfiguration(Stub):
- """SyncConfiguration — 同步配置"""
-
- def __init__(self, authority: str, account: Any, userId: int = 0):
- super().__init__()
- self._authority = authority
- self._account = account
- self._user_id = userId
- self._sync_enabled = True
- self._sync_automatically = True
- self._sync_interval = 3600
- self._sync_flex = 300
- self._is_active = False
- self._pending = False
- self._last_sync_time: Optional[float] = None
- self._last_sync_result: Optional[SyncResult] = None
- self._delay_until = 0
- self._backoff_time = 0
- self._backoff_delay = 0
- self._authority_settings: Dict[str, Any] = {}
-
- def getAuthority(self) -> str:
- return self._authority
-
- def getAccount(self) -> Any:
- return self._account
-
- def getUserId(self) -> int:
- return self._user_id
-
- def isSyncEnabled(self) -> bool:
- return self._sync_enabled
-
- def setSyncEnabled(self, enabled: bool) -> None:
- self._sync_enabled = enabled
-
- def isSyncAutomatically(self) -> bool:
- return self._sync_automatically
-
- def setSyncAutomatically(self, auto: bool) -> None:
- self._sync_automatically = auto
-
- def getSyncInterval(self) -> int:
- return self._sync_interval
-
- def setSyncInterval(self, intervalSec: int) -> None:
- self._sync_interval = intervalSec
-
- def getSyncFlex(self) -> int:
- return self._sync_flex
-
- def setSyncFlex(self, flexSec: int) -> None:
- self._sync_flex = flexSec
-
- def getDelayUntil(self) -> int:
- return self._delay_until
-
- def setDelayUntil(self, delayUntil: int) -> None:
- self._delay_until = delayUntil
-
- def getLastSyncTime(self) -> Optional[float]:
- return self._last_sync_time
-
- def setLastSyncTime(self, syncTime: float) -> None:
- self._last_sync_time = syncTime
-
- def isActive(self) -> bool:
- return self._is_active
-
- def isPending(self) -> bool:
- return self._pending
-
- def toString(self) -> str:
- return f"SyncConfiguration(authority={self._authority}, enabled={self._sync_enabled})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncAdaptersCache
-# ═══════════════════════════════════════════════════════════════
-
-class SyncAdaptersCache(Stub):
- """SyncAdaptersCache — 同步适配器缓存"""
-
- def __init__(self):
- super().__init__()
- self._adapters: Dict[str, SyncAdapter] = {}
- self._configs: Dict[str, SyncConfiguration] = {}
- self._lock = threading.Lock()
-
- def put(self, authority: str, adapter: SyncAdapter) -> None:
- with self._lock:
- self._adapters[authority] = adapter
-
- def get(self, authority: str) -> Optional[SyncAdapter]:
- with self._lock:
- return self._adapters.get(authority)
-
- def remove(self, authority: str) -> None:
- with self._lock:
- self._adapters.pop(authority, None)
-
- def containsAuthority(self, authority: str) -> bool:
- with self._lock:
- return authority in self._adapters
-
- def getAuthorities(self) -> List[str]:
- with self._lock:
- return list(self._adapters.keys())
-
- def getAdapterCount(self) -> int:
- with self._lock:
- return len(self._adapters)
-
- def clear(self) -> None:
- with self._lock:
- self._adapters.clear()
-
- def getConfiguration(self, authority: str) -> Optional[SyncConfiguration]:
- with self._lock:
- return self._configs.get(authority)
-
- def putConfiguration(self, config: SyncConfiguration) -> None:
- with self._lock:
- self._configs[config.getAuthority()] = config
-
- def getAllConfigurations(self) -> List[SyncConfiguration]:
- with self._lock:
- return list(self._configs.values())
-
- def toString(self) -> str:
- with self._lock:
- return f"SyncAdaptersCache(adapters={len(self._adapters)}, configs={len(self._configs)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncManager
-# ═══════════════════════════════════════════════════════════════
-
-class SyncManager(Stub):
- """SyncManager — 同步管理器 (桌面存根)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._lock = threading.Lock()
- self._active_syncs: Dict[str, SyncInfo] = {}
- self._pending_syncs: List[SyncRequest] = []
- self._observers: List[SyncStatusObserver] = []
- self._adapters_cache = SyncAdaptersCache()
- self._sync_automatically = True
- self._master_sync_automatically = True
- self._sync_enabled = True
- self._is_syncable = True
- self._sync_backoff_enabled = True
- self._worker_thread: Optional[threading.Thread] = None
- self._running = True
- self._pending_sync_count = 0
- self._total_sync_count = 0
- self._last_sync_time: Optional[float] = None
- self._start_worker()
-
- def _start_worker(self) -> None:
- if self._worker_thread is None or not self._worker_thread.is_alive():
- self._running = True
- self._worker_thread = threading.Thread(target=self._sync_loop, daemon=True)
- self._worker_thread.start()
-
- def _sync_loop(self) -> None:
- while self._running:
- with self._lock:
- if self._pending_syncs:
- req = self._pending_syncs.pop(0)
- self._execute_sync(req)
- time.sleep(1.0)
-
- def _execute_sync(self, request: SyncRequest) -> None:
- authority = request.getAuthority()
- if authority:
- info = SyncInfo(authority, request._account, 0)
- self._active_syncs[authority] = info
- self._total_sync_count += 1
- adapter = self._adapters_cache.get(authority)
- if adapter:
- result = SyncResult()
- try:
- adapter.onPerformSync(
- request._account, request._extras, authority, None, result
- )
- except Exception:
- pass
- info._result = result
- time.sleep(0.1)
- self._active_syncs.pop(authority, None)
- self._last_sync_time = time.time()
-
- def getSyncableAccountsForAuthority(self, authority: str) -> List[Any]:
- return []
-
- def getSyncableAccounts(self) -> List[Any]:
- return []
-
- def scheduleSync(self, request: SyncRequest) -> None:
- with self._lock:
- self._pending_syncs.append(request)
- self._pending_sync_count = len(self._pending_syncs)
-
- def schedule(self, account: Any, authority: str, extras: Any) -> None:
- req = SyncRequest.Builder().setSyncAdapter(account, authority).build()
- self.scheduleSync(req)
-
- def cancelSync(self, request: SyncRequest) -> None:
- with self._lock:
- self._pending_syncs = [
- r for r in self._pending_syncs
- if r.getAuthority() != request.getAuthority()
- ]
- self._pending_sync_count = len(self._pending_syncs)
-
- def cancelSync(self, authority: str = None) -> None:
- with self._lock:
- if authority:
- self._pending_syncs = [
- r for r in self._pending_syncs
- if r.getAuthority() != authority
- ]
- else:
- self._pending_syncs.clear()
- self._pending_sync_count = len(self._pending_syncs)
-
- def getCurrentSyncs(self) -> List[SyncInfo]:
- with self._lock:
- return list(self._active_syncs.values())
-
- def getSyncAutomatically(self, account: Any, authority: str) -> bool:
- return self._sync_automatically
-
- def setSyncAutomatically(self, account: Any, authority: str, sync: bool) -> None:
- self._sync_automatically = sync
-
- def getMasterSyncAutomatically(self) -> bool:
- return self._master_sync_automatically
-
- def setMasterSyncAutomatically(self, sync: bool) -> None:
- self._master_sync_automatically = sync
-
- def setIsSyncable(self, account: Any, authority: str, syncable: int) -> None:
- self._is_syncable = syncable != 0
-
- def getIsSyncable(self, account: Any, authority: str) -> int:
- return 1 if self._is_syncable else 0
-
- def addStatusChangeListener(self, which: int, observer: SyncStatusObserver) -> None:
- if observer not in self._observers:
- self._observers.append(observer)
-
- def removeStatusChangeListener(self, observer: SyncStatusObserver) -> None:
- if observer in self._observers:
- self._observers.remove(observer)
-
- def notifyStatusChange(self, which: int) -> None:
- for observer in self._observers:
- try:
- observer.onStatusChanged(which)
- except Exception:
- pass
-
- def getSyncAdapterTypes(self) -> List[Any]:
- return []
-
- def getSyncAdapterPackagesForAuthority(self, authority: str) -> List[str]:
- return []
-
- def isSyncActive(self, account: Any, authority: str) -> bool:
- with self._lock:
- return authority in self._active_syncs
-
- def isSyncPending(self, account: Any, authority: str) -> bool:
- with self._lock:
- for req in self._pending_syncs:
- if req.getAuthority() == authority:
- return True
- return False
-
- def getSyncInfo(self, authority: str) -> Optional[SyncInfo]:
- with self._lock:
- return self._active_syncs.get(authority)
-
- def getAdaptersCache(self) -> SyncAdaptersCache:
- return self._adapters_cache
-
- def getTotalSyncCount(self) -> int:
- return self._total_sync_count
-
- def getLastSyncTime(self) -> Optional[float]:
- return self._last_sync_time
-
- def getPendingSyncCount(self) -> int:
- with self._lock:
- return len(self._pending_syncs)
-
- def toString(self) -> str:
- with self._lock:
- return (
- f"SyncManager(active={len(self._active_syncs)}, "
- f"pending={len(self._pending_syncs)}, "
- f"total={self._total_sync_count})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContentResolver (Sync 扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class ContentResolverSync(Stub):
- """ContentResolver — 同步扩展方法"""
-
- SYNC_EXTRAS_REQUIRE_CHARGING = SYNC_EXTRAS_REQUIRE_CHARGING
- SYNC_EXTRAS_UPLOAD = SYNC_EXTRAS_UPLOAD
- SYNC_EXTRAS_MANUAL = SYNC_EXTRAS_MANUAL
- SYNC_EXTRAS_IGNORE_BACKOFF = SYNC_EXTRAS_IGNORE_BACKOFF
- SYNC_EXTRAS_DO_NOT_RETRY = SYNC_EXTRAS_DO_NOT_RETRY
- SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS
- SYNC_EXTRAS_EXPEDITED = SYNC_EXTRAS_EXPEDITED
- SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS
- SYNC_EXTRAS_ALLOW_METERED = SYNC_EXTRAS_ALLOW_METERED
- SYNC_EXTRAS_INITIALIZE = SYNC_EXTRAS_INITIALIZE
- SYNC_EXTRAS_IGNORE_SETTINGS = SYNC_EXTRAS_IGNORE_SETTINGS
-
- NOTIFY_SYNC_RESULT = NOTIFY_SYNC_RESULT
- NOTIFY_SETTINGS_CHANGE = NOTIFY_SETTINGS_CHANGE
- NOTIFY_SYNC_START = NOTIFY_SYNC_START
- NOTIFY_SYNC_STOP = NOTIFY_SYNC_STOP
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def requestSync(account: Any, authority: str, extras: Any) -> None:
- pass
-
- @staticmethod
- def requestSync(request: SyncRequest) -> None:
- pass
-
- @staticmethod
- def cancelSync(request: SyncRequest) -> None:
- pass
-
- @staticmethod
- def cancelSync(account: Any, authority: str) -> None:
- pass
-
- @staticmethod
- def getSyncAdapterTypes() -> List[Any]:
- return []
-
- @staticmethod
- def getSyncAutomatically(account: Any, authority: str) -> bool:
- return True
-
- @staticmethod
- def setSyncAutomatically(account: Any, authority: str, sync: bool) -> None:
- pass
-
- @staticmethod
- def getMasterSyncAutomatically() -> bool:
- return True
-
- @staticmethod
- def setMasterSyncAutomatically(sync: bool) -> None:
- pass
-
- @staticmethod
- def isSyncActive(account: Any, authority: str) -> bool:
- return False
-
- @staticmethod
- def isSyncPending(account: Any, authority: str) -> bool:
- return False
-
- @staticmethod
- def addStatusChangeListener(which: int, observer: SyncStatusObserver) -> None:
- pass
-
- @staticmethod
- def removeStatusChangeListener(observer: SyncStatusObserver) -> None:
- pass
-
- @staticmethod
- def validateSyncExtrasBundle(extras: Any) -> None:
- pass
-
- @staticmethod
- def getPeriodicSyncs(account: Any, authority: str) -> List[SyncRequest]:
- return []
-
- @staticmethod
- def addPeriodicSync(account: Any, authority: str, extras: Any, pollFrequency: int) -> None:
- pass
-
- @staticmethod
- def removePeriodicSync(account: Any, authority: str, extras: Any) -> None:
- pass
-
- @staticmethod
- def setIsSyncable(account: Any, authority: str, syncable: int) -> None:
- pass
-
- @staticmethod
- def getIsSyncable(account: Any, authority: str) -> int:
- return 1
-
- @staticmethod
- def getSyncAdapterPackagesForAuthority(authority: str) -> List[str]:
- return []
-
- @staticmethod
- def invalidateSegments(authority: str) -> None:
- pass
-
- @staticmethod
- def wrapSyncExtras(extras: Any) -> Any:
- return extras
-
- def toString(self) -> str:
- return "ContentResolver(Sync)"
-
-SyncRequest.Builder = SyncRequest.Builder
\ No newline at end of file
diff --git a/android_pyapi/android/credentials.py b/android_pyapi/android/credentials.py
deleted file mode 100644
index 8445bba..0000000
--- a/android_pyapi/android/credentials.py
+++ /dev/null
@@ -1,418 +0,0 @@
-"""
-Android Credentials API — CredentialManager, CreateCredentialRequest, GetCredentialRequest 等
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "CredentialManager",
- "CreateCredentialRequest",
- "CreateCredentialResponse",
- "GetCredentialRequest",
- "GetCredentialResponse",
- "CredentialDescription",
- "CredentialManagerState",
- "PrepareGetCredentialResponse",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# CredentialManager
-# ═══════════════════════════════════════════════════════════════
-
-class CredentialManager(Stub):
- """CredentialManager — 凭据管理器 (桌面存根)"""
-
- ACTION_CREATE_CREDENTIAL = "android.credentials.action.CREATE_CREDENTIAL"
- ACTION_GET_CREDENTIAL = "android.credentials.action.GET_CREDENTIAL"
- ACTION_CLEAR_CREDENTIAL = "android.credentials.action.CLEAR_CREDENTIAL"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._descriptions: List["CredentialDescription"] = []
-
- def createCredential(
- self,
- request: "CreateCredentialRequest",
- cancellationSignal: Any = None,
- executor: Any = None,
- callback: Callable = None,
- ):
- """创建凭据"""
- raise AndroidOnlyError("CredentialManager.createCredential() 仅在 Android 设备上可用")
-
- def getCredential(
- self,
- request: "GetCredentialRequest",
- cancellationSignal: Any = None,
- executor: Any = None,
- callback: Callable = None,
- ):
- """获取凭据"""
- raise AndroidOnlyError("CredentialManager.getCredential() 仅在 Android 设备上可用")
-
- def clearCredentialState(
- self,
- request: Any = None,
- cancellationSignal: Any = None,
- executor: Any = None,
- callback: Callable = None,
- ):
- """清除凭据状态"""
- raise AndroidOnlyError("CredentialManager.clearCredentialState() 仅在 Android 设备上可用")
-
- def registerCredentialDescription(
- self,
- credentialDescription: "CredentialDescription",
- cancellationSignal: Any = None,
- executor: Any = None,
- callback: Callable = None,
- ):
- """注册凭据描述"""
- if credentialDescription not in self._descriptions:
- self._descriptions.append(credentialDescription)
-
- def unregisterCredentialDescription(
- self,
- credentialDescription: "CredentialDescription",
- ):
- """注销凭据描述"""
- if credentialDescription in self._descriptions:
- self._descriptions.remove(credentialDescription)
-
- def getCredentialManagerState(self) -> "CredentialManagerState":
- """获取凭据管理器状态"""
- return CredentialManagerState()
-
- def toString(self) -> str:
- return f"CredentialManager@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CreateCredentialRequest
-# ═══════════════════════════════════════════════════════════════
-
-class CreateCredentialRequest(Stub):
- """CreateCredentialRequest — 创建凭据请求"""
-
- class Builder(Stub):
- """CreateCredentialRequest.Builder — 创建凭据请求构建器"""
-
- def __init__(self, credentialType: str = ""):
- super().__init__()
- self._credential_type = credentialType
- self._credential_data = None
- self._candidate_query_data = None
- self._always_send_app_uri = False
- self._origin = ""
-
- def setCredentialData(self, data: Any) -> "CreateCredentialRequest.Builder":
- self._credential_data = data
- return self
-
- def setCandidateQueryData(
- self, data: Any
- ) -> "CreateCredentialRequest.Builder":
- self._candidate_query_data = data
- return self
-
- def setAlwaysSendAppUri(
- self, alwaysSend: bool
- ) -> "CreateCredentialRequest.Builder":
- self._always_send_app_uri = alwaysSend
- return self
-
- def setOrigin(self, origin: str) -> "CreateCredentialRequest.Builder":
- self._origin = origin
- return self
-
- def build(self) -> "CreateCredentialRequest":
- req = CreateCredentialRequest.__new__(CreateCredentialRequest)
- req._credential_type = self._credential_type
- req._credential_data = self._credential_data
- req._candidate_query_data = self._candidate_query_data
- req._always_send_app_uri = self._always_send_app_uri
- req._origin = self._origin
- return req
-
- def toString(self) -> str:
- return f"CreateCredentialRequest.Builder(type={self._credential_type})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self):
- super().__init__()
- self._credential_type = ""
- self._credential_data = None
- self._candidate_query_data = None
- self._always_send_app_uri = False
- self._origin = ""
-
- def getCredentialData(self) -> Optional[Any]:
- return self._credential_data
-
- def getCredentialType(self) -> str:
- return self._credential_type
-
- def getCandidateQueryData(self) -> Optional[Any]:
- return self._candidate_query_data
-
- def alwaysSendAppUri(self) -> bool:
- return self._always_send_app_uri
-
- def getOrigin(self) -> str:
- return self._origin
-
- def toString(self) -> str:
- return f"CreateCredentialRequest(type={self._credential_type})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, CreateCredentialRequest):
- return False
- return self._credential_type == other._credential_type
-
- def hashCode(self) -> int:
- return hash(self._credential_type) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CreateCredentialResponse
-# ═══════════════════════════════════════════════════════════════
-
-class CreateCredentialResponse(Stub):
- """CreateCredentialResponse — 创建凭据响应"""
-
- def __init__(self):
- super().__init__()
- self._credential_data = None
- self._credential_data_result = None
-
- def getCredentialData(self) -> Optional[Any]:
- return self._credential_data
-
- def getCredentialDataResult(self) -> Optional[Any]:
- return self._credential_data_result
-
- def toString(self) -> str:
- return f"CreateCredentialResponse@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# GetCredentialRequest
-# ═══════════════════════════════════════════════════════════════
-
-class GetCredentialRequest(Stub):
- """GetCredentialRequest — 获取凭据请求"""
-
- class Builder(Stub):
- """GetCredentialRequest.Builder — 获取凭据请求构建器"""
-
- def __init__(self):
- super().__init__()
- self._credential_data = None
- self._origin = ""
- self._always_send_app_uri = False
- self._candidate_query_data = None
-
- def setCredentialData(
- self, data: Any
- ) -> "GetCredentialRequest.Builder":
- self._credential_data = data
- return self
-
- def setOrigin(self, origin: str) -> "GetCredentialRequest.Builder":
- self._origin = origin
- return self
-
- def setAlwaysSendAppUri(
- self, alwaysSend: bool
- ) -> "GetCredentialRequest.Builder":
- self._always_send_app_uri = alwaysSend
- return self
-
- def setCandidateQueryData(
- self, data: Any
- ) -> "GetCredentialRequest.Builder":
- self._candidate_query_data = data
- return self
-
- def build(self) -> "GetCredentialRequest":
- req = GetCredentialRequest.__new__(GetCredentialRequest)
- req._credential_data = self._credential_data
- req._origin = self._origin
- req._always_send_app_uri = self._always_send_app_uri
- req._candidate_query_data = self._candidate_query_data
- return req
-
- def toString(self) -> str:
- return f"GetCredentialRequest.Builder@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self):
- super().__init__()
- self._credential_data = None
- self._origin = ""
- self._always_send_app_uri = False
- self._candidate_query_data = None
-
- def getCredentialData(self) -> Optional[Any]:
- return self._credential_data
-
- def getOrigin(self) -> str:
- return self._origin
-
- def alwaysSendAppUri(self) -> bool:
- return self._always_send_app_uri
-
- def getCandidateQueryData(self) -> Optional[Any]:
- return self._candidate_query_data
-
- def toString(self) -> str:
- return f"GetCredentialRequest@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# GetCredentialResponse
-# ═══════════════════════════════════════════════════════════════
-
-class GetCredentialResponse(Stub):
- """GetCredentialResponse — 获取凭据响应"""
-
- def __init__(self):
- super().__init__()
- self._credential_data_results: List[Any] = []
-
- def getCredentialDataResults(self) -> List[Any]:
- return list(self._credential_data_results)
-
- def toString(self) -> str:
- return f"GetCredentialResponse(results={len(self._credential_data_results)})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CredentialDescription
-# ═══════════════════════════════════════════════════════════════
-
-class CredentialDescription(Stub):
- """CredentialDescription — 凭据描述"""
-
- def __init__(self, credentialType: str = "", origin: str = ""):
- super().__init__()
- self._credential_type = credentialType
- self._origin = origin
-
- def getCredentialType(self) -> str:
- return self._credential_type
-
- def getOrigin(self) -> str:
- return self._origin
-
- def toString(self) -> str:
- return f"CredentialDescription(type={self._credential_type})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, CredentialDescription):
- return False
- return (self._credential_type == other._credential_type
- and self._origin == other._origin)
-
- def hashCode(self) -> int:
- return hash((self._credential_type, self._origin)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CredentialManagerState
-# ═══════════════════════════════════════════════════════════════
-
-class CredentialManagerState(Stub):
- """CredentialManagerState — 凭据管理器状态"""
-
- def __init__(self):
- super().__init__()
- self._registered_descriptions: List["CredentialDescription"] = []
- self._is_enabled = True
-
- def getRegisteredCredentialDescriptions(self) -> List["CredentialDescription"]:
- return list(self._registered_descriptions)
-
- def isEnabled(self) -> bool:
- return self._is_enabled
-
- def toString(self) -> str:
- return f"CredentialManagerState(enabled={self._is_enabled})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrepareGetCredentialResponse
-# ═══════════════════════════════════════════════════════════════
-
-class PrepareGetCredentialResponse(Stub):
- """PrepareGetCredentialResponse — 预备获取凭据响应"""
-
- def __init__(self):
- super().__init__()
- self._has_results = False
- self._pending_credential = None
-
- def hasResults(self) -> bool:
- return self._has_results
-
- def getPendingGetCredentialResponse(self) -> Optional["GetCredentialResponse"]:
- return self._pending_credential
-
- def toString(self) -> str:
- return f"PrepareGetCredentialResponse(hasResults={self._has_results})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/database.py b/android_pyapi/android/database.py
deleted file mode 100644
index 807ec00..0000000
--- a/android_pyapi/android/database.py
+++ /dev/null
@@ -1,1092 +0,0 @@
-"""
-Android Database 组件 — Cursor, MatrixCursor, ContentObserver 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLException hierarchy
-# ═══════════════════════════════════════════════════════════════
-
-class SQLException(RuntimeError):
- """SQLException — 数据库异常基类"""
-
- def __init__(self, message: str = ""):
- super().__init__(message)
- self._error_message = message
-
- def getMessage(self) -> str:
- return self._error_message
-
- def toString(self) -> str:
- return f"SQLException: {self._error_message}"
-
-
-class CursorIndexOutOfBoundsException(SQLException):
- """CursorIndexOutOfBoundsException — 游标越界"""
-
- def __init__(self, message: str = ""):
- super().__init__(message)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContentObserver
-# ═══════════════════════════════════════════════════════════════
-
-class ContentObserver(Stub):
- """ContentObserver — 内容观察者"""
-
- def __init__(self, handler: Any = None):
- super().__init__()
- self._handler = handler
- self._notify_for_descendants = False
-
- def onChange(self, self_change: bool = True):
- pass
-
- def onChange(self, self_change: bool, uri: Any = None): # type: ignore
- pass
-
- def deliverSelfNotifications(self) -> bool:
- return True
-
- def getSelfChangeNotify(self) -> bool:
- return True
-
- def dispatchChange(self, self_change: bool, uri: Any = None):
- self.onChange(self_change, uri)
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataSetObserver
-# ═══════════════════════════════════════════════════════════════
-
-class DataSetObserver(Stub):
- """DataSetObserver — 数据集观察者"""
-
- def onChanged(self):
- pass
-
- def onInvalidated(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContentObservable
-# ═══════════════════════════════════════════════════════════════
-
-class ContentObservable(Stub):
- """ContentObservable — 内容可观察对象"""
-
- def __init__(self):
- super().__init__()
- self._observers: List[ContentObserver] = []
-
- def registerObserver(self, observer: ContentObserver):
- if observer not in self._observers:
- self._observers.append(observer)
-
- def unregisterObserver(self, observer: ContentObserver):
- self._observers = [o for o in self._observers if o is not observer]
-
- def dispatchChange(self, self_change: bool, uri: Any = None):
- for observer in list(self._observers):
- observer.dispatchChange(self_change, uri)
-
- def notifyChange(self, self_change: bool):
- for observer in list(self._observers):
- observer.onChange(self_change)
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataSetObservable
-# ═══════════════════════════════════════════════════════════════
-
-class DataSetObservable(Stub):
- """DataSetObservable — 数据集可观察对象"""
-
- def __init__(self):
- super().__init__()
- self._observers: List[DataSetObserver] = []
-
- def registerObserver(self, observer: DataSetObserver):
- if observer not in self._observers:
- self._observers.append(observer)
-
- def unregisterObserver(self, observer: DataSetObserver):
- self._observers = [o for o in self._observers if o is not observer]
-
- def notifyChanged(self):
- for observer in list(self._observers):
- observer.onChanged()
-
- def notifyInvalidated(self):
- for observer in list(self._observers):
- observer.onInvalidated()
-
-
-# ═══════════════════════════════════════════════════════════════
-# CharArrayBuffer
-# ═══════════════════════════════════════════════════════════════
-
-class CharArrayBuffer(Stub):
- """CharArrayBuffer — 字符数组缓冲区"""
-
- def __init__(self, size: int = 0):
- super().__init__()
- self.data: List[str] = [""] * size
-
-
-# ═══════════════════════════════════════════════════════════════
-# DatabaseErrorHandler
-# ═══════════════════════════════════════════════════════════════
-
-class DatabaseErrorHandler(Stub):
- """DatabaseErrorHandler — 数据库错误处理器"""
-
- def onCorruption(self, db_obj: Any):
- pass
-
-
-class DefaultDatabaseErrorHandler(DatabaseErrorHandler):
- """DefaultDatabaseErrorHandler — 默认数据库错误处理器"""
-
- def onCorruption(self, db_obj: Any):
- import sys
- sys.stderr.write(f"[DatabaseError] Corruption detected for {db_obj}\n")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CursorWindow
-# ═══════════════════════════════════════════════════════════════
-
-class CursorWindow(Stub):
- """CursorWindow — 游标窗口"""
-
- def __init__(self, name: str = "unnamed"):
- super().__init__()
- self._name = name
- self._start_position: int = 0
- self._num_rows: int = 0
- self._num_columns: int = 0
- self._data: List[List[Optional[Any]]] = []
-
- def setStartPosition(self, pos: int):
- self._start_position = pos
-
- def getStartPosition(self) -> int:
- return self._start_position
-
- def allocRow(self) -> bool:
- self._data.append([None] * self._num_columns)
- self._num_rows = len(self._data)
- return True
-
- def freeRow(self, row: int):
- if 0 <= row < len(self._data):
- self._data[row] = [None] * self._num_columns
-
- def freeLastRow(self):
- if self._data:
- self._data.pop()
- self._num_rows = len(self._data)
-
- def getNumRows(self) -> int:
- return self._num_rows
-
- def setNumColumns(self, num_columns: int):
- self._num_columns = num_columns
-
- def getNumColumns(self) -> int:
- return self._num_columns
-
- def writeString(self, value: str, row: int, col: int):
- while len(self._data) <= row:
- self._data.append([None] * self._num_columns)
- while len(self._data[row]) <= col:
- self._data[row].append(None)
- self._data[row][col] = value
-
- def writeLong(self, value: int, row: int, col: int):
- while len(self._data) <= row:
- self._data.append([None] * self._num_columns)
- while len(self._data[row]) <= col:
- self._data[row].append(None)
- self._data[row][col] = value
-
- def writeDouble(self, value: float, row: int, col: int):
- while len(self._data) <= row:
- self._data.append([None] * self._num_columns)
- while len(self._data[row]) <= col:
- self._data[row].append(None)
- self._data[row][col] = value
-
- def writeBlob(self, value: bytes, row: int, col: int):
- while len(self._data) <= row:
- self._data.append([None] * self._num_columns)
- while len(self._data[row]) <= col:
- self._data[row].append(None)
- self._data[row][col] = value
-
- def writeNull(self, row: int, col: int):
- while len(self._data) <= row:
- self._data.append([None] * self._num_columns)
- while len(self._data[row]) <= col:
- self._data[row].append(None)
- self._data[row][col] = None
-
- def getString(self, row: int, col: int) -> Optional[str]:
- try:
- v = self._data[row][col]
- return str(v) if v is not None else None
- except (IndexError, TypeError):
- return None
-
- def getLong(self, row: int, col: int) -> int:
- try:
- v = self._data[row][col]
- return int(v) if v is not None else 0
- except (IndexError, ValueError, TypeError):
- return 0
-
- def getDouble(self, row: int, col: int) -> float:
- try:
- v = self._data[row][col]
- return float(v) if v is not None else 0.0
- except (IndexError, ValueError, TypeError):
- return 0.0
-
- def getBlob(self, row: int, col: int) -> Optional[bytes]:
- try:
- v = self._data[row][col]
- if isinstance(v, bytes):
- return v
- if isinstance(v, str):
- return v.encode("utf-8")
- return None
- except IndexError:
- return None
-
- def isNull(self, row: int, col: int) -> bool:
- try:
- return self._data[row][col] is None
- except IndexError:
- return True
-
- def clear(self):
- self._data.clear()
- self._num_rows = 0
-
- def toString(self) -> str:
- return f"CursorWindow(name={self._name}, rows={self._num_rows}, cols={self._num_columns})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Cursor interface
-# ═══════════════════════════════════════════════════════════════
-
-class Cursor(Stub):
- """Cursor — 游标接口"""
-
- FIELD_TYPE_NULL = 0
- FIELD_TYPE_INTEGER = 1
- FIELD_TYPE_FLOAT = 2
- FIELD_TYPE_STRING = 3
- FIELD_TYPE_BLOB = 4
-
- def __init__(self):
- super().__init__()
- self._pos: int = -1
- self._closed: bool = False
-
- def getCount(self) -> int:
- return 0
-
- def getPosition(self) -> int:
- return self._pos
-
- def moveToFirst(self) -> bool:
- return self.moveToPosition(0)
-
- def moveToLast(self) -> bool:
- return self.moveToPosition(self.getCount() - 1)
-
- def moveToNext(self) -> bool:
- return self.moveToPosition(self._pos + 1)
-
- def moveToPrevious(self) -> bool:
- return self.moveToPosition(self._pos - 1)
-
- def move(self, offset: int) -> bool:
- return self.moveToPosition(self._pos + offset)
-
- def moveToPosition(self, position: int) -> bool:
- count = self.getCount()
- if position >= count:
- self._pos = count
- return False
- if position < -1:
- self._pos = -1
- return False
- self._pos = position
- return True
-
- def isFirst(self) -> bool:
- return self._pos == 0 and self.getCount() > 0
-
- def isLast(self) -> bool:
- count = self.getCount()
- return count > 0 and self._pos == count - 1
-
- def isBeforeFirst(self) -> bool:
- if self.getCount() == 0:
- return True
- return self._pos < 0
-
- def isAfterLast(self) -> bool:
- if self.getCount() == 0:
- return True
- return self._pos >= self.getCount()
-
- def getColumnIndex(self, column_name: str) -> int:
- names = self.getColumnNames()
- try:
- return names.index(column_name)
- except ValueError:
- return -1
-
- def getColumnIndexOrThrow(self, column_name: str) -> int:
- idx = self.getColumnIndex(column_name)
- if idx < 0:
- raise IllegalArgumentException(f"Column '{column_name}' does not exist")
- return idx
-
- def getColumnName(self, column_index: int) -> str:
- names = self.getColumnNames()
- if 0 <= column_index < len(names):
- return names[column_index]
- return ""
-
- def getColumnNames(self) -> List[str]:
- return []
-
- def getColumnCount(self) -> int:
- return len(self.getColumnNames())
-
- def getType(self, column_index: int) -> int:
- return self.FIELD_TYPE_NULL
-
- def getString(self, column_index: int) -> Optional[str]:
- return None
-
- def getInt(self, column_index: int) -> int:
- return 0
-
- def getLong(self, column_index: int) -> int:
- return 0
-
- def getFloat(self, column_index: int) -> float:
- return 0.0
-
- def getDouble(self, column_index: int) -> float:
- return 0.0
-
- def getShort(self, column_index: int) -> int:
- return 0
-
- def getBlob(self, column_index: int) -> Optional[bytes]:
- return None
-
- def getBytes(self, column_index: int) -> Optional[bytes]:
- return self.getBlob(column_index)
-
- def close(self):
- self._closed = True
-
- def isClosed(self) -> bool:
- return self._closed
-
- def requery(self) -> bool:
- return False
-
- def deactivate(self):
- pass
-
- def registerContentObserver(self, observer: ContentObserver):
- pass
-
- def unregisterContentObserver(self, observer: ContentObserver):
- pass
-
- def registerDataSetObserver(self, observer: DataSetObserver):
- pass
-
- def unregisterDataSetObserver(self, observer: DataSetObserver):
- pass
-
- def getWantsAllOnMoveCalls(self) -> bool:
- return False
-
- def getExtras(self) -> Any:
- return None
-
- def respond(self, extras: Any) -> Any:
- return None
-
- def setNotificationUri(self, cr: Any, uri: Any):
- pass
-
- def getNotificationUri(self) -> Any:
- return None
-
- def fillWindow(self, pos: int, window: CursorWindow):
- pass
-
- def copyStringToBuffer(self, column_index: int, buffer: CharArrayBuffer):
- val = self.getString(column_index)
- if val is not None:
- buffer.data = list(val)
-
- def isNull(self, column_index: int) -> bool:
- return self.getType(column_index) == self.FIELD_TYPE_NULL
-
-
-# ═══════════════════════════════════════════════════════════════
-# AbstractCursor
-# ═══════════════════════════════════════════════════════════════
-
-class AbstractCursor(Cursor):
- """AbstractCursor — 游标抽象基类"""
-
- def __init__(self):
- super().__init__()
- self._content_observable = ContentObservable()
- self._data_set_observable = DataSetObservable()
- self._notification_uri: Any = None
- self._self_observer: Optional[ContentObserver] = None
-
- def getCount(self) -> int:
- return 0
-
- def getColumnNames(self) -> List[str]:
- return []
-
- def registerContentObserver(self, observer: ContentObserver):
- self._content_observable.registerObserver(observer)
-
- def unregisterContentObserver(self, observer: ContentObserver):
- self._content_observable.unregisterObserver(observer)
-
- def registerDataSetObserver(self, observer: DataSetObserver):
- self._data_set_observable.registerObserver(observer)
-
- def unregisterDataSetObserver(self, observer: DataSetObserver):
- self._data_set_observable.unregisterObserver(observer)
-
- def setNotificationUri(self, cr: Any, uri: Any):
- self._notification_uri = uri
-
- def getNotificationUri(self) -> Any:
- return self._notification_uri
-
- def onChange(self, self_change: bool):
- self._content_observable.dispatchChange(self_change)
-
- def getWantsAllOnMoveCalls(self) -> bool:
- return False
-
- def getExtras(self) -> Any:
- return None
-
- def respond(self, extras: Any) -> Any:
- return None
-
- def fillWindow(self, pos: int, window: CursorWindow):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AbstractWindowedCursor
-# ═══════════════════════════════════════════════════════════════
-
-class AbstractWindowedCursor(AbstractCursor):
- """AbstractWindowedCursor — 带窗口的游标"""
-
- def __init__(self):
- super().__init__()
- self._window: Optional[CursorWindow] = None
-
- def getWindow(self) -> Optional[CursorWindow]:
- return self._window
-
- def setWindow(self, window: CursorWindow):
- self._window = window
-
- def hasWindow(self) -> bool:
- return self._window is not None
-
- def clearBlobCache(self):
- pass
-
- def fillWindow(self, pos: int, window: CursorWindow):
- if self._window:
- self._window.clear()
-
- def getString(self, column_index: int) -> Optional[str]:
- if self._window and self._pos >= 0:
- return self._window.getString(self._pos, column_index)
- return None
-
- def getInt(self, column_index: int) -> int:
- if self._window and self._pos >= 0:
- return self._window.getLong(self._pos, column_index)
- return 0
-
- def getLong(self, column_index: int) -> int:
- if self._window and self._pos >= 0:
- return self._window.getLong(self._pos, column_index)
- return 0
-
- def getFloat(self, column_index: int) -> float:
- if self._window and self._pos >= 0:
- return self._window.getDouble(self._pos, column_index)
- return 0.0
-
- def getDouble(self, column_index: int) -> float:
- if self._window and self._pos >= 0:
- return self._window.getDouble(self._pos, column_index)
- return 0.0
-
- def getBlob(self, column_index: int) -> Optional[bytes]:
- if self._window and self._pos >= 0:
- return self._window.getBlob(self._pos, column_index)
- return None
-
- def isNull(self, column_index: int) -> bool:
- if self._window and self._pos >= 0:
- return self._window.isNull(self._pos, column_index)
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# CursorWrapper
-# ═══════════════════════════════════════════════════════════════
-
-class CursorWrapper(Cursor):
- """CursorWrapper — 游标包装器"""
-
- def __init__(self, cursor: Cursor):
- super().__init__()
- self._wrapped_cursor = cursor
-
- def getWrappedCursor(self) -> Cursor:
- return self._wrapped_cursor
-
- def getCount(self) -> int:
- return self._wrapped_cursor.getCount()
-
- def getPosition(self) -> int:
- return self._wrapped_cursor.getPosition()
-
- def moveToFirst(self) -> bool:
- return self._wrapped_cursor.moveToFirst()
-
- def moveToLast(self) -> bool:
- return self._wrapped_cursor.moveToLast()
-
- def moveToNext(self) -> bool:
- return self._wrapped_cursor.moveToNext()
-
- def moveToPrevious(self) -> bool:
- return self._wrapped_cursor.moveToPrevious()
-
- def move(self, offset: int) -> bool:
- return self._wrapped_cursor.move(offset)
-
- def moveToPosition(self, position: int) -> bool:
- return self._wrapped_cursor.moveToPosition(position)
-
- def getColumnNames(self) -> List[str]:
- return self._wrapped_cursor.getColumnNames()
-
- def getColumnIndex(self, column_name: str) -> int:
- return self._wrapped_cursor.getColumnIndex(column_name)
-
- def getColumnIndexOrThrow(self, column_name: str) -> int:
- return self._wrapped_cursor.getColumnIndexOrThrow(column_name)
-
- def getString(self, column_index: int) -> Optional[str]:
- return self._wrapped_cursor.getString(column_index)
-
- def getInt(self, column_index: int) -> int:
- return self._wrapped_cursor.getInt(column_index)
-
- def getLong(self, column_index: int) -> int:
- return self._wrapped_cursor.getLong(column_index)
-
- def getFloat(self, column_index: int) -> float:
- return self._wrapped_cursor.getFloat(column_index)
-
- def getDouble(self, column_index: int) -> float:
- return self._wrapped_cursor.getDouble(column_index)
-
- def getShort(self, column_index: int) -> int:
- return self._wrapped_cursor.getShort(column_index)
-
- def getBlob(self, column_index: int) -> Optional[bytes]:
- return self._wrapped_cursor.getBlob(column_index)
-
- def close(self):
- self._wrapped_cursor.close()
-
- def isClosed(self) -> bool:
- return self._wrapped_cursor.isClosed()
-
- def registerContentObserver(self, observer: ContentObserver):
- self._wrapped_cursor.registerContentObserver(observer)
-
- def unregisterContentObserver(self, observer: ContentObserver):
- self._wrapped_cursor.unregisterContentObserver(observer)
-
- def registerDataSetObserver(self, observer: DataSetObserver):
- self._wrapped_cursor.registerDataSetObserver(observer)
-
- def unregisterDataSetObserver(self, observer: DataSetObserver):
- self._wrapped_cursor.unregisterDataSetObserver(observer)
-
- def getWantsAllOnMoveCalls(self) -> bool:
- return self._wrapped_cursor.getWantsAllOnMoveCalls()
-
-
-# ═══════════════════════════════════════════════════════════════
-# CrossProcessCursor / CrossProcessCursorWrapper
-# ═══════════════════════════════════════════════════════════════
-
-class CrossProcessCursor(Cursor):
- """CrossProcessCursor — 跨进程游标"""
-
- def fillWindow(self, pos: int, window: CursorWindow):
- pass
-
- def getWindow(self) -> Optional[CursorWindow]:
- return None
-
- def onMove(self, old_position: int, new_position: int) -> bool:
- return True
-
-
-class CrossProcessCursorWrapper(CursorWrapper):
- """CrossProcessCursorWrapper — 跨进程游标包装器"""
-
- def __init__(self, cursor: Cursor):
- super().__init__(cursor)
- self._cursor = cursor
-
- def fillWindow(self, pos: int, window: CursorWindow):
- if isinstance(self._cursor, CrossProcessCursor):
- self._cursor.fillWindow(pos, window)
-
- def getWindow(self) -> Optional[CursorWindow]:
- if isinstance(self._cursor, CrossProcessCursor):
- return self._cursor.getWindow()
- return None
-
- def onMove(self, old_position: int, new_position: int) -> bool:
- if isinstance(self._cursor, CrossProcessCursor):
- return self._cursor.onMove(old_position, new_position)
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# MatrixCursor
-# ═══════════════════════════════════════════════════════════════
-
-class MatrixCursor(AbstractCursor):
- """MatrixCursor — 内存矩阵游标"""
-
- class RowBuilder(Stub):
- """RowBuilder — 行构建器"""
-
- def __init__(self, cursor: "MatrixCursor", row_index: int):
- super().__init__()
- self._cursor = cursor
- self._row_index = row_index
-
- def add(self, column_value: Any) -> "MatrixCursor.RowBuilder":
- self._cursor._add_row_value(self._row_index, column_value)
- return self
-
- def __init__(self, column_names: List[str], initial_capacity: int = 0):
- super().__init__()
- self._column_names = list(column_names)
- self._rows: List[List[Optional[Any]]] = []
- self._num_columns = len(column_names)
-
- def _add_row_value(self, row_index: int, value: Any):
- while len(self._rows) <= row_index:
- self._rows.append([])
- self._rows[row_index].append(value)
-
- def addRow(self, values: Union[List[Any], Tuple[Any, ...]]) -> None:
- row = list(values) + [None] * (self._num_columns - len(values))
- self._rows.append(row[:self._num_columns])
-
- def newRow(self) -> RowBuilder:
- row_index = len(self._rows)
- self._rows.append([])
- return MatrixCursor.RowBuilder(self, row_index)
-
- def getCount(self) -> int:
- return len(self._rows)
-
- def getColumnNames(self) -> List[str]:
- return list(self._column_names)
-
- def getString(self, column_index: int) -> Optional[str]:
- if self._pos < 0 or self._pos >= len(self._rows):
- return None
- if column_index < 0 or column_index >= len(self._rows[self._pos]):
- return None
- v = self._rows[self._pos][column_index]
- return str(v) if v is not None else None
-
- def getInt(self, column_index: int) -> int:
- v = self.getString(column_index)
- if v is None:
- return 0
- try:
- return int(float(v))
- except (ValueError, TypeError):
- return 0
-
- def getLong(self, column_index: int) -> int:
- return self.getInt(column_index)
-
- def getShort(self, column_index: int) -> int:
- return self.getInt(column_index)
-
- def getFloat(self, column_index: int) -> float:
- v = self.getString(column_index)
- if v is None:
- return 0.0
- try:
- return float(v)
- except (ValueError, TypeError):
- return 0.0
-
- def getDouble(self, column_index: int) -> float:
- return self.getFloat(column_index)
-
- def getBlob(self, column_index: int) -> Optional[bytes]:
- if self._pos < 0 or self._pos >= len(self._rows):
- return None
- if column_index < 0 or column_index >= len(self._rows[self._pos]):
- return None
- v = self._rows[self._pos][column_index]
- if isinstance(v, bytes):
- return v
- if isinstance(v, str):
- return v.encode("utf-8")
- return None
-
- def getType(self, column_index: int) -> int:
- v = None
- if 0 <= self._pos < len(self._rows):
- row = self._rows[self._pos]
- if 0 <= column_index < len(row):
- v = row[column_index]
- if v is None:
- return Cursor.FIELD_TYPE_NULL
- if isinstance(v, int):
- return Cursor.FIELD_TYPE_INTEGER
- if isinstance(v, float):
- return Cursor.FIELD_TYPE_FLOAT
- if isinstance(v, bytes):
- return Cursor.FIELD_TYPE_BLOB
- return Cursor.FIELD_TYPE_STRING
-
- def isNull(self, column_index: int) -> bool:
- return self.getType(column_index) == Cursor.FIELD_TYPE_NULL
-
- def toString(self) -> str:
- return f"MatrixCursor(cols={self._column_names}, rows={len(self._rows)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MergeCursor
-# ═══════════════════════════════════════════════════════════════
-
-class MergeCursor(AbstractCursor):
- """MergeCursor — 合并多个游标"""
-
- def __init__(self, cursors: List[Cursor]):
- super().__init__()
- self._cursors = cursors
- self._cursor_index = 0
- self._current_cursor: Optional[Cursor] = None
-
- def getCount(self) -> int:
- return sum(c.getCount() for c in self._cursors)
-
- def getColumnNames(self) -> List[str]:
- if self._cursors:
- return self._cursors[0].getColumnNames()
- return []
-
- def moveToPosition(self, position: int) -> bool:
- if position < -1:
- return False
- if position >= self.getCount():
- return False
- offset = 0
- for i, c in enumerate(self._cursors):
- count = c.getCount()
- if position < offset + count:
- self._cursor_index = i
- self._current_cursor = c
- return c.moveToPosition(position - offset)
- offset += count
- return False
-
- def getString(self, column_index: int) -> Optional[str]:
- if self._current_cursor and self._pos >= 0:
- return self._current_cursor.getString(column_index)
- return None
-
- def getInt(self, column_index: int) -> int:
- if self._current_cursor and self._pos >= 0:
- return self._current_cursor.getInt(column_index)
- return 0
-
- def close(self):
- for c in self._cursors:
- c.close()
- super().close()
-
-
-# ═══════════════════════════════════════════════════════════════
-# CursorJoiner
-# ═══════════════════════════════════════════════════════════════
-
-class CursorJoiner(Stub):
- """CursorJoiner — 游标连接器"""
-
- class Result(Stub):
- BOTH = 0
- LEFT = 1
- RIGHT = 2
-
- def __init__(self, cursor_a: Cursor, column_names_a: List[str],
- cursor_b: Cursor, column_names_b: List[str]):
- super().__init__()
- self._cursor_a = cursor_a
- self._cursor_b = cursor_b
- self._col_names_a = column_names_a
- self._col_names_b = column_names_b
- self._has_next = False
-
- def hasNext(self) -> bool:
- return self._has_next
-
- def next(self) -> int:
- return self.Result.BOTH
-
-
-# ═══════════════════════════════════════════════════════════════
-# DatabaseUtils
-# ═══════════════════════════════════════════════════════════════
-
-class DatabaseUtils(Stub):
- """DatabaseUtils — 数据库工具"""
-
- STATEMENT_ABORT = "ABORT"
- STATEMENT_FAIL = "FAIL"
- STATEMENT_IGNORE = "IGNORE"
- STATEMENT_REPLACE = "REPLACE"
- STATEMENT_ROLLBACK = "ROLLBACK"
-
- @staticmethod
- def cursorFillWindow(cursor: Cursor, pos: int, window: CursorWindow):
- cursor.fillWindow(pos, window)
-
- @staticmethod
- def cursorStringToContentValues(cursor: Cursor, field: str, values: Any):
- pass
-
- @staticmethod
- def cursorIntToContentValues(cursor: Cursor, field: str, values: Any):
- pass
-
- @staticmethod
- def cursorLongToContentValues(cursor: Cursor, field: str, values: Any):
- pass
-
- @staticmethod
- def cursorDoubleToContentValues(cursor: Cursor, field: str, values: Any):
- pass
-
- @staticmethod
- def cursorRowToContentValues(cursor: Cursor, values: Any):
- for col_name in cursor.getColumnNames():
- idx = cursor.getColumnIndex(col_name)
- val = cursor.getString(idx)
- if hasattr(values, "put"):
- values.put(col_name, val)
-
- @staticmethod
- def dumpCursor(cursor: Cursor):
- col_names = cursor.getColumnNames()
- sys.stderr.write(f"Rows: {cursor.getCount()}\n")
- sys.stderr.write(f"Columns: {col_names}\n")
-
- @staticmethod
- def dumpCursorToString(cursor: Cursor) -> str:
- return f"Cursor(count={cursor.getCount()})"
-
- @staticmethod
- def bindObjectToProgram(program: Any, index: int, value: Any):
- pass
-
- @staticmethod
- def cursorToContentValues(cursor: Cursor, values: Any):
- DatabaseUtils.cursorRowToContentValues(cursor, values)
-
- @staticmethod
- def longForQuery(db: Any, query: str, args: Optional[List[str]] = None) -> int:
- return 0
-
- @staticmethod
- def stringForQuery(db: Any, query: str, args: Optional[List[str]] = None) -> Optional[str]:
- return None
-
- @staticmethod
- def blobForQuery(db: Any, query: str, args: Optional[List[str]] = None) -> Optional[bytes]:
- return None
-
- @staticmethod
- def sqlEscapeString(value: str) -> str:
- return value.replace("'", "''")
-
- @staticmethod
- def appendEscapedSQLString(sb: Any, value: str):
- escaped = DatabaseUtils.sqlEscapeString(value)
- sb.append(f"'{escaped}'")
-
- @staticmethod
- def appendValueToSql(sb: Any, value: Any):
- if value is None:
- sb.append("NULL")
- elif isinstance(value, bool):
- sb.append("1" if value else "0")
- elif isinstance(value, (int, float)):
- sb.append(str(value))
- else:
- DatabaseUtils.appendEscapedSQLString(sb, str(value))
-
- @staticmethod
- def appendSelectionArgs(original_values: List[str], new_values: List[str]) -> List[str]:
- return list(original_values) + list(new_values)
-
- @staticmethod
- def getCollationKey(name: str) -> str:
- return name.lower()
-
- @staticmethod
- def getHexCollationKey(name: str) -> str:
- return name.lower().encode("utf-8").hex()
-
- @staticmethod
- def createDbFromSqlStatements(context: Any, db_name: str, db_version: int, sql_statements: str):
- from .database_sqlite import SQLiteDatabase
- db_path = os.path.join(_app_data_dir, "databases", db_name)
- os.makedirs(os.path.dirname(db_path), exist_ok=True)
- db = SQLiteDatabase.openOrCreateDatabase(db_path, None)
- for stmt in sql_statements.split(";"):
- stmt = stmt.strip()
- if stmt:
- try:
- db.execSQL(stmt)
- except Exception:
- pass
- return db
-
-
-# ═══════════════════════════════════════════════════════════════
-# DatabaseUtilsInsertHelper
-# ═══════════════════════════════════════════════════════════════
-
-class DatabaseUtilsInsertHelper(Stub):
- """DatabaseUtils.InsertHelper — 插入辅助类"""
-
- TABLE_INFO_PRAGMA_COLUMNNAME_INDEX = 1
-
- def __init__(self, db: Any, table_name: str):
- super().__init__()
- self._db = db
- self._table_name = table_name
-
- def getTableName(self) -> str:
- return self._table_name
-
- def prepareForInsert(self) -> int:
- return 0
-
- def prepareForReplace(self) -> int:
- return 0
-
- def bind(self, index: int, value: Any):
- pass
-
- def execute(self) -> int:
- return 0
-
- def close(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Helper
-# ═══════════════════════════════════════════════════════════════
-
-class IllegalArgumentException(RuntimeError):
- """IllegalArgumentException — 非法参数异常"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Cursor",
- "MatrixCursor",
- "AbstractCursor",
- "AbstractWindowedCursor",
- "ContentObservable",
- "ContentObserver",
- "DataSetObservable",
- "DatabaseErrorHandler",
- "DatabaseUtils",
- "DefaultDatabaseErrorHandler",
- "CharArrayBuffer",
- "CursorJoiner",
- "CursorWindow",
- "CursorWrapper",
- "CrossProcessCursor",
- "CrossProcessCursorWrapper",
- "DataSetObserver",
- "MergeCursor",
- "SQLException",
- "CursorIndexOutOfBoundsException",
- "DatabaseUtilsInsertHelper",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/database_ext.py b/android_pyapi/android/database_ext.py
deleted file mode 100644
index 11c2cca..0000000
--- a/android_pyapi/android/database_ext.py
+++ /dev/null
@@ -1,866 +0,0 @@
-"""
-Android Database Extension 组件 — ContentObserver, DataSetObserver, CrossProcessCursor, CursorWindow 等
-方法签名完全对齐 Android SDK (android.database 包扩展)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContentObserver
-# ═══════════════════════════════════════════════════════════════
-
-class ContentObserver(Stub):
- """ContentObserver — 内容观察者"""
-
- NOTIFY_URIS = 0
- NOTIFY_SYNC_TO_NETWORK = 1
- NOTIFY_SKIP_SYNC = 2
-
- def __init__(self, handler: Any = None):
- super().__init__()
- self._handler = handler
- self._is_alive: bool = True
- self._self_change_count: int = 0
- self._change_count: int = 0
- self._observed_uris: List[str] = []
-
- def onChange(self, self_change: bool = False):
- """内容变化回调"""
- pass
-
- def onChange(self, self_change: bool, uri: Any = None):
- """内容变化回调 (带 URI)"""
- pass
-
- def onChange(self, self_change: bool, uri: Any, user_id: int = 0):
- pass
-
- def deliverSelfNotifications(self) -> bool:
- """是否传递自身通知"""
- return False
-
- def isAlive(self) -> bool:
- return self._is_alive
-
- def release(self):
- """释放观察者"""
- self._is_alive = False
- self._observed_uris.clear()
-
- def dispatchChange(self, self_change: bool, uri: Any = None, user_id: int = 0):
- """调度变化"""
- if self._is_alive:
- if uri is not None:
- self.onChange(self_change, uri, user_id)
- else:
- self.onChange(self_change)
-
- def getHandler(self) -> Any:
- return self._handler
-
- def getChangeCount(self) -> int:
- return self._change_count
-
- def incrementChangeCount(self):
- self._change_count += 1
-
- def addObservedUri(self, uri: str):
- if uri not in self._observed_uris:
- self._observed_uris.append(uri)
-
- def removeObservedUri(self, uri: str):
- self._observed_uris = [u for u in self._observed_uris if u != uri]
-
- def getObservedUris(self) -> List[str]:
- return list(self._observed_uris)
-
- def isObservingUri(self, uri: str) -> bool:
- return uri in self._observed_uris
-
- def toString(self) -> str:
- return f"ContentObserver(alive={self._is_alive}, uris={len(self._observed_uris)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataSetObserver
-# ═══════════════════════════════════════════════════════════════
-
-class DataSetObserver(Stub):
- """DataSetObserver — 数据集观察者"""
-
- def __init__(self):
- super().__init__()
- self._is_alive: bool = True
- self._notify_count: int = 0
-
- def onChanged(self):
- """数据集变化回调"""
- self._notify_count += 1
-
- def onInvalidated(self):
- """数据集失效回调"""
- pass
-
- def isAlive(self) -> bool:
- return self._is_alive
-
- def release(self):
- self._is_alive = False
-
- def getNotifyCount(self) -> int:
- return self._notify_count
-
- def toString(self) -> str:
- return f"DataSetObserver(alive={self._is_alive}, notified={self._notify_count})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataSetValidatable
-# ═══════════════════════════════════════════════════════════════
-
-class DataSetValidatable(Stub):
- """DataSetValidatable — 数据集可验证接口"""
-
- def isValid(self) -> bool:
- """检查数据集是否有效"""
- return True
-
- def validate(self) -> bool:
- """验证数据集"""
- return self.isValid()
-
- def getValidationError(self) -> Optional[str]:
- """获取验证错误信息"""
- return None
-
- def resetValidation(self):
- """重置验证状态"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# CrossProcessCursor
-# ═══════════════════════════════════════════════════════════════
-
-class CrossProcessCursor(Stub):
- """CrossProcessCursor — 跨进程游标"""
-
- def __init__(self):
- super().__init__()
- self._window: Optional[CursorWindow] = None
- self._position: int = -1
- self._row_count: int = 0
- self._column_count: int = 0
-
- def getWindow(self) -> Optional[CursorWindow]:
- return self._window
-
- def setWindow(self, window: CursorWindow):
- self._window = window
-
- def fillWindow(self, position: int, window: CursorWindow):
- """填充窗口"""
- self._window = window
- self._position = position
-
- def onMove(self, old_position: int, new_position: int) -> bool:
- """移动回调"""
- return 0 <= new_position < self._row_count
-
- def getPosition(self) -> int:
- return self._position
-
- def moveToPosition(self, position: int) -> bool:
- if 0 <= position < self._row_count:
- old = self._position
- self._position = position
- return self.onMove(old, position)
- return False
-
- def moveToFirst(self) -> bool:
- return self.moveToPosition(0)
-
- def moveToLast(self) -> bool:
- return self.moveToPosition(self._row_count - 1)
-
- def moveToNext(self) -> bool:
- return self.moveToPosition(self._position + 1)
-
- def moveToPrevious(self) -> bool:
- return self.moveToPosition(self._position - 1)
-
- def isFirst(self) -> bool:
- return self._position == 0
-
- def isLast(self) -> bool:
- return self._position == self._row_count - 1
-
- def isBeforeFirst(self) -> bool:
- return self._position < 0
-
- def isAfterLast(self) -> bool:
- return self._position >= self._row_count
-
- def getRowCount(self) -> int:
- return self._row_count
-
- def setRowCount(self, count: int):
- self._row_count = count
-
- def getColumnCount(self) -> int:
- return self._column_count
-
- def setColumnCount(self, count: int):
- self._column_count = count
-
- def getColumnIndex(self, column_name: str) -> int:
- return -1
-
- def getColumnName(self, index: int) -> str:
- return ""
-
- def getColumnNames(self) -> List[str]:
- return []
-
- def getString(self, column_index: int) -> Optional[str]:
- return None
-
- def getInt(self, column_index: int) -> int:
- return 0
-
- def getLong(self, column_index: int) -> int:
- return 0
-
- def getFloat(self, column_index: int) -> float:
- return 0.0
-
- def getDouble(self, column_index: int) -> float:
- return 0.0
-
- def isNull(self, column_index: int) -> bool:
- return True
-
- def close(self):
- self._window = None
- self._row_count = 0
-
- def requery(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"CrossProcessCursor(rows={self._row_count}, pos={self._position})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CrossProcessCursorWrapper
-# ═══════════════════════════════════════════════════════════════
-
-class CrossProcessCursorWrapper(CrossProcessCursor):
- """CrossProcessCursorWrapper — 跨进程游标包装器"""
-
- def __init__(self, cursor: Optional[CrossProcessCursor] = None):
- super().__init__()
- self._wrapped_cursor = cursor
-
- def getWrappedCursor(self) -> Optional[CrossProcessCursor]:
- return self._wrapped_cursor
-
- def setWrappedCursor(self, cursor: CrossProcessCursor):
- self._wrapped_cursor = cursor
-
- def getWindow(self) -> Optional[CursorWindow]:
- if self._wrapped_cursor:
- return self._wrapped_cursor.getWindow()
- return self._window
-
- def fillWindow(self, position: int, window: CursorWindow):
- if self._wrapped_cursor:
- self._wrapped_cursor.fillWindow(position, window)
- else:
- super().fillWindow(position, window)
-
- def onMove(self, old_position: int, new_position: int) -> bool:
- if self._wrapped_cursor:
- return self._wrapped_cursor.onMove(old_position, new_position)
- return super().onMove(old_position, new_position)
-
- def getRowCount(self) -> int:
- if self._wrapped_cursor:
- return self._wrapped_cursor.getRowCount()
- return self._row_count
-
- def getColumnCount(self) -> int:
- if self._wrapped_cursor:
- return self._wrapped_cursor.getColumnCount()
- return self._column_count
-
- def getColumnNames(self) -> List[str]:
- if self._wrapped_cursor:
- return self._wrapped_cursor.getColumnNames()
- return []
-
- def getColumnIndex(self, column_name: str) -> int:
- if self._wrapped_cursor:
- return self._wrapped_cursor.getColumnIndex(column_name)
- return -1
-
- def getString(self, column_index: int) -> Optional[str]:
- if self._wrapped_cursor:
- return self._wrapped_cursor.getString(column_index)
- return None
-
- def getInt(self, column_index: int) -> int:
- if self._wrapped_cursor:
- return self._wrapped_cursor.getInt(column_index)
- return 0
-
- def getLong(self, column_index: int) -> int:
- if self._wrapped_cursor:
- return self._wrapped_cursor.getLong(column_index)
- return 0
-
- def getDouble(self, column_index: int) -> float:
- if self._wrapped_cursor:
- return self._wrapped_cursor.getDouble(column_index)
- return 0.0
-
- def moveToPosition(self, position: int) -> bool:
- if self._wrapped_cursor:
- return self._wrapped_cursor.moveToPosition(position)
- return super().moveToPosition(position)
-
- def close(self):
- if self._wrapped_cursor:
- self._wrapped_cursor.close()
- super().close()
-
- def toString(self) -> str:
- return f"CrossProcessCursorWrapper(wrapped={self._wrapped_cursor})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CursorWindow
-# ═══════════════════════════════════════════════════════════════
-
-class CursorWindow(Stub):
- """CursorWindow — 游标窗口"""
-
- WINDOW_SIZE_LIMIT = 2097152 # 2MB
-
- TYPE_NULL = 0
- TYPE_INTEGER = 1
- TYPE_FLOAT = 2
- TYPE_BLOB = 4
- TYPE_STRING = 5
-
- def __init__(self, name: str = "CursorWindow"):
- super().__init__()
- self._name = name
- self._start_position: int = 0
- self._num_rows: int = 0
- self._is_open: bool = True
- self._data: Dict[Tuple[int, int], Any] = {}
- self._types: Dict[Tuple[int, int], int] = {}
- self._allocated_memory: int = 0
- self._max_allocated_memory: int = CursorWindow.WINDOW_SIZE_LIMIT
-
- @staticmethod
- def newFromParcel(data: Any) -> CursorWindow:
- return CursorWindow("from_parcel")
-
- def clear(self):
- """清空窗口"""
- self._data.clear()
- self._types.clear()
- self._num_rows = 0
- self._allocated_memory = 0
-
- def getStartPosition(self) -> int:
- return self._start_position
-
- def setStartPosition(self, pos: int):
- self._start_position = pos
-
- def getNumRows(self) -> int:
- return self._num_rows
-
- def setNumColumns(self, num_columns: int):
- self._num_columns = num_columns
-
- def getNumColumns(self) -> int:
- return self._num_columns
-
- def allocRow(self) -> bool:
- """分配一行"""
- self._num_rows += 1
- return True
-
- def freeLastRow(self):
- """释放最后一行"""
- if self._num_rows > 0:
- self._num_rows -= 1
- keys_to_remove = [k for k in self._data if k[0] == self._num_rows]
- for k in keys_to_remove:
- del self._data[k]
- del self._types[k]
-
- def putString(self, value: str, row: int, col: int) -> bool:
- self._data[(row, col)] = value
- self._types[(row, col)] = CursorWindow.TYPE_STRING
- self._allocated_memory += len(value)
- return True
-
- def putLong(self, value: int, row: int, col: int) -> bool:
- self._data[(row, col)] = value
- self._types[(row, col)] = CursorWindow.TYPE_INTEGER
- self._allocated_memory += 8
- return True
-
- def putDouble(self, value: float, row: int, col: int) -> bool:
- self._data[(row, col)] = value
- self._types[(row, col)] = CursorWindow.TYPE_FLOAT
- self._allocated_memory += 8
- return True
-
- def putBlob(self, value: bytes, row: int, col: int) -> bool:
- self._data[(row, col)] = value
- self._types[(row, col)] = CursorWindow.TYPE_BLOB
- self._allocated_memory += len(value)
- return True
-
- def putNull(self, row: int, col: int) -> bool:
- self._data[(row, col)] = None
- self._types[(row, col)] = CursorWindow.TYPE_NULL
- return True
-
- def getString(self, row: int, col: int) -> Optional[str]:
- val = self._data.get((row, col))
- if isinstance(val, str):
- return val
- if val is None:
- return None
- return str(val)
-
- def getLong(self, row: int, col: int) -> int:
- val = self._data.get((row, col), 0)
- if isinstance(val, int):
- return val
- if isinstance(val, float):
- return int(val)
- if isinstance(val, str):
- try:
- return int(val)
- except ValueError:
- return 0
- return 0
-
- def getDouble(self, row: int, col: int) -> float:
- val = self._data.get((row, col), 0.0)
- if isinstance(val, (int, float)):
- return float(val)
- if isinstance(val, str):
- try:
- return float(val)
- except ValueError:
- return 0.0
- return 0.0
-
- def getBlob(self, row: int, col: int) -> Optional[bytes]:
- val = self._data.get((row, col))
- if isinstance(val, bytes):
- return val
- if isinstance(val, str):
- return val.encode("utf-8")
- return None
-
- def getType(self, row: int, col: int) -> int:
- return self._types.get((row, col), CursorWindow.TYPE_NULL)
-
- def isNull(self, row: int, col: int) -> bool:
- return self.getType(row, col) == CursorWindow.TYPE_NULL
-
- def isOpen(self) -> bool:
- return self._is_open
-
- def close(self):
- """关闭窗口"""
- self._is_open = False
- self.clear()
-
- def toString(self) -> str:
- return f"CursorWindow(name={self._name}, rows={self._num_rows}, open={self._is_open})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DatabaseUtils
-# ═══════════════════════════════════════════════════════════════
-
-class DatabaseUtils(Stub):
- """DatabaseUtils — 数据库工具"""
-
- STATEMENT_ABORT = 0
- STATEMENT_ATTACH = 1
- STATEMENT_BEGIN = 2
- STATEMENT_COMMIT = 3
- STATEMENT_DELETE = 4
- STATEMENT_DETACH = 5
- STATEMENT_DROP_INDEX = 6
- STATEMENT_DROP_TABLE = 7
- STATEMENT_DROP_TRIGGER = 8
- STATEMENT_DROP_VIEW = 9
- STATEMENT_INSERT = 10
- STATEMENT_PRAGMA = 11
- STATEMENT_REINDEX = 12
- STATEMENT_RELEASE = 13
- STATEMENT_REPLACE = 14
- STATEMENT_ROLLBACK = 15
- STATEMENT_SAVEPOINT = 16
- STATEMENT_SELECT = 17
- STATEMENT_UPDATE = 18
- STATEMENT_OTHER = 99
-
- @staticmethod
- def sqlEscapeString(value: str) -> str:
- """SQL 转义字符串"""
- return "'" + value.replace("'", "''") + "'"
-
- @staticmethod
- def appendValueToSql(sql: str, value: Any) -> str:
- """将值附加到 SQL"""
- if value is None:
- return sql + " NULL"
- if isinstance(value, bool):
- return sql + (" 1" if value else " 0")
- if isinstance(value, int):
- return sql + f" {value}"
- if isinstance(value, float):
- return sql + f" {value}"
- return sql + f" '{DatabaseUtils.sqlEscapeString(str(value))}'"
-
- @staticmethod
- def concatenateWhere(a: str, b: str) -> str:
- """连接 WHERE 子句"""
- if a is None or a == "":
- return b
- if b is None or b == "":
- return a
- return f"({a}) AND ({b})"
-
- @staticmethod
- def getCollationKey(name: str) -> str:
- """获取排序键"""
- return name.lower()
-
- @staticmethod
- def getHexCollationKey(name: str) -> str:
- """获取十六进制排序键"""
- if not name:
- return ""
- return name.encode("utf-8").hex()
-
- @staticmethod
- def dumpCursor(cursor: CrossProcessCursor):
- """转储游标内容"""
- rows = cursor.getRowCount()
- cols = cursor.getColumnCount()
- names = cursor.getColumnNames()
- for r in range(rows):
- cursor.moveToPosition(r)
- row_data = {}
- for c in range(cols):
- name = names[c] if c < len(names) else f"col{c}"
- row_data[name] = cursor.getString(c)
- print(str(row_data))
-
- @staticmethod
- def cursorRowToContentValues(cursor: CrossProcessCursor) -> Dict[str, Any]:
- """将游标行转换为内容值"""
- values = {}
- for c in range(cursor.getColumnCount()):
- name = cursor.getColumnName(c)
- values[name] = cursor.getString(c)
- return values
-
- @staticmethod
- def LongToHexString(value: int) -> str:
- """将长整型转换为十六进制字符串"""
- return f"{value:#018x}"
-
- @staticmethod
- def bindObjectToProgram(statement: Any, index: int, value: Any):
- """绑定对象到 SQL 程序"""
- pass
-
- @staticmethod
- def createDbFromSqlStatements(context: Any, name: str,
- sql_statements: List[str]) -> Any:
- """从 SQL 语句创建数据库"""
- return None
-
- @staticmethod
- def queryNumEntries(db: Any, table: str, selection: str = "") -> int:
- """查询条目数"""
- return 0
-
- @staticmethod
- def stringOrEmpty(s: Optional[str]) -> str:
- """返回字符串或空"""
- return s if s else ""
-
- @staticmethod
- def isTableExists(db: Any, table_name: str) -> bool:
- """检查表是否存在"""
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# DefaultDatabaseErrorHandler
-# ═══════════════════════════════════════════════════════════════
-
-class DefaultDatabaseErrorHandler(Stub):
- """DefaultDatabaseErrorHandler — 默认数据库错误处理器"""
-
- ERROR_TYPE_CORRUPT = 1
- ERROR_TYPE_FULL = 2
- ERROR_TYPE_PERMISSION = 3
- ERROR_TYPE_IO = 4
- ERROR_TYPE_NOMEM = 5
- ERROR_TYPE_TOOBIG = 6
- ERROR_TYPE_CONSTRAINT = 7
- ERROR_TYPE_MISMATCH = 8
- ERROR_TYPE_MISUSE = 9
- ERROR_TYPE_NOTADB = 10
- ERROR_TYPE_INTERNAL = 11
-
- def __init__(self):
- super().__init__()
- self._error_count: int = 0
- self._last_error: int = 0
- self._error_message: str = ""
- self._is_recovering: bool = False
-
- def onCorruption(self, db_obj: Any):
- """数据库损坏回调"""
- self._error_count += 1
- self._last_error = DefaultDatabaseErrorHandler.ERROR_TYPE_CORRUPT
- self._error_message = "Database corruption detected"
- self._is_recovering = True
- self._tryRecover(db_obj)
- self._is_recovering = False
-
- def onError(self, db_obj: Any, error_type: int, message: str = ""):
- """错误回调"""
- self._error_count += 1
- self._last_error = error_type
- self._error_message = message
-
- def _tryRecover(self, db_obj: Any):
- """尝试恢复数据库"""
- pass
-
- def getErrorCount(self) -> int:
- return self._error_count
-
- def getLastError(self) -> int:
- return self._last_error
-
- def getErrorMessage(self) -> str:
- return self._error_message
-
- def isRecovering(self) -> bool:
- return self._is_recovering
-
- def toString(self) -> str:
- return f"DefaultDatabaseErrorHandler(errors={self._error_count})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Extras (Database 扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class Extras(Stub):
- """Extras — 数据库扩展附加类"""
-
- EXTRA_DATABASE_NAME = "database_name"
- EXTRA_TABLE_NAME = "table_name"
- EXTRA_SQL_COMMAND = "sql_command"
- EXTRA_ERROR_DESCRIPTION = "error_description"
- EXTRA_ROW_COUNT = "row_count"
- EXTRA_PAGE_SIZE = "page_size"
- EXTRA_PAGE_COUNT = "page_count"
- EXTRA_DATABASE_SIZE = "database_size"
- EXTRA_JOURNAL_MODE = "journal_mode"
- EXTRA_SYNC_MODE = "sync_mode"
- EXTRA_CACHE_SIZE = "cache_size"
- EXTRA_FOREIGN_KEYS = "foreign_keys"
- EXTRA_ENCODING = "encoding"
- EXTRA_SCHEMA_VERSION = "schema_version"
- EXTRA_USER_VERSION = "user_version"
-
- FLAG_READ_ONLY = 1
- FLAG_WRITE_AHEAD_LOGGING = 2
- FLAG_ENABLE_FOREIGN_KEYS = 4
- FLAG_CREATE_IF_NECESSARY = 8
- FLAG_NO_LOCALIZED_COLLATORS = 16
- FLAG_OPEN_READONLY = 32
- FLAG_ENABLE_WRITE_AHEAD_LOGGING = 64
- FLAG_DISABLE_COMPATIBILITY_WAL = 128
- FLAG_OPEN_READ_WRITE = 256
-
- def __init__(self):
- super().__init__()
- self._extras: Dict[str, Any] = {}
- self._flags: int = 0
-
- def getString(self, key: str, default: str = "") -> str:
- return str(self._extras.get(key, default))
-
- def getInt(self, key: str, default: int = 0) -> int:
- val = self._extras.get(key, default)
- return int(val) if val is not None else default
-
- def getBoolean(self, key: str, default: bool = False) -> bool:
- val = self._extras.get(key, default)
- return bool(val) if val is not None else default
-
- def putString(self, key: str, value: str):
- self._extras[key] = value
-
- def putInt(self, key: str, value: int):
- self._extras[key] = value
-
- def putBoolean(self, key: str, value: bool):
- self._extras[key] = value
-
- def putAll(self, extras: Dict[str, Any]):
- self._extras.update(extras)
-
- def containsKey(self, key: str) -> bool:
- return key in self._extras
-
- def getKeys(self) -> List[str]:
- return list(self._extras.keys())
-
- def size(self) -> int:
- return len(self._extras)
-
- def isEmpty(self) -> bool:
- return len(self._extras) == 0
-
- def clear(self):
- self._extras.clear()
-
- def getFlags(self) -> int:
- return self._flags
-
- def setFlags(self, flags: int):
- self._flags = flags
-
- def hasFlag(self, flag: int) -> bool:
- return bool(self._flags & flag)
-
- def toString(self) -> str:
- return f"Extras(entries={len(self._extras)}, flags={self._flags})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BulkCursorDescriptor (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class BulkCursorDescriptor(Stub):
- """BulkCursorDescriptor — 批量游标描述符"""
-
- def __init__(self):
- super().__init__()
- self._cursor: Optional[CrossProcessCursor] = None
- self._column_names: List[str] = []
- self._wants_all_on_move_calls: bool = False
- self._count: int = 0
- self._window: Optional[CursorWindow] = None
-
- def getCursor(self) -> Optional[CrossProcessCursor]:
- return self._cursor
-
- def setCursor(self, cursor: CrossProcessCursor):
- self._cursor = cursor
-
- def getColumnNames(self) -> List[str]:
- return list(self._column_names)
-
- def setColumnNames(self, names: List[str]):
- self._column_names = list(names)
-
- def wantsAllOnMoveCalls(self) -> bool:
- return self._wants_all_on_move_calls
-
- def setWantsAllOnMoveCalls(self, wants: bool):
- self._wants_all_on_move_calls = wants
-
- def getCount(self) -> int:
- return self._count
-
- def setCount(self, count: int):
- self._count = count
-
- def getWindow(self) -> Optional[CursorWindow]:
- return self._window
-
- def setWindow(self, window: CursorWindow):
- self._window = window
-
- def toString(self) -> str:
- return f"BulkCursorDescriptor(columns={len(self._column_names)}, count={self._count})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CursorJoiner (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class CursorJoiner(Stub):
- """CursorJoiner — 游标连接器"""
-
- RESULT_BOTH = 0
- RESULT_LEFT = 1
- RESULT_RIGHT = 2
-
- def __init__(self, cursor_left: CrossProcessCursor,
- column_names_left: List[str],
- cursor_right: CrossProcessCursor,
- column_names_right: List[str]):
- super().__init__()
- self._left = cursor_left
- self._right = cursor_right
- self._left_cols = column_names_left
- self._right_cols = column_names_right
- self._left_pos: int = -1
- self._right_pos: int = -1
- self._result: int = CursorJoiner.RESULT_BOTH
-
- def hasNext(self) -> bool:
- return (self._left_pos + 1 < self._left.getRowCount() or
- self._right_pos + 1 < self._right.getRowCount())
-
- def next(self) -> int:
- self._left_pos += 1
- self._right_pos += 1
- return self._result
-
- def getLeftCursor(self) -> CrossProcessCursor:
- return self._left
-
- def getRightCursor(self) -> CrossProcessCursor:
- return self._right
-
- def reset(self):
- self._left_pos = -1
- self._right_pos = -1
-
- def toString(self) -> str:
- return f"CursorJoiner(left={self._left_pos}, right={self._right_pos})"
\ No newline at end of file
diff --git a/android_pyapi/android/database_sqlite.py b/android_pyapi/android/database_sqlite.py
deleted file mode 100644
index 650ed2f..0000000
--- a/android_pyapi/android/database_sqlite.py
+++ /dev/null
@@ -1,1118 +0,0 @@
-"""
-Android SQLite 组件 — SQLiteDatabase, SQLiteOpenHelper, SQLiteStatement 等
-使用 Python sqlite3 模块作为后端
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-import threading
-import sqlite3 as _sqlite3
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-from .database import (
- Cursor, AbstractCursor, ContentObserver, DataSetObserver, SQLException as BaseSQLException,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLiteException hierarchy
-# ═══════════════════════════════════════════════════════════════
-
-class SQLiteException(BaseSQLException):
- """SQLiteException — SQLite 异常基类"""
-
- def __init__(self, message: str = ""):
- super().__init__(message)
- self._error_message = message
-
-
-class SQLiteAbortException(SQLiteException):
- pass
-
-
-class SQLiteAccessPermException(SQLiteException):
- pass
-
-
-class SQLiteBindOrColumnIndexOutOfRangeException(SQLiteException):
- pass
-
-
-class SQLiteBlobTooBigException(SQLiteException):
- pass
-
-
-class SQLiteCantOpenDatabaseException(SQLiteException):
- pass
-
-
-class SQLiteConstraintException(SQLiteException):
- pass
-
-
-class SQLiteDatabaseCorruptException(SQLiteException):
- pass
-
-
-class SQLiteDatabaseLockedException(SQLiteException):
- pass
-
-
-class SQLiteDatatypeMismatchException(SQLiteException):
- pass
-
-
-class SQLiteDiskIOException(SQLiteException):
- pass
-
-
-class SQLiteDoneException(SQLiteException):
- pass
-
-
-class SQLiteException_General(SQLiteException):
- pass
-
-
-class SQLiteFullException(SQLiteException):
- pass
-
-
-class SQLiteMisuseException(SQLiteException):
- pass
-
-
-class SQLiteOutOfMemoryException(SQLiteException):
- pass
-
-
-class SQLiteReadOnlyDatabaseException(SQLiteException):
- pass
-
-
-class SQLiteTableLockedException(SQLiteException):
- pass
-
-
-class SQLiteUnsupportedOperationException(SQLiteException):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLiteClosable
-# ═══════════════════════════════════════════════════════════════
-
-class SQLiteClosable(Stub):
- """SQLiteClosable — 可关闭资源基类"""
-
- def __init__(self):
- super().__init__()
- self._closed = False
- self._reference_count = 1
-
- def acquireReference(self):
- if self._closed:
- raise IllegalStateException("already closed")
- self._reference_count += 1
-
- def releaseReference(self):
- self._reference_count -= 1
- if self._reference_count <= 0:
- self.onAllReferencesReleased()
-
- def releaseReferenceFromContainer(self):
- self.releaseReference()
-
- def onAllReferencesReleased(self):
- self.close()
-
- def close(self):
- self._closed = True
-
- def isClosed(self) -> bool:
- return self._closed
-
-
-class IllegalStateException(RuntimeError):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLiteProgram
-# ═══════════════════════════════════════════════════════════════
-
-class SQLiteProgram(SQLiteClosable):
- """SQLiteProgram — SQL 程序基类"""
-
- def __init__(self, db: "SQLiteDatabase", sql: str):
- super().__init__()
- self._db = db
- self._sql = sql
- self._bindings: Dict[int, Any] = {}
- self._next_bind_index = 1
-
- def getDatabase(self) -> "SQLiteDatabase":
- return self._db
-
- def getSql(self) -> str:
- return self._sql
-
- def bindNull(self, index: int):
- self._bindings[index] = None
-
- def bindLong(self, index: int, value: int):
- self._bindings[index] = value
-
- def bindDouble(self, index: int, value: float):
- self._bindings[index] = value
-
- def bindString(self, index: int, value: str):
- self._bindings[index] = value
-
- def bindBlob(self, index: int, value: bytes):
- self._bindings[index] = value
-
- def clearBindings(self):
- self._bindings.clear()
-
- def _ordered_bind_args(self) -> list:
- """按绑定索引升序返回参数列表(1-based 索引排序)。"""
- return [self._bindings[k] for k in sorted(self._bindings.keys())]
-
- def _bind_parameters(self, cursor: _sqlite3.Cursor):
- for idx in sorted(self._bindings.keys()):
- cursor.bind(idx, self._bindings[idx])
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLiteStatement
-# ═══════════════════════════════════════════════════════════════
-
-class SQLiteStatement(SQLiteProgram):
- """SQLiteStatement — 预编译语句"""
-
- def __init__(self, db: "SQLiteDatabase", sql: str):
- super().__init__(db, sql)
-
- def execute(self):
- try:
- conn = self._db._acquire_connection()
- conn.execute(self._sql, self._ordered_bind_args())
- if not self._db._in_transaction:
- conn.commit()
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), self._sql)
-
- def executeUpdateDelete(self) -> int:
- try:
- conn = self._db._acquire_connection()
- cursor = conn.execute(self._sql, self._ordered_bind_args())
- if not self._db._in_transaction:
- conn.commit()
- return cursor.rowcount
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), self._sql)
-
- def executeInsert(self) -> int:
- try:
- conn = self._db._acquire_connection()
- cursor = conn.execute(self._sql, self._ordered_bind_args())
- if not self._db._in_transaction:
- conn.commit()
- return cursor.lastrowid
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), self._sql)
-
- def simpleQueryForLong(self) -> int:
- try:
- conn = self._db._acquire_connection()
- cursor = conn.execute(self._sql, self._ordered_bind_args())
- row = cursor.fetchone()
- if not self._db._in_transaction:
- conn.commit()
- if row:
- return int(row[0]) if row[0] is not None else 0
- raise SQLiteDoneException("no results")
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), self._sql)
-
- def simpleQueryForString(self) -> Optional[str]:
- try:
- conn = self._db._acquire_connection()
- cursor = conn.execute(self._sql, self._ordered_bind_args())
- row = cursor.fetchone()
- if not self._db._in_transaction:
- conn.commit()
- if row:
- return str(row[0]) if row[0] is not None else None
- raise SQLiteDoneException("no results")
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), self._sql)
-
- def simpleQueryForBlobString(self) -> Optional[bytes]:
- try:
- conn = self._db._acquire_connection()
- cursor = conn.execute(self._sql, self._ordered_bind_args())
- row = cursor.fetchone()
- if not self._db._in_transaction:
- conn.commit()
- if row:
- v = row[0]
- if v is None:
- return None
- if isinstance(v, bytes):
- return v
- if isinstance(v, str):
- return v.encode("utf-8")
- return bytes(str(v), "utf-8")
- raise SQLiteDoneException("no results")
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), self._sql)
-
- def execQuery(self) -> "SQLiteCursor":
- """执行查询 SQL 并返回 SQLiteCursor。"""
- query = SQLiteQuery(self._db, self._sql)
- for idx, val in self._bindings.items():
- query.bind(idx, val)
- return SQLiteCursor(self._db, query)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLiteQuery
-# ═══════════════════════════════════════════════════════════════
-
-class SQLiteQuery(SQLiteProgram):
- """SQLiteQuery — 查询对象"""
-
- def __init__(self, db: "SQLiteDatabase", sql: str):
- super().__init__(db, sql)
-
- def toString(self) -> str:
- return f"SQLiteQuery: {self._sql}"
-
- def sql(self) -> str:
- return self._sql
-
- def bind(self, index: int, value: Any):
- self._bindings[index] = value
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLiteCursor
-# ═══════════════════════════════════════════════════════════════
-
-class SQLiteCursor(AbstractCursor):
- """SQLiteCursor — SQLite 游标实现"""
-
- def __init__(self, db: "SQLiteDatabase", query: SQLiteQuery):
- super().__init__()
- self._db = db
- self._query = query
- self._column_names: List[str] = []
- self._rows: List[List[Any]] = []
- self._current_row: Optional[List[Any]] = None
- self._loaded = False
- self._closed = False
-
- def _load(self):
- if self._loaded or self._closed:
- return
- self._loaded = True
- try:
- conn = self._db._acquire_connection()
- cursor = conn.execute(self._query.getSql(), list(self._query._bindings.values()))
- self._column_names = [desc[0] for desc in cursor.description] if cursor.description else []
- self._rows = cursor.fetchall()
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), self._query.getSql())
-
- def getCount(self) -> int:
- self._load()
- return len(self._rows)
-
- def getColumnNames(self) -> List[str]:
- self._load()
- return list(self._column_names)
-
- def getColumnIndex(self, column_name: str) -> int:
- self._load()
- try:
- return self._column_names.index(column_name)
- except ValueError:
- return -1
-
- def moveToPosition(self, position: int) -> bool:
- self._load()
- count = len(self._rows)
- if position >= count:
- self._pos = count
- self._current_row = None
- return False
- if position < -1:
- self._pos = -1
- self._current_row = None
- return False
- self._pos = position
- if 0 <= position < count:
- self._current_row = self._rows[position]
- else:
- self._current_row = None
- return True
-
- def getString(self, column_index: int) -> Optional[str]:
- if self._current_row is None or column_index < 0 or column_index >= len(self._current_row):
- return None
- v = self._current_row[column_index]
- return str(v) if v is not None else None
-
- def getInt(self, column_index: int) -> int:
- if self._current_row is None or column_index < 0 or column_index >= len(self._current_row):
- return 0
- v = self._current_row[column_index]
- if v is None:
- return 0
- try:
- return int(v)
- except (ValueError, TypeError):
- return 0
-
- def getLong(self, column_index: int) -> int:
- return self.getInt(column_index)
-
- def getFloat(self, column_index: int) -> float:
- if self._current_row is None or column_index < 0 or column_index >= len(self._current_row):
- return 0.0
- v = self._current_row[column_index]
- if v is None:
- return 0.0
- try:
- return float(v)
- except (ValueError, TypeError):
- return 0.0
-
- def getDouble(self, column_index: int) -> float:
- return self.getFloat(column_index)
-
- def getShort(self, column_index: int) -> int:
- return self.getInt(column_index)
-
- def getBlob(self, column_index: int) -> Optional[bytes]:
- if self._current_row is None or column_index < 0 or column_index >= len(self._current_row):
- return None
- v = self._current_row[column_index]
- if isinstance(v, bytes):
- return v
- if v is not None:
- return bytes(str(v), "utf-8")
- return None
-
- def getType(self, column_index: int) -> int:
- self._load()
- if self._current_row is None or column_index < 0 or column_index >= len(self._current_row):
- return Cursor.FIELD_TYPE_NULL
- v = self._current_row[column_index]
- if v is None:
- return Cursor.FIELD_TYPE_NULL
- if isinstance(v, int):
- return Cursor.FIELD_TYPE_INTEGER
- if isinstance(v, float):
- return Cursor.FIELD_TYPE_FLOAT
- if isinstance(v, bytes):
- return Cursor.FIELD_TYPE_BLOB
- return Cursor.FIELD_TYPE_STRING
-
- def isNull(self, column_index: int) -> bool:
- return self.getType(column_index) == Cursor.FIELD_TYPE_NULL
-
- def close(self):
- self._closed = True
- self._rows.clear()
- self._current_row = None
-
- def requery(self) -> bool:
- self._loaded = False
- self._rows.clear()
- self._current_row = None
- self._pos = -1
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLiteQueryBuilder
-# ═══════════════════════════════════════════════════════════════
-
-class SQLiteQueryBuilder(Stub):
- """SQLiteQueryBuilder — 查询构建器"""
-
- def __init__(self):
- super().__init__()
- self._tables: str = ""
- self._distinct: bool = False
- self._where: Optional[str] = None
-
- def setTables(self, tables: str):
- self._tables = tables
-
- def getTables(self) -> str:
- return self._tables
-
- def appendWhere(self, where: str):
- if self._where:
- self._where = f"({self._where}) AND ({where})"
- else:
- self._where = where
-
- def appendWhereStandalone(self, where: str):
- self._where = where
-
- def setDistinct(self, distinct: bool):
- self._distinct = distinct
-
- def buildQueryString(self, distinct: bool, tables: str,
- columns: Optional[List[str]], where: Optional[str],
- group_by: Optional[str], having: Optional[str],
- order_by: Optional[str], limit: Optional[str]) -> str:
- sql = "SELECT "
- if distinct:
- sql += "DISTINCT "
- if columns and len(columns) > 0:
- sql += ", ".join(columns)
- else:
- sql += "*"
- sql += f" FROM {tables}"
- if where:
- sql += f" WHERE ({where})"
- if group_by:
- sql += f" GROUP BY {group_by}"
- if having:
- sql += f" HAVING {having}"
- if order_by:
- sql += f" ORDER BY {order_by}"
- if limit:
- sql += f" LIMIT {limit}"
- return sql
-
- def buildQuery(self, columns: Optional[List[str]], where: Optional[str],
- group_by: Optional[str], having: Optional[str],
- order_by: Optional[str], limit: Optional[str]) -> str:
- return self.buildQueryString(self._distinct, self._tables,
- columns, where or self._where,
- group_by, having, order_by, limit)
-
- def query(self, db: "SQLiteDatabase", columns: Optional[List[str]],
- where: Optional[str], group_by: Optional[str],
- having: Optional[str], order_by: Optional[str],
- limit: Optional[str]) -> SQLiteCursor:
- sql = self.buildQuery(columns, where, group_by, having, order_by, limit)
- return db.rawQuery(sql, None)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLiteDatabase
-# ═══════════════════════════════════════════════════════════════
-
-def _map_sqlite_error(msg: str, sql: str = "") -> SQLiteException:
- msg_lower = msg.lower()
- if "constraint" in msg_lower:
- return SQLiteConstraintException(msg)
- if "locked" in msg_lower:
- return SQLiteDatabaseLockedException(msg)
- if "corrupt" in msg_lower:
- return SQLiteDatabaseCorruptException(msg)
- if "readonly" in msg_lower or "read only" in msg_lower:
- return SQLiteReadOnlyDatabaseException(msg)
- if "disk" in msg_lower or "full" in msg_lower:
- return SQLiteDiskIOException(msg) if "disk" in msg_lower else SQLiteFullException(msg)
- if "abort" in msg_lower:
- return SQLiteAbortException(msg)
- if "permission" in msg_lower:
- return SQLiteAccessPermException(msg)
- if "out of memory" in msg_lower:
- return SQLiteOutOfMemoryException(msg)
- if "not a database" in msg_lower or "cantopen" in msg_lower:
- return SQLiteCantOpenDatabaseException(msg)
- if "misuse" in msg_lower:
- return SQLiteMisuseException(msg)
- return SQLiteException(msg)
-
-
-def _extract_value_pairs(values: Any) -> List[Tuple[str, Any]]:
- """从 ContentValues / dict / 类似对象中提取 (列名, 值) 列表。
-
- 注意: 本实现中 ContentValues.valueSet() 返回的是键集合而非 (键, 值) 对,
- 因此需要通过 get() 取值。
- """
- if values is None:
- return []
- if isinstance(values, dict):
- return list(values.items())
- # ContentValues 内部使用 _values dict
- inner = getattr(values, "_values", None)
- if isinstance(inner, dict):
- return list(inner.items())
- # ContentValues.valueSet() 在本实现中返回键集合
- if hasattr(values, "valueSet") and hasattr(values, "get"):
- try:
- return [(str(k), values.get(k)) for k in values.valueSet()]
- except Exception:
- pass
- if hasattr(values, "keySet") and hasattr(values, "get"):
- try:
- return [(str(k), values.get(k)) for k in values.keySet()]
- except Exception:
- pass
- if hasattr(values, "items"):
- try:
- return [(str(k), v) for k, v in values.items()]
- except Exception:
- pass
- return []
-
-
-class SQLiteDatabase(SQLiteClosable):
- """SQLiteDatabase — 数据库操作类"""
-
- CONFLICT_ROLLBACK = 1
- CONFLICT_ABORT = 2
- CONFLICT_FAIL = 3
- CONFLICT_IGNORE = 4
- CONFLICT_REPLACE = 5
-
- OPEN_READWRITE = 0
- OPEN_READONLY = 1
- CREATE_IF_NECESSARY = 268435456
- NO_LOCALIZED_COLLATORS = 16
-
- _db_registry: Dict[str, "SQLiteDatabase"] = {}
- _lock = threading.Lock()
-
- def __init__(self, path: str, flags: int = 0):
- super().__init__()
- self._path = path
- self._flags = flags
- self._conn: Optional[_sqlite3.Connection] = None
- self._in_transaction = False
- self._transaction_successful = False
- self._version: int = 0
- self._max_size: int = 0
- self._page_size: int = 4096
- self._enable_wal = False
- self._attached_dbs: List[Dict[str, Any]] = []
-
- @staticmethod
- def openDatabase(path: str, cursor_factory: Any = None,
- flags: int = 0, error_handler: Any = None) -> "SQLiteDatabase":
- db = SQLiteDatabase(path, flags)
- try:
- db._conn = _sqlite3.connect(path)
- db._conn.execute("PRAGMA journal_mode=WAL")
- conn_cursor = db._conn.execute("PRAGMA user_version")
- row = conn_cursor.fetchone()
- if row:
- db._version = int(row[0])
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e))
- SQLiteDatabase._db_registry[path] = db
- return db
-
- @staticmethod
- def openOrCreateDatabase(path: str, cursor_factory: Any = None,
- error_handler: Any = None) -> "SQLiteDatabase":
- return SQLiteDatabase.openDatabase(path, cursor_factory,
- SQLiteDatabase.CREATE_IF_NECESSARY, error_handler)
-
- @staticmethod
- def create(cursor_factory: Any = None, error_handler: Any = None) -> "SQLiteDatabase":
- import tempfile
- tmp = tempfile.NamedTemporaryFile(suffix=".db", delete=False)
- tmp.close()
- return SQLiteDatabase.openOrCreateDatabase(tmp.name, cursor_factory, error_handler)
-
- @staticmethod
- def deleteDatabase(path: str) -> bool:
- try:
- if path in SQLiteDatabase._db_registry:
- db = SQLiteDatabase._db_registry[path]
- db.close()
- del SQLiteDatabase._db_registry[path]
- os.remove(path)
- wal_path = path + "-wal"
- if os.path.exists(wal_path):
- os.remove(wal_path)
- shm_path = path + "-shm"
- if os.path.exists(shm_path):
- os.remove(shm_path)
- return True
- except (OSError, Exception):
- return False
-
- @staticmethod
- def databaseList() -> List[str]:
- return list(SQLiteDatabase._db_registry.keys())
-
- def _acquire_connection(self) -> _sqlite3.Connection:
- if self._conn is None:
- raise SQLiteCantOpenDatabaseException("Database not open")
- return self._conn
-
- def execSQL(self, sql: str, bind_args: Optional[List[Any]] = None):
- self._ensure_open()
- try:
- conn = self._acquire_connection()
- args = bind_args or []
- conn.execute(sql, args)
- if not self._in_transaction:
- conn.commit()
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), sql)
-
- def rawQuery(self, sql: str, selection_args: Optional[List[Any]] = None) -> SQLiteCursor:
- self._ensure_open()
- query = SQLiteQuery(self, sql)
- if selection_args:
- for i, arg in enumerate(selection_args):
- query.bind(i + 1, arg)
- cursor = SQLiteCursor(self, query)
- return cursor
-
- def insert(self, table: str, null_column_hack: Optional[str],
- values: Any) -> int:
- self._ensure_open()
- if values is None:
- return -1
- items = _extract_value_pairs(values)
- if not items:
- cols = ["_id"]
- vals: List[Any] = [None]
- else:
- cols = [str(k) for k, _ in items]
- vals = [v for _, v in items]
- col_str = ", ".join(cols)
- placeholders = ", ".join(["?"] * len(vals))
- sql = f"INSERT INTO {table} ({col_str}) VALUES ({placeholders})"
- try:
- conn = self._acquire_connection()
- cursor = conn.execute(sql, vals)
- if not self._in_transaction:
- conn.commit()
- return cursor.lastrowid
- except _sqlite3.DatabaseError:
- return -1
-
- def insertOrThrow(self, table: str, null_column_hack: Optional[str],
- values: Any) -> int:
- self._ensure_open()
- if values is None:
- raise SQLiteException("null values not allowed")
- items = _extract_value_pairs(values)
- if not items:
- cols = ["_id"]
- vals: List[Any] = [None]
- else:
- cols = [str(k) for k, _ in items]
- vals = [v for _, v in items]
- col_str = ", ".join(cols)
- placeholders = ", ".join(["?"] * len(vals))
- sql = f"INSERT INTO {table} ({col_str}) VALUES ({placeholders})"
- try:
- conn = self._acquire_connection()
- cursor = conn.execute(sql, vals)
- if not self._in_transaction:
- conn.commit()
- return cursor.lastrowid
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), sql)
-
- def replace(self, table: str, null_column_hack: Optional[str],
- values: Any) -> int:
- self._ensure_open()
- if values is None:
- return -1
- items = _extract_value_pairs(values)
- if not items:
- cols = ["_id"]
- vals: List[Any] = [None]
- else:
- cols = [str(k) for k, _ in items]
- vals = [v for _, v in items]
- col_str = ", ".join(cols)
- placeholders = ", ".join(["?"] * len(vals))
- sql = f"INSERT OR REPLACE INTO {table} ({col_str}) VALUES ({placeholders})"
- try:
- conn = self._acquire_connection()
- cursor = conn.execute(sql, vals)
- if not self._in_transaction:
- conn.commit()
- return cursor.lastrowid
- except _sqlite3.DatabaseError:
- return -1
-
- def update(self, table: str, values: Any,
- where_clause: Optional[str] = None,
- where_args: Optional[List[Any]] = None) -> int:
- self._ensure_open()
- if values is None:
- return 0
- items = _extract_value_pairs(values)
- if not items:
- return 0
- set_pairs = [f"{k} = ?" for k, _ in items]
- vals: List[Any] = [v for _, v in items]
- set_str = ", ".join(set_pairs)
- sql = f"UPDATE {table} SET {set_str}"
- if where_clause:
- sql += f" WHERE {where_clause}"
- if where_args:
- vals.extend(where_args)
- try:
- conn = self._acquire_connection()
- cursor = conn.execute(sql, vals)
- if not self._in_transaction:
- conn.commit()
- return cursor.rowcount
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), sql)
-
- def delete(self, table: str, where_clause: Optional[str] = None,
- where_args: Optional[List[Any]] = None) -> int:
- self._ensure_open()
- sql = f"DELETE FROM {table}"
- vals: List[Any] = []
- if where_clause:
- sql += f" WHERE {where_clause}"
- if where_args:
- vals = list(where_args)
- try:
- conn = self._acquire_connection()
- cursor = conn.execute(sql, vals)
- if not self._in_transaction:
- conn.commit()
- return cursor.rowcount
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e), sql)
-
- def query(self, table: str, columns: Optional[List[str]] = None,
- selection: Optional[str] = None,
- selection_args: Optional[List[Any]] = None,
- group_by: Optional[str] = None, having: Optional[str] = None,
- order_by: Optional[str] = None,
- limit: Optional[str] = None) -> SQLiteCursor:
- col_str = ", ".join(columns) if columns else "*"
- sql = f"SELECT {col_str} FROM {table}"
- if selection:
- sql += f" WHERE {selection}"
- if group_by:
- sql += f" GROUP BY {group_by}"
- if having:
- sql += f" HAVING {having}"
- if order_by:
- sql += f" ORDER BY {order_by}"
- if limit:
- sql += f" LIMIT {limit}"
- return self.rawQuery(sql, selection_args)
-
- def compileStatement(self, sql: str) -> SQLiteStatement:
- return SQLiteStatement(self, sql)
-
- def beginTransaction(self):
- self._ensure_open()
- try:
- conn = self._acquire_connection()
- conn.execute("BEGIN TRANSACTION")
- self._in_transaction = True
- self._transaction_successful = False
- except _sqlite3.DatabaseError as e:
- raise _map_sqlite_error(str(e))
-
- def endTransaction(self):
- if self._in_transaction and self._conn:
- try:
- if not self._transaction_successful:
- self._conn.rollback()
- else:
- self._conn.commit()
- except _sqlite3.DatabaseError:
- pass
- self._in_transaction = False
-
- def setTransactionSuccessful(self):
- if not self._in_transaction:
- raise IllegalStateException("Not in transaction")
- self._transaction_successful = True
-
- def inTransaction(self) -> bool:
- return self._in_transaction
-
- def isOpen(self) -> bool:
- return self._conn is not None
-
- def getPath(self) -> str:
- return self._path
-
- def getVersion(self) -> int:
- if self._conn:
- try:
- cursor = self._conn.execute("PRAGMA user_version")
- row = cursor.fetchone()
- if row:
- self._version = int(row[0])
- return self._version
- except _sqlite3.DatabaseError:
- pass
- return self._version
-
- def setVersion(self, version: int):
- self._version = int(version)
- if self._conn:
- try:
- self._conn.execute(f"PRAGMA user_version = {int(version)}")
- if not self._in_transaction:
- self._conn.commit()
- except _sqlite3.DatabaseError:
- pass
-
- def onCreate(self, db: "SQLiteDatabase"):
- pass
-
- def onConfigure(self, db: "SQLiteDatabase"):
- pass
-
- def enableWriteAheadLogging(self) -> bool:
- self._ensure_open()
- try:
- self._conn.execute("PRAGMA journal_mode=WAL")
- self._enable_wal = True
- return True
- except _sqlite3.DatabaseError:
- return False
-
- def disableWriteAheadLogging(self):
- try:
- self._conn.execute("PRAGMA journal_mode=DELETE")
- self._enable_wal = False
- except _sqlite3.DatabaseError:
- pass
-
- def isWriteAheadLoggingEnabled(self) -> bool:
- return self._enable_wal
-
- def getMaximumSize(self) -> int:
- if self._conn:
- try:
- page_size = self.getPageSize()
- if page_size <= 0:
- page_size = 4096
- cursor = self._conn.execute("PRAGMA max_page_count")
- row = cursor.fetchone()
- if row:
- self._max_size = int(row[0]) * page_size
- return self._max_size
- except _sqlite3.DatabaseError:
- pass
- return self._max_size
-
- def getPageSize(self) -> int:
- if self._conn:
- try:
- cursor = self._conn.execute("PRAGMA page_size")
- row = cursor.fetchone()
- if row:
- self._page_size = int(row[0])
- return self._page_size
- except _sqlite3.DatabaseError:
- pass
- return self._page_size
-
- def setMaximumSize(self, size: int) -> int:
- self._max_size = int(size)
- if self._conn:
- try:
- page_size = self.getPageSize()
- if page_size <= 0:
- page_size = 4096
- max_pages = max(1, int(size) // page_size)
- cursor = self._conn.execute(f"PRAGMA max_page_count = {max_pages}")
- row = cursor.fetchone()
- if row:
- self._max_size = int(row[0]) * page_size
- return self._max_size
- except _sqlite3.DatabaseError:
- pass
- return self._max_size
-
- def setPageSize(self, size: int):
- self._page_size = int(size)
- if self._conn:
- try:
- self._conn.execute(f"PRAGMA page_size = {int(size)}")
- except _sqlite3.DatabaseError:
- pass
-
- def getPageCount(self) -> int:
- if self._conn:
- try:
- cursor = self._conn.execute("PRAGMA page_count")
- row = cursor.fetchone()
- if row:
- return row[0]
- except _sqlite3.DatabaseError:
- pass
- return 0
-
- def yieldIfContendedSafely(self, sleep_time: int = 0) -> bool:
- return True
-
- def needUpgrade(self, new_version: int) -> bool:
- return new_version > self._version
-
- def getAttachedDbs(self) -> Optional[List[Dict[str, Any]]]:
- return self._attached_dbs
-
- def isReadOnly(self) -> bool:
- return bool(self._flags & self.OPEN_READONLY)
-
- def close(self):
- if self._conn:
- try:
- self._conn.close()
- except Exception:
- pass
- self._conn = None
- super().close()
-
- def _ensure_open(self):
- if self._conn is None:
- raise SQLiteCantOpenDatabaseException("Database not open")
-
- def toString(self) -> str:
- return f"SQLiteDatabase(path={self._path})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SQLiteOpenHelper
-# ═══════════════════════════════════════════════════════════════
-
-class SQLiteOpenHelper(Stub):
- """SQLiteOpenHelper — 数据库打开辅助类"""
-
- def __init__(self, context: Any, name: Optional[str],
- factory: Any, version: int,
- error_handler: Any = None):
- super().__init__()
- self._context = context
- self._name = name
- self._factory = factory
- self._version = version
- self._error_handler = error_handler
- self._readable_db: Optional[SQLiteDatabase] = None
- self._writable_db: Optional[SQLiteDatabase] = None
- self._database_path: Optional[str] = None
- self._is_initialized = False
-
- def _get_database_path(self) -> str:
- if self._database_path:
- return self._database_path
- db_dir = os.path.join(_app_data_dir, "databases")
- os.makedirs(db_dir, exist_ok=True)
- if self._name:
- self._database_path = os.path.join(db_dir, self._name)
- else:
- import tempfile
- tmp = tempfile.NamedTemporaryFile(suffix=".db", delete=False)
- tmp.close()
- self._database_path = tmp.name
- return self._database_path
-
- def getWritableDatabase(self) -> SQLiteDatabase:
- if self._writable_db and self._writable_db.isOpen():
- return self._writable_db
- path = self._get_database_path()
- db = SQLiteDatabase.openOrCreateDatabase(path, self._factory, self._error_handler)
- if not self._is_initialized:
- self._is_initialized = True
- current_version = db.getVersion()
- if current_version == 0:
- self.onCreate(db)
- db.setVersion(self._version)
- elif current_version < self._version:
- self.onUpgrade(db, current_version, self._version)
- elif current_version > self._version:
- self.onDowngrade(db, current_version, self._version)
- self.onOpen(db)
- self._writable_db = db
- self._readable_db = db
- return db
-
- def getReadableDatabase(self) -> SQLiteDatabase:
- return self.getWritableDatabase()
-
- def onCreate(self, db: SQLiteDatabase):
- pass
-
- def onUpgrade(self, db: SQLiteDatabase, old_version: int, new_version: int):
- pass
-
- def onDowngrade(self, db: SQLiteDatabase, old_version: int, new_version: int):
- pass
-
- def onOpen(self, db: SQLiteDatabase):
- pass
-
- def close(self):
- if self._writable_db:
- self._writable_db.close()
- self._writable_db = None
- if self._readable_db:
- self._readable_db = None
-
- def getDatabaseName(self) -> Optional[str]:
- return self._name
-
- def getReadableDB(self) -> Optional[SQLiteDatabase]:
- return self._readable_db
-
- def getWriteableDB(self) -> Optional[SQLiteDatabase]:
- return self._writable_db
-
- def toString(self) -> str:
- return f"SQLiteOpenHelper(name={self._name}, version={self._version})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "SQLiteDatabase",
- "SQLiteOpenHelper",
- "SQLiteStatement",
- "SQLiteCursor",
- "SQLiteQuery",
- "SQLiteQueryBuilder",
- "SQLiteClosable",
- "SQLiteProgram",
- "SQLiteAbortException",
- "SQLiteAccessPermException",
- "SQLiteBindOrColumnIndexOutOfRangeException",
- "SQLiteBlobTooBigException",
- "SQLiteCantOpenDatabaseException",
- "SQLiteConstraintException",
- "SQLiteDatabaseCorruptException",
- "SQLiteDatabaseLockedException",
- "SQLiteDatatypeMismatchException",
- "SQLiteDiskIOException",
- "SQLiteDoneException",
- "SQLiteException",
- "SQLiteFullException",
- "SQLiteMisuseException",
- "SQLiteOutOfMemoryException",
- "SQLiteReadOnlyDatabaseException",
- "SQLiteTableLockedException",
- "SQLiteUnsupportedOperationException",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/drm.py b/android_pyapi/android/drm.py
deleted file mode 100644
index c385b37..0000000
--- a/android_pyapi/android/drm.py
+++ /dev/null
@@ -1,1090 +0,0 @@
-"""
-Android DRM 组件 — DrmManager, DrmStore, DrmInfo, DrmManagerClient, DrmOutputStream 等
-方法签名完全对齐 Android SDK (android.drm 包)
-"""
-
-from __future__ import annotations
-
-import os
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmStore
-# ═══════════════════════════════════════════════════════════════
-
-class DrmStore(Stub):
- """DrmStore — DRM 存储常量"""
-
- # ═══════════════════════════════════════════════════
- # DrmStore.Action
- # ═══════════════════════════════════════════════════
-
- class Action(Stub):
- """DrmStore.Action — DRM 操作类型"""
-
- PLAY = 1
- RINGTONE = 2
- TRANSFER = 3
- OUTPUT = 4
- PREVIEW = 5
- EXECUTE = 6
- DISPLAY = 7
- PRINT = 8
- WALLPAPER = 9
- RINGTONEOUTGOING = 10
- RINGTONECALL = 11
- RINGTONESILENT = 12
- RINGTONESILENTCALL = 13
- RINGTONESILENTOUTGOING = 14
- RINGTONESILENTALARM = 15
- ALARM = 16
- NOTIFICATION = 17
- CALENDAR = 18
- CLOCK = 19
- MAX = 20
-
- @staticmethod
- def toString(action: int) -> str:
- names = {
- DrmStore.Action.PLAY: "PLAY",
- DrmStore.Action.RINGTONE: "RINGTONE",
- DrmStore.Action.TRANSFER: "TRANSFER",
- DrmStore.Action.OUTPUT: "OUTPUT",
- DrmStore.Action.PREVIEW: "PREVIEW",
- DrmStore.Action.EXECUTE: "EXECUTE",
- DrmStore.Action.DISPLAY: "DISPLAY",
- DrmStore.Action.PRINT: "PRINT",
- DrmStore.Action.WALLPAPER: "WALLPAPER",
- DrmStore.Action.ALARM: "ALARM",
- DrmStore.Action.NOTIFICATION: "NOTIFICATION",
- }
- return names.get(action, f"UNKNOWN({action})")
-
- class ActionConstant(Stub):
- PLAY = 1
- RINGTONE = 2
- TRANSFER = 3
- OUTPUT = 4
- PREVIEW = 5
- EXECUTE = 6
- DISPLAY = 7
- PRINT = 8
- WALLPAPER = 9
- ALARM = 10
- NOTIFICATION = 11
-
- class ActionDescription(Stub):
- PLAY_DESCRIPTION = "play"
- RINGTONE_DESCRIPTION = "ringtone"
- TRANSFER_DESCRIPTION = "transfer"
- OUTPUT_DESCRIPTION = "output"
- PREVIEW_DESCRIPTION = "preview"
- EXECUTE_DESCRIPTION = "execute"
- DISPLAY_DESCRIPTION = "display"
- PRINT_DESCRIPTION = "print"
- WALLPAPER_DESCRIPTION = "wallpaper"
- ALARM_DESCRIPTION = "alarm"
- NOTIFICATION_DESCRIPTION = "notification"
-
- # ═══════════════════════════════════════════════════
- # DrmStore.ConstraintsColumns
- # ═══════════════════════════════════════════════════
-
- class ConstraintsColumns(Stub):
- """DrmStore.ConstraintsColumns — DRM 约束列"""
-
- MAX_REPEAT_COUNT = "max_repeat_count"
- REMAINING_REPEAT_COUNT = "remaining_repeat_count"
- LICENSE_START_TIME = "license_start_time"
- LICENSE_EXPIRY_TIME = "license_expiry_time"
- AVAILABLE_PERIOD = "available_period"
- EXTENDED_METADATA = "extended_metadata"
- LICENSE_AVAILABLE_TIME = "license_available_time"
- LICENSE_AVAILABLE_PERIOD = "license_available_period"
- LICENSE_USE_COUNT = "license_use_count"
- LICENSE_USE_LIMIT = "license_use_limit"
- LICENSE_RIGHTS = "license_rights"
- LICENSE_RIGHTS_INFO = "license_rights_info"
- LICENSE_CATEGORY = "license_category"
- LICENSE_VERSION = "license_version"
-
- # ═══════════════════════════════════════════════════
- # DrmStore.DrmObjectType
- # ═══════════════════════════════════════════════════
-
- class DrmObjectType(Stub):
- """DrmStore.DrmObjectType — DRM 对象类型"""
-
- UNKNOWN = 0
- CONTENT = 1
- RIGHTS_OBJECT = 2
- TRIGGER_OBJECT = 3
-
- # ═══════════════════════════════════════════════════
- # DrmStore.PlaybackCtrl
- # ═══════════════════════════════════════════════════
-
- class PlaybackCtrl(Stub):
- """DrmStore.PlaybackCtrl — 播放控制"""
-
- START = 0
- STOP = 1
- PAUSE = 2
- RESUME = 3
-
- # ═══════════════════════════════════════════════════
- # DrmStore.RightsStatus
- # ═══════════════════════════════════════════════════
-
- class RightsStatus(Stub):
- """DrmStore.RightsStatus — 权限状态"""
-
- RIGHTS_VALID = 0
- RIGHTS_INVALID = 1
- RIGHTS_EXPIRED = 2
- RIGHTS_NOT_ACQUIRED = 3
- RIGHTS_PROTECTED = 4
- RIGHTS_UNPROTECTED = 5
- RIGHTS_NOT_INSTALLED = 6
- RIGHTS_INSTALLED = 7
- RIGHTS_META = 8
- RIGHTS_COPYRIGHT = 9
- RIGHTS_COPYRIGHT_EXPIRED = 10
- RIGHTS_NOT_COPYRIGHT = 11
- RIGHTS_SECURE = 12
- RIGHTS_NOT_SECURE = 13
- RIGHTS_UNLIMITED = 14
- RIGHTS_LIMITED = 15
-
- # ═══════════════════════════════════════════════════
- # DrmStore.DrmMethod
- # ═══════════════════════════════════════════════════
-
- class DrmMethod(Stub):
- """DrmStore.DrmMethod — DRM 方法"""
-
- METHOD_UNKNOWN = 0
- METHOD_FL = 1
- METHOD_NONE = 2
- METHOD_FLD = 3
- METHOD_SD = 4
- METHOD_SD_PRELOAD = 5
- METHOD_SD_DOWNLOAD = 6
- METHOD_FLD_FOREGROUND = 7
- METHOD_FLD_BACKGROUND = 8
-
- # ═══════════════════════════════════════════════════
- # DrmStore.DrmStatus
- # ═══════════════════════════════════════════════════
-
- class DrmStatus(Stub):
- """DrmStore.DrmStatus — DRM 状态"""
-
- STATUS_OK = 0
- STATUS_ERROR = 1
- STATUS_WAITING = 2
- STATUS_CANCELLED = 3
- STATUS_REJECTED = 4
- STATUS_NOT_SUPPORTED = 5
- STATUS_NO_RIGHTS = 6
- STATUS_NO_PERMISSION = 7
- STATUS_PENDING = 8
- STATUS_PROCESSING = 9
- STATUS_COMPLETED = 10
- STATUS_FAILED = 11
- STATUS_INTERRUPTED = 12
- STATUS_TIMEOUT = 13
- STATUS_NO_MEMORY = 14
- STATUS_SERVICE_NOT_FOUND = 15
- STATUS_SERVICE_NOT_AVAILABLE = 16
- STATUS_INVALID_ARGUMENT = 17
- STATUS_ILLEGAL_STATE = 18
- STATUS_NETWORK_ERROR = 19
- STATUS_STORAGE_ERROR = 20
- STATUS_SECURITY_ERROR = 21
- STATUS_LICENSE_EXPIRED = 22
- STATUS_LICENSE_NOT_FOUND = 23
- STATUS_LICENSE_NOT_AVAILABLE = 24
-
- DRM_METHOD_FL = 1
- DRM_METHOD_NONE = 2
- DRM_METHOD_UNKNOWN = 0
-
- EXTENSION_NONE = "none"
- EXTENSION_FL = ".fl"
- EXTENSION_DCF = ".dcf"
- EXTENSION_DM = ".dm"
- EXTENSION_ODF = ".odf"
- EXTENSION_SDCF = ".sdcf"
- EXTENSION_FLD = ".fld"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmInfo
-# ═══════════════════════════════════════════════════════════════
-
-class DrmInfo(Stub):
- """DrmInfo — DRM 信息"""
-
- def __init__(self, mime_type: str = "", data: bytes = b""):
- super().__init__()
- self._mime_type = mime_type
- self._data = data
- self._attributes: Dict[str, str] = {}
- self._info_type: int = 0
- self._content_type: str = ""
- self._content_uri: str = ""
- self._content_data: bytes = b""
- self._is_valid: bool = True
- self._metadata: Dict[str, str] = {}
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def setMimeType(self, mime_type: str):
- self._mime_type = mime_type
-
- def getData(self) -> bytes:
- return self._data
-
- def setData(self, data: bytes):
- self._data = data
-
- def get(self, key: str) -> Optional[str]:
- return self._attributes.get(key)
-
- def put(self, key: str, value: str):
- self._attributes[key] = value
-
- def getAttributes(self) -> Dict[str, str]:
- return dict(self._attributes)
-
- def getInfoType(self) -> int:
- return self._info_type
-
- def setInfoType(self, type_: int):
- self._info_type = type_
-
- def getContentType(self) -> str:
- return self._content_type
-
- def setContentType(self, type_: str):
- self._content_type = type_
-
- def getContentUri(self) -> str:
- return self._content_uri
-
- def setContentUri(self, uri: str):
- self._content_uri = uri
-
- def getContentData(self) -> bytes:
- return self._content_data
-
- def setContentData(self, data: bytes):
- self._content_data = data
-
- def isValid(self) -> bool:
- return self._is_valid
-
- def setValid(self, valid: bool):
- self._is_valid = valid
-
- def getMetadata(self) -> Dict[str, str]:
- return dict(self._metadata)
-
- def setMetadata(self, metadata: Dict[str, str]):
- self._metadata = dict(metadata)
-
- def toString(self) -> str:
- return f"DrmInfo(mime={self._mime_type}, type={self._info_type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmInfoRequest
-# ═══════════════════════════════════════════════════════════════
-
-class DrmInfoRequest(Stub):
- """DrmInfoRequest — DRM 信息请求"""
-
- TYPE_REGISTRATION_INFO = 1
- TYPE_UNREGISTRATION_INFO = 2
- TYPE_RIGHTS_ACQUISITION_INFO = 3
- TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4
- TYPE_MERGE_INFO = 5
- TYPE_REMOVE_INFO = 6
- TYPE_ACCOUNT_INFO = 7
- TYPE_ACCOUNT_REGISTRATION_INFO = 8
- TYPE_ACCOUNT_UNREGISTRATION_INFO = 9
- TYPE_ACCOUNT_UPDATE_INFO = 10
- TYPE_ADAPTER_INFO = 11
- TYPE_ADAPTER_CONFIG_INFO = 12
- TYPE_ADAPTER_REGISTRATION_INFO = 13
- TYPE_METADATA_INFO = 14
-
- def __init__(self, info_type: int = TYPE_REGISTRATION_INFO,
- mime_type: str = ""):
- super().__init__()
- self._info_type = info_type
- self._mime_type = mime_type
- self._attributes: Dict[str, str] = {}
-
- def getInfoType(self) -> int:
- return self._info_type
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def get(self, key: str) -> Optional[str]:
- return self._attributes.get(key)
-
- def put(self, key: str, value: str):
- self._attributes[key] = value
-
- def getAttributes(self) -> Dict[str, str]:
- return dict(self._attributes)
-
- def toString(self) -> str:
- return f"DrmInfoRequest(type={self._info_type}, mime={self._mime_type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmInfoResponse
-# ═══════════════════════════════════════════════════════════════
-
-class DrmInfoResponse(Stub):
- """DrmInfoResponse — DRM 信息响应"""
-
- def __init__(self):
- super().__init__()
- self._info: Optional[DrmInfo] = None
- self._status: int = 0
- self._error_message: str = ""
- self._request: Optional[DrmInfoRequest] = None
- self._response_data: bytes = b""
- self._timestamp: int = 0
-
- def getInfo(self) -> Optional[DrmInfo]:
- return self._info
-
- def setInfo(self, info: DrmInfo):
- self._info = info
-
- def getStatus(self) -> int:
- return self._status
-
- def setStatus(self, status: int):
- self._status = status
-
- def getErrorMessage(self) -> str:
- return self._error_message
-
- def setErrorMessage(self, msg: str):
- self._error_message = msg
-
- def getRequest(self) -> Optional[DrmInfoRequest]:
- return self._request
-
- def setRequest(self, request: DrmInfoRequest):
- self._request = request
-
- def getResponseData(self) -> bytes:
- return self._response_data
-
- def setResponseData(self, data: bytes):
- self._response_data = data
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def setTimestamp(self, ts: int):
- self._timestamp = ts
-
- def isSuccessful(self) -> bool:
- return self._status == DrmStore.DrmStatus.STATUS_OK
-
- def toString(self) -> str:
- return f"DrmInfoResponse(status={self._status})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmConvertedStatus
-# ═══════════════════════════════════════════════════════════════
-
-class DrmConvertedStatus(Stub):
- """DrmConvertedStatus — DRM 转换状态"""
-
- STATUS_OK = 0
- STATUS_ERROR = 1
- STATUS_INPUT_DATA_ERROR = 2
- STATUS_OPERATION_NOT_SUPPORTED = 3
- STATUS_INTERNAL_ERROR = 4
- STATUS_INVALID_DATA = 5
- STATUS_NO_RIGHTS = 6
- STATUS_ENCRYPTION_ERROR = 7
-
- def __init__(self, status_code: int = STATUS_OK,
- converted_data: bytes = b"",
- mime_type: str = ""):
- super().__init__()
- self._status_code = status_code
- self._converted_data = converted_data
- self._mime_type = mime_type
- self._converted_file_path: str = ""
- self._original_file_path: str = ""
- self._conversion_time: int = 0
-
- def getStatusCode(self) -> int:
- return self._status_code
-
- def setStatusCode(self, code: int):
- self._status_code = code
-
- def getConvertedData(self) -> bytes:
- return self._converted_data
-
- def setConvertedData(self, data: bytes):
- self._converted_data = data
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def setMimeType(self, mime_type: str):
- self._mime_type = mime_type
-
- def getConvertedFilePath(self) -> str:
- return self._converted_file_path
-
- def setConvertedFilePath(self, path: str):
- self._converted_file_path = path
-
- def getOriginalFilePath(self) -> str:
- return self._original_file_path
-
- def setOriginalFilePath(self, path: str):
- self._original_file_path = path
-
- def isSuccessful(self) -> bool:
- return self._status_code == DrmConvertedStatus.STATUS_OK
-
- def toString(self) -> str:
- return f"DrmConvertedStatus(status={self._status_code})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmEvent
-# ═══════════════════════════════════════════════════════════════
-
-class DrmEvent(Stub):
- """DrmEvent — DRM 事件"""
-
- TYPE_ALL_RIGHTS_REMOVED = 1001
- TYPE_DRM_INFO_PROCESSED = 1002
- TYPE_RIGHTS_INSTALLED = 1003
- TYPE_RIGHTS_REMOVED = 1004
- TYPE_RIGHTS_EXPIRED = 1005
- TYPE_RIGHTS_ACQUISITION_STARTED = 1006
- TYPE_RIGHTS_ACQUISITION_FINISHED = 1007
- TYPE_RIGHTS_ACQUISITION_PROGRESS = 1008
- TYPE_RIGHTS_ACQUISITION_FAILED = 1009
- TYPE_META_DATA_AVAILABLE = 1010
- TYPE_META_DATA_UPDATED = 1011
- TYPE_META_DATA_REMOVED = 1012
- TYPE_ACCOUNT_ALREADY_REGISTERED = 1013
- TYPE_ACCOUNT_REGISTERED = 1014
- TYPE_ACCOUNT_UNREGISTERED = 1015
-
- def __init__(self, unique_id: int = 0, type_: int = 0,
- message: str = ""):
- super().__init__()
- self._unique_id = unique_id
- self._type = type_
- self._message = message
- self._attributes: Dict[str, Any] = {}
- self._timestamp: int = int(time.time() * 1000)
-
- def getUniqueId(self) -> int:
- return self._unique_id
-
- def getType(self) -> int:
- return self._type
-
- def getMessage(self) -> str:
- return self._message
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def getAttribute(self, key: str) -> Optional[Any]:
- return self._attributes.get(key)
-
- def getAttributes(self) -> Dict[str, Any]:
- return dict(self._attributes)
-
- def setAttribute(self, key: str, value: Any):
- self._attributes[key] = value
-
- def toString(self) -> str:
- return f"DrmEvent(type={self._type}, msg={self._message})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmErrorEvent
-# ═══════════════════════════════════════════════════════════════
-
-class DrmErrorEvent(DrmEvent):
- """DrmErrorEvent — DRM 错误事件"""
-
- TYPE_RIGHTS_NOT_INSTALLED = 2001
- TYPE_RIGHTS_ACQUISITION_FAILED = 2002
- TYPE_RIGHTS_NOT_ACQUIRED = 2003
- TYPE_PROCESS_DRM_INFO_FAILED = 2004
- TYPE_REMOVE_ALL_RIGHTS_FAILED = 2005
- TYPE_ACQUIRE_RIGHTS_FAILED = 2006
- TYPE_SIGNATURE_MISMATCH = 2007
- TYPE_INVALID_DRM_INFO = 2008
- TYPE_CERTIFICATE_REVOKED = 2009
- TYPE_LICENSE_EXPIRED = 2010
- TYPE_LICENSE_NOT_FOUND = 2011
- TYPE_SECURITY_VIOLATION = 2012
- TYPE_NETWORK_ERROR = 2013
-
- def __init__(self, unique_id: int = 0, type_: int = 0,
- message: str = ""):
- super().__init__(unique_id, type_, message)
- self._error_code: int = 0
- self._recoverable: bool = False
- self._stack_trace: str = ""
-
- def getErrorCode(self) -> int:
- return self._error_code
-
- def setErrorCode(self, code: int):
- self._error_code = code
-
- def isRecoverable(self) -> bool:
- return self._recoverable
-
- def setRecoverable(self, recoverable: bool):
- self._recoverable = recoverable
-
- def getStackTrace(self) -> str:
- return self._stack_trace
-
- def setStackTrace(self, trace: str):
- self._stack_trace = trace
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmInfoEvent
-# ═══════════════════════════════════════════════════════════════
-
-class DrmInfoEvent(DrmEvent):
- """DrmInfoEvent — DRM 信息事件"""
-
- TYPE_ACCOUNT_ALREADY_REGISTERED = 3001
- TYPE_ACCOUNT_REGISTERED = 3002
- TYPE_ACCOUNT_UNREGISTERED = 3003
- TYPE_ACCOUNT_REGISTRATION_COMPLETED = 3004
- TYPE_ACCOUNT_REGISTRATION_FAILED = 3005
- TYPE_ACCOUNT_UNREGISTRATION_COMPLETED = 3006
- TYPE_ACCOUNT_UNREGISTRATION_FAILED = 3007
- TYPE_ADAPTER_REGISTRATION_COMPLETED = 3008
- TYPE_ADAPTER_REGISTRATION_FAILED = 3009
- TYPE_METADATA_RETRIEVED = 3010
- TYPE_METADATA_RETRIEVAL_FAILED = 3011
- TYPE_RIGHTS_ACQUISITION_PROGRESS = 3012
- TYPE_RIGHTS_ACQUISITION_COMPLETED = 3013
- TYPE_RIGHTS_ACQUISITION_FAILED = 3014
-
- def __init__(self, unique_id: int = 0, type_: int = 0,
- message: str = ""):
- super().__init__(unique_id, type_, message)
- self._data: Any = None
- self._info_request: Optional[DrmInfoRequest] = None
-
- def getData(self) -> Any:
- return self._data
-
- def setData(self, data: Any):
- self._data = data
-
- def getInfoRequest(self) -> Optional[DrmInfoRequest]:
- return self._info_request
-
- def setInfoRequest(self, request: DrmInfoRequest):
- self._info_request = request
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmManagerClient
-# ═══════════════════════════════════════════════════════════════
-
-class DrmManagerClient(Stub):
- """DrmManagerClient — DRM 管理器客户端"""
-
- ERROR_NONE = 0
- ERROR_UNKNOWN = -1
- ERROR_NOT_INITIALIZED = -2
- ERROR_NOT_SUPPORTED = -3
- ERROR_INVALID_ARGUMENT = -4
- ERROR_PERMISSION_DENIED = -5
- ERROR_SERVICE_NOT_FOUND = -6
- ERROR_SERVICE_NOT_AVAILABLE = -7
- ERROR_NETWORK = -8
- ERROR_STORAGE = -9
- ERROR_IO = -10
- ERROR_INVALID_DRM_INFO = -11
- ERROR_RIGHTS_NOT_ACQUIRED = -12
- ERROR_RIGHTS_EXPIRED = -13
- ERROR_NO_RIGHTS = -14
- ERROR_INTERNAL = -99
-
- class OnErrorListener(Stub):
- """DrmManagerClient.OnErrorListener — 错误监听器"""
-
- def onError(self, client: DrmManagerClient, event: DrmErrorEvent):
- pass
-
- class OnInfoListener(Stub):
- """DrmManagerClient.OnInfoListener — 信息监听器"""
-
- def onInfo(self, client: DrmManagerClient, event: DrmInfoEvent):
- pass
-
- class OnEventListener(Stub):
- """DrmManagerClient.OnEventListener — 事件监听器"""
-
- def onEvent(self, client: DrmManagerClient, event: DrmEvent):
- pass
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._unique_id: int = id(self)
- self._is_initialized: bool = True
- self._error_listeners: List[DrmManagerClient.OnErrorListener] = []
- self._info_listeners: List[DrmManagerClient.OnInfoListener] = []
- self._event_listeners: List[DrmManagerClient.OnEventListener] = []
-
- def acquireRights(self, drm_info_request: DrmInfoRequest) -> DrmInfoResponse:
- """获取权限"""
- response = DrmInfoResponse()
- response.setRequest(drm_info_request)
- response.setStatus(DrmStore.DrmStatus.STATUS_OK)
- return response
-
- def processDrmInfo(self, drm_info: DrmInfo) -> DrmInfoResponse:
- """处理 DRM 信息"""
- response = DrmInfoResponse()
- response.setInfo(drm_info)
- response.setStatus(DrmStore.DrmStatus.STATUS_OK)
- return response
-
- def getDrmInfo(self, drm_info_request: DrmInfoRequest) -> Optional[DrmInfo]:
- """获取 DRM 信息"""
- drm_info = DrmInfo(drm_info_request.getMimeType())
- drm_info.setInfoType(drm_info_request.getInfoType())
- return drm_info
-
- def getConstraints(self, path: str, action: int) -> Dict[str, Any]:
- """获取约束"""
- return {}
-
- def getMetadata(self, path: str) -> Dict[str, str]:
- """获取元数据"""
- return {}
-
- def canHandle(self, path: str, mime_type: str) -> bool:
- """检查能否处理"""
- return True
-
- def removeAllListener(self):
- """移除所有监听器"""
- self._error_listeners.clear()
- self._info_listeners.clear()
- self._event_listeners.clear()
-
- def removeListener(self, listener: Any):
- """移除监听器"""
- if listener in self._error_listeners:
- self._error_listeners.remove(listener)
- if listener in self._info_listeners:
- self._info_listeners.remove(listener)
- if listener in self._event_listeners:
- self._event_listeners.remove(listener)
-
- def setOnErrorListener(self, listener: OnErrorListener):
- self._error_listeners.append(listener)
-
- def setOnInfoListener(self, listener: OnInfoListener):
- self._info_listeners.append(listener)
-
- def setOnEventListener(self, listener: OnEventListener):
- self._event_listeners.append(listener)
-
- def getUniqueId(self) -> int:
- return self._unique_id
-
- def release(self):
- """释放客户端"""
- self._is_initialized = False
- self.removeAllListener()
-
- def isInitialized(self) -> bool:
- return self._is_initialized
-
- def toString(self) -> str:
- return f"DrmManagerClient(id={self._unique_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmOutputStream
-# ═══════════════════════════════════════════════════════════════
-
-class DrmOutputStream(Stub):
- """DrmOutputStream — DRM 输出流"""
-
- def __init__(self, file_path: str = ""):
- super().__init__()
- self._file_path = file_path
- self._is_open: bool = False
- self._is_finished: bool = False
- self._buffer: bytes = b""
- self._bytes_written: int = 0
- self._mime_type: str = ""
- self._drm_info: Optional[DrmInfo] = None
-
- def open(self) -> bool:
- """打开输出流"""
- self._is_open = True
- return True
-
- def write(self, data: bytes) -> int:
- """写入数据"""
- if not self._is_open:
- return -1
- self._buffer += data
- self._bytes_written += len(data)
- return len(data)
-
- def close(self):
- """关闭输出流"""
- if self._is_open:
- self._is_open = False
- self._is_finished = True
-
- def finish(self):
- """完成写入"""
- self._is_finished = True
-
- def getFilePath(self) -> str:
- return self._file_path
-
- def setFilePath(self, path: str):
- self._file_path = path
-
- def isOpen(self) -> bool:
- return self._is_open
-
- def isFinished(self) -> bool:
- return self._is_finished
-
- def getBytesWritten(self) -> int:
- return self._bytes_written
-
- def getBuffer(self) -> bytes:
- return self._buffer
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def setMimeType(self, mime_type: str):
- self._mime_type = mime_type
-
- def toString(self) -> str:
- return f"DrmOutputStream(path={self._file_path}, written={self._bytes_written})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmRights
-# ═══════════════════════════════════════════════════════════════
-
-class DrmRights(Stub):
- """DrmRights — DRM 权限"""
-
- def __init__(self, rights_data: bytes = b"", mime_type: str = "",
- account_id: str = "", subscription_id: str = ""):
- super().__init__()
- self._rights_data = rights_data
- self._mime_type = mime_type
- self._account_id = account_id
- self._subscription_id = subscription_id
- self._is_valid: bool = True
- self._expiry_time: int = 0
- self._issued_time: int = int(time.time() * 1000)
-
- def getData(self) -> bytes:
- return self._rights_data
-
- def setData(self, data: bytes):
- self._rights_data = data
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def setMimeType(self, mime_type: str):
- self._mime_type = mime_type
-
- def getAccountId(self) -> str:
- return self._account_id
-
- def setAccountId(self, account_id: str):
- self._account_id = account_id
-
- def getSubscriptionId(self) -> str:
- return self._subscription_id
-
- def setSubscriptionId(self, sub_id: str):
- self._subscription_id = sub_id
-
- def isValid(self) -> bool:
- return self._is_valid and (self._expiry_time == 0 or
- self._expiry_time > int(time.time() * 1000))
-
- def setValid(self, valid: bool):
- self._is_valid = valid
-
- def getExpiryTime(self) -> int:
- return self._expiry_time
-
- def setExpiryTime(self, expiry_ms: int):
- self._expiry_time = expiry_ms
-
- def getIssuedTime(self) -> int:
- return self._issued_time
-
- def isExpired(self) -> bool:
- if self._expiry_time == 0:
- return False
- return self._expiry_time < int(time.time() * 1000)
-
- def toString(self) -> str:
- return f"DrmRights(mime={self._mime_type}, valid={self._is_valid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmSupportInfo
-# ═══════════════════════════════════════════════════════════════
-
-class DrmSupportInfo(Stub):
- """DrmSupportInfo — DRM 支持信息"""
-
- def __init__(self):
- super().__init__()
- self._mime_types: Set[str] = set()
- self._file_suffixes: Set[str] = set()
- self._descriptions: List[str] = []
- self._plug_in_id: str = ""
- self._vendor_name: str = ""
- self._plugin_version: str = ""
- self._is_available: bool = True
-
- def addMimeType(self, mime_type: str):
- self._mime_types.add(mime_type)
-
- def addFileSuffix(self, file_suffix: str):
- self._file_suffixes.add(file_suffix)
-
- def addDescription(self, description: str):
- self._descriptions.append(description)
-
- def getMimeTypes(self) -> Set[str]:
- return set(self._mime_types)
-
- def getFileSuffixes(self) -> Set[str]:
- return set(self._file_suffixes)
-
- def getDescriptions(self) -> List[str]:
- return list(self._descriptions)
-
- def isSupportedMimeType(self, mime_type: str) -> bool:
- return mime_type in self._mime_types
-
- def isSupportedFileSuffix(self, suffix: str) -> bool:
- return suffix in self._file_suffixes
-
- def getPlugInId(self) -> str:
- return self._plug_in_id
-
- def setPlugInId(self, plugin_id: str):
- self._plug_in_id = plugin_id
-
- def getVendorName(self) -> str:
- return self._vendor_name
-
- def setVendorName(self, name: str):
- self._vendor_name = name
-
- def getPluginVersion(self) -> str:
- return self._plugin_version
-
- def setPluginVersion(self, version: str):
- self._plugin_version = version
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def setAvailable(self, available: bool):
- self._is_available = available
-
- def toString(self) -> str:
- return f"DrmSupportInfo(mimeTypes={len(self._mime_types)}, suffixes={len(self._file_suffixes)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmUtils
-# ═══════════════════════════════════════════════════════════════
-
-class DrmUtils(Stub):
- """DrmUtils — DRM 工具类"""
-
- EXTENSION_DCF = ".dcf"
- EXTENSION_FL = ".fl"
- EXTENSION_DM = ".dm"
- EXTENSION_ODF = ".odf"
- EXTENSION_SDCF = ".sdcf"
- EXTENSION_FLD = ".fld"
- EXTENSION_HTML = ".html"
- EXTENSION_XHTML = ".xhtml"
- EXTENSION_XML = ".xml"
-
- MIME_TYPE_DCF = "application/vnd.oma.drm.content"
- MIME_TYPE_FL = "application/vnd.oma.drm.message"
- MIME_TYPE_DM = "application/vnd.oma.drm.message"
- MIME_TYPE_ODF = "application/vnd.oma.drm.content"
- MIME_TYPE_SDCF = "application/vnd.oma.drm.content"
- MIME_TYPE_UNKNOWN = "application/octet-stream"
-
- @staticmethod
- def getOriginalMimeType(context: Any, file_path: str) -> str:
- """获取原始 MIME 类型"""
- return DrmUtils.MIME_TYPE_UNKNOWN
-
- @staticmethod
- def getOriginalFileSuffix(context: Any, file_path: str) -> str:
- """获取原始文件后缀"""
- _, ext = os.path.splitext(file_path) if hasattr(os.path, 'splitext') else (file_path, "")
- return ext
-
- @staticmethod
- def isDrmFile(file_path: str) -> bool:
- """检查是否为 DRM 文件"""
- if not file_path:
- return False
- suffix = os.path.splitext(file_path)[1].lower() if hasattr(os.path, 'splitext') else ""
- drm_extensions = {DrmUtils.EXTENSION_DCF, DrmUtils.EXTENSION_FL,
- DrmUtils.EXTENSION_DM, DrmUtils.EXTENSION_ODF,
- DrmUtils.EXTENSION_SDCF, DrmUtils.EXTENSION_FLD}
- return suffix in drm_extensions
-
- @staticmethod
- def isDrmMimeType(mime_type: str) -> bool:
- """检查是否为 DRM MIME 类型"""
- drm_mime_types = {DrmUtils.MIME_TYPE_DCF, DrmUtils.MIME_TYPE_FL,
- DrmUtils.MIME_TYPE_DM, DrmUtils.MIME_TYPE_ODF,
- DrmUtils.MIME_TYPE_SDCF}
- return mime_type in drm_mime_types
-
- @staticmethod
- def getDrmFileType(file_path: str) -> int:
- """获取 DRM 文件类型"""
- if not DrmUtils.isDrmFile(file_path):
- return DrmStore.DrmObjectType.UNKNOWN
- return DrmStore.DrmObjectType.CONTENT
-
- @staticmethod
- def getSupportedMimeTypes() -> Set[str]:
- """获取支持的 MIME 类型"""
- return {DrmUtils.MIME_TYPE_DCF, DrmUtils.MIME_TYPE_FL,
- DrmUtils.MIME_TYPE_DM, DrmUtils.MIME_TYPE_ODF,
- DrmUtils.MIME_TYPE_SDCF}
-
- @staticmethod
- def convertToDrmFile(input_path: str, output_path: str,
- mime_type: str) -> DrmConvertedStatus:
- """转换为 DRM 文件"""
- with open(input_path, "rb") as f:
- data = f.read()
- status = DrmConvertedStatus(DrmConvertedStatus.STATUS_OK, data, mime_type)
- status.setOriginalFilePath(input_path)
- status.setConvertedFilePath(output_path)
- return status
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrmManager (高层管理器)
-# ═══════════════════════════════════════════════════════════════
-
-class DrmManager(Stub):
- """DrmManager — DRM 管理器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._clients: Dict[int, DrmManagerClient] = {}
- self._is_available: bool = True
- self._support_infos: List[DrmSupportInfo] = []
-
- @staticmethod
- def getInstance(context: Any) -> DrmManager:
- return DrmManager(context)
-
- def getDrmManagerClient(self) -> DrmManagerClient:
- client = DrmManagerClient(self._context)
- client_id = client.getUniqueId()
- self._clients[client_id] = client
- return client
-
- def releaseDrmManagerClient(self, client: DrmManagerClient):
- client_id = client.getUniqueId()
- if client_id in self._clients:
- client.release()
- del self._clients[client_id]
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def setAvailable(self, available: bool):
- self._is_available = available
-
- def getSupportInfos(self) -> List[DrmSupportInfo]:
- return list(self._support_infos)
-
- def addSupportInfo(self, info: DrmSupportInfo):
- self._support_infos.append(info)
-
- def removeSupportInfo(self, info: DrmSupportInfo):
- self._support_infos = [i for i in self._support_infos if i is not info]
-
- def canHandle(self, path: str, mime_type: str) -> bool:
- for client in self._clients.values():
- if client.canHandle(path, mime_type):
- return True
- return False
-
- def getAvailableClients(self) -> List[DrmManagerClient]:
- return [c for c in self._clients.values() if c.isInitialized()]
-
- def release(self):
- for client in list(self._clients.values()):
- client.release()
- self._clients.clear()
- self._support_infos.clear()
-
- def toString(self) -> str:
- return f"DrmManager(clients={len(self._clients)}, available={self._is_available})"
\ No newline at end of file
diff --git a/android_pyapi/android/gesture.py b/android_pyapi/android/gesture.py
deleted file mode 100644
index fe22a03..0000000
--- a/android_pyapi/android/gesture.py
+++ /dev/null
@@ -1,545 +0,0 @@
-"""
-Android gesture 包 — Gesture, GestureOverlayView, GesturePoint, GestureStroke,
-GestureLibrary, GestureStore, Prediction, OrientedBoundingBox, GestureUtils
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "Gesture",
- "GestureOverlayView",
- "GesturePoint",
- "GestureStroke",
- "GestureLibrary",
- "GestureStore",
- "Prediction",
- "OrientedBoundingBox",
- "GestureUtils",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# GesturePoint
-# ═══════════════════════════════════════════════════════════════
-
-class GesturePoint(Stub):
- """GesturePoint — 手势点"""
-
- def __init__(self, x: float = 0.0, y: float = 0.0, timestamp: int = 0):
- super().__init__()
- self.x = x
- self.y = y
- self.timestamp = timestamp
-
- def toString(self) -> str:
- return f"GesturePoint({self.x}, {self.y})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# OrientedBoundingBox
-# ═══════════════════════════════════════════════════════════════
-
-class OrientedBoundingBox(Stub):
- """OrientedBoundingBox — 有向包围盒"""
-
- def __init__(self, center_x: float = 0.0, center_y: float = 0.0,
- width: float = 0.0, height: float = 0.0, orientation: float = 0.0):
- super().__init__()
- self.centerX = center_x
- self.centerY = center_y
- self.width = width
- self.height = height
- self.orientation = orientation
-
- def toRect(self) -> Tuple[float, float, float, float]:
- """转换为矩形"""
- hw = self.width / 2.0
- hh = self.height / 2.0
- return (self.centerX - hw, self.centerY - hh,
- self.centerX + hw, self.centerY + hh)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Prediction
-# ═══════════════════════════════════════════════════════════════
-
-class Prediction(Stub):
- """Prediction — 预测结果"""
-
- def __init__(self, name: str = "", score: float = 0.0):
- super().__init__()
- self.name = name
- self.score = score
-
- def toString(self) -> str:
- return f"Prediction(name={self.name}, score={self.score})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureStroke
-# ═══════════════════════════════════════════════════════════════
-
-class GestureStroke(Stub):
- """GestureStroke — 手势笔划"""
-
- def __init__(self, points: Optional[List[GesturePoint]] = None):
- super().__init__()
- self._points = points or []
- self._path: Optional[Any] = None
- self._length = self._compute_length()
- self._bounding_box = OrientedBoundingBox()
-
- def _compute_length(self) -> float:
- length = 0.0
- for i in range(1, len(self._points)):
- dx = self._points[i].x - self._points[i - 1].x
- dy = self._points[i].y - self._points[i - 1].y
- length += math.sqrt(dx * dx + dy * dy)
- return length
-
- def getLength(self) -> float:
- """获取长度"""
- return self._length
-
- def getPoints(self) -> List[GesturePoint]:
- """获取点列表"""
- return self._points.copy()
-
- def getPath(self) -> Optional[Any]:
- """获取路径"""
- return self._path
-
- def toPath(self, width: float = 1.0, height: float = 1.0, num_sample: int = 0) -> Any:
- """转换为路径"""
- return self._path
-
- def clearPath(self) -> None:
- """清除路径"""
- self._path = None
-
- def computeOrientedBoundingBox(self) -> OrientedBoundingBox:
- """计算有向包围盒"""
- return self._bounding_box
-
-
-# ═══════════════════════════════════════════════════════════════
-# Gesture
-# ═══════════════════════════════════════════════════════════════
-
-class Gesture(Stub):
- """Gesture — 手势"""
-
- def __init__(self):
- super().__init__()
- self._strokes: List[GestureStroke] = []
- self._id = 0
- self._bounding_box: Optional[Tuple[float, float, float, float]] = None
- self._length = 0.0
-
- def getStrokes(self) -> List[GestureStroke]:
- """获取笔划列表"""
- return self._strokes.copy()
-
- def getLength(self) -> float:
- """获取手势长度"""
- return sum(s.getLength() for s in self._strokes)
-
- def getBoundingBox(self) -> Tuple[float, float, float, float]:
- """获取包围盒"""
- if self._bounding_box:
- return self._bounding_box
- if not self._strokes:
- return (0.0, 0.0, 0.0, 0.0)
- min_x = min(p.x for s in self._strokes for p in s._points) if self._strokes else 0
- min_y = min(p.y for s in self._strokes for p in s._points) if self._strokes else 0
- max_x = max(p.x for s in self._strokes for p in s._points) if self._strokes else 0
- max_y = max(p.y for s in self._strokes for p in s._points) if self._strokes else 0
- return (min_x, min_y, max_x, max_y)
-
- def getID(self) -> int:
- """获取 ID"""
- return self._id
-
- def setID(self, id_: int) -> None:
- """设置 ID"""
- self._id = id_
-
- def toPath(self) -> Optional[Any]:
- """转换为路径"""
- return None
-
- def toTempPath(self) -> Optional[Any]:
- """转换为临时路径"""
- return None
-
- def toBitmap(self) -> Optional[Any]:
- """转换为位图"""
- return None
-
- def getStrokesCount(self) -> int:
- """获取笔划数量"""
- return len(self._strokes)
-
- def getGestureStroke(self, index: int) -> Optional[GestureStroke]:
- """获取指定索引的笔划"""
- if 0 <= index < len(self._strokes):
- return self._strokes[index]
- return None
-
- def addStroke(self, stroke: GestureStroke) -> None:
- """添加笔划"""
- self._strokes.append(stroke)
-
- def toString(self) -> str:
- return f"Gesture(id={self._id}, strokes={len(self._strokes)})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, Gesture):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return hash(self._id) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureOverlayView
-# ═══════════════════════════════════════════════════════════════
-
-class GestureOverlayView(Stub):
- """GestureOverlayView — 手势覆盖视图 (桌面存根)"""
-
- GESTURE_STROKE_TYPE_SINGLE = 0
- GESTURE_STROKE_TYPE_MULTIPLE = 1
- ORIENTATION_HORIZONTAL = 0
- ORIENTATION_VERTICAL = 1
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._gesture: Optional[Gesture] = None
- self._gesture_color = 0xFFFFFF00
- self._uncertain_gesture_color = 0xFFFF0000
- self._gesture_stroke_width = 4.0
- self._gesture_stroke_type = GestureOverlayView.GESTURE_STROKE_TYPE_SINGLE
- self._gesture_stroke_length_threshold = 50.0
- self._gesture_stroke_squareness_threshold = 0.5
- self._fade_enabled = True
- self._fade_offset = 0
- self._fade_duration = 150
- self._events_interception_enabled = True
- self._gesture_visible = True
- self._gesture_listeners: List[Any] = []
- self._gesture_performed_listeners: List[Any] = []
- self._gesturing_listeners: List[Any] = []
-
- def getGesture(self) -> Optional[Gesture]:
- return self._gesture
-
- def setGesture(self, gesture: Gesture) -> None:
- self._gesture = gesture
-
- def setGestureColor(self, color: int) -> None:
- self._gesture_color = color
-
- def getGestureColor(self) -> int:
- return self._gesture_color
-
- def setUncertainGestureColor(self, color: int) -> None:
- self._uncertain_gesture_color = color
-
- def getUncertainGestureColor(self) -> int:
- return self._uncertain_gesture_color
-
- def setGestureStrokeWidth(self, width: float) -> None:
- self._gesture_stroke_width = width
-
- def getGestureStrokeWidth(self) -> float:
- return self._gesture_stroke_width
-
- def setGestureStrokeType(self, type_: int) -> None:
- self._gesture_stroke_type = type_
-
- def getGestureStrokeType(self) -> int:
- return self._gesture_stroke_type
-
- def setGestureStrokeLengthThreshold(self, threshold: float) -> None:
- self._gesture_stroke_length_threshold = threshold
-
- def getGestureStrokeLengthThreshold(self) -> float:
- return self._gesture_stroke_length_threshold
-
- def setGestureStrokeSquarenessThreshold(self, threshold: float) -> None:
- self._gesture_stroke_squareness_threshold = threshold
-
- def getGestureStrokeSquarenessThreshold(self) -> float:
- return self._gesture_stroke_squareness_threshold
-
- def setFadeEnabled(self, enabled: bool) -> None:
- self._fade_enabled = enabled
-
- def isFadeEnabled(self) -> bool:
- return self._fade_enabled
-
- def setFadeOffset(self, offset: int) -> None:
- self._fade_offset = offset
-
- def getFadeOffset(self) -> int:
- return self._fade_offset
-
- def setFadeDuration(self, duration: int) -> None:
- self._fade_duration = duration
-
- def getFadeDuration(self) -> int:
- return self._fade_duration
-
- def setEventsInterceptionEnabled(self, enabled: bool) -> None:
- self._events_interception_enabled = enabled
-
- def isEventsInterceptionEnabled(self) -> bool:
- return self._events_interception_enabled
-
- def setGestureVisible(self, visible: bool) -> None:
- self._gesture_visible = visible
-
- def isGestureVisible(self) -> bool:
- return self._gesture_visible
-
- def addOnGestureListener(self, listener: Any) -> None:
- self._gesture_listeners.append(listener)
-
- def removeOnGestureListener(self, listener: Any) -> None:
- if listener in self._gesture_listeners:
- self._gesture_listeners.remove(listener)
-
- def removeAllOnGestureListeners(self) -> None:
- self._gesture_listeners.clear()
-
- def addOnGesturePerformedListener(self, listener: Any) -> None:
- self._gesture_performed_listeners.append(listener)
-
- def removeOnGesturePerformedListener(self, listener: Any) -> None:
- if listener in self._gesture_performed_listeners:
- self._gesture_performed_listeners.remove(listener)
-
- def removeAllOnGesturePerformedListeners(self) -> None:
- self._gesture_performed_listeners.clear()
-
- def addOnGesturingListener(self, listener: Any) -> None:
- self._gesturing_listeners.append(listener)
-
- def removeOnGesturingListener(self, listener: Any) -> None:
- if listener in self._gesturing_listeners:
- self._gesturing_listeners.remove(listener)
-
- def removeAllOnGesturingListeners(self) -> None:
- self._gesturing_listeners.clear()
-
- def cancelGesture(self) -> None:
- self._gesture = None
-
- def clear(self) -> None:
- self._gesture = None
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureLibrary
-# ═══════════════════════════════════════════════════════════════
-
-class GestureLibrary(Stub):
- """GestureLibrary — 手势库 (桌面存根)"""
-
- ORIENTATION_INVARIANT = 0
- ORIENTATION_SENSITIVE = 1
- ORIENTATION_SEQUENTIAL_SENSITIVE = 2
- SEQUENCE_INVARIANT = 0
- SEQUENCE_SENSITIVE = 1
-
- def __init__(self):
- super().__init__()
- self._gestures: Dict[str, List[Gesture]] = {}
- self._read_only = False
- self._orientation_style = GestureLibrary.ORIENTATION_SENSITIVE
- self._sequence_type = GestureLibrary.SEQUENCE_SENSITIVE
-
- def store(self) -> bool:
- """存储手势库"""
- return True
-
- def load(self) -> bool:
- """加载手势库"""
- return True
-
- def getGestureEntries(self) -> List[str]:
- """获取手势条目"""
- return list(self._gestures.keys())
-
- def getGestures(self, entry_name: str) -> List[Gesture]:
- """获取手势列表"""
- return self._gestures.get(entry_name, [])
-
- def recognize(self, gesture: Gesture) -> List[Prediction]:
- """识别手势"""
- return []
-
- def removeGesture(self, entry_name: str, gesture: Gesture) -> None:
- """移除手势"""
- if entry_name in self._gestures and gesture in self._gestures[entry_name]:
- self._gestures[entry_name].remove(gesture)
-
- def removeEntry(self, entry_name: str) -> None:
- """移除条目"""
- self._gestures.pop(entry_name, None)
-
- def addGesture(self, entry_name: str, gesture: Gesture) -> None:
- """添加手势"""
- if entry_name not in self._gestures:
- self._gestures[entry_name] = []
- self._gestures[entry_name].append(gesture)
-
- def isReadOnly(self) -> bool:
- """检查是否只读"""
- return self._read_only
-
- def setOrientationStyle(self, style: int) -> None:
- self._orientation_style = style
-
- def getOrientationStyle(self) -> int:
- return self._orientation_style
-
- def setSequenceType(self, type_: int) -> None:
- self._sequence_type = type_
-
- def getSequenceType(self) -> int:
- return self._sequence_type
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureStore
-# ═══════════════════════════════════════════════════════════════
-
-class GestureStore(Stub):
- """GestureStore — 手势存储 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
- self._gestures: Dict[str, List[Gesture]] = {}
- self._orientation_style = GestureLibrary.ORIENTATION_SENSITIVE
- self._sequence_type = GestureLibrary.SEQUENCE_SENSITIVE
- self._change_listener: Optional[Any] = None
-
- def addGesture(self, entry_name: str, gesture: Gesture) -> None:
- if entry_name not in self._gestures:
- self._gestures[entry_name] = []
- self._gestures[entry_name].append(gesture)
-
- def removeGesture(self, entry_name: str, gesture: Gesture) -> None:
- if entry_name in self._gestures and gesture in self._gestures[entry_name]:
- self._gestures[entry_name].remove(gesture)
-
- def removeEntry(self, entry_name: str) -> None:
- self._gestures.pop(entry_name, None)
-
- def getGestureEntries(self) -> List[str]:
- return list(self._gestures.keys())
-
- def getGestures(self, entry_name: str) -> List[Gesture]:
- return self._gestures.get(entry_name, [])
-
- def recognize(self, gesture: Gesture) -> List[Prediction]:
- return []
-
- def recognizeAsync(self, gesture: Gesture) -> None:
- pass
-
- def setOrientationStyle(self, style: int) -> None:
- self._orientation_style = style
-
- def getOrientationStyle(self) -> int:
- return self._orientation_style
-
- def setSequenceType(self, type_: int) -> None:
- self._sequence_type = type_
-
- def getSequenceType(self) -> int:
- return self._sequence_type
-
- def load(self, store_file: Any) -> None:
- pass
-
- def save(self, store_file: Any) -> None:
- pass
-
- def setChangeListener(self, listener: Any) -> None:
- self._change_listener = listener
-
- def getChangeListener(self) -> Any:
- return self._change_listener
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureUtils
-# ═══════════════════════════════════════════════════════════════
-
-class GestureUtils(Stub):
- """GestureUtils — 手势工具类"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def copy(gesture: Gesture) -> Gesture:
- """复制手势"""
- new_gesture = Gesture()
- for stroke in gesture.getStrokes():
- new_stroke = GestureStroke(stroke.getPoints())
- new_gesture.addStroke(new_stroke)
- return new_gesture
-
- @staticmethod
- def boundingBox(gesture: Gesture) -> OrientedBoundingBox:
- """计算手势包围盒"""
- bbox = gesture.getBoundingBox()
- cx = (bbox[0] + bbox[2]) / 2.0 if bbox[2] != bbox[0] else 0.0
- cy = (bbox[1] + bbox[3]) / 2.0 if bbox[3] != bbox[1] else 0.0
- w = bbox[2] - bbox[0]
- h = bbox[3] - bbox[1]
- return OrientedBoundingBox(cx, cy, w, h, 0.0)
-
- @staticmethod
- def boundingBox_stroke(stroke: GestureStroke) -> OrientedBoundingBox:
- """计算笔划包围盒"""
- return stroke.computeOrientedBoundingBox()
-
- @staticmethod
- def spatialSampling(gesture: Gesture, num_samples: int) -> List[float]:
- """空间采样"""
- return []
-
- @staticmethod
- def temporalSampling(gesture: Gesture, num_samples: int) -> List[float]:
- """时间采样"""
- return []
-
- @staticmethod
- def computeOrientedBoundingBox(points: List[GesturePoint]) -> OrientedBoundingBox:
- """计算有向包围盒"""
- if not points:
- return OrientedBoundingBox()
- xs = [p.x for p in points]
- ys = [p.y for p in points]
- cx = sum(xs) / len(xs)
- cy = sum(ys) / len(ys)
- w = max(xs) - min(xs)
- h = max(ys) - min(ys)
- return OrientedBoundingBox(cx, cy, w, h, 0.0)
\ No newline at end of file
diff --git a/android_pyapi/android/gesture_ext.py b/android_pyapi/android/gesture_ext.py
deleted file mode 100644
index 49495d4..0000000
--- a/android_pyapi/android/gesture_ext.py
+++ /dev/null
@@ -1,1158 +0,0 @@
-"""
-Android Gesture 扩展组件 — GestureLibraries, GestureBuilderActivity,
-GestureOverlayView (扩展), GestureStroke (扩展), GesturePoint (扩展),
-各种手势识别器 (TapGesture, LongPressGesture, SwipeGesture 等)
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import time
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-__all__ = [
- "GestureLibraries", "GestureBuilderActivity",
- "GestureOverlayView", "GestureStroke", "GesturePoint",
- "OrientationGesture", "FlingGesture", "SwipeGesture",
- "PinchGesture", "TapGesture", "LongPressGesture",
- "DoubleTapGesture", "ScrollGesture", "DragGesture",
- "MultiFingerGesture", "GestureConfiguration", "GestureEvent",
- "GestureRecognizer", "GesturePerformedListener",
- "GestureDrawingListener", "GestureInputListener",
- "GestureFeedback", "GestureFeedbackProvider",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 手势常量
-# ═══════════════════════════════════════════════════════════════
-
-ORIENTATION_ANY = 0
-ORIENTATION_HORIZONTAL = 1
-ORIENTATION_VERTICAL = 2
-ORIENTATION_DIAGONAL_UP = 3
-ORIENTATION_DIAGONAL_DOWN = 4
-ORIENTATION_LEFT = 5
-ORIENTATION_RIGHT = 6
-ORIENTATION_UP = 7
-ORIENTATION_DOWN = 8
-
-GESTURE_STATE_UNDEFINED = 0
-GESTURE_STATE_STARTED = 1
-GESTURE_STATE_IN_PROGRESS = 2
-GESTURE_STATE_COMPLETED = 3
-GESTURE_STATE_CANCELLED = 4
-GESTURE_STATE_FAILED = 5
-
-GESTURE_EVENT_TYPE_TAP = 0
-GESTURE_EVENT_TYPE_DOUBLE_TAP = 1
-GESTURE_EVENT_TYPE_LONG_PRESS = 2
-GESTURE_EVENT_TYPE_SWIPE = 3
-GESTURE_EVENT_TYPE_FLING = 4
-GESTURE_EVENT_TYPE_PINCH = 5
-GESTURE_EVENT_TYPE_SCROLL = 6
-GESTURE_EVENT_TYPE_DRAG = 7
-GESTURE_EVENT_TYPE_ROTATION = 8
-GESTURE_EVENT_TYPE_MULTI_FINGER_TAP = 9
-GESTURE_EVENT_TYPE_ORIENTATION = 10
-
-GESTURE_LIBRARY_FILE = 0
-GESTURE_LIBRARY_RESOURCE = 1
-GESTURE_LIBRARY_RAW = 2
-GESTURE_LIBRARY_PRIVATE = 3
-
-GESTURE_DIRECTION_ANY = 0
-GESTURE_DIRECTION_LEFT = 1
-GESTURE_DIRECTION_RIGHT = 2
-GESTURE_DIRECTION_UP = 3
-GESTURE_DIRECTION_DOWN = 4
-GESTURE_DIRECTION_HORIZONTAL = 5
-GESTURE_DIRECTION_VERTICAL = 6
-
-GESTURE_FEEDBACK_NONE = 0
-GESTURE_FEEDBACK_VIBRATE = 1
-GESTURE_FEEDBACK_SOUND = 2
-GESTURE_FEEDBACK_VISUAL = 4
-GESTURE_FEEDBACK_ALL = 7
-
-
-# ═══════════════════════════════════════════════════════════════
-# GesturePoint (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class GesturePoint(Stub):
- """GesturePoint — 手势点 (完整版)"""
-
- def __init__(self, x: float = 0.0, y: float = 0.0,
- timestamp: int = 0, pressure: float = 1.0,
- size: float = 0.0, pointerId: int = 0):
- super().__init__()
- self._x = x
- self._y = y
- self._timestamp = timestamp
- self._pressure = pressure
- self._size = size
- self._pointer_id = pointerId
-
- def getX(self) -> float:
- return self._x
-
- def getY(self) -> float:
- return self._y
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def getPressure(self) -> float:
- return self._pressure
-
- def getSize(self) -> float:
- return self._size
-
- def getPointerId(self) -> int:
- return self._pointer_id
-
- def distance(self, other: "GesturePoint") -> float:
- dx = self._x - other._x
- dy = self._y - other._y
- return math.sqrt(dx * dx + dy * dy)
-
- def velocity(self, other: "GesturePoint") -> float:
- dt = self._timestamp - other._timestamp
- if dt <= 0:
- return 0.0
- dist = self.distance(other)
- return dist / dt * 1000.0
-
- def toString(self) -> str:
- return f"GesturePoint({self._x:.1f}, {self._y:.1f})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, GesturePoint):
- return False
- return (self._x == other._x and self._y == other._y and
- self._timestamp == other._timestamp)
-
- def hashCode(self) -> int:
- return hash((self._x, self._y, self._timestamp)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureStroke (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class GestureStroke(Stub):
- """GestureStroke — 手势笔画 (完整版)"""
-
- def __init__(self, points: List[GesturePoint] = None):
- super().__init__()
- self._points = points or []
- self._length = 0.0
- self._bounding_box = (0, 0, 0, 0)
- self._orientation = 0.0
- self._recalculate()
-
- def _recalculate(self):
- if not self._points:
- self._length = 0.0
- self._bounding_box = (0, 0, 0, 0)
- return
- min_x = min(p.getX() for p in self._points)
- max_x = max(p.getX() for p in self._points)
- min_y = min(p.getY() for p in self._points)
- max_y = max(p.getY() for p in self._points)
- self._bounding_box = (min_x, min_y, max_x - min_x, max_y - min_y)
- length = 0.0
- for i in range(1, len(self._points)):
- length += self._points[i - 1].distance(self._points[i])
- self._length = length
-
- def getPoints(self) -> List[GesturePoint]:
- return list(self._points)
-
- def getLength(self) -> float:
- return self._length
-
- def getBoundingBox(self) -> Tuple[float, float, float, float]:
- return self._bounding_box
-
- def getBoundingBoxCenter(self) -> Tuple[float, float]:
- x, y, w, h = self._bounding_box
- return (x + w / 2, y + h / 2)
-
- def getOrientation(self) -> float:
- return self._orientation
-
- def addPoint(self, point: GesturePoint):
- self._points.append(point)
- self._recalculate()
-
- def clear(self):
- self._points.clear()
- self._recalculate()
-
- def isLongEnough(self, minLength: float) -> bool:
- return self._length >= minLength
-
- def isShortEnough(self, maxLength: float) -> bool:
- return self._length <= maxLength
-
- def getDuration(self) -> int:
- if len(self._points) < 2:
- return 0
- return self._points[-1].getTimestamp() - self._points[0].getTimestamp()
-
- def toString(self) -> str:
- return f"GestureStroke(points={len(self._points)}, length={self._length:.1f})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, GestureStroke):
- return False
- return (self._length == other._length and
- self._bounding_box == other._bounding_box)
-
- def hashCode(self) -> int:
- return hash(self._bounding_box) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class GestureConfiguration(Stub):
- """GestureConfiguration — 手势配置"""
-
- def __init__(self):
- super().__init__()
- self._tap_timeout_ms = 300
- self._double_tap_timeout_ms = 400
- self._long_press_timeout_ms = 500
- self._swipe_min_distance = 50.0
- self._swipe_max_distance = 500.0
- self._fling_min_velocity = 200.0
- self._pinch_min_span = 20.0
- self._multi_finger_min_count = 2
- self._gesture_min_length = 10.0
- self._gesture_max_length = 500.0
- self._orientation_slop = 30.0
-
- def getTapTimeoutMs(self) -> int:
- return self._tap_timeout_ms
-
- def setTapTimeoutMs(self, timeout: int):
- self._tap_timeout_ms = timeout
-
- def getDoubleTapTimeoutMs(self) -> int:
- return self._double_tap_timeout_ms
-
- def setDoubleTapTimeoutMs(self, timeout: int):
- self._double_tap_timeout_ms = timeout
-
- def getLongPressTimeoutMs(self) -> int:
- return self._long_press_timeout_ms
-
- def setLongPressTimeoutMs(self, timeout: int):
- self._long_press_timeout_ms = timeout
-
- def getSwipeMinDistance(self) -> float:
- return self._swipe_min_distance
-
- def setSwipeMinDistance(self, distance: float):
- self._swipe_min_distance = distance
-
- def getSwipeMaxDistance(self) -> float:
- return self._swipe_max_distance
-
- def setSwipeMaxDistance(self, distance: float):
- self._swipe_max_distance = distance
-
- def getFlingMinVelocity(self) -> float:
- return self._fling_min_velocity
-
- def setFlingMinVelocity(self, velocity: float):
- self._fling_min_velocity = velocity
-
- def getPinchMinSpan(self) -> float:
- return self._pinch_min_span
-
- def setPinchMinSpan(self, span: float):
- self._pinch_min_span = span
-
- def getMultiFingerMinCount(self) -> int:
- return self._multi_finger_min_count
-
- def setMultiFingerMinCount(self, count: int):
- self._multi_finger_min_count = count
-
- def getGestureMinLength(self) -> float:
- return self._gesture_min_length
-
- def setGestureMinLength(self, length: float):
- self._gesture_min_length = length
-
- def getGestureMaxLength(self) -> float:
- return self._gesture_max_length
-
- def setGestureMaxLength(self, length: float):
- self._gesture_max_length = length
-
- def getOrientationSlop(self) -> float:
- return self._orientation_slop
-
- def setOrientationSlop(self, slop: float):
- self._orientation_slop = slop
-
- def toString(self) -> str:
- return f"GestureConfiguration(tap={self._tap_timeout_ms}ms)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureEvent
-# ═══════════════════════════════════════════════════════════════
-
-class GestureEvent(Stub):
- """GestureEvent — 手势事件"""
-
- def __init__(self, eventType: int = GESTURE_EVENT_TYPE_TAP,
- position: Tuple[float, float] = (0.0, 0.0),
- velocity: float = 0.0, direction: int = GESTURE_DIRECTION_ANY,
- span: float = 0.0, fingerCount: int = 1,
- stroke: Optional[GestureStroke] = None,
- timestamp: int = 0, state: int = GESTURE_STATE_COMPLETED):
- super().__init__()
- self._event_type = eventType
- self._x, self._y = position
- self._velocity = velocity
- self._direction = direction
- self._span = span
- self._finger_count = fingerCount
- self._stroke = stroke
- self._timestamp = timestamp or int(time.time() * 1000)
- self._state = state
-
- def getEventType(self) -> int:
- return self._event_type
-
- def getX(self) -> float:
- return self._x
-
- def getY(self) -> float:
- return self._y
-
- def getVelocity(self) -> float:
- return self._velocity
-
- def getDirection(self) -> int:
- return self._direction
-
- def getSpan(self) -> float:
- return self._span
-
- def getFingerCount(self) -> int:
- return self._finger_count
-
- def getStroke(self) -> Optional[GestureStroke]:
- return self._stroke
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def getState(self) -> int:
- return self._state
-
- def toString(self) -> str:
- return (f"GestureEvent(type={self._event_type}, "
- f"pos=({self._x:.0f},{self._y:.0f}))")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, GestureEvent):
- return False
- return (self._event_type == other._event_type and
- self._timestamp == other._timestamp)
-
- def hashCode(self) -> int:
- return hash((self._event_type, self._timestamp)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# 手势监听器
-# ═══════════════════════════════════════════════════════════════
-
-class GesturePerformedListener(Stub):
- """GesturePerformedListener — 手势执行监听器"""
-
- def onGesturePerformed(self, gesture: GestureStroke):
- pass
-
- def toString(self) -> str:
- return f"GesturePerformedListener@{hex(id(self))}"
-
-
-class GestureDrawingListener(Stub):
- """GestureDrawingListener — 手势绘制监听器"""
-
- def onGestureStarted(self, stroke: GestureStroke):
- pass
-
- def onGestureUpdated(self, stroke: GestureStroke):
- pass
-
- def onGestureCompleted(self, stroke: GestureStroke):
- pass
-
- def onGestureCancelled(self, stroke: GestureStroke):
- pass
-
- def toString(self) -> str:
- return f"GestureDrawingListener@{hex(id(self))}"
-
-
-class GestureInputListener(Stub):
- """GestureInputListener — 手势输入监听器"""
-
- def onGestureEvent(self, event: GestureEvent):
- pass
-
- def toString(self) -> str:
- return f"GestureInputListener@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureFeedback / GestureFeedbackProvider
-# ═══════════════════════════════════════════════════════════════
-
-class GestureFeedback(Stub):
- """GestureFeedback — 手势反馈"""
-
- def __init__(self, type_: int = GESTURE_FEEDBACK_NONE,
- intensity: float = 1.0, durationMs: int = 50):
- super().__init__()
- self._type = type_
- self._intensity = intensity
- self._duration_ms = durationMs
-
- def getType(self) -> int:
- return self._type
-
- def getIntensity(self) -> float:
- return self._intensity
-
- def getDurationMs(self) -> int:
- return self._duration_ms
-
- def toString(self) -> str:
- return f"GestureFeedback(type={self._type})"
-
-
-class GestureFeedbackProvider(Stub):
- """GestureFeedbackProvider — 手势反馈提供器"""
-
- def __init__(self):
- super().__init__()
- self._vibrate_enabled = True
- self._sound_enabled = False
- self._visual_enabled = False
-
- def provideFeedback(self, feedback: GestureFeedback):
- pass
-
- def isVibrateEnabled(self) -> bool:
- return self._vibrate_enabled
-
- def setVibrateEnabled(self, enabled: bool):
- self._vibrate_enabled = enabled
-
- def isSoundEnabled(self) -> bool:
- return self._sound_enabled
-
- def setSoundEnabled(self, enabled: bool):
- self._sound_enabled = enabled
-
- def isVisualEnabled(self) -> bool:
- return self._visual_enabled
-
- def setVisualEnabled(self, enabled: bool):
- self._visual_enabled = enabled
-
- def toString(self) -> str:
- return f"GestureFeedbackProvider(vibrate={self._vibrate_enabled})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureRecognizer
-# ═══════════════════════════════════════════════════════════════
-
-class GestureRecognizer(Stub):
- """GestureRecognizer — 手势识别器基类"""
-
- def __init__(self):
- super().__init__()
- self._listeners: List[GestureInputListener] = []
- self._configuration = GestureConfiguration()
- self._enabled = True
- self._current_stroke: Optional[GestureStroke] = None
-
- def addListener(self, listener: GestureInputListener):
- self._listeners.append(listener)
-
- def removeListener(self, listener: GestureInputListener):
- self._listeners = [l for l in self._listeners if l is not listener]
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def getConfiguration(self) -> GestureConfiguration:
- return self._configuration
-
- def setConfiguration(self, config: GestureConfiguration):
- self._configuration = config
-
- def reset(self):
- self._current_stroke = None
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- return None
-
- def toString(self) -> str:
- return f"GestureRecognizer@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TapGesture / DoubleTapGesture / LongPressGesture
-# ═══════════════════════════════════════════════════════════════
-
-class TapGesture(GestureRecognizer):
- """TapGesture — 点击手势识别器"""
-
- def __init__(self):
- super().__init__()
- self._touch_down_x = 0.0
- self._touch_down_y = 0.0
- self._touch_down_time = 0
- self._touch_down_id = -1
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- if not self._enabled:
- return None
- now = int(time.time() * 1000)
- if action == 0: # DOWN
- self._touch_down_x = x
- self._touch_down_y = y
- self._touch_down_time = now
- self._touch_down_id = pointerId
- elif action == 1: # UP
- if pointerId != self._touch_down_id:
- return None
- dt = now - self._touch_down_time
- dx = x - self._touch_down_x
- dy = y - self._touch_down_y
- dist = math.sqrt(dx * dx + dy * dy)
- if dt <= self._configuration.getTapTimeoutMs() and \
- dist <= 30.0:
- return GestureEvent(
- eventType=GESTURE_EVENT_TYPE_TAP,
- position=(x, y),
- fingerCount=1,
- state=GESTURE_STATE_COMPLETED,
- timestamp=now,
- )
- return None
-
-
-class DoubleTapGesture(GestureRecognizer):
- """DoubleTapGesture — 双击手势识别器"""
-
- def __init__(self):
- super().__init__()
- self._first_tap_time = 0
- self._first_tap_x = 0.0
- self._first_tap_y = 0.0
- self._touch_down_count = 0
- self._touch_down_id = -1
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- if not self._enabled:
- return None
- now = int(time.time() * 1000)
- if action == 1: # UP
- self._touch_down_count += 1
- if self._touch_down_count == 1:
- self._first_tap_time = now
- self._first_tap_x = x
- self._first_tap_y = y
- self._touch_down_id = pointerId
- elif self._touch_down_count == 2:
- dt = now - self._first_tap_time
- dx = x - self._first_tap_x
- dy = y - self._first_tap_y
- dist = math.sqrt(dx * dx + dy * dy)
- if dt <= self._configuration.getDoubleTapTimeoutMs() and \
- dist <= 40.0:
- self._touch_down_count = 0
- return GestureEvent(
- eventType=GESTURE_EVENT_TYPE_DOUBLE_TAP,
- position=(x, y),
- fingerCount=1,
- state=GESTURE_STATE_COMPLETED,
- timestamp=now,
- )
- self._touch_down_count = 1
- self._first_tap_time = now
- self._first_tap_x = x
- self._first_tap_y = y
- return None
-
-
-class LongPressGesture(GestureRecognizer):
- """LongPressGesture — 长按手势识别器"""
-
- def __init__(self):
- super().__init__()
- self._press_start_x = 0.0
- self._press_start_y = 0.0
- self._press_start_time = 0
- self._is_pressing = False
- self._has_fired = False
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- if not self._enabled:
- return None
- now = int(time.time() * 1000)
- if action == 0:
- self._press_start_x = x
- self._press_start_y = y
- self._press_start_time = now
- self._is_pressing = True
- self._has_fired = False
- elif action == 1:
- if self._is_pressing and not self._has_fired:
- dt = now - self._press_start_time
- if dt >= self._configuration.getLongPressTimeoutMs():
- self._has_fired = True
- self._is_pressing = False
- return GestureEvent(
- eventType=GESTURE_EVENT_TYPE_LONG_PRESS,
- position=(self._press_start_x, self._press_start_y),
- state=GESTURE_STATE_COMPLETED,
- timestamp=now,
- )
- self._is_pressing = False
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# SwipeGesture / ScrollGesture / FlingGesture
-# ═══════════════════════════════════════════════════════════════
-
-class SwipeGesture(GestureRecognizer):
- """SwipeGesture — 滑动手势识别器"""
-
- def __init__(self, direction: int = GESTURE_DIRECTION_ANY):
- super().__init__()
- self._direction = direction
- self._start_x = 0.0
- self._start_y = 0.0
- self._start_time = 0
- self._is_tracking = False
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- if not self._enabled:
- return None
- now = int(time.time() * 1000)
- if action == 0:
- self._start_x = x
- self._start_y = y
- self._start_time = now
- self._is_tracking = True
- elif action == 1 and self._is_tracking:
- dx = x - self._start_x
- dy = y - self._start_y
- dist = math.sqrt(dx * dx + dy * dy)
- min_dist = self._configuration.getSwipeMinDistance()
- max_dist = self._configuration.getSwipeMaxDistance()
- if min_dist <= dist <= max_dist:
- direction = self._compute_direction(dx, dy)
- if self._direction == GESTURE_DIRECTION_ANY or \
- self._direction == direction:
- self._is_tracking = False
- return GestureEvent(
- eventType=GESTURE_EVENT_TYPE_SWIPE,
- position=(x, y),
- direction=direction,
- stroke=GestureStroke([
- GesturePoint(self._start_x, self._start_y, self._start_time),
- GesturePoint(x, y, now),
- ]),
- state=GESTURE_STATE_COMPLETED,
- timestamp=now,
- )
- self._is_tracking = False
- return None
-
- def _compute_direction(self, dx: float, dy: float) -> int:
- angle = math.degrees(math.atan2(dy, dx))
- if -45 <= angle <= 45:
- return GESTURE_DIRECTION_RIGHT
- if 45 < angle <= 135:
- return GESTURE_DIRECTION_DOWN
- if -135 <= angle < -45:
- return GESTURE_DIRECTION_UP
- return GESTURE_DIRECTION_LEFT
-
-
-class ScrollGesture(GestureRecognizer):
- """ScrollGesture — 滚动手势识别器"""
-
- def __init__(self):
- super().__init__()
- self._start_x = 0.0
- self._start_y = 0.0
- self._last_x = 0.0
- self._last_y = 0.0
- self._is_scrolling = False
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- if not self._enabled:
- return None
- if action == 0:
- self._start_x = x
- self._start_y = y
- self._last_x = x
- self._last_y = y
- self._is_scrolling = False
- elif action == 2: # MOVE
- dx = x - self._last_x
- dy = y - self._last_y
- dist = math.sqrt(dx * dx + dy * dy)
- if dist > 5.0:
- self._is_scrolling = True
- self._last_x = x
- self._last_y = y
- return GestureEvent(
- eventType=GESTURE_EVENT_TYPE_SCROLL,
- position=(x, y),
- stroke=GestureStroke([
- GesturePoint(self._start_x, self._start_y, 0),
- GesturePoint(x, y, int(time.time() * 1000)),
- ]),
- state=GESTURE_STATE_IN_PROGRESS,
- )
- elif action == 1 and self._is_scrolling:
- self._is_scrolling = False
- return None
-
-
-class FlingGesture(GestureRecognizer):
- """FlingGesture — 甩动手势识别器"""
-
- def __init__(self):
- super().__init__()
- self._start_x = 0.0
- self._start_y = 0.0
- self._start_time = 0
- self._is_tracking = False
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- if not self._enabled:
- return None
- now = int(time.time() * 1000)
- if action == 0:
- self._start_x = x
- self._start_y = y
- self._start_time = now
- self._is_tracking = True
- elif action == 1 and self._is_tracking:
- dt = now - self._start_time
- if dt <= 0:
- return None
- dx = x - self._start_x
- dy = y - self._start_y
- dist = math.sqrt(dx * dx + dy * dy)
- velocity = dist / dt * 1000.0
- if velocity >= self._configuration.getFlingMinVelocity():
- self._is_tracking = False
- return GestureEvent(
- eventType=GESTURE_EVENT_TYPE_FLING,
- position=(x, y),
- velocity=velocity,
- state=GESTURE_STATE_COMPLETED,
- timestamp=now,
- )
- self._is_tracking = False
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# PinchGesture / DragGesture / MultiFingerGesture
-# ═══════════════════════════════════════════════════════════════
-
-class PinchGesture(GestureRecognizer):
- """PinchGesture — 捏合手势识别器"""
-
- def __init__(self):
- super().__init__()
- self._initial_span = 0.0
- self._current_span = 0.0
- self._finger1_start: Optional[Tuple[float, float]] = None
- self._finger2_start: Optional[Tuple[float, float]] = None
- self._active = False
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- return None
-
-
-class DragGesture(GestureRecognizer):
- """DragGesture — 拖拽手势识别器"""
-
- def __init__(self):
- super().__init__()
- self._start_x = 0.0
- self._start_y = 0.0
- self._is_dragging = False
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- if not self._enabled:
- return None
- if action == 0:
- self._start_x = x
- self._start_y = y
- self._is_dragging = False
- elif action == 2:
- dx = x - self._start_x
- dy = y - self._start_y
- dist = math.sqrt(dx * dx + dy * dy)
- if dist > 15.0:
- self._is_dragging = True
- return GestureEvent(
- eventType=GESTURE_EVENT_TYPE_DRAG,
- position=(x, y),
- state=GESTURE_STATE_IN_PROGRESS,
- )
- elif action == 1 and self._is_dragging:
- self._is_dragging = False
- return None
-
-
-class MultiFingerGesture(GestureRecognizer):
- """MultiFingerGesture — 多指手势识别器"""
-
- def __init__(self, minFingers: int = 2):
- super().__init__()
- self._min_fingers = minFingers
- self._active_pointers: Dict[int, Tuple[float, float]] = {}
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- if not self._enabled:
- return None
- if action == 0:
- self._active_pointers[pointerId] = (x, y)
- elif action == 1:
- self._active_pointers.pop(pointerId, None)
- if len(self._active_pointers) >= self._min_fingers:
- return GestureEvent(
- eventType=GESTURE_EVENT_TYPE_MULTI_FINGER_TAP,
- position=(x, y),
- fingerCount=len(self._active_pointers),
- state=GESTURE_STATE_COMPLETED,
- )
- elif action == 2:
- self._active_pointers[pointerId] = (x, y)
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# OrientationGesture
-# ═══════════════════════════════════════════════════════════════
-
-class OrientationGesture(GestureRecognizer):
- """OrientationGesture — 方向手势识别器"""
-
- def __init__(self, orientation: int = ORIENTATION_ANY):
- super().__init__()
- self._orientation = orientation
- self._start_x = 0.0
- self._start_y = 0.0
- self._is_tracking = False
-
- def processTouchEvent(self, x: float, y: float,
- action: int, pointerId: int = 0,
- pressure: float = 1.0) -> Optional[GestureEvent]:
- if not self._enabled:
- return None
- if action == 0:
- self._start_x = x
- self._start_y = y
- self._is_tracking = True
- elif action == 1 and self._is_tracking:
- dx = x - self._start_x
- dy = y - self._start_y
- orientation = self._compute_orientation(dx, dy)
- if self._orientation == ORIENTATION_ANY or self._orientation == orientation:
- self._is_tracking = False
- return GestureEvent(
- eventType=GESTURE_EVENT_TYPE_ORIENTATION,
- position=(x, y),
- state=GESTURE_STATE_COMPLETED,
- )
- self._is_tracking = False
- return None
-
- def _compute_orientation(self, dx: float, dy: float) -> int:
- adx = abs(dx)
- ady = abs(dy)
- if adx < 10 and ady < 10:
- return ORIENTATION_ANY
- if adx > ady * 2:
- return ORIENTATION_HORIZONTAL if dx > 0 else ORIENTATION_LEFT
- elif ady > adx * 2:
- return ORIENTATION_VERTICAL if dy > 0 else ORIENTATION_UP
- elif dx > 0 and dy > 0:
- return ORIENTATION_DIAGONAL_DOWN
- elif dx > 0 and dy < 0:
- return ORIENTATION_DIAGONAL_UP
- elif dx < 0 and dy > 0:
- return ORIENTATION_DIAGONAL_DOWN
- return ORIENTATION_DIAGONAL_UP
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureOverlayView (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class GestureOverlayView(Stub):
- """GestureOverlayView — 手势叠加视图 (完整版)"""
-
- GESTURE_STROKE_TYPE_SINGLE = 0
- GESTURE_STROKE_TYPE_MULTIPLE = 1
-
- ORIENTATION_HORIZONTAL = ORIENTATION_HORIZONTAL
- ORIENTATION_VERTICAL = ORIENTATION_VERTICAL
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._current_stroke: Optional[GestureStroke] = None
- self._gestures: List[GestureStroke] = []
- self._stroke_type = GestureOverlayView.GESTURE_STROKE_TYPE_SINGLE
- self._gesture_color = 0xFFFFFF00
- self._gesture_length = 0.0
- self._is_gesture_visible = True
- self._events_enabled = True
- self._performed_listeners: List[GesturePerformedListener] = []
- self._drawing_listeners: List[GestureDrawingListener] = []
- self._gesture_recognizer = GestureRecognizer()
-
- def getCurrentStroke(self) -> Optional[GestureStroke]:
- return self._current_stroke
-
- def getGestures(self) -> List[GestureStroke]:
- return list(self._gestures)
-
- def setGestureColor(self, color: int):
- self._gesture_color = color
-
- def getGestureColor(self) -> int:
- return self._gesture_color
-
- def setGestureStrokeType(self, type_: int):
- self._stroke_type = type_
-
- def getGestureStrokeType(self) -> int:
- return self._stroke_type
-
- def setGestureStrokeLengthThreshold(self, length: float):
- self._gesture_length = length
-
- def getGestureStrokeLengthThreshold(self) -> float:
- return self._gesture_length
-
- def setGestureVisible(self, visible: bool):
- self._is_gesture_visible = visible
-
- def isGestureVisible(self) -> bool:
- return self._is_gesture_visible
-
- def setEventsEnabled(self, enabled: bool):
- self._events_enabled = enabled
-
- def isEventsEnabled(self) -> bool:
- return self._events_enabled
-
- def addOnGesturePerformedListener(self, listener: GesturePerformedListener):
- self._performed_listeners.append(listener)
-
- def removeOnGesturePerformedListener(self, listener: GesturePerformedListener):
- self._performed_listeners = [l for l in self._performed_listeners if l is not listener]
-
- def addOnGestureDrawingListener(self, listener: GestureDrawingListener):
- self._drawing_listeners.append(listener)
-
- def removeOnGestureDrawingListener(self, listener: GestureDrawingListener):
- self._drawing_listeners = [l for l in self._drawing_listeners if l is not listener]
-
- def clear(self):
- self._gestures.clear()
- self._current_stroke = None
-
- def cancelGesture(self):
- if self._current_stroke:
- for l in self._drawing_listeners:
- l.onGestureCancelled(self._current_stroke)
- self._current_stroke = None
-
- def toString(self) -> str:
- return f"GestureOverlayView(strokes={len(self._gestures)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureBuilderActivity
-# ═══════════════════════════════════════════════════════════════
-
-class GestureBuilderActivity(Stub):
- """GestureBuilderActivity — 手势构建器活动"""
-
- def __init__(self):
- super().__init__()
- self._overlay = GestureOverlayView()
- self._library: Optional["GestureLibraries"] = None
- self._current_name: str = ""
-
- def getGestureOverlayView(self) -> GestureOverlayView:
- return self._overlay
-
- def setGestureLibrary(self, library: "GestureLibraries"):
- self._library = library
-
- def getGestureLibrary(self) -> Optional["GestureLibraries"]:
- return self._library
-
- def setCurrentGestureName(self, name: str):
- self._current_name = name
-
- def getCurrentGestureName(self) -> str:
- return self._current_name
-
- def saveGesture(self):
- if self._library and self._current_name and self._overlay.getCurrentStroke():
- stroke = self._overlay.getCurrentStroke()
- self._library.store(self._current_name, stroke)
- self._library.save()
-
- def toString(self) -> str:
- return f"GestureBuilderActivity(name={self._current_name})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureLibraries
-# ═══════════════════════════════════════════════════════════════
-
-class GestureLibraries(Stub):
- """GestureLibraries — 手势库"""
-
- def __init__(self, storeType: int = GESTURE_LIBRARY_FILE,
- path: str = "", loadOnInit: bool = True):
- super().__init__()
- self._store_type = storeType
- self._path = path
- self._gestures: Dict[str, List[GestureStroke]] = {}
- self._loaded = False if loadOnInit else False
-
- def load(self) -> bool:
- self._loaded = True
- return True
-
- def save(self) -> bool:
- return True
-
- def isLoaded(self) -> bool:
- return self._loaded
-
- def getGestures(self, name: str) -> List[GestureStroke]:
- return self._gestures.get(name, [])
-
- def getGestureNames(self) -> List[str]:
- return list(self._gestures.keys())
-
- def store(self, name: str, stroke: GestureStroke):
- if name not in self._gestures:
- self._gestures[name] = []
- self._gestures[name].append(stroke)
-
- def remove(self, name: str):
- self._gestures.pop(name, None)
-
- def removeEntry(self, name: str, stroke: GestureStroke):
- strokes = self._gestures.get(name)
- if strokes:
- try:
- strokes.remove(stroke)
- except ValueError:
- pass
- if not strokes:
- self._gestures.pop(name, None)
-
- def getCount(self) -> int:
- return sum(len(s) for s in self._gestures.values())
-
- @staticmethod
- def fromFile(path: str) -> "GestureLibraries":
- return GestureLibraries(storeType=GESTURE_LIBRARY_FILE, path=path)
-
- @staticmethod
- def fromResource(context: Any, resourceId: int) -> "GestureLibraries":
- return GestureLibraries(storeType=GESTURE_LIBRARY_RESOURCE, path=str(resourceId))
-
- @staticmethod
- def fromRaw(context: Any, resourceId: int) -> "GestureLibraries":
- return GestureLibraries(storeType=GESTURE_LIBRARY_RAW, path=str(resourceId))
-
- @staticmethod
- def fromPrivateFile(context: Any, name: str) -> "GestureLibraries":
- return GestureLibraries(storeType=GESTURE_LIBRARY_PRIVATE, path=name)
-
- def toString(self) -> str:
- return f"GestureLibraries(type={self._store_type}, gestures={self.getCount()})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/graphics.py b/android_pyapi/android/graphics.py
deleted file mode 100644
index 86e4f98..0000000
--- a/android_pyapi/android/graphics.py
+++ /dev/null
@@ -1,3455 +0,0 @@
-"""
-Android Graphics 组件 — Bitmap, Canvas, Paint, Color, Path, Rect 等
-方法签名完全对齐 Android SDK
-"""
-
-import array
-import math
-import struct
-import io
-import os
-import time
-from enum import IntEnum
-from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError, android_context, HAS_PIL, resolve_android_path
-
-# Re-export Typeface from text module
-from .text import Typeface
-
-
-# ═══════════════════════════════════════════════════════════════
-# Color
-# ═══════════════════════════════════════════════════════════════
-
-class Color(Stub):
- """Color — 颜色工具类"""
-
- BLACK = 0xFF000000
- DKGRAY = 0xFF444444
- GRAY = 0xFF888888
- LTGRAY = 0xFFCCCCCC
- WHITE = 0xFFFFFFFF
- RED = 0xFFFF0000
- GREEN = 0xFF00FF00
- BLUE = 0xFF0000FF
- YELLOW = 0xFFFFFF00
- CYAN = 0xFF00FFFF
- MAGENTA = 0xFFFF00FF
- TRANSPARENT = 0
-
- @staticmethod
- def alpha(color: int) -> int:
- return (color >> 24) & 0xFF
-
- @staticmethod
- def red(color: int) -> int:
- return (color >> 16) & 0xFF
-
- @staticmethod
- def green(color: int) -> int:
- return (color >> 8) & 0xFF
-
- @staticmethod
- def blue(color: int) -> int:
- return color & 0xFF
-
- @staticmethod
- def rgb(r: int, g: int, b: int) -> int:
- return 0xFF000000 | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF)
-
- @staticmethod
- def argb(a: int, r: int, g: int, b: int) -> int:
- return ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF)
-
- @staticmethod
- def parseColor(colorString: str) -> int:
- s = colorString.strip()
- if s.startswith("#"):
- s = s[1:]
- if len(s) == 3:
- s = "".join(c * 2 for c in s)
- if len(s) == 6:
- s = "FF" + s
- return int(s, 16) & 0xFFFFFFFF
- if s.startswith("0x"):
- return int(s, 16) & 0xFFFFFFFF
- name_map = {
- "black": Color.BLACK, "white": Color.WHITE, "red": Color.RED,
- "green": Color.GREEN, "blue": Color.BLUE, "yellow": Color.YELLOW,
- "cyan": Color.CYAN, "magenta": Color.MAGENTA, "transparent": Color.TRANSPARENT,
- "dkgray": Color.DKGRAY, "gray": Color.GRAY, "ltgray": Color.LTGRAY,
- "darkgray": Color.DKGRAY, "lightgray": Color.LTGRAY,
- }
- return name_map.get(s.lower(), Color.BLACK)
-
- @staticmethod
- def RGBToHSV(red: int, green: int, blue: int, hsv: List[float]):
- r, g, b = red / 255.0, green / 255.0, blue / 255.0
- mx = max(r, g, b)
- mn = min(r, g, b)
- df = mx - mn
- if df == 0:
- h = 0.0
- elif mx == r:
- h = ((g - b) / df) % 6.0
- elif mx == g:
- h = (b - r) / df + 2.0
- else:
- h = (r - g) / df + 4.0
- h = h * 60.0
- if h < 0:
- h += 360.0
- s = 0.0 if mx == 0 else (df / mx)
- v = mx
- hsv[0] = h
- hsv[1] = s
- hsv[2] = v
-
- @staticmethod
- def HSVToColor(hsv: List[float]) -> int:
- return Color.HSVToColor(255, hsv)
-
- @staticmethod
- def HSVToColor(alpha: int, hsv: List[float]) -> int:
- h, s, v = hsv[0], hsv[1], hsv[2]
- hi = int(h / 60.0) % 6
- f = (h / 60.0) - hi
- p = v * (1.0 - s)
- q = v * (1.0 - f * s)
- t = v * (1.0 - (1.0 - f) * s)
- if hi == 0:
- r, g, b = v, t, p
- elif hi == 1:
- r, g, b = q, v, p
- elif hi == 2:
- r, g, b = p, v, t
- elif hi == 3:
- r, g, b = p, q, v
- elif hi == 4:
- r, g, b = t, p, v
- else:
- r, g, b = v, p, q
- return Color.argb(alpha, int(r * 255 + 0.5), int(g * 255 + 0.5), int(b * 255 + 0.5))
-
- @staticmethod
- def ColorToHSV(color: int, hsv: List[float]):
- Color.RGBToHSV(Color.red(color), Color.green(color), Color.blue(color), hsv)
-
- @staticmethod
- def getHue(color: int) -> float:
- hsv = [0.0, 0.0, 0.0]
- Color.ColorToHSV(color, hsv)
- return hsv[0]
-
- @staticmethod
- def getSaturation(color: int) -> float:
- hsv = [0.0, 0.0, 0.0]
- Color.ColorToHSV(color, hsv)
- return hsv[1]
-
- @staticmethod
- def getBrightness(color: int) -> float:
- hsv = [0.0, 0.0, 0.0]
- Color.ColorToHSV(color, hsv)
- return hsv[2]
-
- @staticmethod
- def HSLToColor(hsl: List[float], alpha: float = 1.0) -> int:
- h, s, l = hsl[0] / 360.0, hsl[1], hsl[2]
- if s == 0:
- r = g = b = l
- else:
- def hue2rgb(p, q, t):
- if t < 0:
- t += 1
- if t > 1:
- t -= 1
- if t < 1.0 / 6.0:
- return p + (q - p) * 6.0 * t
- if t < 1.0 / 2.0:
- return q
- if t < 2.0 / 3.0:
- return p + (q - p) * (2.0 / 3.0 - t) * 6.0
- return p
- q = l * (1 + s) if l < 0.5 else l + s - l * s
- p = 2 * l - q
- r = hue2rgb(p, q, h + 1.0 / 3.0)
- g = hue2rgb(p, q, h)
- b = hue2rgb(p, q, h - 1.0 / 3.0)
- a = max(0, min(255, int(alpha * 255)))
- return Color.argb(a, int(r * 255), int(g * 255), int(b * 255))
-
- @staticmethod
- def ColorToHSL(color: int, hsl: List[float]):
- r, g, b = Color.red(color) / 255.0, Color.green(color) / 255.0, Color.blue(color) / 255.0
- mx = max(r, g, b)
- mn = min(r, g, b)
- l = (mx + mn) / 2.0
- if mx == mn:
- h = 0.0
- s = 0.0
- else:
- d = mx - mn
- s = d / (1 - abs(2 * l - 1))
- if mx == r:
- h = ((g - b) / d) % 6.0
- elif mx == g:
- h = (b - r) / d + 2.0
- else:
- h = (r - g) / d + 4.0
- h = h * 60.0
- if h < 0:
- h += 360.0
- hsl[0] = h
- hsl[1] = s
- hsl[2] = l
-
-
-# ═══════════════════════════════════════════════════════════════
-# Rect
-# ═══════════════════════════════════════════════════════════════
-
-class Rect(Stub):
- """Rect — 矩形 (int 坐标)"""
-
- def __init__(self, left: int = 0, top: int = 0, right: int = 0, bottom: int = 0):
- super().__init__()
- self.left = left
- self.top = top
- self.right = right
- self.bottom = bottom
-
- def width(self) -> int:
- return self.right - self.left
-
- def height(self) -> int:
- return self.bottom - self.top
-
- def centerX(self) -> int:
- return (self.left + self.right) // 2
-
- def centerY(self) -> int:
- return (self.top + self.bottom) // 2
-
- def exactCenterX(self) -> float:
- return (self.left + self.right) * 0.5
-
- def exactCenterY(self) -> float:
- return (self.top + self.bottom) * 0.5
-
- def set(self, left: int, top: int, right: int, bottom: int):
- self.left, self.top, self.right, self.bottom = left, top, right, bottom
-
- def offset(self, dx: int, dy: int):
- self.left += dx
- self.top += dy
- self.right += dx
- self.bottom += dy
-
- def offsetTo(self, newLeft: int, newTop: int):
- self.right += newLeft - self.left
- self.bottom += newTop - self.top
- self.left = newLeft
- self.top = newTop
-
- def inset(self, dx: int, dy: int):
- self.left += dx
- self.top += dy
- self.right -= dx
- self.bottom -= dy
-
- def contains(self, *args) -> bool:
- if len(args) == 2:
- x, y = args
- return (self.left < self.right and self.top < self.bottom
- and x >= self.left and x < self.right and y >= self.top and y < self.bottom)
- elif len(args) == 4:
- left, top, right, bottom = args
- return (self.left < self.right and self.top < self.bottom
- and self.left <= left and self.top <= top
- and self.right >= right and self.bottom >= bottom)
- return False
-
- def intersect(self, left: int, top: int, right: int, bottom: int) -> bool:
- nL = max(self.left, left)
- nT = max(self.top, top)
- nR = min(self.right, right)
- nB = min(self.bottom, bottom)
- if nL < nR and nT < nB:
- self.left, self.top, self.right, self.bottom = nL, nT, nR, nB
- return True
- return False
-
- def intersects(self, left: int, top: int, right: int, bottom: int) -> bool:
- return self.left < right and self.right > left \
- and self.top < bottom and self.bottom > top
-
- @staticmethod
- def intersects(a: "Rect", b: "Rect") -> bool:
- return a.left < b.right and a.right > b.left \
- and a.top < b.bottom and a.bottom > b.top
-
- def union(self, left: int, top: int, right: int, bottom: int):
- if self.isEmpty():
- self.set(left, top, right, bottom)
- else:
- self.left = min(self.left, left)
- self.top = min(self.top, top)
- self.right = max(self.right, right)
- self.bottom = max(self.bottom, bottom)
-
- def sort(self):
- if self.left > self.right:
- self.left, self.right = self.right, self.left
- if self.top > self.bottom:
- self.top, self.bottom = self.bottom, self.top
-
- def isEmpty(self) -> bool:
- return self.left >= self.right or self.top >= self.bottom
-
- def setEmpty(self):
- self.left = self.top = self.right = self.bottom = 0
-
- def toShortString(self) -> str:
- return f"[{self.left},{self.top}][{self.right},{self.bottom}]"
-
- def flattenToString(self) -> str:
- return f"{self.left} {self.top} {self.right} {self.bottom}"
-
- @staticmethod
- def unflattenFromString(s: str) -> "Rect":
- parts = s.split()
- if len(parts) >= 4:
- return Rect(int(parts[0]), int(parts[1]), int(parts[2]), int(parts[3]))
- return Rect()
-
- def toString(self) -> str:
- return f"Rect({self.left}, {self.top}, {self.right}, {self.bottom})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RectF
-# ═══════════════════════════════════════════════════════════════
-
-class RectF(Stub):
- """RectF — 矩形 (float 坐标)"""
-
- def __init__(self, left: float = 0.0, top: float = 0.0, right: float = 0.0, bottom: float = 0.0):
- super().__init__()
- self.left = left
- self.top = top
- self.right = right
- self.bottom = bottom
-
- def width(self) -> float:
- return self.right - self.left
-
- def height(self) -> float:
- return self.bottom - self.top
-
- def centerX(self) -> float:
- return (self.left + self.right) * 0.5
-
- def centerY(self) -> float:
- return (self.top + self.bottom) * 0.5
-
- def set(self, left: float, top: float, right: float, bottom: float):
- self.left, self.top, self.right, self.bottom = left, top, right, bottom
-
- def offset(self, dx: float, dy: float):
- self.left += dx
- self.top += dy
- self.right += dx
- self.bottom += dy
-
- def offsetTo(self, newLeft: float, newTop: float):
- self.right += newLeft - self.left
- self.bottom += newTop - self.top
- self.left = newLeft
- self.top = newTop
-
- def inset(self, dx: float, dy: float):
- self.left += dx
- self.top += dy
- self.right -= dx
- self.bottom -= dy
-
- def contains(self, x: float, y: float) -> bool:
- return self.left < self.right and self.top < self.bottom \
- and x >= self.left and x < self.right and y >= self.top and y < self.bottom
-
- def intersect(self, left: float, top: float, right: float, bottom: float) -> bool:
- nL = max(self.left, left)
- nT = max(self.top, top)
- nR = min(self.right, right)
- nB = min(self.bottom, bottom)
- if nL < nR and nT < nB:
- self.left, self.top, self.right, self.bottom = nL, nT, nR, nB
- return True
- return False
-
- def intersects(self, left: float, top: float, right: float, bottom: float) -> bool:
- return self.left < right and self.right > left \
- and self.top < bottom and self.bottom > top
-
- @staticmethod
- def intersects(a: "RectF", b: "RectF") -> bool:
- return a.left < b.right and a.right > b.left \
- and a.top < b.bottom and a.bottom > b.top
-
- def union(self, left: float, top: float, right: float, bottom: float):
- if self.isEmpty():
- self.set(left, top, right, bottom)
- else:
- self.left = min(self.left, left)
- self.top = min(self.top, top)
- self.right = max(self.right, right)
- self.bottom = max(self.bottom, bottom)
-
- def round(self, r: Rect):
- r.left = int(self.left + 0.5)
- r.top = int(self.top + 0.5)
- r.right = int(self.right + 0.5)
- r.bottom = int(self.bottom + 0.5)
-
- def roundOut(self, r: Rect):
- r.left = int(math.floor(self.left))
- r.top = int(math.floor(self.top))
- r.right = int(math.ceil(self.right))
- r.bottom = int(math.ceil(self.bottom))
-
- def sort(self):
- if self.left > self.right:
- self.left, self.right = self.right, self.left
- if self.top > self.bottom:
- self.top, self.bottom = self.bottom, self.top
-
- def isEmpty(self) -> bool:
- return self.left >= self.right or self.top >= self.bottom
-
- def setEmpty(self):
- self.left = self.top = self.right = self.bottom = 0.0
-
- def toShortString(self) -> str:
- return f"[{self.left:.1f},{self.top:.1f}][{self.right:.1f},{self.bottom:.1f}]"
-
- def toString(self) -> str:
- return f"RectF({self.left}, {self.top}, {self.right}, {self.bottom})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Point / PointF
-# ═══════════════════════════════════════════════════════════════
-
-class Point(Stub):
- """Point — 整数坐标点"""
-
- def __init__(self, x: int = 0, y: int = 0):
- super().__init__()
- self.x = x
- self.y = y
-
- def set(self, x: int, y: int):
- self.x, self.y = x, y
-
- def offset(self, dx: int, dy: int):
- self.x += dx
- self.y += dy
-
- def equals(self, other) -> bool:
- if isinstance(other, Point):
- return self.x == other.x and self.y == other.y
- return False
-
- def hashCode(self) -> int:
- return self.x * 32713 + self.y
-
- def toString(self) -> str:
- return f"Point({self.x}, {self.y})"
-
-
-class PointF(Stub):
- """PointF — 浮点坐标点"""
-
- def __init__(self, x: float = 0.0, y: float = 0.0):
- super().__init__()
- self.x = x
- self.y = y
-
- def set(self, x: float, y: float):
- self.x, self.y = x, y
-
- def offset(self, dx: float, dy: float):
- self.x += dx
- self.y += dy
-
- def equals(self, other) -> bool:
- if isinstance(other, PointF):
- return self.x == other.x and self.y == other.y
- return False
-
- def hashCode(self) -> int:
- return int(self.x * 32713 + self.y)
-
- def toString(self) -> str:
- return f"PointF({self.x}, {self.y})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Path
-# ═══════════════════════════════════════════════════════════════
-
-class Path(Stub):
- """Path — 路径"""
-
- class Direction:
- CW = 0
- CCW = 1
-
- class FillType:
- WINDING = 0
- EVEN_ODD = 1
- INVERSE_WINDING = 2
- INVERSE_EVEN_ODD = 3
-
- class Op:
- DIFFERENCE = 0
- INTERSECT = 1
- UNION = 2
- XOR = 3
- REVERSE_DIFFERENCE = 4
-
- def __init__(self):
- super().__init__()
- self._segments: List[dict] = []
- self._fill_type = Path.FillType.WINDING
- self._start_x = 0.0
- self._start_y = 0.0
- self._current_x = 0.0
- self._current_y = 0.0
-
- def moveTo(self, x: float, y: float):
- self._segments.append({"type": "move", "x": x, "y": y})
- self._current_x = x
- self._current_y = y
-
- def lineTo(self, x: float, y: float):
- self._segments.append({"type": "line", "x": x, "y": y})
- self._current_x = x
- self._current_y = y
-
- def quadTo(self, x1: float, y1: float, x2: float, y2: float):
- self._segments.append({"type": "quad", "x1": x1, "y1": y1, "x2": x2, "y2": y2})
- self._current_x = x2
- self._current_y = y2
-
- def cubicTo(self, x1: float, y1: float, x2: float, y2: float, x3: float, y3: float):
- self._segments.append({"type": "cubic", "x1": x1, "y1": y1, "x2": x2, "y2": y2, "x3": x3, "y3": y3})
- self._current_x = x3
- self._current_y = y3
-
- def rMoveTo(self, dx: float, dy: float):
- self.moveTo(self._current_x + dx, self._current_y + dy)
-
- def rLineTo(self, dx: float, dy: float):
- self.lineTo(self._current_x + dx, self._current_y + dy)
-
- def rQuadTo(self, dx1: float, dy1: float, dx2: float, dy2: float):
- self.quadTo(self._current_x + dx1, self._current_y + dy1,
- self._current_x + dx2, self._current_y + dy2)
-
- def rCubicTo(self, dx1: float, dy1: float, dx2: float, dy2: float, dx3: float, dy3: float):
- self.cubicTo(self._current_x + dx1, self._current_y + dy1,
- self._current_x + dx2, self._current_y + dy2,
- self._current_x + dx3, self._current_y + dy3)
-
- def addRect(self, left: float, top: float, right: float, bottom: float,
- dir: int = Direction.CW):
- self.moveTo(left, top)
- self.lineTo(right, top)
- self.lineTo(right, bottom)
- self.lineTo(left, bottom)
- self.close()
-
- def addRoundRect(self, rect: Union["RectF", tuple], rx: float, ry: float,
- dir: int = Direction.CW):
- if isinstance(rect, RectF):
- l, t, r, b = rect.left, rect.top, rect.right, rect.bottom
- else:
- l, t, r, b = rect
- self.moveTo(l + rx, t)
- self.lineTo(r - rx, t)
- self.quadTo(r, t, r, t + ry)
- self.lineTo(r, b - ry)
- self.quadTo(r, b, r - rx, b)
- self.lineTo(l + rx, b)
- self.quadTo(l, b, l, b - ry)
- self.lineTo(l, t + ry)
- self.quadTo(l, t, l + rx, t)
- self.close()
-
- def addCircle(self, x: float, y: float, radius: float, dir: int = Direction.CW):
- k = 0.5522847498
- self.moveTo(x + radius, y)
- self.cubicTo(x + radius, y + radius * k, x + radius * k, y + radius, x, y + radius)
- self.cubicTo(x - radius * k, y + radius, x - radius, y + radius * k, x - radius, y)
- self.cubicTo(x - radius, y - radius * k, x - radius * k, y - radius, x, y - radius)
- self.cubicTo(x + radius * k, y - radius, x + radius, y - radius * k, x + radius, y)
- self.close()
-
- def addOval(self, rect: Union["RectF", tuple], dir: int = Direction.CW):
- if isinstance(rect, RectF):
- l, t, r, b = rect.left, rect.top, rect.right, rect.bottom
- else:
- l, t, r, b = rect
- cx = (l + r) / 2.0
- cy = (t + b) / 2.0
- rx = (r - l) / 2.0
- ry = (b - t) / 2.0
- kx = rx * 0.5522847498
- ky = ry * 0.5522847498
- self.moveTo(cx + rx, cy)
- self.cubicTo(cx + rx, cy + ky, cx + kx, cy + ry, cx, cy + ry)
- self.cubicTo(cx - kx, cy + ry, cx - rx, cy + ky, cx - rx, cy)
- self.cubicTo(cx - rx, cy - ky, cx - kx, cy - ry, cx, cy - ry)
- self.cubicTo(cx + kx, cy - ry, cx + rx, cy - ky, cx + rx, cy)
- self.close()
-
- def addArc(self, rect: Union["RectF", tuple], startAngle: float, sweepAngle: float):
- if isinstance(rect, RectF):
- l, t, r, b = rect.left, rect.top, rect.right, rect.bottom
- else:
- l, t, r, b = rect
- cx = (l + r) / 2.0
- cy = (t + b) / 2.0
- rx = (r - l) / 2.0
- ry = (b - t) / 2.0
- start_rad = math.radians(startAngle)
- end_rad = math.radians(startAngle + sweepAngle)
- segments = 4
- da = (end_rad - start_rad) / segments
- for i in range(segments + 1):
- a = start_rad + i * da
- px = cx + rx * math.cos(a)
- py = cy + ry * math.sin(a)
- if i == 0:
- self.moveTo(px, py)
- else:
- self.lineTo(px, py)
-
- def addPath(self, path: "Path", dx: float = 0.0, dy: float = 0.0):
- for seg in path._segments:
- s = dict(seg)
- if "x" in s:
- s["x"] = s["x"] + dx
- if "y" in s:
- s["y"] = s["y"] + dy
- if "x1" in s:
- s["x1"] = s["x1"] + dx
- if "y1" in s:
- s["y1"] = s["y1"] + dy
- if "x2" in s:
- s["x2"] = s["x2"] + dx
- if "y2" in s:
- s["y2"] = s["y2"] + dy
- if "x3" in s:
- s["x3"] = s["x3"] + dx
- if "y3" in s:
- s["y3"] = s["y3"] + dy
- self._segments.append(s)
- self._current_x = path._current_x + dx
- self._current_y = path._current_y + dy
-
- def arcTo(self, rect: Union["RectF", tuple], startAngle: float, sweepAngle: float,
- forceMoveTo: bool = False):
- if isinstance(rect, RectF):
- l, t, r, b = rect.left, rect.top, rect.right, rect.bottom
- else:
- l, t, r, b = rect
- cx = (l + r) / 2.0
- cy = (t + b) / 2.0
- rx = (r - l) / 2.0
- ry = (b - t) / 2.0
- start_rad = math.radians(startAngle)
- end_rad = math.radians(startAngle + sweepAngle)
- segments = 4
- da = (end_rad - start_rad) / segments
- for i in range(segments + 1):
- a = start_rad + i * da
- px = cx + rx * math.cos(a)
- py = cy + ry * math.sin(a)
- if i == 0 and forceMoveTo:
- self.moveTo(px, py)
- elif i == 0:
- self.lineTo(px, py)
- else:
- self.lineTo(px, py)
-
- def close(self):
- self._segments.append({"type": "close"})
-
- def reset(self):
- self._segments.clear()
- self._current_x = 0.0
- self._current_y = 0.0
-
- def rewind(self):
- self._segments.clear()
- self._current_x = 0.0
- self._current_y = 0.0
-
- def set(self, src: "Path"):
- self._segments = list(src._segments)
- self._fill_type = src._fill_type
- self._current_x = src._current_x
- self._current_y = src._current_y
-
- def computeBounds(self, exact: bool = False) -> RectF:
- if not self._segments:
- return RectF(0, 0, 0, 0)
- min_x = float("inf")
- min_y = float("inf")
- max_x = float("-inf")
- max_y = float("-inf")
- for seg in self._segments:
- for key in ("x", "x1", "x2", "x3"):
- if key in seg:
- if seg[key] < min_x:
- min_x = seg[key]
- if seg[key] > max_x:
- max_x = seg[key]
- for key in ("y", "y1", "y2", "y3"):
- if key in seg:
- if seg[key] < min_y:
- min_y = seg[key]
- if seg[key] > max_y:
- max_y = seg[key]
- if min_x == float("inf"):
- return RectF(0, 0, 0, 0)
- return RectF(min_x, min_y, max_x, max_y)
-
- def incReserve(self, extraPtCount: int):
- pass
-
- def op(self, other: "Path", op: int) -> bool:
- """对两个路径执行布尔运算。基于包围盒的近似实现。"""
- if other is None:
- return False
- self_bounds = self.computeBounds()
- other_bounds = other.computeBounds()
- if op == Path.Op.UNION:
- # 合并:将 other 的段追加到 self
- self.addPath(other)
- return True
- if op == Path.Op.INTERSECT:
- # 交集:仅当包围盒相交时保留相交区域
- if not RectF.intersects(self_bounds, other_bounds):
- self.reset()
- return False
- # 用相交包围盒作为近似结果
- inter = RectF(self_bounds.left, self_bounds.top,
- self_bounds.right, self_bounds.bottom)
- inter.intersect(other_bounds.left, other_bounds.top,
- other_bounds.right, other_bounds.bottom)
- self.reset()
- self.addRect(inter.left, inter.top, inter.right, inter.bottom)
- return True
- if op == Path.Op.DIFFERENCE:
- # 差集:若包围盒不相交则 self 不变,否则标记(近似)
- if not RectF.intersects(self_bounds, other_bounds):
- return True
- # 近似:无法精确计算,保留 self 不变
- return True
- if op == Path.Op.REVERSE_DIFFERENCE:
- # 反向差集:用 other 替换 self
- self.set(other)
- return True
- if op == Path.Op.XOR:
- # 异或:合并两者
- self.addPath(other)
- return True
- return False
-
- def isRect(self) -> bool:
- if len(self._segments) != 5:
- return False
- types = [s["type"] for s in self._segments]
- return types == ["move", "line", "line", "line", "close"]
-
- def isConvex(self) -> bool:
- return True
-
- def setFillType(self, ft: int):
- self._fill_type = ft
-
- def getFillType(self) -> int:
- return self._fill_type
-
- def toggleReverseFillType(self):
- mapping = {
- Path.FillType.WINDING: Path.FillType.INVERSE_WINDING,
- Path.FillType.EVEN_ODD: Path.FillType.INVERSE_EVEN_ODD,
- Path.FillType.INVERSE_WINDING: Path.FillType.WINDING,
- Path.FillType.INVERSE_EVEN_ODD: Path.FillType.EVEN_ODD,
- }
- self._fill_type = mapping.get(self._fill_type, Path.FillType.WINDING)
-
-
-# ═══════════════════════════════════════════════════════════════
-# PathMeasure
-# ═══════════════════════════════════════════════════════════════
-
-class PathMeasure(Stub):
- """PathMeasure — 路径测量"""
-
- def __init__(self, path: Path = None, forceClosed: bool = False):
- super().__init__()
- self._path = path
- self._force_closed = forceClosed
- self._contours: List[List[Tuple[float, float, float]]] = []
- self._contour_lengths: List[float] = []
- self._total_length: float = 0.0
- if path is not None:
- self._flatten()
-
- def _flatten(self):
- """将路径展平为线段列表,计算累积长度。"""
- self._contours = []
- self._contour_lengths = []
- self._total_length = 0.0
- if not self._path:
- return
- segs = self._path._segments
- cur_x = 0.0
- cur_y = 0.0
- start_x = 0.0
- start_y = 0.0
- contour: List[Tuple[float, float, float]] = []
- contour_len = 0.0
- for seg in segs:
- t = seg.get("type")
- if t == "move":
- if contour:
- self._contours.append(contour)
- self._contour_lengths.append(contour_len)
- self._total_length += contour_len
- cur_x = seg.get("x", 0.0)
- cur_y = seg.get("y", 0.0)
- start_x = cur_x
- start_y = cur_y
- contour = [(cur_x, cur_y, 0.0)]
- contour_len = 0.0
- elif t == "line":
- nx = seg.get("x", cur_x)
- ny = seg.get("y", cur_y)
- d = math.hypot(nx - cur_x, ny - cur_y)
- contour_len += d
- contour.append((nx, ny, contour_len))
- cur_x = nx
- cur_y = ny
- elif t == "quad":
- x1, y1 = seg.get("x1", cur_x), seg.get("y1", cur_y)
- x2, y2 = seg.get("x2", cur_x), seg.get("y2", cur_y)
- steps = 16
- prev_x, prev_y = cur_x, cur_y
- for i in range(1, steps + 1):
- tt = i / steps
- mt = 1 - tt
- nx = mt * mt * cur_x + 2 * mt * tt * x1 + tt * tt * x2
- ny = mt * mt * cur_y + 2 * mt * tt * y1 + tt * tt * y2
- d = math.hypot(nx - prev_x, ny - prev_y)
- contour_len += d
- contour.append((nx, ny, contour_len))
- prev_x, prev_y = nx, ny
- cur_x = x2
- cur_y = y2
- elif t == "cubic":
- x1, y1 = seg.get("x1", cur_x), seg.get("y1", cur_y)
- x2, y2 = seg.get("x2", cur_x), seg.get("y2", cur_y)
- x3, y3 = seg.get("x3", cur_x), seg.get("y3", cur_y)
- steps = 24
- prev_x, prev_y = cur_x, cur_y
- for i in range(1, steps + 1):
- tt = i / steps
- mt = 1 - tt
- nx = mt ** 3 * cur_x + 3 * mt ** 2 * tt * x1 + 3 * mt * tt ** 2 * x2 + tt ** 3 * x3
- ny = mt ** 3 * cur_y + 3 * mt ** 2 * tt * y1 + 3 * mt * tt ** 2 * y2 + tt ** 3 * y3
- d = math.hypot(nx - prev_x, ny - prev_y)
- contour_len += d
- contour.append((nx, ny, contour_len))
- prev_x, prev_y = nx, ny
- cur_x = x3
- cur_y = y3
- elif t == "close":
- if contour:
- d = math.hypot(start_x - cur_x, start_y - cur_y)
- if d > 1e-10:
- contour_len += d
- contour.append((start_x, start_y, contour_len))
- cur_x = start_x
- cur_y = start_y
- if contour:
- if self._force_closed and segs and segs[-1].get("type") != "close":
- d = math.hypot(start_x - cur_x, start_y - cur_y)
- if d > 1e-10:
- contour_len += d
- contour.append((start_x, start_y, contour_len))
- self._contours.append(contour)
- self._contour_lengths.append(contour_len)
- self._total_length += contour_len
-
- def setPath(self, path: Path, forceClosed: bool):
- self._path = path
- self._force_closed = forceClosed
- self._contours = []
- self._contour_lengths = []
- self._total_length = 0.0
- if path is not None:
- self._flatten()
-
- def getLength(self) -> float:
- """返回当前轮廓的长度。"""
- if self._contour_lengths:
- return self._contour_lengths[0]
- return 0.0
-
- def getPosTan(self, distance: float, pos: List[float], tan: List[float]) -> bool:
- """获取指定距离处的坐标和切线方向。"""
- if not self._contours:
- return False
- contour = self._contours[0]
- length = self._contour_lengths[0]
- if length <= 0:
- return False
- # 钳制距离
- d = max(0.0, min(distance, length))
- # 二分查找
- lo, hi = 0, len(contour) - 1
- while lo < hi:
- mid = (lo + hi) // 2
- if contour[mid][2] < d:
- lo = mid + 1
- else:
- hi = mid
- idx = max(1, lo)
- px, py, pd = contour[idx - 1]
- nx, ny, nd = contour[idx]
- seg_len = nd - pd
- if seg_len < 1e-10:
- t = 0.0
- else:
- t = (d - pd) / seg_len
- x = px + (nx - px) * t
- y = py + (ny - py) * t
- dx = nx - px
- dy = ny - py
- dl = math.hypot(dx, dy)
- if dl < 1e-10:
- tx, ty = 1.0, 0.0
- else:
- tx, ty = dx / dl, dy / dl
- if len(pos) >= 2:
- pos[0] = x
- pos[1] = y
- if len(tan) >= 2:
- tan[0] = tx
- tan[1] = ty
- return True
-
- def getMatrix(self, distance: float, matrix: "Matrix", flags: int) -> bool:
- """获取指定距离处的变换矩阵(平移+旋转)。"""
- pos = [0.0, 0.0]
- tan = [0.0, 0.0]
- if not self.getPosTan(distance, pos, tan):
- return False
- angle = math.degrees(math.atan2(tan[1], tan[0]))
- matrix.reset()
- matrix.postRotate(angle)
- matrix.postTranslate(pos[0], pos[1])
- return True
-
- def getSegment(self, startD: float, stopD: float, dst: Path, startWithMoveTo: bool) -> bool:
- """提取路径中 [startD, stopD] 区间的子路径。"""
- if not self._contours:
- return False
- contour = self._contours[0]
- length = self._contour_lengths[0]
- if length <= 0:
- return False
- startD = max(0.0, min(startD, length))
- stopD = max(0.0, min(stopD, length))
- if startD >= stopD:
- return False
- first = True
- for i in range(1, len(contour)):
- px, py, pd = contour[i - 1]
- nx, ny, nd = contour[i]
- if nd < startD:
- continue
- if pd > stopD:
- break
- seg_len = nd - pd
- if seg_len < 1e-10:
- continue
- # 计算线段两端在 [startD, stopD] 内的参数
- t0 = max(0.0, (startD - pd) / seg_len)
- t1 = min(1.0, (stopD - pd) / seg_len)
- x0 = px + (nx - px) * t0
- y0 = py + (ny - py) * t0
- x1 = px + (nx - px) * t1
- y1 = py + (ny - py) * t1
- if first and startWithMoveTo:
- dst.moveTo(x0, y0)
- else:
- dst.lineTo(x0, y0)
- dst.lineTo(x1, y1)
- first = False
- return True
-
- def isClosed(self) -> bool:
- if not self._path or not self._path._segments:
- return self._force_closed
- if self._force_closed:
- return True
- return any(s.get("type") == "close" for s in self._path._segments)
-
- def nextContour(self) -> bool:
- """移动到下一个轮廓。"""
- if len(self._contours) > 1:
- self._contours.pop(0)
- self._contour_lengths.pop(0)
- return True
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# PorterDuff
-# ═══════════════════════════════════════════════════════════════
-
-class PorterDuff(Stub):
- """PorterDuff — 图形混合模式"""
-
- class Mode:
- CLEAR = 0
- SRC = 1
- DST = 2
- SRC_OVER = 3
- DST_OVER = 4
- SRC_IN = 5
- DST_IN = 6
- SRC_OUT = 7
- DST_OUT = 8
- SRC_ATOP = 9
- DST_ATOP = 10
- XOR = 11
- ADD = 12
- MULTIPLY = 13
- SCREEN = 14
- OVERLAY = 15
- DARKEN = 16
- LIGHTEN = 17
-
-
-# ═══════════════════════════════════════════════════════════════
-# ClipOp
-# ═══════════════════════════════════════════════════════════════
-
-class ClipOp(Stub):
- """ClipOp — 裁剪操作"""
- DIFFERENCE = 0
- INTERSECT = 1
- REPLACE = 2
-
-
-# ═══════════════════════════════════════════════════════════════
-# BlendMode
-# ═══════════════════════════════════════════════════════════════
-
-class BlendMode(Stub):
- """BlendMode — Android 29+ 混合模式"""
- CLEAR = 0
- SRC = 1
- DST = 2
- SRC_OVER = 3
- DST_OVER = 4
- SRC_IN = 5
- DST_IN = 6
- SRC_OUT = 7
- DST_OUT = 8
- SRC_ATOP = 9
- DST_ATOP = 10
- XOR = 11
- PLUS = 12
- MODULATE = 13
- SCREEN = 14
- OVERLAY = 15
- DARKEN = 16
- LIGHTEN = 17
-
-
-# ═══════════════════════════════════════════════════════════════
-# BlendModeColorFilter
-# ═══════════════════════════════════════════════════════════════
-
-class BlendModeColorFilter(Stub):
- """BlendModeColorFilter — 混合模式颜色过滤器"""
-
- def __init__(self, color: int, mode):
- super().__init__()
- self._color = color
- self._mode = mode
-
- def getColor(self) -> int:
- return self._color
-
- def getMode(self):
- return self._mode
-
-
-# ═══════════════════════════════════════════════════════════════
-# ColorFilter
-# ═══════════════════════════════════════════════════════════════
-
-class ColorFilter(Stub):
- """ColorFilter — 颜色过滤器的抽象基类"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# PorterDuffColorFilter
-# ═══════════════════════════════════════════════════════════════
-
-class PorterDuffColorFilter(ColorFilter):
- """PorterDuffColorFilter — PorterDuff 颜色过滤器"""
-
- def __init__(self, color: int, mode):
- super().__init__()
- self._color = color
- self._mode = mode
-
- def getColor(self) -> int:
- return self._color
-
- def getMode(self):
- return self._mode
-
-
-# ═══════════════════════════════════════════════════════════════
-# LightingColorFilter
-# ═══════════════════════════════════════════════════════════════
-
-class LightingColorFilter(ColorFilter):
- """LightingColorFilter — 光照颜色过滤器"""
-
- def __init__(self, mul: int, add: int):
- super().__init__()
- self._mul = mul
- self._add = add
-
- def getMultiply(self) -> int:
- return self._mul
-
- def getAdd(self) -> int:
- return self._add
-
-
-# ═══════════════════════════════════════════════════════════════
-# ComposeColorFilter
-# ═══════════════════════════════════════════════════════════════
-
-class ComposeColorFilter(ColorFilter):
- """ComposeColorFilter — 组合颜色过滤器"""
-
- def __init__(self, cf1: ColorFilter, cf2: ColorFilter):
- super().__init__()
- self._cf1 = cf1
- self._cf2 = cf2
-
- def getColorFilters(self) -> Tuple[ColorFilter, ColorFilter]:
- return (self._cf1, self._cf2)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ColorMatrix
-# ═══════════════════════════════════════════════════════════════
-
-class ColorMatrix(Stub):
- """ColorMatrix — 4x5 颜色变换矩阵"""
-
- def __init__(self, src: "ColorMatrix" = None):
- super().__init__()
- if src:
- self._array = list(src._array)
- else:
- self._array = [1, 0, 0, 0, 0,
- 0, 1, 0, 0, 0,
- 0, 0, 1, 0, 0,
- 0, 0, 0, 1, 0]
-
- def getArray(self) -> List[float]:
- return self._array
-
- def set(self, src: "ColorMatrix"):
- self._array = list(src._array)
-
- def reset(self):
- self._array = [1, 0, 0, 0, 0,
- 0, 1, 0, 0, 0,
- 0, 0, 1, 0, 0,
- 0, 0, 0, 1, 0]
-
- def setSaturation(self, sat: float):
- R_lum = 0.213
- G_lum = 0.715
- B_lum = 0.072
- one_minus = 1.0 - sat
- self._array = [
- R_lum * one_minus + sat, G_lum * one_minus, B_lum * one_minus, 0, 0,
- R_lum * one_minus, G_lum * one_minus + sat, B_lum * one_minus, 0, 0,
- R_lum * one_minus, G_lum * one_minus, B_lum * one_minus + sat, 0, 0,
- 0, 0, 0, 1, 0,
- ]
-
- def setRotate(self, axis: int, degrees: float):
- rad = math.radians(degrees)
- c = math.cos(rad)
- s = math.sin(rad)
- self.reset()
- if axis == 0:
- self._array[5] = c
- self._array[6] = s
- self._array[9] = -s
- self._array[10] = c
- elif axis == 1:
- self._array[0] = c
- self._array[2] = -s
- self._array[8] = s
- self._array[10] = c
- elif axis == 2:
- self._array[0] = c
- self._array[1] = s
- self._array[4] = -s
- self._array[5] = c
-
- def setConcat(self, a: "ColorMatrix", b: "ColorMatrix"):
- a_arr = a._array
- b_arr = b._array
- result = [0.0] * 20
- for i in range(4):
- for j in range(5):
- s = 0.0
- for k in range(4):
- s += a_arr[i * 5 + k] * b_arr[k * 5 + j]
- result[i * 5 + j] = s
- self._array = result
-
- def preConcat(self, other: "ColorMatrix"):
- new = ColorMatrix()
- new.setConcat(self, other)
- self._array = new._array
-
- def postConcat(self, other: "ColorMatrix"):
- new = ColorMatrix()
- new.setConcat(other, self)
- self._array = new._array
-
- def setScale(self, rScale: float, gScale: float, bScale: float, aScale: float):
- self._array = [
- rScale, 0, 0, 0, 0,
- 0, gScale, 0, 0, 0,
- 0, 0, bScale, 0, 0,
- 0, 0, 0, aScale, 0,
- ]
-
-
-# ═══════════════════════════════════════════════════════════════
-# ColorMatrixColorFilter
-# ═══════════════════════════════════════════════════════════════
-
-class ColorMatrixColorFilter(ColorFilter):
- """ColorMatrixColorFilter — 颜色矩阵过滤器"""
-
- def __init__(self, matrix: ColorMatrix):
- super().__init__()
- self._matrix = matrix
-
- def getMatrix(self) -> ColorMatrix:
- return self._matrix
-
-
-# ═══════════════════════════════════════════════════════════════
-# Matrix
-# ═══════════════════════════════════════════════════════════════
-
-class Matrix(Stub):
- """Matrix — 3x3 变换矩阵"""
-
- IDENTITY_MATRIX: "Matrix" = None
-
- MPERSP_0 = 6
- MPERSP_1 = 7
- MPERSP_2 = 8
- MSCALE_X = 0
- MSCALE_Y = 4
- MSKEW_X = 1
- MSKEW_Y = 3
- MTRANS_X = 2
- MTRANS_Y = 5
-
- def __init__(self, src: "Matrix" = None):
- super().__init__()
- if src:
- self._values = list(src._values)
- else:
- self._values = [1, 0, 0,
- 0, 1, 0,
- 0, 0, 1]
-
- def getValues(self) -> List[float]:
- return self._values
-
- def setValues(self, values: List[float]):
- self._values = list(values)
-
- def reset(self):
- self._values = [1, 0, 0, 0, 1, 0, 0, 0, 1]
-
- def isIdentity(self) -> bool:
- return self._values == [1, 0, 0, 0, 1, 0, 0, 0, 1]
-
- def invert(self, inverse: "Matrix") -> bool:
- v = self._values
- det = v[0] * (v[4] * v[8] - v[5] * v[7]) \
- - v[1] * (v[3] * v[8] - v[5] * v[6]) \
- + v[2] * (v[3] * v[7] - v[4] * v[6])
- if abs(det) < 1e-10:
- return False
- inv_det = 1.0 / det
- inv = [
- (v[4] * v[8] - v[5] * v[7]) * inv_det,
- (v[2] * v[7] - v[1] * v[8]) * inv_det,
- (v[1] * v[5] - v[2] * v[4]) * inv_det,
- (v[5] * v[6] - v[3] * v[8]) * inv_det,
- (v[0] * v[8] - v[2] * v[6]) * inv_det,
- (v[2] * v[3] - v[0] * v[5]) * inv_det,
- (v[3] * v[7] - v[4] * v[6]) * inv_det,
- (v[1] * v[6] - v[0] * v[7]) * inv_det,
- (v[0] * v[4] - v[1] * v[3]) * inv_det,
- ]
- inverse._values = inv
- return True
-
- def setTranslate(self, dx: float, dy: float):
- self._values = [1, 0, dx, 0, 1, dy, 0, 0, 1]
-
- def setScale(self, sx: float, sy: float, px: float = 0.0, py: float = 0.0):
- self._values = [sx, 0, px - sx * px, 0, sy, py - sy * py, 0, 0, 1]
-
- def setRotate(self, degrees: float, px: float = 0.0, py: float = 0.0):
- rad = math.radians(degrees)
- c = math.cos(rad)
- s = math.sin(rad)
- tx = px - px * c + py * s
- ty = py - px * s - py * c
- self._values = [c, -s, tx, s, c, ty, 0, 0, 1]
-
- def setSkew(self, kx: float, ky: float, px: float = 0.0, py: float = 0.0):
- self._values = [1, kx, -kx * px, ky, 1, -ky * py, 0, 0, 1]
-
- def setConcat(self, a: "Matrix", b: "Matrix"):
- va, vb = a._values, b._values
- self._values = [
- va[0] * vb[0] + va[1] * vb[3] + va[2] * vb[6],
- va[0] * vb[1] + va[1] * vb[4] + va[2] * vb[7],
- va[0] * vb[2] + va[1] * vb[5] + va[2] * vb[8],
- va[3] * vb[0] + va[4] * vb[3] + va[5] * vb[6],
- va[3] * vb[1] + va[4] * vb[4] + va[5] * vb[7],
- va[3] * vb[2] + va[4] * vb[5] + va[5] * vb[8],
- va[6] * vb[0] + va[7] * vb[3] + va[8] * vb[6],
- va[6] * vb[1] + va[7] * vb[4] + va[8] * vb[7],
- va[6] * vb[2] + va[7] * vb[5] + va[8] * vb[8],
- ]
-
- def preConcat(self, other: "Matrix"):
- new = Matrix()
- new.setConcat(self, other)
- self._values = new._values
-
- def postConcat(self, other: "Matrix"):
- new = Matrix()
- new.setConcat(other, self)
- self._values = new._values
-
- def preTranslate(self, dx: float, dy: float):
- m = Matrix()
- m.setTranslate(dx, dy)
- self.preConcat(m)
-
- def preScale(self, sx: float, sy: float, px: float = 0.0, py: float = 0.0):
- m = Matrix()
- m.setScale(sx, sy, px, py)
- self.preConcat(m)
-
- def preRotate(self, degrees: float, px: float = 0.0, py: float = 0.0):
- m = Matrix()
- m.setRotate(degrees, px, py)
- self.preConcat(m)
-
- def preSkew(self, kx: float, ky: float, px: float = 0.0, py: float = 0.0):
- m = Matrix()
- m.setSkew(kx, ky, px, py)
- self.preConcat(m)
-
- def postTranslate(self, dx: float, dy: float):
- m = Matrix()
- m.setTranslate(dx, dy)
- self.postConcat(m)
-
- def postScale(self, sx: float, sy: float, px: float = 0.0, py: float = 0.0):
- m = Matrix()
- m.setScale(sx, sy, px, py)
- self.postConcat(m)
-
- def postRotate(self, degrees: float, px: float = 0.0, py: float = 0.0):
- m = Matrix()
- m.setRotate(degrees, px, py)
- self.postConcat(m)
-
- def postSkew(self, kx: float, ky: float, px: float = 0.0, py: float = 0.0):
- m = Matrix()
- m.setSkew(kx, ky, px, py)
- self.postConcat(m)
-
- def setRectToRect(self, src: RectF, dst: RectF, stf: int) -> bool:
- if src.isEmpty() or dst.isEmpty():
- return False
- sx = dst.width() / src.width()
- sy = dst.height() / src.height()
- tx = dst.left - src.left * sx
- ty = dst.top - src.top * sy
- self._values = [sx, 0, tx, 0, sy, ty, 0, 0, 1]
- return True
-
- def mapRect(self, src: RectF, dst: RectF = None) -> RectF:
- pts = [src.left, src.top, src.right, src.bottom]
- self.mapPoints(pts)
- if dst:
- dst.set(pts[0], pts[1], pts[2], pts[3])
- return dst
- return RectF(pts[0], pts[1], pts[2], pts[3])
-
- def mapPoints(self, pts: List[float], offset: int = 0, count: int = -1):
- if count < 0:
- count = len(pts) - offset
- v = self._values
- for i in range(offset, offset + count, 2):
- x = pts[i]
- y = pts[i + 1]
- pts[i] = x * v[0] + y * v[1] + v[2]
- pts[i + 1] = x * v[3] + y * v[4] + v[5]
-
- def mapVectors(self, vecs: List[float]):
- v = self._values
- for i in range(0, len(vecs), 2):
- x = vecs[i]
- y = vecs[i + 1]
- vecs[i] = x * v[0] + y * v[1]
- vecs[i + 1] = x * v[3] + y * v[4]
-
- def mapRadius(self, radius: float) -> float:
- v = self._values
- sx = math.sqrt(v[0] * v[0] + v[3] * v[3])
- sy = math.sqrt(v[1] * v[1] + v[4] * v[4])
- return radius * max(sx, sy)
-
- def toString(self) -> str:
- return f"Matrix({self._values})"
-
-
-Matrix.IDENTITY_MATRIX = Matrix()
-
-
-# ═══════════════════════════════════════════════════════════════
-# Shader
-# ═══════════════════════════════════════════════════════════════
-
-class Shader(Stub):
- """Shader — 着色器基类"""
-
- class TileMode:
- CLAMP = 0
- REPEAT = 1
- MIRROR = 2
-
- def __init__(self):
- super().__init__()
- self._local_matrix = None
-
- def setLocalMatrix(self, matrix: Matrix):
- self._local_matrix = matrix
-
- def getLocalMatrix(self) -> Optional[Matrix]:
- return self._local_matrix
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinearGradient
-# ═══════════════════════════════════════════════════════════════
-
-class LinearGradient(Shader):
- """LinearGradient — 线性渐变"""
-
- def __init__(self, x0: float, y0: float, x1: float, y1: float,
- colors: Sequence[int], positions: Sequence[float],
- tile: int = Shader.TileMode.CLAMP):
- super().__init__()
- self._x0, self._y0 = x0, y0
- self._x1, self._y1 = x1, y1
- self._colors = list(colors)
- self._positions = list(positions) if positions else None
- self._tile = tile
-
-
-# ═══════════════════════════════════════════════════════════════
-# RadialGradient
-# ═══════════════════════════════════════════════════════════════
-
-class RadialGradient(Shader):
- """RadialGradient — 径向渐变"""
-
- CENTER_COLOR = 0
- EDGE_COLOR = 1
-
- def __init__(self, x: float, y: float, radius: float,
- colors: Sequence[int], positions: Sequence[float],
- tile: int = Shader.TileMode.CLAMP,
- centerColor: int = Shader.TileMode.CLAMP):
- """centerColor is ignored, kept for API compatibility"""
- super().__init__()
- self._x, self._y = x, y
- self._radius = radius
- self._colors = list(colors)
- self._positions = list(positions) if positions else None
- self._tile = tile
-
- def getX(self) -> float:
- return self._x
-
- def getY(self) -> float:
- return self._y
-
- def getRadius(self) -> float:
- return self._radius
-
-
-# ═══════════════════════════════════════════════════════════════
-# SweepGradient
-# ═══════════════════════════════════════════════════════════════
-
-class SweepGradient(Shader):
- """SweepGradient — 扫描渐变"""
-
- def __init__(self, x: float, y: float,
- colors: Sequence[int], positions: Sequence[float]):
- super().__init__()
- self._x, self._y = x, y
- self._colors = list(colors)
- self._positions = list(positions) if positions else None
-
- def getX(self) -> float:
- return self._x
-
- def getY(self) -> float:
- return self._y
-
-
-# ═══════════════════════════════════════════════════════════════
-# BitmapShader
-# ═══════════════════════════════════════════════════════════════
-
-class BitmapShader(Shader):
- """BitmapShader — 位图着色器"""
-
- def __init__(self, bitmap: "Bitmap", tileX: int, tileY: int):
- super().__init__()
- self._bitmap = bitmap
- self._tile_x = tileX
- self._tile_y = tileY
-
- def getBitmap(self) -> "Bitmap":
- return self._bitmap
-
-
-# ═══════════════════════════════════════════════════════════════
-# ComposeShader
-# ═══════════════════════════════════════════════════════════════
-
-class ComposeShader(Shader):
- """ComposeShader — 组合着色器"""
-
- def __init__(self, shaderA: Shader, shaderB: Shader, mode):
- super().__init__()
- self._shader_a = shaderA
- self._shader_b = shaderB
- self._mode = mode
-
-
-# ═══════════════════════════════════════════════════════════════
-# MaskFilter / BlurMaskFilter / EmbossMaskFilter
-# ═══════════════════════════════════════════════════════════════
-
-class MaskFilter(Stub):
- """MaskFilter — 遮罩过滤器基类"""
- pass
-
-
-class BlurMaskFilter(MaskFilter):
- """BlurMaskFilter — 模糊遮罩过滤器"""
-
- NORMAL = 0
- SOLID = 1
- OUTER = 2
- INNER = 3
-
- def __init__(self, radius: float, style: int):
- super().__init__()
- self._radius = radius
- self._style = style
-
- def getRadius(self) -> float:
- return self._radius
-
- def getStyle(self) -> int:
- return self._style
-
-
-class EmbossMaskFilter(MaskFilter):
- """EmbossMaskFilter — 浮雕遮罩过滤器"""
-
- def __init__(self, direction: List[float], ambient: float, specular: float, blurRadius: float):
- super().__init__()
- self._direction = list(direction)
- self._ambient = ambient
- self._specular = specular
- self._blur_radius = blurRadius
-
-
-# ═══════════════════════════════════════════════════════════════
-# PathEffect hierarchy
-# ═══════════════════════════════════════════════════════════════
-
-class PathEffect(Stub):
- """PathEffect — 路径效果基类"""
- pass
-
-
-class ComposePathEffect(PathEffect):
- """ComposePathEffect — 组合路径效果"""
-
- def __init__(self, outerpe: PathEffect, innerpe: PathEffect):
- super().__init__()
- self._outer = outerpe
- self._inner = innerpe
-
-
-class CornerPathEffect(PathEffect):
- """CornerPathEffect — 圆角路径效果"""
-
- def __init__(self, radius: float):
- super().__init__()
- self._radius = radius
-
-
-class DashPathEffect(PathEffect):
- """DashPathEffect — 虚线路径效果"""
-
- def __init__(self, intervals: List[float], phase: float):
- super().__init__()
- self._intervals = list(intervals)
- self._phase = phase
-
-
-class DiscretePathEffect(PathEffect):
- """DiscretePathEffect — 离散路径效果"""
-
- def __init__(self, segmentLength: float, deviation: float):
- super().__init__()
- self._segment_length = segmentLength
- self._deviation = deviation
-
-
-class PathDashPathEffect(PathEffect):
- """PathDashPathEffect — 路径虚线效果"""
-
- ROTATE = 0
- MORPH = 1
- TRANSLATE = 2
-
- def __init__(self, shape: Path, advance: float, phase: float, style: int):
- super().__init__()
- self._shape = shape
- self._advance = advance
- self._phase = phase
- self._style = style
-
-
-class SumPathEffect(PathEffect):
- """SumPathEffect — 求和路径效果"""
-
- def __init__(self, first: PathEffect, second: PathEffect):
- super().__init__()
- self._first = first
- self._second = second
-
-
-# ═══════════════════════════════════════════════════════════════
-# Xfermode hierarchy
-# ═══════════════════════════════════════════════════════════════
-
-class Xfermode(Stub):
- """Xfermode — 传输模式基类"""
- pass
-
-
-class PorterDuffXfermode(Xfermode):
- """PorterDuffXfermode — PorterDuff 传输模式"""
-
- def __init__(self, mode):
- super().__init__()
- self._mode = mode
-
- def getMode(self):
- return self._mode
-
-
-class AvoidXfermode(Xfermode):
- """AvoidXfermode — deprecated, kept for API compatibility"""
-
- TARGET = 0
- AVOID = 1
-
- def __init__(self, opColor: int, tolerance: int, mode: int):
- super().__init__()
- self._op_color = opColor
- self._tolerance = tolerance
- self._mode = mode
-
-
-class PixelXorXfermode(Xfermode):
- """PixelXorXfermode — deprecated, kept for API compatibility"""
-
- def __init__(self, opColor: int):
- super().__init__()
- self._op_color = opColor
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrawFilter
-# ═══════════════════════════════════════════════════════════════
-
-class DrawFilter(Stub):
- """DrawFilter — 绘制过滤器基类"""
- pass
-
-
-class PaintFlagsDrawFilter(DrawFilter):
- """PaintFlagsDrawFilter — 画笔标志绘制过滤器"""
-
- def __init__(self, clearBits: int, setBits: int):
- super().__init__()
- self._clear_bits = clearBits
- self._set_bits = setBits
-
-
-# ═══════════════════════════════════════════════════════════════
-# Camera
-# ═══════════════════════════════════════════════════════════════
-
-class Camera(Stub):
- """Camera — 3D 相机变换"""
-
- def __init__(self):
- super().__init__()
- self._location_x = 0.0
- self._location_y = 0.0
- self._location_z = -8.0
- self._rot_x = 0.0
- self._rot_y = 0.0
- self._rot_z = 0.0
- self._trans_x = 0.0
- self._trans_y = 0.0
- self._trans_z = 0.0
- self._stack: List[Tuple[float, float, float, float, float, float, float, float, float]] = []
-
- def save(self):
- """保存当前变换状态到栈。"""
- self._stack.append((self._rot_x, self._rot_y, self._rot_z,
- self._trans_x, self._trans_y, self._trans_z,
- self._location_x, self._location_y, self._location_z))
-
- def restore(self):
- """从栈恢复上次保存的变换状态。"""
- if self._stack:
- (self._rot_x, self._rot_y, self._rot_z,
- self._trans_x, self._trans_y, self._trans_z,
- self._location_x, self._location_y, self._location_z) = self._stack.pop()
-
- def translate(self, x: float, y: float, z: float):
- self._trans_x += x
- self._trans_y += y
- self._trans_z += z
-
- def rotateX(self, deg: float):
- """绕 X 轴旋转(累积角度)。"""
- self._rot_x += deg
-
- def rotateY(self, deg: float):
- """绕 Y 轴旋转(累积角度)。"""
- self._rot_y += deg
-
- def rotateZ(self, deg: float):
- """绕 Z 轴旋转(累积角度)。"""
- self._rot_z += deg
-
- def rotate(self, x: float, y: float, z: float):
- """同时绕 X/Y/Z 轴旋转。"""
- self._rot_x += x
- self._rot_y += y
- self._rot_z += z
-
- def _compute_matrix(self) -> List[float]:
- """计算 4x4 变换矩阵并投影为 3x3 仿射矩阵。"""
- rx = math.radians(self._rot_x)
- ry = math.radians(self._rot_y)
- rz = math.radians(self._rot_z)
- cx, sx = math.cos(rx), math.sin(rx)
- cy, sy = math.cos(ry), math.sin(ry)
- cz, sz = math.cos(rz), math.sin(rz)
- # 旋转矩阵 R = Rz * Ry * Rx
- r00 = cz * cy
- r01 = cz * sy * sx - sz * cx
- r02 = cz * sy * cx + sz * sx
- r10 = sz * cy
- r11 = sz * sy * sx + cz * cx
- r12 = sz * sy * cx - cz * sx
- r20 = -sy
- r21 = cy * sx
- r22 = cy * cx
- # 应用平移
- tx = self._trans_x
- ty = self._trans_y
- tz = self._trans_z
- # 相机位置(z 越负越远)
- cam_z = self._location_z
- # 透视投影:z' = z + cam_z,当 cam_z != 0 时做透视除法
- # 简化为:将 3D 点投影到 2D
- # 点 (x,y,z) -> (x*r00+y*r01+z*r02+tx, x*r10+y*r11+z*r12+ty, x*r20+y*r21+z*r22+tz)
- # 透视:screen_x = x' * d / (d - z'), screen_y = y' * d / (d - z')
- d = -cam_z # 相机到原点距离
- if abs(d) < 1e-10:
- # 正交投影
- return [r00, r01, tx, r10, r11, ty, 0.0, 0.0, 1.0]
- # 透视投影矩阵(近似):将 z 影响缩放到 x,y
- # m[0]=r00, m[1]=r01, m[2]=tx, m[3]=r10, m[4]=r11, m[5]=ty
- # 透视项:m[6]=r20/d, m[7]=r21/d, m[8]=1 - tz/d
- return [r00, r01, tx,
- r10, r11, ty,
- r20 / d, r21 / d, 1.0 - tz / d]
-
- def getMatrix(self, matrix: Matrix):
- """计算变换矩阵并写入给定的 Matrix。"""
- matrix._values = self._compute_matrix()
-
- def applyToCanvas(self, canvas: "Canvas"):
- """将相机变换应用到 Canvas。"""
- m = Matrix()
- self.getMatrix(m)
- if hasattr(canvas, "concat"):
- canvas.concat(m)
-
- def setLocation(self, x: float, y: float, z: float):
- self._location_x = x
- self._location_y = y
- self._location_z = z
-
- def dotWithNormal(self, dx: float, dy: float, dz: float) -> float:
- """计算向量与变换后 Z 轴法线的点积。"""
- rx = math.radians(self._rot_x)
- ry = math.radians(self._rot_y)
- rz = math.radians(self._rot_z)
- cy, sy = math.cos(ry), math.sin(ry)
- cx, sx = math.cos(rx), math.sin(rx)
- # 变换后的 Z 轴法线
- nz_x = sy
- nz_y = -cy * sx
- nz_z = cy * cx
- return dx * nz_x + dy * nz_y + dz * nz_z
-
-
-# ═══════════════════════════════════════════════════════════════
-# LayerRasterizer / Rasterizer
-# ═══════════════════════════════════════════════════════════════
-
-class Rasterizer(Stub):
- """Rasterizer — 光栅化基类 (deprecated)"""
- pass
-
-
-class LayerRasterizer(Rasterizer):
- """LayerRasterizer — 分层光栅化 (deprecated)"""
-
- def __init__(self):
- super().__init__()
-
- def addLayer(self, paint: "Paint", dx: float = 0.0, dy: float = 0.0):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# NinePatch
-# ═══════════════════════════════════════════════════════════════
-
-class NinePatch(Stub):
- """NinePatch — 九宫格图片"""
-
- def __init__(self, bitmap: "Bitmap", chunk: bytes):
- super().__init__()
- self._bitmap = bitmap
- self._chunk = chunk if chunk else b""
-
- def getBitmap(self) -> "Bitmap":
- return self._bitmap
-
- def getWidth(self) -> int:
- return self._bitmap.getWidth() if self._bitmap else 0
-
- def getHeight(self) -> int:
- return self._bitmap.getHeight() if self._bitmap else 0
-
- @staticmethod
- def isNinePatchChunk(chunk: bytes) -> bool:
- return bool(chunk and len(chunk) > 0)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Picture / PictureDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class Picture(Stub):
- """Picture — 图画录制与回放"""
-
- def __init__(self):
- super().__init__()
- self._recorded = []
-
- def beginRecording(self, width: int, height: int) -> "Canvas":
- canvas = Canvas(width, height)
- self._canvas = canvas
- return canvas
-
- def endRecording(self):
- self._canvas = None
-
- def draw(self, canvas: "Canvas"):
- """回放录制的绘制命令到指定 Canvas。"""
- for cmd in self._recorded:
- method = cmd.get("method")
- args = cmd.get("args", [])
- if method and hasattr(canvas, method):
- try:
- getattr(canvas, method)(*args)
- except Exception:
- pass
-
- def getWidth(self) -> int:
- return self._canvas.getWidth() if hasattr(self, "_canvas") and self._canvas else 0
-
- def getHeight(self) -> int:
- return self._canvas.getHeight() if hasattr(self, "_canvas") and self._canvas else 0
-
- def createFromStream(self, stream) -> "Picture":
- return Picture()
-
- def writeToStream(self, stream) -> bool:
- return True
-
-
-class PictureDrawable(Stub):
- """PictureDrawable — 图画 Drawable"""
-
- def __init__(self, picture: Picture):
- super().__init__()
- self._picture = picture
-
- def getPicture(self) -> Picture:
- return self._picture
-
- def setPicture(self, picture: Picture):
- self._picture = picture
-
- def draw(self, canvas: "Canvas"):
- """将 Picture 回放到指定 Canvas。"""
- if self._picture is not None:
- self._picture.draw(canvas)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurfaceTexture
-# ═══════════════════════════════════════════════════════════════
-
-class SurfaceTexture(Stub):
- """SurfaceTexture — 表面纹理"""
-
- def __init__(self, texName: int = 0):
- super().__init__()
- self._tex_name = texName
- self._timestamp = 0
- self._buffer_width = 0
- self._buffer_height = 0
- self._attached = texName != 0
- self._released = False
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def updateTexImage(self):
- self._timestamp = int(time.time() * 1e9)
-
- def release(self):
- """释放 SurfaceTexture 资源。"""
- self._released = True
- self._attached = False
-
- def setDefaultBufferSize(self, width: int, height: int):
- """设置默认缓冲区大小。"""
- self._buffer_width = width
- self._buffer_height = height
-
- def attachToGLContext(self, texName: int):
- """将 SurfaceTexture 附加到 GL 纹理。"""
- self._tex_name = texName
- self._attached = True
- self._released = False
-
- def detachFromGLContext(self):
- """从 GL 纹理分离 SurfaceTexture。"""
- self._attached = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Region / RegionIterator
-# ═══════════════════════════════════════════════════════════════
-
-class Region(Stub):
- """Region — 区域"""
-
- OP_DIFFERENCE = 0
- OP_INTERSECT = 1
- OP_UNION = 2
- OP_XOR = 3
- OP_REVERSE_DIFFERENCE = 4
- OP_REPLACE = 5
-
- def __init__(self, *args):
- super().__init__()
- if len(args) == 4:
- self._rect = Rect(args[0], args[1], args[2], args[3])
- elif len(args) == 1 and isinstance(args[0], Rect):
- self._rect = Rect(args[0].left, args[0].top, args[0].right, args[0].bottom)
- else:
- self._rect = Rect()
-
- def set(self, *args) -> bool:
- if len(args) == 4:
- self._rect.set(args[0], args[1], args[2], args[3])
- elif len(args) == 1 and isinstance(args[0], Rect):
- r = args[0]
- self._rect.set(r.left, r.top, r.right, r.bottom)
- return True
-
- def getBounds(self, r: Rect = None) -> Rect:
- if r:
- r.set(self._rect.left, self._rect.top, self._rect.right, self._rect.bottom)
- return r
- return Rect(self._rect.left, self._rect.top, self._rect.right, self._rect.bottom)
-
- def isEmpty(self) -> bool:
- return self._rect.isEmpty()
-
- def contains(self, x: int, y: int) -> bool:
- return self._rect.contains(x, y)
-
- def op(self, *args) -> bool:
- """对区域执行布尔运算。支持 op(rect, op) / op(region, op) / op(left,top,right,bottom,op)。"""
- if len(args) == 2:
- operand, op_code = args
- if isinstance(operand, Rect):
- other = Rect(operand.left, operand.top, operand.right, operand.bottom)
- elif isinstance(operand, Region):
- other = Rect(operand._rect.left, operand._rect.top,
- operand._rect.right, operand._rect.bottom)
- else:
- return False
- elif len(args) == 5:
- left, top, right, bottom, op_code = args
- other = Rect(left, top, right, bottom)
- else:
- return False
- self_r = self._rect
- if op_code == Region.OP_INTERSECT:
- nL = max(self_r.left, other.left)
- nT = max(self_r.top, other.top)
- nR = min(self_r.right, other.right)
- nB = min(self_r.bottom, other.bottom)
- if nL < nR and nT < nB:
- self_r.set(nL, nT, nR, nB)
- return True
- self_r.setEmpty()
- return False
- if op_code == Region.OP_UNION:
- if self_r.isEmpty():
- self_r.set(other.left, other.top, other.right, other.bottom)
- else:
- self_r.left = min(self_r.left, other.left)
- self_r.top = min(self_r.top, other.top)
- self_r.right = max(self_r.right, other.right)
- self_r.bottom = max(self_r.bottom, other.bottom)
- return True
- if op_code == Region.OP_REPLACE:
- self_r.set(other.left, other.top, other.right, other.bottom)
- return True
- if op_code == Region.OP_DIFFERENCE:
- # 差集:若不相交则不变;若完全包含则清空;否则近似为不变
- if not Rect.intersects(self_r, other):
- return True
- if other.contains(self_r.left, self_r.top) and other.contains(self_r.right - 1, self_r.bottom - 1):
- self_r.setEmpty()
- return False
- return True
- if op_code == Region.OP_REVERSE_DIFFERENCE:
- self_r.set(other.left, other.top, other.right, other.bottom)
- return True
- if op_code == Region.OP_XOR:
- if not Rect.intersects(self_r, other):
- self_r.union(other.left, other.top, other.right, other.bottom)
- return True
- return False
-
- def isRect(self) -> bool:
- return True
-
- def isComplex(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"Region({self._rect})"
-
-
-class RegionIterator(Stub):
- """RegionIterator — 区域迭代器"""
-
- def __init__(self, region: Region):
- super().__init__()
- self._region = region
- self._done = False
-
- def next(self, r: Rect) -> bool:
- if self._done:
- return False
- r.set(self._region._rect.left, self._region._rect.top,
- self._region._rect.right, self._region._rect.bottom)
- self._done = True
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# Paint
-# ═══════════════════════════════════════════════════════════════
-
-class Paint(Stub):
- """Paint — 画笔"""
-
- class Style:
- FILL = 0
- STROKE = 1
- FILL_AND_STROKE = 2
-
- class Cap:
- BUTT = 0
- ROUND = 1
- SQUARE = 2
-
- class Join:
- MITER = 0
- ROUND = 1
- BEVEL = 2
-
- class Align:
- LEFT = 0
- CENTER = 1
- RIGHT = 2
-
- ANTI_ALIAS_FLAG = 0x01
- FILTER_BITMAP_FLAG = 0x02
- DITHER_FLAG = 0x04
- UNDERLINE_TEXT_FLAG = 0x08
- STRIKE_THRU_TEXT_FLAG = 0x10
- FAKE_BOLD_TEXT_FLAG = 0x20
- LINEAR_TEXT_FLAG = 0x40
- SUBPIXEL_TEXT_FLAG = 0x80
- DEV_KERN_TEXT_FLAG = 0x100
-
- ALIGN_LEFT = 0
- ALIGN_CENTER = 1
- ALIGN_RIGHT = 2
-
- def __init__(self, flags: int = 0):
- super().__init__()
- self._flags = flags
- self._color = 0xFF000000
- self._alpha = 255
- self._style = Paint.Style.FILL
- self._stroke_width = 0.0
- self._text_size = 12.0
- self._typeface = None
- self._anti_alias = bool(flags & Paint.ANTI_ALIAS_FLAG)
- self._color_filter = None
- self._mask_filter = None
- self._shader = None
- self._path_effect = None
- self._xfermode = None
- self._filter_bitmap = bool(flags & Paint.FILTER_BITMAP_FLAG)
- self._dither = bool(flags & Paint.DITHER_FLAG)
- self._subpixel_text = bool(flags & Paint.SUBPIXEL_TEXT_FLAG)
- self._underline_text = bool(flags & Paint.UNDERLINE_TEXT_FLAG)
- self._strike_thru_text = bool(flags & Paint.STRIKE_THRU_TEXT_FLAG)
- self._text_align = Paint.Align.LEFT
- self._text_scale_x = 1.0
- self._text_skew_x = 0.0
- self._shadow_layer = None
-
- def setColor(self, color: int):
- self._color = color
- self._alpha = (color >> 24) & 0xFF
-
- def getColor(self) -> int:
- return self._color
-
- def setARGB(self, a: int, r: int, g: int, b: int):
- self.setColor(Color.argb(a, r, g, b))
-
- def setAlpha(self, alpha: int):
- self._alpha = max(0, min(255, alpha))
- self._color = (self._color & 0x00FFFFFF) | (self._alpha << 24)
-
- def getAlpha(self) -> int:
- return self._alpha
-
- def setStyle(self, style: int):
- self._style = style
-
- def getStyle(self) -> int:
- return self._style
-
- def setStrokeWidth(self, width: float):
- self._stroke_width = width
-
- def getStrokeWidth(self) -> float:
- return self._stroke_width
-
- def setTextSize(self, textSize: float):
- self._text_size = textSize
- self._font_cache = None
-
- def getTextSize(self) -> float:
- return self._text_size
-
- def _get_font(self):
- """获取 PIL ImageFont 对象(带缓存)。"""
- if not HAS_PIL:
- return None
- cache_key = (self._text_size, id(self._typeface) if self._typeface else None)
- if getattr(self, "_font_cache_key", None) == cache_key and getattr(self, "_font_cache", None):
- return self._font_cache
- try:
- from PIL import ImageFont
- font_path = None
- if self._typeface and hasattr(self._typeface, "_path") and self._typeface._path:
- font_path = self._typeface._path
- if font_path and os.path.exists(font_path):
- self._font_cache = ImageFont.truetype(font_path, int(self._text_size))
- else:
- self._font_cache = ImageFont.load_default()
- self._font_cache_key = cache_key
- return self._font_cache
- except Exception:
- return None
-
- def setTypeface(self, typeface: Optional[Typeface]):
- self._typeface = typeface
-
- def getTypeface(self) -> Optional[Typeface]:
- return self._typeface
-
- def setAntiAlias(self, aa: bool):
- self._anti_alias = aa
-
- def isAntiAlias(self) -> bool:
- return self._anti_alias
-
- def setColorFilter(self, filter: Optional[ColorFilter]):
- self._color_filter = filter
-
- def getColorFilter(self) -> Optional[ColorFilter]:
- return self._color_filter
-
- def setMaskFilter(self, maskfilter: Optional[MaskFilter]):
- self._mask_filter = maskfilter
-
- def getMaskFilter(self) -> Optional[MaskFilter]:
- return self._mask_filter
-
- def setShader(self, shader: Optional[Shader]):
- self._shader = shader
-
- def getShader(self) -> Optional[Shader]:
- return self._shader
-
- def setPathEffect(self, effect: Optional[PathEffect]):
- self._path_effect = effect
-
- def getPathEffect(self) -> Optional[PathEffect]:
- return self._path_effect
-
- def setXfermode(self, xfermode: Optional[Xfermode]):
- self._xfermode = xfermode
-
- def getXfermode(self) -> Optional[Xfermode]:
- return self._xfermode
-
- def setFlags(self, flags: int):
- self._flags = flags
-
- def getFlags(self) -> int:
- return self._flags
-
- def setFilterBitmap(self, filter: bool):
- self._filter_bitmap = filter
-
- def isFilterBitmap(self) -> bool:
- return self._filter_bitmap
-
- def setDither(self, dither: bool):
- self._dither = dither
-
- def isDither(self) -> bool:
- return self._dither
-
- def setSubpixelText(self, subpixel: bool):
- self._subpixel_text = subpixel
-
- def isSubpixelText(self) -> bool:
- return self._subpixel_text
-
- def setUnderlineText(self, underline: bool):
- self._underline_text = underline
-
- def isUnderlineText(self) -> bool:
- return self._underline_text
-
- def setStrikeThruText(self, strike: bool):
- self._strike_thru_text = strike
-
- def isStrikeThruText(self) -> bool:
- return self._strike_thru_text
-
- def setTextScaleX(self, scaleX: float):
- self._text_scale_x = scaleX
-
- def getTextScaleX(self) -> float:
- return self._text_scale_x
-
- def setTextSkewX(self, skewX: float):
- self._text_skew_x = skewX
-
- def getTextSkewX(self) -> float:
- return self._text_skew_x
-
- def setTextAlign(self, align: int):
- self._text_align = align
-
- def getTextAlign(self) -> int:
- return self._text_align
-
- def setTextLocales(self, locales):
- pass
-
- def setShadowLayer(self, radius: float, dx: float, dy: float, color: int):
- self._shadow_layer = (radius, dx, dy, color)
-
- def clearShadowLayer(self):
- self._shadow_layer = None
-
- def measureText(self, text: str) -> float:
- """测量文本宽度。优先使用 PIL ImageFont 获取精确宽度。"""
- font = self._get_font()
- if font is not None:
- try:
- if hasattr(font, "getlength"):
- return float(font.getlength(text))
- bbox = font.getbbox(text)
- return float(bbox[2] - bbox[0])
- except Exception:
- pass
- return len(text) * self._text_size * 0.5
-
- def breakText(self, text: str, maxWidth: float, measuredWidth: List[float]) -> int:
- """在最大宽度内截断文本,返回可容纳的字符数。"""
- font = self._get_font()
- width = 0.0
- count = 0
- for i, ch in enumerate(text):
- if font is not None:
- try:
- cw = font.getlength(ch) if hasattr(font, "getlength") else (font.getbbox(ch)[2])
- except Exception:
- cw = self._text_size * 0.5
- else:
- cw = self._text_size * 0.5
- if width + cw > maxWidth:
- break
- width += cw
- count += 1
- measuredWidth[0] = width
- return count
-
- def getTextWidths(self, text: str, widths: List[float]) -> int:
- """获取每个字符的宽度。"""
- font = self._get_font()
- for i, ch in enumerate(text):
- if font is not None:
- try:
- widths[i] = float(font.getlength(ch)) if hasattr(font, "getlength") else float(font.getbbox(ch)[2])
- except Exception:
- widths[i] = self._text_size * 0.5
- else:
- widths[i] = self._text_size * 0.5
- return len(text)
-
- def getTextPath(self, text: str, start: int, end: int, x: float, y: float, path: Path):
- path.moveTo(x, y)
- for i in range(start, end):
- path.lineTo(x + (i - start + 1) * self._text_size * 0.3, y)
-
- def getFontMetrics(self) -> Dict[str, float]:
- """返回字体度量信息。优先使用 PIL ImageFont 获取真实度量。"""
- size = self._text_size
- font = self._get_font()
- if font is not None:
- try:
- if hasattr(font, "getmetrics"):
- ascent, descent = font.getmetrics()
- return {
- "ascent": -float(ascent),
- "descent": float(descent),
- "top": -float(ascent) - 2.0,
- "bottom": float(descent) + 2.0,
- "leading": 0.0,
- }
- except Exception:
- pass
- return {
- "ascent": -size * 0.8,
- "descent": size * 0.2,
- "top": -size * 0.95,
- "bottom": size * 0.25,
- "leading": 0.0,
- }
-
- def getFontMetricsInt(self) -> Dict[str, int]:
- fm = self.getFontMetrics()
- return {k: int(v) for k, v in fm.items()}
-
- def ascent(self) -> float:
- return -self._text_size * 0.8
-
- def descent(self) -> float:
- return self._text_size * 0.2
-
- def setStrokeCap(self, cap):
- self._stroke_cap = cap
-
- def getStrokeCap(self):
- return getattr(self, '_stroke_cap', 0)
-
- def setStrokeJoin(self, join):
- self._stroke_join = join
-
- def getStrokeJoin(self):
- return getattr(self, '_stroke_join', 0)
-
- def setStrokeMiter(self, miter):
- self._stroke_miter = miter
-
- def getStrokeMiter(self):
- return getattr(self, '_stroke_miter', 4.0)
-
- def getTextBounds(self, text, start, end, bounds):
- """返回文本边界矩形。优先使用 PIL ImageFont 获取真实边界。"""
- font = self._get_font()
- if font is not None:
- try:
- sub = text[start:end]
- bbox = font.getbbox(sub)
- bounds.left = int(bbox[0])
- bounds.top = int(bbox[1])
- bounds.right = int(bbox[2])
- bounds.bottom = int(bbox[3])
- return
- except Exception:
- pass
- if hasattr(self, '_text_size'):
- w = len(text[start:end]) * self._text_size * 0.5
- h = self._text_size
- else:
- w = len(text[start:end]) * 12
- h = 24
- bounds.left = 0
- bounds.top = -int(h * 0.8)
- bounds.right = int(w)
- bounds.bottom = int(h * 0.2)
-
- def setBlendMode(self, blendmode):
- self._blend_mode = blendmode
-
- def getBlendMode(self):
- return getattr(self, '_blend_mode', None)
-
- def setLetterSpacing(self, letterSpacing):
- self._letter_spacing = letterSpacing
-
- def getLetterSpacing(self):
- return getattr(self, '_letter_spacing', 0.0)
-
- def setFontFeatureSettings(self, settings):
- self._font_feature_settings = settings
-
- def getFontFeatureSettings(self):
- return getattr(self, '_font_feature_settings', None)
-
- def setHinting(self, mode):
- self._hinting = mode
-
- def getHinting(self):
- return getattr(self, '_hinting', 2) # HINTING_ON
-
- def setFakeBoldText(self, fakeBoldText):
- self._fake_bold_text = fakeBoldText
-
- def isFakeBoldText(self):
- return getattr(self, '_fake_bold_text', False)
-
- def hasGlyph(self, string):
- return len(string) > 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# Bitmap
-# ═══════════════════════════════════════════════════════════════
-
-class Bitmap(Stub):
- """Bitmap — 位图"""
-
- class Config:
- ALPHA_8 = "ALPHA_8"
- ARGB_4444 = "ARGB_4444"
- ARGB_8888 = "ARGB_8888"
- RGB_565 = "RGB_565"
- RGBA_F16 = "RGBA_F16"
-
- class CompressFormat:
- JPEG = "JPEG"
- PNG = "PNG"
- WEBP = "WEBP"
- WEBP_LOSSY = "WEBP_LOSSY"
- WEBP_LOSSLESS = "WEBP_LOSSLESS"
-
- def __init__(self, width: int, height: int, config: str = Config.ARGB_8888):
- super().__init__()
- self._width = width
- self._height = height
- self._config = config
- self._recycled = False
- self._has_alpha = config in (Bitmap.Config.ARGB_8888, Bitmap.Config.ARGB_4444,
- Bitmap.Config.ALPHA_8, Bitmap.Config.RGBA_F16)
- self._generation_id = 1
-
- if HAS_PIL:
- from PIL import Image
- if config == Bitmap.Config.ALPHA_8:
- mode = "L"
- elif config == Bitmap.Config.RGB_565:
- mode = "RGB"
- else:
- mode = "RGBA"
- self._image = Image.new(mode, (width, height), (0, 0, 0, 0))
- else:
- bpp = 4 if config == Bitmap.Config.ARGB_8888 else (
- 2 if config in (Bitmap.Config.ARGB_4444, Bitmap.Config.RGB_565) else 1
- )
- self._pixels = bytearray(width * height * bpp)
-
- @staticmethod
- def createBitmap(width, height=None, config=None):
- if isinstance(width, Bitmap):
- src = width
- dst = Bitmap(src._width, src._height, src._config)
- if HAS_PIL and hasattr(src, "_image"):
- from PIL import Image
- dst._image = src._image.copy()
- elif hasattr(src, "_pixels"):
- dst._pixels = bytearray(src._pixels)
- return dst
- return Bitmap(width, height, config)
-
- @staticmethod
- def createScaledBitmap(src: "Bitmap", dstWidth: int, dstHeight: int,
- filter: bool = True) -> "Bitmap":
- if HAS_PIL and hasattr(src, "_image"):
- from PIL import Image
- dst = Bitmap(dstWidth, dstHeight, src._config)
- dst._image = src._image.resize((dstWidth, dstHeight), Image.LANCZOS if filter else Image.NEAREST)
- return dst
- dst = Bitmap(dstWidth, dstHeight, src._config)
- return dst
-
- def copy(self, config: str, isMutable: bool) -> "Bitmap":
- dst = Bitmap(self._width, self._height, config)
- if HAS_PIL and hasattr(self, "_image"):
- from PIL import Image
- if config != self._config:
- mode_map = {Bitmap.Config.ARGB_8888: "RGBA", Bitmap.Config.RGB_565: "RGB",
- Bitmap.Config.ALPHA_8: "L"}
- dst._image = self._image.convert(mode_map.get(config, "RGBA"))
- else:
- dst._image = self._image.copy()
- elif hasattr(self, "_pixels"):
- dst._pixels = bytearray(self._pixels)
- return dst
-
- def compress(self, format: str, quality: int, stream) -> bool:
- if self._recycled:
- return False
- if HAS_PIL and hasattr(self, "_image"):
- pil_fmt = format.lower()
- if pil_fmt == "jpeg":
- pil_fmt = "jpeg"
- elif pil_fmt == "webp":
- pil_fmt = "webp"
- else:
- pil_fmt = "png"
- if pil_fmt == "jpeg" and self._image.mode == "RGBA":
- self._image = self._image.convert("RGB")
- self._image.save(stream, format=pil_fmt.upper(), quality=quality)
- return True
- return False
-
- def recycle(self):
- self._recycled = True
- if HAS_PIL and hasattr(self, "_image"):
- self._image = None
- if hasattr(self, "_pixels"):
- self._pixels = None
-
- def isRecycled(self) -> bool:
- return self._recycled
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getConfig(self) -> str:
- return self._config
-
- def getRowBytes(self) -> int:
- bpp = {"ALPHA_8": 1, "ARGB_4444": 2, "ARGB_8888": 4, "RGB_565": 2, "RGBA_F16": 8}
- return self._width * bpp.get(self._config, 4)
-
- def getByteCount(self) -> int:
- return self.getRowBytes() * self._height
-
- def getAllocationByteCount(self) -> int:
- return self.getByteCount()
-
- def getPixel(self, x: int, y: int) -> int:
- if self._recycled:
- return 0
- if HAS_PIL and hasattr(self, "_image"):
- p = self._image.getpixel((x, y))
- if self._image.mode == "RGBA":
- return Color.argb(p[3], p[0], p[1], p[2])
- elif self._image.mode == "RGB":
- return Color.rgb(p[0], p[1], p[2])
- elif self._image.mode == "L":
- return Color.argb(255, p, p, p)
- return 0
-
- def getPixels(self, pixels: List[int], offset: int, stride: int,
- x: int, y: int, width: int, height: int):
- if self._recycled:
- return
- for row in range(height):
- for col in range(width):
- px = x + col
- py = y + row
- idx = offset + row * stride + col
- if 0 <= idx < len(pixels) and 0 <= px < self._width and 0 <= py < self._height:
- pixels[idx] = self.getPixel(px, py)
-
- def setPixel(self, x: int, y: int, color: int):
- if self._recycled:
- return
- if HAS_PIL and hasattr(self, "_image"):
- if self._image.mode == "RGBA":
- self._image.putpixel((x, y), (
- Color.red(color), Color.green(color),
- Color.blue(color), Color.alpha(color)
- ))
- elif self._image.mode == "RGB":
- self._image.putpixel((x, y), (
- Color.red(color), Color.green(color), Color.blue(color)
- ))
- elif self._image.mode == "L":
- self._image.putpixel((x, y), Color.red(color))
- else:
- pass
-
- def setPixels(self, pixels: List[int], offset: int, stride: int,
- x: int, y: int, width: int, height: int):
- for row in range(height):
- for col in range(width):
- idx = offset + row * stride + col
- if idx < len(pixels):
- self.setPixel(x + col, y + row, pixels[idx])
-
- def eraseColor(self, color: int):
- if self._recycled:
- return
- if HAS_PIL and hasattr(self, "_image"):
- from PIL import Image
- w, h = self._image.size
- if self._image.mode == "RGBA":
- self._image = Image.new("RGBA", (w, h),
- (Color.red(color), Color.green(color),
- Color.blue(color), Color.alpha(color)))
- elif self._image.mode == "RGB":
- self._image = Image.new("RGB", (w, h),
- (Color.red(color), Color.green(color), Color.blue(color)))
-
- def extractAlpha(self, paint: Paint = None) -> "Bitmap":
- return Bitmap(self._width, self._height, Bitmap.Config.ALPHA_8)
-
- def sameAs(self, other: "Bitmap") -> bool:
- """比较两个 Bitmap 的像素是否完全相同。"""
- if not isinstance(other, Bitmap):
- return False
- if self._width != other._width or self._height != other._height:
- return False
- if self._config != other._config:
- return False
- if self._recycled or other._recycled:
- return False
- # 使用 PIL 比较像素
- if HAS_PIL and hasattr(self, "_image") and hasattr(other, "_image"):
- try:
- from PIL import ImageChops
- diff = ImageChops.difference(self._image, other._image)
- return diff.getbbox() is None
- except Exception:
- return list(self._image.getdata()) == list(other._image.getdata())
- # 回退到字节比较
- if hasattr(self, "_pixels") and hasattr(other, "_pixels"):
- return bytes(self._pixels) == bytes(other._pixels)
- return True
-
- def prepareToDraw(self):
- """提示将位图数据上传到 GPU 缓存。桌面端为空操作。"""
- pass
-
- def hasAlpha(self) -> bool:
- return self._has_alpha
-
- def setHasAlpha(self, hasAlpha: bool):
- self._has_alpha = hasAlpha
-
- def getGenerationId(self) -> int:
- return self._generation_id
-
- def describeContents(self) -> int:
- return 0
-
- def writeToParcel(self, dest, flags: int):
- pass
-
- def copyPixelsToBuffer(self, dst):
- if HAS_PIL and hasattr(self, "_image"):
- buf = self._image.tobytes()
- dst.write(buf)
-
- def copyPixelsFromBuffer(self, src):
- if HAS_PIL and hasattr(self, "_image"):
- data = src.read()
- import io as _io
- buf = _io.BytesIO(data)
- from PIL import Image
- self._image = Image.open(buf)
- self._image = self._image.resize((self._width, self._height))
-
- def asMutable(self) -> "Bitmap":
- return Bitmap.createBitmap(self)
-
- def toString(self) -> str:
- return f"Bitmap({self._width}x{self._height}, config={self._config})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BitmapFactory
-# ═══════════════════════════════════════════════════════════════
-
-class BitmapFactory(Stub):
- """BitmapFactory — 位图工厂"""
-
- class Options(Stub):
- """BitmapFactory.Options — 解码选项"""
-
- def __init__(self):
- super().__init__()
- self.inJustDecodeBounds = False
- self.outWidth = 0
- self.outHeight = 0
- self.inSampleSize = 1
- self.inPreferredConfig = Bitmap.Config.ARGB_8888
- self.inDensity = 0
- self.inTargetDensity = 0
- self.inScaled = True
- self.inMutable = False
- self.outMimeType = ""
- self.inPurgeable = False
- self.inInputShareable = False
-
- @staticmethod
- def decodeFile(pathName: str, opts: Options = None) -> Optional[Bitmap]:
- resolved = resolve_android_path(pathName)
- if not os.path.exists(resolved):
- return None
- if HAS_PIL:
- from PIL import Image
- try:
- img = Image.open(resolved)
- if opts and opts.inJustDecodeBounds:
- opts.outWidth, opts.outHeight = img.size
- opts.outMimeType = f"image/{img.format.lower() if img.format else 'png'}"
- return None
- w, h = img.size
- bm = Bitmap(w, h, opts.inPreferredConfig if opts else Bitmap.Config.ARGB_8888)
- if img.mode != "RGBA":
- img = img.convert("RGBA")
- bm._image = img
- return bm
- except Exception:
- return None
- return Bitmap(100, 100, Bitmap.Config.ARGB_8888)
-
- @staticmethod
- def decodeResource(res, resId: int, opts: Options = None) -> Optional[Bitmap]:
- """从资源解码位图。尝试通过 Resources 打开原始资源流。"""
- # 尝试通过 Resources 获取资源路径或流
- if res is not None:
- try:
- # 尝试 openRawResource
- stream = res.openRawResource(resId)
- if stream is not None:
- return BitmapFactory.decodeStream(stream, None, opts)
- except Exception:
- pass
- try:
- # 尝试通过资源名查找文件
- name = res.getResourceEntryName(resId) if hasattr(res, "getResourceEntryName") else None
- if name and name != "unknown":
- for ext in (".png", ".jpg", ".jpeg", ".webp", ".bmp"):
- candidate = resolve_android_path("res/drawable/" + name + ext)
- if os.path.exists(candidate):
- return BitmapFactory.decodeFile(candidate, opts)
- candidate = resolve_android_path("res/drawable-xxhdpi/" + name + ext)
- if os.path.exists(candidate):
- return BitmapFactory.decodeFile(candidate, opts)
- except Exception:
- pass
- return Bitmap(100, 100, Bitmap.Config.ARGB_8888)
-
- @staticmethod
- def decodeStream(stream, outPadding: "Rect" = None, opts: Options = None) -> Optional[Bitmap]:
- if stream is None:
- return None
- if HAS_PIL:
- from PIL import Image
- try:
- img = Image.open(stream)
- if opts and opts.inJustDecodeBounds:
- opts.outWidth, opts.outHeight = img.size
- return None
- w, h = img.size
- bm = Bitmap(w, h, opts.inPreferredConfig if opts else Bitmap.Config.ARGB_8888)
- if img.mode != "RGBA":
- img = img.convert("RGBA")
- bm._image = img
- return bm
- except Exception:
- return None
- return Bitmap(100, 100, Bitmap.Config.ARGB_8888)
-
- @staticmethod
- def decodeByteArray(data: bytes, offset: int, length: int, opts: Options = None) -> Optional[Bitmap]:
- if not data:
- return None
- if HAS_PIL:
- from PIL import Image
- import io as _io
- try:
- buf = _io.BytesIO(data[offset:offset + length])
- img = Image.open(buf)
- if opts and opts.inJustDecodeBounds:
- opts.outWidth, opts.outHeight = img.size
- return None
- w, h = img.size
- bm = Bitmap(w, h, opts.inPreferredConfig if opts else Bitmap.Config.ARGB_8888)
- if img.mode != "RGBA":
- img = img.convert("RGBA")
- bm._image = img
- return bm
- except Exception:
- return None
- return Bitmap(100, 100, Bitmap.Config.ARGB_8888)
-
- @staticmethod
- def decodeResourceStream(res, value, stream, pad: "Rect", opts: Options = None) -> Optional[Bitmap]:
- return BitmapFactory.decodeStream(stream, pad, opts)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Canvas
-# ═══════════════════════════════════════════════════════════════
-
-class Canvas(Stub):
- """Canvas — 画布"""
-
- ALL_SAVE_FLAG = 0x1F
-
- def __init__(self, width=0, height=0):
- super().__init__()
- # 支持 Canvas(Bitmap) 重载
- if isinstance(width, Bitmap):
- bitmap = width
- self._bitmap = bitmap
- self._width = bitmap.getWidth()
- self._height = bitmap.getHeight()
- if HAS_PIL:
- from PIL import Image, ImageDraw
- self._image = bitmap._image if hasattr(bitmap, '_image') and bitmap._image else None
- self._draw = ImageDraw.Draw(self._image) if self._image else None
- else:
- self._pixels = None
- self._save_count = 0
- self._matrix_stack = [Matrix()]
- self._clip_stack = [Rect(0, 0, self._width, self._height)]
- self._matrix = Matrix()
- return
- if HAS_PIL:
- from PIL import Image, ImageDraw
- self._width = width
- self._height = height
- if width > 0 and height > 0:
- self._image = Image.new("RGBA", (width, height), (0, 0, 0, 0))
- self._draw = ImageDraw.Draw(self._image)
- else:
- self._image = None
- self._draw = None
- else:
- self._width = width
- self._height = height
- self._pixels = None
- self._bitmap = None
- self._save_count = 0
- self._matrix_stack = [Matrix()]
- self._clip_stack = [Rect(0, 0, width, height)]
- self._matrix = Matrix()
-
- def setBitmap(self, bitmap: Bitmap):
- self._bitmap = bitmap
- self._width = bitmap.getWidth()
- self._height = bitmap.getHeight()
- if HAS_PIL:
- from PIL import ImageDraw
- if hasattr(bitmap, "_image") and bitmap._image:
- self._image = bitmap._image
- self._draw = ImageDraw.Draw(self._image)
-
- def getBitmap(self) -> Optional[Bitmap]:
- return self._bitmap
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def save(self) -> int:
- self._save_count += 1
- self._matrix_stack.append(Matrix(self._matrix))
- self._clip_stack.append(Rect(
- self._clip_stack[-1].left, self._clip_stack[-1].top,
- self._clip_stack[-1].right, self._clip_stack[-1].bottom
- ))
- return self._save_count
-
- def restore(self):
- if len(self._matrix_stack) > 1:
- self._matrix = self._matrix_stack.pop()
- self._clip_stack.pop()
- self._save_count -= 1
-
- def saveLayer(self, bounds: RectF, paint: Paint = None, saveFlags: int = ALL_SAVE_FLAG) -> int:
- return self.save()
-
- def getSaveCount(self) -> int:
- return self._save_count
-
- def restoreToCount(self, saveCount: int):
- while self._save_count > saveCount:
- self.restore()
-
- def translate(self, dx: float, dy: float):
- self._matrix.postTranslate(dx, dy)
-
- def scale(self, sx: float, sy: float, px: float = 0.0, py: float = 0.0):
- self._matrix.postScale(sx, sy, px, py)
-
- def rotate(self, degrees: float, px: float = 0.0, py: float = 0.0):
- self._matrix.postRotate(degrees, px, py)
-
- def skew(self, sx: float, sy: float):
- self._matrix.postSkew(sx, sy)
-
- def concat(self, matrix: Matrix):
- self._matrix.postConcat(matrix)
-
- def setMatrix(self, matrix: Matrix):
- self._matrix = Matrix(matrix)
-
- def getMatrix(self, ctm: Matrix = None) -> Matrix:
- if ctm:
- ctm._values = list(self._matrix._values)
- return ctm
- return Matrix(self._matrix)
-
- def getLocalTransform(self, transform: Matrix = None) -> Matrix:
- return self.getMatrix(transform)
-
- def getDeviceTransform(self, transform: Matrix = None) -> Matrix:
- if transform:
- transform.reset()
- return transform
- return Matrix()
-
- def clipRect(self, left: float, top: float, right: float, bottom: float,
- op: int = ClipOp.INTERSECT):
- r = self._clip_stack[-1]
- if op == ClipOp.INTERSECT:
- self._clip_stack[-1] = Rect(
- max(r.left, int(left)), max(r.top, int(top)),
- min(r.right, int(right)), min(r.bottom, int(bottom))
- )
- elif op == ClipOp.DIFFERENCE:
- pass
-
- def clipPath(self, path: Path, op: int = ClipOp.INTERSECT):
- bounds = path.computeBounds()
- self.clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, op)
-
- def clipRegion(self, region: Region, op: int = ClipOp.INTERSECT):
- r = region._rect
- self.clipRect(float(r.left), float(r.top), float(r.right), float(r.bottom), op)
-
- def getClipBounds(self, bounds: Rect = None) -> Rect:
- r = self._clip_stack[-1]
- if bounds:
- bounds.set(r.left, r.top, r.right, r.bottom)
- return bounds
- return Rect(r.left, r.top, r.right, r.bottom)
-
- def quickReject(self, *args) -> bool:
- """判断给定矩形是否完全在裁剪区域之外。"""
- clip = self._clip_stack[-1]
- if len(args) == 1:
- r = args[0]
- if isinstance(r, Rect):
- left, top, right, bottom = r.left, r.top, r.right, r.bottom
- elif isinstance(r, RectF):
- left, top, right, bottom = r.left, r.top, r.right, r.bottom
- else:
- return False
- elif len(args) == 4:
- left, top, right, bottom = args
- else:
- return False
- return (right <= clip.left or left >= clip.right or
- bottom <= clip.top or top >= clip.bottom)
-
- def drawColor(self, color: int):
- if HAS_PIL and self._draw is not None:
- r, g, b = Color.red(color), Color.green(color), Color.blue(color)
- a = Color.alpha(color)
- self._draw.rectangle([0, 0, self._width, self._height],
- fill=(r, g, b, a))
-
- def drawARGB(self, a: int, r: int, g: int, b: int):
- self.drawColor(Color.argb(a, r, g, b))
-
- def drawRGB(self, r: int, g: int, b: int):
- self.drawARGB(255, r, g, b)
-
- def drawPaint(self, paint: Paint):
- self.drawColor(paint.getColor())
-
- def drawPoint(self, x: float, y: float, paint: Paint):
- if HAS_PIL and self._draw is not None:
- c = paint.getColor()
- self._draw.point([(x, y)], fill=(
- Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c)
- ))
-
- def drawPoints(self, pts: List[float], offset: int = 0, count: int = -1, paint: Paint = None):
- if paint is None:
- paint = Paint()
- if count < 0:
- count = len(pts) - offset
- for i in range(offset, offset + count, 2):
- self.drawPoint(pts[i], pts[i + 1], paint)
-
- def drawLine(self, startX: float, startY: float, stopX: float, stopY: float, paint: Paint):
- if HAS_PIL and self._draw is not None:
- c = paint.getColor()
- w = paint.getStrokeWidth() if paint.getStyle() != Paint.Style.FILL else 1
- self._draw.line([(startX, startY), (stopX, stopY)],
- fill=(Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c)),
- width=max(1, int(w)))
-
- def drawLines(self, pts: List[float], offset: int = 0, count: int = -1, paint: Paint = None):
- if paint is None:
- paint = Paint()
- if count < 0:
- count = len(pts) - offset
- for i in range(offset, offset + count, 4) if count >= 4 else []:
- self.drawLine(pts[i], pts[i + 1], pts[i + 2], pts[i + 3], paint)
-
- def drawRect(self, rect: Union[Rect, RectF, tuple], paint: Paint):
- if isinstance(rect, Rect):
- l, t, r, b = rect.left, rect.top, rect.right, rect.bottom
- elif isinstance(rect, RectF):
- l, t, r, b = rect.left, rect.top, rect.right, rect.bottom
- else:
- l, t, r, b = rect
- if HAS_PIL and self._draw is not None:
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- if paint.getStyle() == Paint.Style.FILL:
- self._draw.rectangle([l, t, r, b], fill=fill_color)
- elif paint.getStyle() == Paint.Style.STROKE:
- w = max(1, int(paint.getStrokeWidth()))
- self._draw.rectangle([l, t, r, b], outline=fill_color, width=w)
- else:
- self._draw.rectangle([l, t, r, b], fill=fill_color)
-
- def drawRoundRect(self, rect: Union[RectF, tuple], rx: float, ry: float, paint: Paint):
- if isinstance(rect, RectF):
- l, t, r, b = rect.left, rect.top, rect.right, rect.bottom
- else:
- l, t, r, b = rect
- if HAS_PIL and self._draw is not None:
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- self._draw.rounded_rectangle(
- [l, t, r, b], radius=rx,
- fill=fill_color if paint.getStyle() != Paint.Style.STROKE else None,
- outline=fill_color if paint.getStyle() != Paint.Style.FILL else None,
- width=max(1, int(paint.getStrokeWidth())) if paint.getStyle() != Paint.Style.FILL else 1
- )
-
- def drawCircle(self, cx: float, cy: float, radius: float, paint: Paint):
- if HAS_PIL and self._draw is not None:
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- bbox = [cx - radius, cy - radius, cx + radius, cy + radius]
- if paint.getStyle() == Paint.Style.FILL:
- self._draw.ellipse(bbox, fill=fill_color)
- elif paint.getStyle() == Paint.Style.STROKE:
- w = max(1, int(paint.getStrokeWidth()))
- self._draw.ellipse(bbox, outline=fill_color, width=w)
- else:
- self._draw.ellipse(bbox, fill=fill_color)
-
- def drawOval(self, rect: Union[RectF, tuple], paint: Paint):
- if isinstance(rect, RectF):
- l, t, r, b = rect.left, rect.top, rect.right, rect.bottom
- else:
- l, t, r, b = rect
- if HAS_PIL and self._draw is not None:
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- self._draw.ellipse([l, t, r, b], fill=fill_color)
-
- def drawArc(self, rect: Union[RectF, tuple], startAngle: float, sweepAngle: float,
- useCenter: bool, paint: Paint):
- if isinstance(rect, RectF):
- l, t, r, b = rect.left, rect.top, rect.right, rect.bottom
- else:
- l, t, r, b = rect
- if HAS_PIL and self._draw is not None:
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- if not HAS_PIL:
- return
- from PIL import ImageDraw
- self._draw.pieslice(
- [l, t, r, b], start=startAngle, end=startAngle + sweepAngle,
- fill=fill_color if useCenter or paint.getStyle() != Paint.Style.STROKE else None,
- outline=fill_color if paint.getStyle() != Paint.Style.FILL else None,
- width=max(1, int(paint.getStrokeWidth())) if paint.getStyle() != Paint.Style.FILL else 1
- )
-
- def drawPath(self, path: Path, paint: Paint):
- if HAS_PIL and self._draw is not None:
- pil_path = []
- for seg in path._segments:
- if seg["type"] == "move":
- pil_path.append(("M", seg["x"], seg["y"]))
- elif seg["type"] == "line":
- pil_path.append(("L", seg["x"], seg["y"]))
- elif seg["type"] == "close":
- pil_path.append(("Z",))
- elif seg["type"] in ("quad", "cubic"):
- pass
- if pil_path:
- from PIL import ImageDraw
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- try:
- if paint.getStyle() == Paint.Style.FILL:
- self._draw.polygon(
- [(s[1], s[2]) for s in pil_path if s[0] in ("M", "L")],
- fill=fill_color
- )
- else:
- w = max(1, int(paint.getStrokeWidth()))
- if len(pil_path) > 1:
- pts = [(s[1], s[2]) for s in pil_path if s[0] in ("M", "L")]
- for i in range(len(pts) - 1):
- self._draw.line([pts[i], pts[i + 1]], fill=fill_color, width=w)
- except Exception:
- pass
-
- def drawBitmap(self, *args):
- """drawBitmap 重载: (bitmap,left,top,paint) / (bitmap,src,dst,paint) / (bitmap,matrix,paint)"""
- if len(args) == 4:
- bitmap, a, b, paint = args
- if isinstance(a, (int, float)) and isinstance(b, (int, float)):
- if HAS_PIL and self._draw is not None and hasattr(bitmap, "_image") and bitmap._image:
- self._image.paste(bitmap._image, (int(a), int(b)))
- elif HAS_PIL and self._image is not None:
- pass
- else:
- src, dst = a, b
- if HAS_PIL and self._image is not None and hasattr(bitmap, "_image") and bitmap._image:
- if src:
- cropped = bitmap._image.crop((src.left, src.top, src.right, src.bottom))
- resized = cropped.resize((int(dst.width()), int(dst.height())))
- self._image.paste(resized, (int(dst.left), int(dst.top)))
- else:
- resized = bitmap._image.resize((int(dst.width()), int(dst.height())))
- self._image.paste(resized, (int(dst.left), int(dst.top)))
- elif len(args) == 3:
- bitmap, matrix, paint = args
- if HAS_PIL and self._image is not None and hasattr(bitmap, "_image") and bitmap._image:
- try:
- from PIL import Image
- inv = Matrix()
- if hasattr(matrix, "invert") and matrix.invert(inv):
- v = inv.getValues()
- elif hasattr(matrix, "getValues"):
- v = matrix.getValues()
- else:
- v = [1, 0, 0, 0, 1, 0, 0, 0, 1]
- transformed = bitmap._image.transform(
- bitmap._image.size, Image.AFFINE,
- (v[0], v[1], v[2], v[3], v[4], v[5]))
- self._image.paste(transformed, (0, 0))
- except Exception:
- pass
-
- def drawText(self, text: str, x: float, y: float, paint: Paint):
- if HAS_PIL and self._draw is not None:
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- self._draw.text((x, y), text, fill=fill_color)
-
- def drawTextOnPath(self, text: str, path: Path, hOffset: float, vOffset: float, paint: Paint):
- """沿路径绘制文本。使用 PathMeasure 逐字符放置。"""
- if not text or not HAS_PIL or self._draw is None:
- return
- pm = PathMeasure(path, False)
- total = pm.getLength()
- if total <= 0:
- return
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- dist = hOffset
- pos = [0.0, 0.0]
- tan = [0.0, 0.0]
- for ch in text:
- cw = paint.measureText(ch)
- if dist > total:
- break
- if pm.getPosTan(dist, pos, tan):
- angle = math.degrees(math.atan2(tan[1], tan[0]))
- # 使用 PIL 旋转绘制每个字符
- try:
- from PIL import Image as _PILImage
- char_img = _PILImage.new("RGBA", (int(cw) + 4, int(paint._text_size) + 4), (0, 0, 0, 0))
- from PIL import ImageDraw as _PILDraw
- cd = _PILDraw.Draw(char_img)
- cd.text((0, 0), ch, fill=fill_color)
- rotated = char_img.rotate(-angle, expand=True, resample=_PILImage.BICUBIC)
- self._image.paste(rotated, (int(pos[0] + vOffset * tan[1]), int(pos[1] - vOffset * tan[0])),
- rotated)
- except Exception:
- self._draw.text((pos[0], pos[1]), ch, fill=fill_color)
- dist += cw
-
- def drawPosText(self, text: str, pos: List[float], paint: Paint):
- if HAS_PIL and self._draw is not None:
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- for i, ch in enumerate(text):
- if i * 2 + 1 < len(pos):
- self._draw.text((pos[i * 2], pos[i * 2 + 1]), ch, fill=fill_color)
-
- def drawPicture(self, picture: Picture, dst: Union[Rect, RectF] = None):
- """回放 Picture 中录制的绘制命令。"""
- if picture is None:
- return
- recorded = getattr(picture, "_recorded", [])
- if not recorded:
- return
- for cmd in recorded:
- method = cmd.get("method")
- args = cmd.get("args", [])
- if method and hasattr(self, method):
- try:
- getattr(self, method)(*args)
- except Exception:
- pass
-
- def drawPatch(self, patch: NinePatch, dst: Rect, paint: Paint = None):
- """绘制 NinePatch(拉伸位图)到目标矩形。"""
- if patch is None or patch._bitmap is None:
- return
- bitmap = patch._bitmap
- if dst is None:
- self.drawBitmap(bitmap, 0, 0, paint)
- return
- # 简单缩放绘制
- if isinstance(dst, (Rect, RectF)):
- dw = dst.right - dst.left
- dh = dst.bottom - dst.top
- else:
- dw, dh = dst[2] - dst[0], dst[3] - dst[1]
- scaled = Bitmap.createScaledBitmap(bitmap, int(dw), int(dh), True)
- self.drawBitmap(scaled, dst.left if hasattr(dst, "left") else dst[0],
- dst.top if hasattr(dst, "top") else dst[1], paint)
-
- def drawDoubleRoundRect(self, outer: RectF, outerRx: float, outerRy: float,
- inner: RectF, innerRx: float, innerRy: float, paint: Paint):
- """绘制双层圆角矩形(外层和内层)。"""
- self.drawRoundRect(outer, outerRx, outerRy, paint)
- self.drawRoundRect(inner, innerRx, innerRy, paint)
-
- def drawBitmapMesh(self, bitmap: Bitmap, meshWidth: int, meshHeight: int,
- verts: List[float], vertOffset: int, colors: List[int],
- colorOffset: int, paint: Paint = None):
- pass
-
- def drawVertices(self, mode: int, vertexCount: int, verts: List[float],
- vertOffset: int, texs: List[float], texOffset: int,
- colors: List[int], colorOffset: int, indices: List[int],
- indexOffset: int, indexCount: int, paint: Paint):
- pass
-
- def isHardwareAccelerated(self) -> bool:
- return False
-
- def isOpaque(self) -> bool:
- return False
-
- def setDensity(self, density: int):
- """设置画布密度(DPI)。"""
- self._density = density
-
- def getDensity(self) -> int:
- """返回画布密度(DPI),默认 0 表示未知。"""
- return getattr(self, "_density", 0)
-
- def toString(self) -> str:
- return f"Canvas({self._width}x{self._height})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- # Core
- "Bitmap", "BitmapFactory", "Canvas", "Paint", "Color", "ColorFilter",
- "PorterDuffColorFilter", "LightingColorFilter", "ComposeColorFilter",
- "ColorMatrix", "ColorMatrixColorFilter", "Path", "PathMeasure",
- "Rect", "RectF", "Point", "PointF", "Typeface", "Matrix",
-
- # Shader hierarchy
- "Shader", "LinearGradient", "RadialGradient", "SweepGradient",
- "BitmapShader", "ComposeShader",
-
- # MaskFilter hierarchy
- "MaskFilter", "BlurMaskFilter", "EmbossMaskFilter",
-
- # PorterDuff
- "PorterDuff", "PorterDuffXfermode", "Xfermode",
- "AvoidXfermode", "PixelXorXfermode",
-
- # DrawFilter
- "DrawFilter", "PaintFlagsDrawFilter",
-
- # PathEffect hierarchy
- "PathEffect", "SumPathEffect", "CornerPathEffect", "DashPathEffect",
- "DiscretePathEffect", "PathDashPathEffect", "ComposePathEffect",
-
- # Misc
- "Camera", "SurfaceTexture", "Region", "RegionIterator",
- "NinePatch", "Picture", "PictureDrawable",
- "Rasterizer", "LayerRasterizer",
-
- # BlendMode
- "BlendMode", "BlendModeColorFilter",
- "ClipOp",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/graphics_drawable.py b/android_pyapi/android/graphics_drawable.py
deleted file mode 100644
index ea929de..0000000
--- a/android_pyapi/android/graphics_drawable.py
+++ /dev/null
@@ -1,1128 +0,0 @@
-"""
-Android Graphics Drawable 组件 — Drawable, BitmapDrawable, ColorDrawable 等
-方法签名完全对齐 Android SDK
-"""
-
-import math
-from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError, android_context, HAS_PIL, resolve_android_path
-from .graphics import (
- Bitmap, Canvas, Color, ColorFilter, Paint, PorterDuff, PorterDuffColorFilter,
- Rect, RectF, Matrix, Path, Shader, Rect,
- BlendMode, BlendModeColorFilter,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ColorStateList
-# ═══════════════════════════════════════════════════════════════
-
-class ColorStateList(Stub):
- """ColorStateList — 颜色状态列表"""
-
- def __init__(self, states: List[List[int]], colors: List[int]):
- super().__init__()
- self._states = list(states)
- self._colors = list(colors)
- self._default_color = colors[-1] if colors else 0
-
- def getColorForState(self, stateSet: List[int], defaultColor: int = 0) -> int:
- return self._default_color
-
- def getDefaultColor(self) -> int:
- return self._default_color
-
- def isStateful(self) -> bool:
- return len(self._states) > 0
-
- def withAlpha(self, alpha: int) -> "ColorStateList":
- new_colors = []
- for c in self._colors:
- a = Color.alpha(c)
- new_a = int(a * alpha / 255)
- new_colors.append(Color.argb(new_a, Color.red(c), Color.green(c), Color.blue(c)))
- return ColorStateList(self._states, new_colors)
-
- @staticmethod
- def valueOf(color: int) -> "ColorStateList":
- return ColorStateList([[]], [color])
-
- def toString(self) -> str:
- return f"ColorStateList({len(self._states)} states)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Drawable
-# ═══════════════════════════════════════════════════════════════
-
-class Drawable(Stub):
- """Drawable — 可绘制对象的抽象基类"""
-
- def __init__(self):
- super().__init__()
- self._bounds = Rect(0, 0, 0, 0)
- self._alpha = 255
- self._color_filter = None
- self._callback = None
- self._visible = True
- self._level = 0
- self._intrinsic_width = -1
- self._intrinsic_height = -1
-
- def setBounds(self, left: int, top: int, right: int, bottom: int):
- self._bounds.set(left, top, right, bottom)
-
- def setBounds(self, bounds: Rect):
- self._bounds.set(bounds.left, bounds.top, bounds.right, bounds.bottom)
-
- def getBounds(self) -> Rect:
- return self._bounds
-
- def copyBounds(self) -> Rect:
- return Rect(self._bounds.left, self._bounds.top,
- self._bounds.right, self._bounds.bottom)
-
- def copyBounds(self, out: Rect) -> Rect:
- out.set(self._bounds.left, self._bounds.top,
- self._bounds.right, self._bounds.bottom)
- return out
-
- def getIntrinsicWidth(self) -> int:
- return self._intrinsic_width
-
- def getIntrinsicHeight(self) -> int:
- return self._intrinsic_height
-
- def setAlpha(self, alpha: int):
- self._alpha = alpha
-
- def getAlpha(self) -> int:
- return self._alpha
-
- def setColorFilter(self, colorFilter: Optional[ColorFilter]):
- self._color_filter = colorFilter
-
- def getColorFilter(self) -> Optional[ColorFilter]:
- return self._color_filter
-
- def getOpacity(self) -> int:
- return 0 # PixelFormat.UNKNOWN
-
- def invalidateSelf(self):
- if self._callback:
- self._callback.invalidateDrawable(self)
-
- def setCallback(self, cb):
- self._callback = cb
-
- def getCallback(self):
- return self._callback
-
- def scheduleDrawable(self, what, who, when: int):
- if self._callback:
- self._callback.scheduleDrawable(what, who, when)
-
- def unscheduleDrawable(self, what, who):
- if self._callback:
- self._callback.unscheduleDrawable(what, who)
-
- def draw(self, canvas: Canvas):
- pass
-
- def setVisible(self, visible: bool, restart: bool = False) -> bool:
- old = self._visible
- self._visible = visible
- return old
-
- def isVisible(self) -> bool:
- return self._visible
-
- def setLevel(self, level: int) -> bool:
- self._level = level
- return True
-
- def getLevel(self) -> int:
- return self._level
-
- def getConstantState(self) -> Optional["DrawableConstantState"]:
- return None
-
- def getCurrent(self) -> "Drawable":
- return self
-
- def mutate(self) -> "Drawable":
- return self
-
- def getMinimumWidth(self) -> int:
- return 0
-
- def getMinimumHeight(self) -> int:
- return 0
-
- def setDither(self, dither: bool):
- pass
-
- def setFilterBitmap(self, filter: bool):
- pass
-
- def setHotspot(self, x: float, y: float):
- pass
-
- def setHotspotBounds(self, left: int, top: int, right: int, bottom: int):
- pass
-
- def getHotspotBounds(self, outRect: Rect):
- outRect.set(0, 0, 0, 0)
-
- def isStateful(self) -> bool:
- return False
-
- def setState(self, stateSet: List[int]) -> bool:
- return False
-
- def getState(self) -> List[int]:
- return []
-
- def jumpToCurrentState(self):
- pass
-
- def clearColorFilter(self):
- self._color_filter = None
-
- def getTransparentRegion(self):
- from .graphics import Region
- return Region(self._bounds)
-
- def onBoundsChange(self, bounds: Rect):
- pass
-
- def onLevelChange(self, level: int) -> bool:
- return False
-
- def onStateChange(self, stateSet: List[int]) -> bool:
- return False
-
- def toString(self) -> str:
- return f"{self.__class__.__name__}({self._bounds})"
-
-
-class DrawableConstantState(Stub):
- """DrawableConstantState — Drawable 常量状态"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# BitmapDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class BitmapDrawable(Drawable):
- """BitmapDrawable — 位图 Drawable"""
-
- def __init__(self, res=None, bitmap: Bitmap = None):
- super().__init__()
- self._bitmap = bitmap if bitmap else Bitmap(0, 0, Bitmap.Config.ARGB_8888)
- self._paint = Paint()
- self._target_density = 160
- self._gravity = 0x33 # Gravity.FILL
- self._tile_mode_x = None
- self._tile_mode_y = None
- self._mutated = False
- if self._bitmap:
- self._intrinsic_width = self._bitmap.getWidth()
- self._intrinsic_height = self._bitmap.getHeight()
-
- def getBitmap(self) -> Bitmap:
- return self._bitmap
-
- def getPaint(self) -> Paint:
- return self._paint
-
- def setAntiAlias(self, aa: bool):
- self._paint.setAntiAlias(aa)
-
- def setFilterBitmap(self, filter: bool):
- self._paint.setFilterBitmap(filter)
-
- def setDither(self, dither: bool):
- self._paint.setDither(dither)
-
- def setTileModeX(self, mode):
- self._tile_mode_x = mode
-
- def setTileModeY(self, mode):
- self._tile_mode_y = mode
-
- def getTileModeX(self):
- return self._tile_mode_x
-
- def getTileModeY(self):
- return self._tile_mode_y
-
- def setGravity(self, gravity: int):
- self._gravity = gravity
-
- def getGravity(self) -> int:
- return self._gravity
-
- def setTargetDensity(self, density: int):
- self._target_density = density
-
- def getTargetDensity(self) -> int:
- return self._target_density
-
- def draw(self, canvas: Canvas):
- if self._bitmap:
- bounds = self._bounds
- if HAS_PIL and hasattr(canvas, "_image") and hasattr(self._bitmap, "_image"):
- bm_img = self._bitmap._image
- if bm_img:
- resized = bm_img.resize((bounds.width(), bounds.height()))
- canvas._image.paste(resized, (bounds.left, bounds.top))
-
- def getIntrinsicWidth(self) -> int:
- return self._bitmap.getWidth() if self._bitmap else -1
-
- def getIntrinsicHeight(self) -> int:
- return self._bitmap.getHeight() if self._bitmap else -1
-
- def getOpacity(self) -> int:
- if self._bitmap:
- return 1 if self._bitmap.hasAlpha() else -1
- return 0
-
- def mutate(self) -> "BitmapDrawable":
- if not self._mutated:
- self._bitmap = Bitmap.createBitmap(self._bitmap)
- self._paint = Paint()
- self._mutated = True
- return self
-
-
-# ═══════════════════════════════════════════════════════════════
-# ColorDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class ColorDrawable(Drawable):
- """ColorDrawable — 纯色 Drawable"""
-
- def __init__(self, color: int = 0):
- super().__init__()
- self._color = color
- self._paint = Paint()
- self._paint.setColor(color)
-
- def getColor(self) -> int:
- return self._color
-
- def setColor(self, color: int):
- self._color = color
- self._paint.setColor(color)
-
- def setAlpha(self, alpha: int):
- self._paint.setAlpha(alpha)
-
- def getAlpha(self) -> int:
- return self._paint.getAlpha()
-
- def draw(self, canvas: Canvas):
- canvas.drawRect(self._bounds, self._paint)
-
- def getOpacity(self) -> int:
- if Color.alpha(self._color) == 255:
- return -1 # OPAQUE
- return -3 # TRANSLUCENT
-
- def mutate(self) -> "ColorDrawable":
- self._paint = Paint()
- self._paint.setColor(self._color)
- return self
-
-
-# ═══════════════════════════════════════════════════════════════
-# GradientDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class GradientDrawable(Drawable):
- """GradientDrawable — 渐变 Drawable"""
-
- RECTANGLE = 0
- OVAL = 1
- LINE = 2
- RING = 3
-
- class Orientation:
- TOP_BOTTOM = 0
- TR_BL = 1
- RIGHT_LEFT = 2
- BR_TL = 3
- BOTTOM_TOP = 4
- BL_TR = 5
- LEFT_RIGHT = 6
- TL_BR = 7
-
- def __init__(self, orientation: int = Orientation.TOP_BOTTOM, colors: List[int] = None):
- super().__init__()
- self._orientation = orientation
- self._colors = colors if colors else [Color.BLACK, Color.WHITE]
- self._shape = GradientDrawable.RECTANGLE
- self._corner_radius = 0.0
- self._corner_radii = None
- self._stroke_width = 0
- self._stroke_color = 0
- self._gradient_type = 0 # LINEAR_GRADIENT
- self._gradient_center_x = 0.5
- self._gradient_center_y = 0.5
- self._use_level = False
- self._width = -1
- self._height = -1
- self._color = None
-
- def setShape(self, shape: int):
- self._shape = shape
-
- def getShape(self) -> int:
- return self._shape
-
- def setSize(self, width: int, height: int):
- self._width = width
- self._height = height
-
- def setStroke(self, width: int, color: int, dashWidth: float = 0, dashGap: float = 0):
- self._stroke_width = width
- self._stroke_color = color
-
- def setCornerRadius(self, radius: float):
- self._corner_radius = radius
- self._corner_radii = None
-
- def setCornerRadii(self, radii: List[float]):
- self._corner_radii = radii
- self._corner_radius = radii[0] if radii else 0
-
- def setColors(self, colors: List[int]):
- self._colors = list(colors)
- self._color = None
-
- def setColor(self, color: int):
- self._color = color
- self._colors = None
-
- def setGradientType(self, gradientType: int):
- self._gradient_type = gradientType
-
- def setGradientCenter(self, x: float, y: float):
- self._gradient_center_x = x
- self._gradient_center_y = y
-
- def setOrientation(self, orientation: int):
- self._orientation = orientation
-
- def setUseLevel(self, useLevel: bool):
- self._use_level = useLevel
-
- def getIntrinsicWidth(self) -> int:
- return self._width if self._width > 0 else super().getIntrinsicWidth()
-
- def getIntrinsicHeight(self) -> int:
- return self._height if self._height > 0 else super().getIntrinsicHeight()
-
- def draw(self, canvas: Canvas):
- bounds = self._bounds
- if HAS_PIL and hasattr(canvas, "_draw") and canvas._draw:
- if self._color is not None:
- c = self._color
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- elif self._colors:
- c = self._colors[0]
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- else:
- fill_color = (0, 0, 0, 255)
-
- if self._shape == GradientDrawable.OVAL:
- canvas._draw.ellipse([bounds.left, bounds.top, bounds.right, bounds.bottom],
- fill=fill_color)
- elif self._shape == GradientDrawable.RECTANGLE and self._corner_radius > 0:
- canvas._draw.rounded_rectangle(
- [bounds.left, bounds.top, bounds.right, bounds.bottom],
- radius=self._corner_radius, fill=fill_color)
- else:
- canvas._draw.rectangle([bounds.left, bounds.top, bounds.right, bounds.bottom],
- fill=fill_color)
-
-
-# ═══════════════════════════════════════════════════════════════
-# LayerDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class LayerDrawable(Drawable):
- """LayerDrawable — 图层 Drawable"""
-
- def __init__(self, layers: List[Drawable]):
- super().__init__()
- self._layers = list(layers)
- self._ids = list(range(len(layers)))
- self._layer_insets = [Rect(0, 0, 0, 0) for _ in layers]
-
- def findDrawableByLayerId(self, id: int) -> Optional[Drawable]:
- for i, lid in enumerate(self._ids):
- if lid == id:
- return self._layers[i]
- return None
-
- def setId(self, index: int, id: int):
- if 0 <= index < len(self._ids):
- self._ids[index] = id
-
- def getNumberOfLayers(self) -> int:
- return len(self._layers)
-
- def getDrawable(self, index: int) -> Optional[Drawable]:
- if 0 <= index < len(self._layers):
- return self._layers[index]
- return None
-
- def setDrawableByLayerId(self, id: int, drawable: Drawable) -> bool:
- for i, lid in enumerate(self._ids):
- if lid == id:
- self._layers[i] = drawable
- return True
- return False
-
- def setLayerInset(self, index: int, l: int, t: int, r: int, b: int):
- if 0 <= index < len(self._layer_insets):
- self._layer_insets[index].set(l, t, r, b)
-
- def setLayerInsetLeft(self, index: int, left: int):
- if 0 <= index < len(self._layer_insets):
- self._layer_insets[index].left = left
-
- def setLayerInsetTop(self, index: int, top: int):
- if 0 <= index < len(self._layer_insets):
- self._layer_insets[index].top = top
-
- def setLayerInsetRight(self, index: int, right: int):
- if 0 <= index < len(self._layer_insets):
- self._layer_insets[index].right = right
-
- def setLayerInsetBottom(self, index: int, bottom: int):
- if 0 <= index < len(self._layer_insets):
- self._layer_insets[index].bottom = bottom
-
- def draw(self, canvas: Canvas):
- for i, layer in enumerate(self._layers):
- ins = self._layer_insets[i] if i < len(self._layer_insets) else Rect(0, 0, 0, 0)
- b = self._bounds
- layer.setBounds(b.left + ins.left, b.top + ins.top,
- b.right - ins.right, b.bottom - ins.bottom)
- layer.draw(canvas)
-
- def mutate(self) -> "LayerDrawable":
- return self
-
- def getOpacity(self) -> int:
- return 0
-
- def isStateful(self) -> bool:
- return any(d.isStateful() for d in self._layers)
-
- def setVisible(self, visible: bool, restart: bool = False) -> bool:
- old = super().setVisible(visible, restart)
- for d in self._layers:
- d.setVisible(visible, restart)
- return old
-
-
-# ═══════════════════════════════════════════════════════════════
-# StateListDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class StateListDrawable(Drawable):
- """StateListDrawable — 状态列表 Drawable"""
-
- def __init__(self):
- super().__init__()
- self._state_sets: List[List[int]] = []
- self._drawables: List[Drawable] = []
- self._current_index = -1
-
- def addState(self, stateSet: List[int], drawable: Drawable):
- self._state_sets.append(stateSet)
- self._drawables.append(drawable)
-
- def selectDrawable(self, index: int) -> bool:
- if 0 <= index < len(self._drawables):
- self._current_index = index
- return True
- return False
-
- def getCurrent(self) -> Drawable:
- if 0 <= self._current_index < len(self._drawables):
- return self._drawables[self._current_index]
- if self._drawables:
- return self._drawables[0]
- return self
-
- def draw(self, canvas: Canvas):
- d = self.getCurrent()
- d.setBounds(self._bounds)
- d.draw(canvas)
-
- def isStateful(self) -> bool:
- return True
-
- def setState(self, stateSet: List[int]) -> bool:
- for i, ss in enumerate(self._state_sets):
- if not ss or all(s in stateSet for s in ss):
- self._current_index = i
- return True
- return False
-
- def mutate(self) -> "StateListDrawable":
- self._drawables = [d.mutate() for d in self._drawables]
- return self
-
-
-# ═══════════════════════════════════════════════════════════════
-# LevelListDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class LevelListDrawable(Drawable):
- """LevelListDrawable — 级别列表 Drawable"""
-
- def __init__(self):
- super().__init__()
- self._levels: List[Tuple[int, int, Drawable]] = []
- self._current_index = -1
-
- def addLevel(self, low: int, high: int, drawable: Drawable):
- self._levels.append((low, high, drawable))
-
- def onLevelChange(self, level: int) -> bool:
- for i, (low, high, d) in enumerate(self._levels):
- if low <= level <= high:
- self._current_index = i
- return True
- return False
-
- def getCurrent(self) -> Drawable:
- if 0 <= self._current_index < len(self._levels):
- return self._levels[self._current_index][2]
- if self._levels:
- return self._levels[0][2]
- return self
-
- def draw(self, canvas: Canvas):
- d = self.getCurrent()
- d.setBounds(self._bounds)
- d.draw(canvas)
-
-
-# ═══════════════════════════════════════════════════════════════
-# TransitionDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class TransitionDrawable(Drawable):
- """TransitionDrawable — 过渡 Drawable"""
-
- def __init__(self, layers: List[Drawable]):
- super().__init__()
- self._layers = list(layers)
- self._transition_progress = 0.0
- self._reverse = False
-
- def startTransition(self, durationMillis: int):
- self._transition_progress = 0.0
- self._reverse = False
-
- def resetTransition(self):
- self._transition_progress = 0.0
- self._reverse = False
-
- def reverse(self, durationMillis: int):
- self._transition_progress = 1.0
- self._reverse = True
-
- def startReverse(self, durationMillis: int = 0):
- self._transition_progress = 1.0
- self._reverse = True
-
- def draw(self, canvas: Canvas):
- for layer in self._layers:
- layer.setBounds(self._bounds)
- layer.draw(canvas)
-
- def getNumberOfLayers(self) -> int:
- return len(self._layers)
-
- def getDrawable(self, index: int) -> Optional[Drawable]:
- if 0 <= index < len(self._layers):
- return self._layers[index]
- return None
-
- def isCrossFadeEnabled(self) -> bool:
- return True
-
- def setCrossFadeEnabled(self, enabled: bool):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# RotateDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class RotateDrawable(Drawable):
- """RotateDrawable — 旋转 Drawable"""
-
- def __init__(self):
- super().__init__()
- self._drawable = None
- self._from_degrees = 0.0
- self._to_degrees = 360.0
- self._pivot_x = 0.5
- self._pivot_y = 0.5
- self._current_degrees = 0.0
-
- def setDrawable(self, drawable: Drawable):
- self._drawable = drawable
-
- def getDrawable(self) -> Optional[Drawable]:
- return self._drawable
-
- def setFromDegrees(self, fromDegrees: float):
- self._from_degrees = fromDegrees
-
- def setToDegrees(self, toDegrees: float):
- self._to_degrees = toDegrees
-
- def setPivotX(self, pivotX: float):
- self._pivot_x = pivotX
-
- def setPivotY(self, pivotY: float):
- self._pivot_y = pivotY
-
- def draw(self, canvas: Canvas):
- if self._drawable:
- self._drawable.setBounds(self._bounds)
- self._drawable.draw(canvas)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScaleDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class ScaleDrawable(Drawable):
- """ScaleDrawable — 缩放 Drawable"""
-
- def __init__(self, drawable: Drawable = None, gravity: int = 0x33, scaleWidth: float = 0.0,
- scaleHeight: float = 0.0):
- super().__init__()
- self._drawable = drawable
- self._gravity = gravity
- self._scale_width = scaleWidth
- self._scale_height = scaleHeight
- self._level = 0
-
- def getDrawable(self) -> Optional[Drawable]:
- return self._drawable
-
- def setLevel(self, level: int) -> bool:
- self._level = level
- if self._drawable:
- self._drawable.setLevel(level)
- return True
-
- def draw(self, canvas: Canvas):
- if self._drawable:
- self._drawable.setBounds(self._bounds)
- self._drawable.draw(canvas)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ClipDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class ClipDrawable(Drawable):
- """ClipDrawable — 裁剪 Drawable"""
-
- HORIZONTAL = 1
- VERTICAL = 2
-
- def __init__(self, drawable: Drawable = None, gravity: int = 0x33, orientation: int = HORIZONTAL):
- super().__init__()
- self._drawable = drawable
- self._gravity = gravity
- self._orientation = orientation
- self._level = 0
-
- def setLevel(self, level: int) -> bool:
- self._level = level
- if self._drawable:
- self._drawable.setLevel(level)
- return True
-
- def draw(self, canvas: Canvas):
- if self._drawable:
- self._drawable.setBounds(self._bounds)
- self._drawable.draw(canvas)
-
-
-# ═══════════════════════════════════════════════════════════════
-# InsetDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class InsetDrawable(Drawable):
- """InsetDrawable — 内嵌 Drawable"""
-
- def __init__(self, drawable: Drawable, inset: float):
- super().__init__()
- self._drawable = drawable
- self._inset = int(inset)
- self._inset_left = int(inset)
- self._inset_top = int(inset)
- self._inset_right = int(inset)
- self._inset_bottom = int(inset)
-
- def getDrawable(self) -> Optional[Drawable]:
- return self._drawable
-
- def getInset(self) -> int:
- return self._inset
-
- def draw(self, canvas: Canvas):
- if self._drawable:
- b = self._bounds
- self._drawable.setBounds(
- b.left + self._inset_left, b.top + self._inset_top,
- b.right - self._inset_right, b.bottom - self._inset_bottom
- )
- self._drawable.draw(canvas)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ShapeDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class ShapeDrawable(Drawable):
- """ShapeDrawable — 形状 Drawable"""
-
- def __init__(self, shape: "Shape" = None):
- super().__init__()
- self._shape = shape
- self._paint = Paint()
- self._intrinsic_width = -1
- self._intrinsic_height = -1
-
- def getShape(self):
- return self._shape
-
- def setShape(self, shape):
- self._shape = shape
-
- def getPaint(self) -> Paint:
- return self._paint
-
- def setIntrinsicWidth(self, width: int):
- self._intrinsic_width = width
-
- def setIntrinsicHeight(self, height: int):
- self._intrinsic_height = height
-
- def getIntrinsicWidth(self) -> int:
- return self._intrinsic_width if self._intrinsic_width > 0 else super().getIntrinsicWidth()
-
- def getIntrinsicHeight(self) -> int:
- return self._intrinsic_height if self._intrinsic_height > 0 else super().getIntrinsicHeight()
-
- def draw(self, canvas: Canvas):
- if self._shape:
- self._shape.draw(canvas, self._paint)
-
-
-class Shape(Stub):
- """Shape — 形状基类"""
- def draw(self, canvas: Canvas, paint: Paint):
- pass
-
-
-class ArcShape(Shape):
- """ArcShape — 弧形"""
- def __init__(self, startAngle: float, sweepAngle: float):
- super().__init__()
- self._start_angle = startAngle
- self._sweep_angle = sweepAngle
-
-
-class OvalShape(Shape):
- """OvalShape — 椭圆"""
- def draw(self, canvas: Canvas, paint: Paint):
- if HAS_PIL and hasattr(canvas, "_draw"):
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- b = canvas.getClipBounds()
- canvas._draw.ellipse([b.left, b.top, b.right, b.bottom], fill=fill_color)
-
-
-class RectShape(Shape):
- """RectShape — 矩形"""
- def draw(self, canvas: Canvas, paint: Paint):
- if HAS_PIL and hasattr(canvas, "_draw"):
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- b = canvas.getClipBounds()
- canvas._draw.rectangle([b.left, b.top, b.right, b.bottom], fill=fill_color)
-
-
-class RoundRectShape(Shape):
- """RoundRectShape — 圆角矩形"""
- def __init__(self, outerRadii: List[float], inset: RectF, innerRadii: List[float]):
- super().__init__()
- self._outer_radii = outerRadii
- self._inset = inset
- self._inner_radii = innerRadii
-
- def draw(self, canvas: Canvas, paint: Paint):
- if HAS_PIL and hasattr(canvas, "_draw"):
- c = paint.getColor()
- fill_color = (Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c))
- b = canvas.getClipBounds()
- radius = self._outer_radii[0] if self._outer_radii else 0
- canvas._draw.rounded_rectangle([b.left, b.top, b.right, b.bottom],
- radius=radius, fill=fill_color)
-
-
-class PaintDrawable(ShapeDrawable):
- """PaintDrawable — 画笔 Drawable (ShapeDrawable 子类)"""
-
- def __init__(self, color: int = 0):
- super().__init__(RectShape())
- self.getPaint().setColor(color)
-
- def setCornerRadius(self, radius: float):
- self.setShape(RoundRectShape([radius, radius, radius, radius], None, None))
-
-
-# ═══════════════════════════════════════════════════════════════
-# VectorDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class VectorDrawable(Drawable):
- """VectorDrawable — 矢量 Drawable"""
-
- def __init__(self):
- super().__init__()
- self._alpha = 255
-
- def setAlpha(self, alpha: int):
- self._alpha = alpha
-
- def getAlpha(self) -> int:
- return self._alpha
-
- def draw(self, canvas: Canvas):
- pass
-
- @staticmethod
- def createFromXml(res, parser) -> "VectorDrawable":
- return VectorDrawable()
-
-
-# ═══════════════════════════════════════════════════════════════
-# RippleDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class RippleDrawable(Drawable):
- """RippleDrawable — 水波纹 Drawable (API 21+)"""
-
- def __init__(self, colorStates: ColorStateList, content: Drawable = None,
- mask: Drawable = None):
- super().__init__()
- self._color_states = colorStates
- self._content = content
- self._mask = mask
- self._radius = -1
-
- def setRadius(self, radius: int):
- self._radius = radius
-
- def getRadius(self) -> int:
- return self._radius
-
- def draw(self, canvas: Canvas):
- if self._content:
- self._content.setBounds(self._bounds)
- self._content.draw(canvas)
-
- def setColor(self, color: ColorStateList):
- self._color_states = color
-
- def getColor(self) -> Optional[ColorStateList]:
- return self._color_states
-
- def mutate(self) -> "RippleDrawable":
- return self
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimatedVectorDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class AnimatedVectorDrawable(Drawable):
- """AnimatedVectorDrawable — 动画矢量 Drawable (API 21+)"""
-
- def __init__(self):
- super().__init__()
- self._running = False
-
- def start(self):
- self._running = True
-
- def stop(self):
- self._running = False
-
- def isRunning(self) -> bool:
- return self._running
-
- def reset(self):
- self._running = False
-
- def draw(self, canvas: Canvas):
- pass
-
- @staticmethod
- def createFromXml(res, parser) -> "AnimatedVectorDrawable":
- return AnimatedVectorDrawable()
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimationDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class AnimationDrawable(Drawable):
- """AnimationDrawable — 帧动画 Drawable"""
-
- def __init__(self):
- super().__init__()
- self._frames: List[Tuple[Drawable, int]] = []
- self._current_frame = 0
- self._oneshot = False
- self._running = False
-
- def addFrame(self, frame: Drawable, duration: int):
- self._frames.append((frame, duration))
-
- def getFrame(self, index: int) -> Optional[Drawable]:
- if 0 <= index < len(self._frames):
- return self._frames[index][0]
- return None
-
- def getNumberOfFrames(self) -> int:
- return len(self._frames)
-
- def getDuration(self, index: int) -> int:
- if 0 <= index < len(self._frames):
- return self._frames[index][1]
- return 0
-
- def setOneShot(self, oneshot: bool):
- self._oneshot = oneshot
-
- def isOneShot(self) -> bool:
- return self._oneshot
-
- def start(self):
- self._running = True
-
- def stop(self):
- self._running = False
-
- def isRunning(self) -> bool:
- return self._running
-
- def run(self):
- pass
-
- def selectDrawable(self, index: int) -> bool:
- if 0 <= index < len(self._frames):
- self._current_frame = index
- return True
- return False
-
- def getCurrent(self) -> Drawable:
- if self._frames:
- return self._frames[self._current_frame][0]
- return self
-
- def draw(self, canvas: Canvas):
- d = self.getCurrent()
- d.setBounds(self._bounds)
- d.draw(canvas)
-
- def setVisible(self, visible: bool, restart: bool = False) -> bool:
- old = super().setVisible(visible, restart)
- if visible and restart:
- self._current_frame = 0
- return old
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrawableContainer
-# ═══════════════════════════════════════════════════════════════
-
-class DrawableContainer(Drawable):
- """DrawableContainer — Drawable 容器"""
-
- def __init__(self):
- super().__init__()
- self._drawables: List[Drawable] = []
- self._current_index = 0
-
- def selectDrawable(self, index: int) -> bool:
- if 0 <= index < len(self._drawables):
- self._current_index = index
- return True
- return False
-
- def getCurrent(self) -> Drawable:
- if self._drawables:
- return self._drawables[self._current_index]
- return self
-
- def draw(self, canvas: Canvas):
- d = self.getCurrent()
- d.setBounds(self._bounds)
- d.draw(canvas)
-
- def setAlpha(self, alpha: int):
- for d in self._drawables:
- d.setAlpha(alpha)
-
- def setColorFilter(self, cf: Optional[ColorFilter]):
- for d in self._drawables:
- d.setColorFilter(cf)
-
- def getOpacity(self) -> int:
- return 0
-
- def isStateful(self) -> bool:
- return any(d.isStateful() for d in self._drawables)
-
- def mutate(self) -> "DrawableContainer":
- return self
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Drawable", "BitmapDrawable", "ColorDrawable", "GradientDrawable",
- "LayerDrawable", "StateListDrawable", "LevelListDrawable",
- "TransitionDrawable", "RotateDrawable", "ScaleDrawable",
- "ClipDrawable", "InsetDrawable", "ShapeDrawable", "PaintDrawable",
- "VectorDrawable", "RippleDrawable", "AnimatedVectorDrawable",
- "AnimationDrawable", "DrawableContainer", "DrawableConstantState",
- "ColorStateList",
- # Shapes
- "Shape", "ArcShape", "OvalShape", "RectShape", "RoundRectShape",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/graphics_drawable_ext.py b/android_pyapi/android/graphics_drawable_ext.py
deleted file mode 100644
index adad698..0000000
--- a/android_pyapi/android/graphics_drawable_ext.py
+++ /dev/null
@@ -1,668 +0,0 @@
-"""
-Android graphics.drawable 扩展 — ShapeDrawable, GradientDrawable, LayerDrawable,
-StateListDrawable, AnimatedVectorDrawable, RippleDrawable 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "ShapeDrawable",
- "PaintDrawable",
- "GradientDrawable",
- "StateListDrawable",
- "LayerDrawable",
- "LevelListDrawable",
- "ScaleDrawable",
- "ClipDrawable",
- "RotateDrawable",
- "TransitionDrawable",
- "AnimatedStateListDrawable",
- "AnimatedImageDrawable",
- "AnimatedVectorDrawable",
- "RippleDrawable",
- "AnimatedRotateDrawable",
- "InsetDrawable",
- "NinePatchDrawable",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# ShapeDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class ShapeDrawable(Stub):
- """ShapeDrawable — 形状可绘制对象 (桌面存根)"""
-
- def __init__(self, shape: Any = None):
- super().__init__()
- self._shape = shape
- self._paint = None
- self._shader_factory = None
- self._bounds = (0, 0, 0, 0)
- self._alpha = 255
-
- def getShape(self) -> Any:
- """获取形状"""
- return self._shape
-
- def setShape(self, shape: Any) -> None:
- """设置形状"""
- self._shape = shape
-
- def getPaint(self) -> Any:
- """获取画笔"""
- return self._paint
-
- def setShaderFactory(self, factory: Any) -> None:
- """设置着色器工厂"""
- self._shader_factory = factory
-
- def getShaderFactory(self) -> Any:
- """获取着色器工厂"""
- return self._shader_factory
-
- def inflate(self, context: Any, attrs: Any) -> None:
- """从 XML 填充"""
- pass
-
- def setAlpha(self, alpha: int) -> None:
- """设置透明度"""
- self._alpha = alpha
-
- def getAlpha(self) -> int:
- """获取透明度"""
- return self._alpha
-
- def setBounds(self, left: int, top: int, right: int, bottom: int) -> None:
- """设置边界"""
- self._bounds = (left, top, right, bottom)
-
- def getIntrinsicWidth(self) -> int:
- """获取内部宽度"""
- if self._shape and hasattr(self._shape, 'getWidth'):
- return self._shape.getWidth()
- return 0
-
- def getIntrinsicHeight(self) -> int:
- """获取内部高度"""
- if self._shape and hasattr(self._shape, 'getHeight'):
- return self._shape.getHeight()
- return 0
-
-
-class PaintDrawable(ShapeDrawable):
- """PaintDrawable — 画笔可绘制对象"""
-
- def __init__(self, color: int = 0):
- super().__init__()
- self._color = color
-
- def setColor(self, color: int) -> None:
- """设置颜色"""
- self._color = color
-
-
-# ═══════════════════════════════════════════════════════════════
-# GradientDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class GradientDrawable(ShapeDrawable):
- """GradientDrawable — 渐变可绘制对象"""
-
- RECTANGLE = 0
- OVAL = 1
- LINE = 2
- RING = 3
- LINEAR_GRADIENT = 0
- RADIAL_GRADIENT = 1
- SWEEP_GRADIENT = 2
-
- def __init__(self, orientation: Any = None, colors: Optional[List[int]] = None):
- super().__init__()
- self._shape_type = GradientDrawable.RECTANGLE
- self._gradient_type = GradientDrawable.LINEAR_GRADIENT
- self._gradient_center = (0.5, 0.5)
- self._corner_radius = 0.0
- self._corner_radii: Optional[List[float]] = None
- self._stroke_width = 0
- self._stroke_color = 0
- self._color = 0
- self._colors = colors or []
- self._orientation = orientation
- self._size = (0, 0)
-
- def setShape(self, shape_type: int) -> None:
- """设置形状类型"""
- self._shape_type = shape_type
-
- def setSize(self, width: int, height: int) -> None:
- """设置尺寸"""
- self._size = (width, height)
-
- def setGradientType(self, gradient_type: int) -> None:
- """设置渐变类型"""
- self._gradient_type = gradient_type
-
- def setGradientCenter(self, x: float, y: float) -> None:
- """设置渐变中心"""
- self._gradient_center = (x, y)
-
- def setCornerRadius(self, radius: float) -> None:
- """设置圆角半径"""
- self._corner_radius = radius
-
- def setCornerRadii(self, radii: List[float]) -> None:
- """设置圆角半径组"""
- self._corner_radii = radii
-
- def setStroke(self, width: int, color: int, dash_width: float = 0.0,
- dash_gap: float = 0.0) -> None:
- """设置描边"""
- self._stroke_width = width
- self._stroke_color = color
-
- def setColor(self, color: int) -> None:
- """设置颜色"""
- self._color = color
-
- def getColor(self) -> int:
- """获取颜色"""
- return self._color
-
- def setColors(self, colors: List[int]) -> None:
- """设置颜色数组"""
- self._colors = colors
-
- def getOrientation(self) -> Any:
- """获取方向"""
- return self._orientation
-
- def getIntrinsicWidth(self) -> int:
- return self._size[0]
-
- def getIntrinsicHeight(self) -> int:
- return self._size[1]
-
-
-# ═══════════════════════════════════════════════════════════════
-# StateListDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class StateListDrawable(ShapeDrawable):
- """StateListDrawable — 状态列表可绘制对象"""
-
- def __init__(self):
- super().__init__()
- self._states: List[Tuple[List[int], Any]] = []
- self._enter_fade_duration = 0
- self._exit_fade_duration = 0
-
- def addState(self, state_set: List[int], drawable: Any) -> None:
- """添加状态"""
- self._states.append((state_set, drawable))
-
- def setState(self, state_set: List[int]) -> bool:
- """设置当前状态"""
- return True
-
- def getStateCount(self) -> int:
- """获取状态数量"""
- return len(self._states)
-
- def getStateSet(self, index: int) -> List[int]:
- """获取指定索引的状态集"""
- if 0 <= index < len(self._states):
- return self._states[index][0]
- return []
-
- def getStateDrawable(self, index: int) -> Any:
- """获取指定索引的可绘制对象"""
- if 0 <= index < len(self._states):
- return self._states[index][1]
- return None
-
- def setEnterFadeDuration(self, duration: int) -> None:
- """设置进入淡出时间"""
- self._enter_fade_duration = duration
-
- def setExitFadeDuration(self, duration: int) -> None:
- """设置退出淡出时间"""
- self._exit_fade_duration = duration
-
-
-# ═══════════════════════════════════════════════════════════════
-# LayerDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class LayerDrawable(ShapeDrawable):
- """LayerDrawable — 图层可绘制对象"""
-
- def __init__(self, layers: Optional[List[Any]] = None):
- super().__init__()
- self._layers: List[Any] = layers or []
- self._layer_insets: Dict[int, Tuple[int, int, int, int]] = {}
- self._padding = (0, 0, 0, 0)
- self._id_map: Dict[int, int] = {}
-
- def setLayerInset(self, index: int, left: int, top: int, right: int, bottom: int) -> None:
- """设置图层嵌入"""
- self._layer_insets[index] = (left, top, right, bottom)
-
- def setLayerInsetRelative(self, index: int, start: int, top: int, end: int, bottom: int) -> None:
- """设置相对图层嵌入"""
- self._layer_insets[index] = (start, top, end, bottom)
-
- def setDrawable(self, index: int, drawable: Any) -> None:
- """设置可绘制对象"""
- while len(self._layers) <= index:
- self._layers.append(None)
- self._layers[index] = drawable
-
- def setDrawableByLayerId(self, id_: int, drawable: Any) -> bool:
- """按图层 ID 设置可绘制对象"""
- if id_ in self._id_map:
- idx = self._id_map[id_]
- self._layers[idx] = drawable
- return True
- return False
-
- def findDrawableByLayerId(self, id_: int) -> Any:
- """按图层 ID 查找可绘制对象"""
- if id_ in self._id_map:
- idx = self._id_map[id_]
- if 0 <= idx < len(self._layers):
- return self._layers[idx]
- return None
-
- def getLayerCount(self) -> int:
- """获取图层数量"""
- return len(self._layers)
-
- def getNumberOfLayers(self) -> int:
- """获取图层数量"""
- return len(self._layers)
-
- def getId(self, index: int) -> int:
- """获取图层 ID"""
- for id_, idx in self._id_map.items():
- if idx == index:
- return id_
- return 0
-
- def setPadding(self, left: int, top: int, right: int, bottom: int) -> None:
- """设置内边距"""
- self._padding = (left, top, right, bottom)
-
- def setLayerGravity(self, index: int, gravity: int) -> None:
- """设置图层重力"""
- pass
-
- def setLayerWidth(self, index: int, width: int) -> None:
- """设置图层宽度"""
- pass
-
- def setLayerHeight(self, index: int, height: int) -> None:
- """设置图层高度"""
- pass
-
- def setLayerInsetLeft(self, index: int, left: int) -> None:
- if index in self._layer_insets:
- l, t, r, b = self._layer_insets[index]
- self._layer_insets[index] = (left, t, r, b)
- else:
- self._layer_insets[index] = (left, 0, 0, 0)
-
- def setLayerInsetRight(self, index: int, right: int) -> None:
- if index in self._layer_insets:
- l, t, r, b = self._layer_insets[index]
- self._layer_insets[index] = (l, t, right, b)
- else:
- self._layer_insets[index] = (0, 0, right, 0)
-
- def setLayerInsetTop(self, index: int, top: int) -> None:
- if index in self._layer_insets:
- l, t, r, b = self._layer_insets[index]
- self._layer_insets[index] = (l, top, r, b)
- else:
- self._layer_insets[index] = (0, top, 0, 0)
-
- def setLayerInsetBottom(self, index: int, bottom: int) -> None:
- if index in self._layer_insets:
- l, t, r, b = self._layer_insets[index]
- self._layer_insets[index] = (l, t, r, bottom)
- else:
- self._layer_insets[index] = (0, 0, 0, bottom)
-
- def setLayerInsetStart(self, index: int, start: int) -> None:
- self.setLayerInsetLeft(index, start)
-
- def setLayerInsetEnd(self, index: int, end: int) -> None:
- self.setLayerInsetRight(index, end)
-
- def mutate(self) -> "LayerDrawable":
- """变异"""
- return self
-
-
-class LevelListDrawable(StateListDrawable):
- """LevelListDrawable — 级别列表可绘制对象"""
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScaleDrawable / ClipDrawable / RotateDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class ScaleDrawable(ShapeDrawable):
- """ScaleDrawable — 缩放可绘制对象"""
-
- def __init__(self, drawable: Any = None, gravity: int = 0,
- scale_width: float = 1.0, scale_height: float = 1.0):
- super().__init__()
- self._drawable = drawable
- self._gravity = gravity
- self._scale_width = scale_width
- self._scale_height = scale_height
- self._level = 0
-
- def setScaleWidth(self, scale_width: float) -> None:
- self._scale_width = scale_width
-
- def setScaleHeight(self, scale_height: float) -> None:
- self._scale_height = scale_height
-
- def getScale(self) -> Tuple[float, float]:
- return (self._scale_width, self._scale_height)
-
- def getLevel(self) -> int:
- return self._level
-
-
-class ClipDrawable(ShapeDrawable):
- """ClipDrawable — 裁剪可绘制对象"""
-
- HORIZONTAL = 1
- VERTICAL = 2
-
- def __init__(self, drawable: Any = None, gravity: int = 0, orientation: int = HORIZONTAL):
- super().__init__()
- self._drawable = drawable
- self._gravity = gravity
- self._orientation = orientation
-
-
-class RotateDrawable(ShapeDrawable):
- """RotateDrawable — 旋转可绘制对象"""
-
- def __init__(self, drawable: Any = None, gravity: int = 0):
- super().__init__()
- self._drawable = drawable
- self._gravity = gravity
- self._rotation = 0.0
- self._pivot_x = 0.5
- self._pivot_y = 0.5
-
- def setRotation(self, rotation: float) -> None:
- self._rotation = rotation
-
-
-# ═══════════════════════════════════════════════════════════════
-# TransitionDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class TransitionDrawable(LayerDrawable):
- """TransitionDrawable — 过渡可绘制对象"""
-
- def __init__(self, layers: Optional[List[Any]] = None):
- super().__init__(layers)
- self._cross_fade_enabled = False
-
- def startTransition(self, duration_ms: int) -> None:
- """开始过渡"""
- pass
-
- def resetTransition(self) -> None:
- """重置过渡"""
- pass
-
- def reverseTransition(self, duration_ms: int) -> None:
- """反向过渡"""
- pass
-
- def crossFadeEnabled(self) -> bool:
- """检查是否启用交叉淡入"""
- return self._cross_fade_enabled
-
- def setCrossFadeEnabled(self, enabled: bool) -> None:
- """设置交叉淡入"""
- self._cross_fade_enabled = enabled
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimatedStateListDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class AnimatedStateListDrawable(StateListDrawable):
- """AnimatedStateListDrawable — 动画状态列表可绘制对象"""
-
- def __init__(self):
- super().__init__()
- self._transitions: Dict[Tuple[int, int], Any] = {}
-
- def addState(self, state_set: List[int], drawable: Any, state_id: int) -> None:
- """添加状态"""
- self._states.append((state_set, drawable))
-
- def addTransition(self, from_id: int, to_id: int, transition: Any) -> None:
- """添加过渡"""
- self._transitions[(from_id, to_id)] = transition
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimatedImageDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class AnimatedImageDrawable(ShapeDrawable):
- """AnimatedImageDrawable — 动画图像可绘制对象"""
-
- LOOP_FINITE = 0
- LOOP_INFINITE = -1
- INFINITE = -1
-
- def __init__(self):
- super().__init__()
- self._running = False
- self._repeat_count = 0
- self._loop_behavior = AnimatedImageDrawable.LOOP_FINITE
-
- def start(self) -> None:
- """开始动画"""
- self._running = True
-
- def stop(self) -> None:
- """停止动画"""
- self._running = False
-
- def isRunning(self) -> bool:
- """检查是否正在运行"""
- return self._running
-
- def setRepeatCount(self, count: int) -> None:
- """设置重复次数"""
- self._repeat_count = count
-
- def getRepeatCount(self) -> int:
- """获取重复次数"""
- return self._repeat_count
-
- def setLoopBehavior(self, behavior: int) -> None:
- """设置循环行为"""
- self._loop_behavior = behavior
-
- def getLoopBehavior(self) -> int:
- """获取循环行为"""
- return self._loop_behavior
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimatedVectorDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class AnimatedVectorDrawable(ShapeDrawable):
- """AnimatedVectorDrawable — 动画矢量可绘制对象"""
-
- def __init__(self):
- super().__init__()
- self._running = False
- self._alpha = 255
- self._hotspot = (0, 0)
- self._hotspot_bounds = (0, 0, 0, 0)
-
- def start(self) -> None:
- """开始动画"""
- self._running = True
-
- def stop(self) -> None:
- """停止动画"""
- self._running = False
-
- def reset(self) -> None:
- """重置动画"""
- self._running = False
-
- def isRunning(self) -> bool:
- """检查是否正在运行"""
- return self._running
-
- def setVisible(self, visible: bool, restart: bool) -> bool:
- """设置可见性"""
- return True
-
- def setAlpha(self, alpha: int) -> None:
- """设置透明度"""
- self._alpha = alpha
-
- def getAlpha(self) -> int:
- """获取透明度"""
- return self._alpha
-
- def setHotspot(self, x: float, y: float) -> None:
- """设置热点"""
- self._hotspot = (x, y)
-
- def setHotspotBounds(self, left: int, top: int, right: int, bottom: int) -> None:
- """设置热点边界"""
- self._hotspot_bounds = (left, top, right, bottom)
-
- def getIntrinsicWidth(self) -> int:
- return 48
-
- def getIntrinsicHeight(self) -> int:
- return 48
-
-
-# ═══════════════════════════════════════════════════════════════
-# RippleDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class RippleDrawable(ShapeDrawable):
- """RippleDrawable — 水波纹可绘制对象"""
-
- RIPPLE_ENTERING = 0
- RIPPLE_EXITING = 1
-
- def __init__(self, color: int = 0, content: Any = None, mask: Any = None):
- super().__init__()
- self._radius = 0
- self._color = color
- self._effect_color = color
- self._content = content
- self._mask = mask
- self._ripple_state = RippleDrawable.RIPPLE_ENTERING
-
- def setRadius(self, radius: int) -> None:
- """设置半径"""
- self._radius = radius
-
- def getRadius(self) -> int:
- """获取半径"""
- return self._radius
-
- def setColor(self, color: int) -> None:
- """设置颜色"""
- self._color = color
-
- def getColor(self) -> int:
- """获取颜色"""
- return self._color
-
- def setEffectColor(self, color: int) -> None:
- """设置效果颜色"""
- self._effect_color = color
-
- def getEffectColor(self) -> int:
- """获取效果颜色"""
- return self._effect_color
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimatedRotateDrawable / InsetDrawable / NinePatchDrawable
-# ═══════════════════════════════════════════════════════════════
-
-class AnimatedRotateDrawable(ShapeDrawable):
- """AnimatedRotateDrawable — 动画旋转可绘制对象"""
-
- def __init__(self, drawable: Any = None, gravity: int = 0):
- super().__init__()
- self._drawable = drawable
- self._gravity = gravity
- self._running = False
-
- def start(self) -> None:
- self._running = True
-
- def stop(self) -> None:
- self._running = False
-
-
-class InsetDrawable(ShapeDrawable):
- """InsetDrawable — 嵌入可绘制对象"""
-
- def __init__(self, drawable: Any = None, inset: int = 0):
- super().__init__()
- self._drawable = drawable
- self._inset = inset
- self._outset = inset
-
- def getInset(self) -> int:
- """获取嵌入"""
- return self._inset
-
- def getOutset(self) -> int:
- """获取外延"""
- return self._outset
-
-
-class NinePatchDrawable(ShapeDrawable):
- """NinePatchDrawable — 九宫格可绘制对象"""
-
- def __init__(self, nine_patch: Any = None):
- super().__init__()
- self._nine_patch = nine_patch
-
- def getIntrinsicWidth(self) -> int:
- return 0
-
- def getIntrinsicHeight(self) -> int:
- return 0
\ No newline at end of file
diff --git a/android_pyapi/android/graphics_drawable_shapes.py b/android_pyapi/android/graphics_drawable_shapes.py
deleted file mode 100644
index 9bd442b..0000000
--- a/android_pyapi/android/graphics_drawable_shapes.py
+++ /dev/null
@@ -1,589 +0,0 @@
-"""
-Android Graphics Drawable Shapes 组件 — Shape, ArcShape, OvalShape, PathShape, RectShape, RoundRectShape
-方法签名完全对齐 Android SDK (android.graphics.drawable.shapes 包)
-"""
-
-from __future__ import annotations
-
-import math
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# Shape
-# ═══════════════════════════════════════════════════════════════
-
-class Shape(Stub):
- """Shape — 形状基类"""
-
- def __init__(self):
- super().__init__()
- self._width: float = 0.0
- self._height: float = 0.0
- self._alpha: int = 255
- self._visible: bool = True
- self._dirty: bool = True
- self._bounds: Tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0)
-
- def getWidth(self) -> float:
- return self._width
-
- def getHeight(self) -> float:
- return self._height
-
- def getAlpha(self) -> int:
- return self._alpha
-
- def setAlpha(self, alpha: int):
- self._alpha = max(0, min(255, alpha))
-
- def isVisible(self) -> bool:
- return self._visible
-
- def setVisible(self, visible: bool):
- self._visible = visible
-
- def resize(self, width: float, height: float):
- """调整大小"""
- self._width = width
- self._height = height
- self._bounds = (0.0, 0.0, width, height)
- self._dirty = True
- self.onResize(width, height)
-
- def onResize(self, width: float, height: float):
- """大小变化回调"""
- pass
-
- def getBounds(self) -> Tuple[float, float, float, float]:
- return self._bounds
-
- def setBounds(self, left: float, top: float, right: float, bottom: float):
- self._bounds = (left, top, right, bottom)
- self._width = right - left
- self._height = bottom - top
-
- def draw(self, canvas: Any, paint: Any):
- """绘制形状 (由子类实现)"""
- pass
-
- def hasAlpha(self) -> bool:
- """检查是否有透明度"""
- return self._alpha < 255
-
- def clone(self) -> Shape:
- """克隆形状"""
- new_shape = self.__class__.__new__(self.__class__)
- new_shape._width = self._width
- new_shape._height = self._height
- new_shape._alpha = self._alpha
- new_shape._visible = self._visible
- new_shape._bounds = self._bounds
- return new_shape
-
- def isDirty(self) -> bool:
- return self._dirty
-
- def setDirty(self, dirty: bool):
- self._dirty = dirty
-
- def invalidate(self):
- self._dirty = True
-
- def toString(self) -> str:
- return f"Shape(w={self._width:.1f}, h={self._height:.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RectShape
-# ═══════════════════════════════════════════════════════════════
-
-class RectShape(Shape):
- """RectShape — 矩形形状"""
-
- def __init__(self):
- super().__init__()
- self._corner_radius: Tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0)
- self._fill_color: int = 0xFF000000
- self._stroke_color: int = 0x00000000
- self._stroke_width: float = 0.0
-
- def draw(self, canvas: Any, paint: Any):
- """绘制矩形"""
- pass
-
- def getCornerRadii(self) -> Tuple[float, float, float, float]:
- return self._corner_radius
-
- def setCornerRadii(self, radii: Tuple[float, float, float, float]):
- self._corner_radius = radii
-
- def getFillColor(self) -> int:
- return self._fill_color
-
- def setFillColor(self, color: int):
- self._fill_color = color
-
- def getStrokeColor(self) -> int:
- return self._stroke_color
-
- def setStrokeColor(self, color: int):
- self._stroke_color = color
-
- def getStrokeWidth(self) -> float:
- return self._stroke_width
-
- def setStrokeWidth(self, width: float):
- self._stroke_width = width
-
- def getCenterX(self) -> float:
- return self._width / 2.0
-
- def getCenterY(self) -> float:
- return self._height / 2.0
-
- def containsPoint(self, x: float, y: float) -> bool:
- """检查是否包含点"""
- return 0.0 <= x <= self._width and 0.0 <= y <= self._height
-
- def clone(self) -> RectShape:
- r = RectShape()
- r._width = self._width
- r._height = self._height
- r._alpha = self._alpha
- r._corner_radius = self._corner_radius
- r._fill_color = self._fill_color
- r._stroke_color = self._stroke_color
- r._stroke_width = self._stroke_width
- r._bounds = self._bounds
- return r
-
- def toString(self) -> str:
- return f"RectShape(w={self._width:.1f}, h={self._height:.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# OvalShape
-# ═══════════════════════════════════════════════════════════════
-
-class OvalShape(Shape):
- """OvalShape — 椭圆形状"""
-
- def __init__(self):
- super().__init__()
- self._fill_color: int = 0xFF000000
- self._stroke_color: int = 0x00000000
- self._stroke_width: float = 0.0
- self._start_angle: float = 0.0
- self._sweep_angle: float = 360.0
-
- def draw(self, canvas: Any, paint: Any):
- """绘制椭圆"""
- pass
-
- def getFillColor(self) -> int:
- return self._fill_color
-
- def setFillColor(self, color: int):
- self._fill_color = color
-
- def getStrokeColor(self) -> int:
- return self._stroke_color
-
- def setStrokeColor(self, color: int):
- self._stroke_color = color
-
- def getStrokeWidth(self) -> float:
- return self._stroke_width
-
- def setStrokeWidth(self, width: float):
- self._stroke_width = width
-
- def getCenterX(self) -> float:
- return self._width / 2.0
-
- def getCenterY(self) -> float:
- return self._height / 2.0
-
- def getRadiusX(self) -> float:
- return self._width / 2.0
-
- def getRadiusY(self) -> float:
- return self._height / 2.0
-
- def getStartAngle(self) -> float:
- return self._start_angle
-
- def setStartAngle(self, angle: float):
- self._start_angle = angle
-
- def getSweepAngle(self) -> float:
- return self._sweep_angle
-
- def setSweepAngle(self, angle: float):
- self._sweep_angle = angle
-
- def isCircle(self) -> bool:
- """检查是否为圆形"""
- return abs(self._width - self._height) < 0.001
-
- def containsPoint(self, x: float, y: float) -> bool:
- """检查是否包含点"""
- cx = self.getCenterX()
- cy = self.getCenterY()
- rx = self.getRadiusX()
- ry = self.getRadiusY()
- if rx <= 0 or ry <= 0:
- return False
- dx = (x - cx) / rx
- dy = (y - cy) / ry
- return (dx * dx + dy * dy) <= 1.0
-
- def clone(self) -> OvalShape:
- o = OvalShape()
- o._width = self._width
- o._height = self._height
- o._alpha = self._alpha
- o._fill_color = self._fill_color
- o._stroke_color = self._stroke_color
- o._stroke_width = self._stroke_width
- o._start_angle = self._start_angle
- o._sweep_angle = self._sweep_angle
- o._bounds = self._bounds
- return o
-
- def toString(self) -> str:
- return f"OvalShape(w={self._width:.1f}, h={self._height:.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ArcShape
-# ═══════════════════════════════════════════════════════════════
-
-class ArcShape(OvalShape):
- """ArcShape — 圆弧形状"""
-
- def __init__(self, start_angle: float = 0.0, sweep_angle: float = 90.0):
- super().__init__()
- self._start_angle = start_angle
- self._sweep_angle = sweep_angle
- self._use_center: bool = False
-
- def draw(self, canvas: Any, paint: Any):
- """绘制圆弧"""
- pass
-
- def getStartAngle(self) -> float:
- return self._start_angle
-
- def setStartAngle(self, angle: float):
- self._start_angle = angle
-
- def getSweepAngle(self) -> float:
- return self._sweep_angle
-
- def setSweepAngle(self, angle: float):
- self._sweep_angle = angle
-
- def isUseCenter(self) -> bool:
- return self._use_center
-
- def setUseCenter(self, use_center: bool):
- self._use_center = use_center
-
- def getArcEndX(self) -> float:
- cx = self.getCenterX()
- cy = self.getCenterY()
- rx = self.getRadiusX()
- ry = self.getRadiusY()
- angle_rad = math.radians(self._start_angle + self._sweep_angle)
- return cx + rx * math.cos(angle_rad)
-
- def getArcEndY(self) -> float:
- cx = self.getCenterX()
- cy = self.getCenterY()
- rx = self.getRadiusX()
- ry = self.getRadiusY()
- angle_rad = math.radians(self._start_angle + self._sweep_angle)
- return cy + ry * math.sin(angle_rad)
-
- def isFullCircle(self) -> bool:
- return abs(self._sweep_angle) >= 360.0
-
- def clone(self) -> ArcShape:
- a = ArcShape(self._start_angle, self._sweep_angle)
- a._width = self._width
- a._height = self._height
- a._alpha = self._alpha
- a._fill_color = self._fill_color
- a._stroke_color = self._stroke_color
- a._stroke_width = self._stroke_width
- a._use_center = self._use_center
- a._bounds = self._bounds
- return a
-
- def toString(self) -> str:
- return f"ArcShape(start={self._start_angle:.1f}, sweep={self._sweep_angle:.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PathShape
-# ═══════════════════════════════════════════════════════════════
-
-class PathShape(Shape):
- """PathShape — 路径形状"""
-
- def __init__(self, path: Any = None, std_width: float = 1.0, std_height: float = 1.0):
- super().__init__()
- self._path = path
- self._std_width = std_width
- self._std_height = std_height
- self._fill_color: int = 0xFF000000
- self._stroke_color: int = 0x00000000
- self._stroke_width: float = 0.0
- self._scale_x: float = 1.0
- self._scale_y: float = 1.0
-
- def draw(self, canvas: Any, paint: Any):
- """绘制路径"""
- pass
-
- def getPath(self) -> Any:
- return self._path
-
- def setPath(self, path: Any):
- self._path = path
-
- def getStdWidth(self) -> float:
- return self._std_width
-
- def getStdHeight(self) -> float:
- return self._std_height
-
- def getFillColor(self) -> int:
- return self._fill_color
-
- def setFillColor(self, color: int):
- self._fill_color = color
-
- def getStrokeColor(self) -> int:
- return self._stroke_color
-
- def setStrokeColor(self, color: int):
- self._stroke_color = color
-
- def getStrokeWidth(self) -> float:
- return self._stroke_width
-
- def setStrokeWidth(self, width: float):
- self._stroke_width = width
-
- def onResize(self, width: float, height: float):
- if self._std_width > 0 and self._std_height > 0:
- self._scale_x = width / self._std_width
- self._scale_y = height / self._std_height
-
- def getScaleX(self) -> float:
- return self._scale_x
-
- def getScaleY(self) -> float:
- return self._scale_y
-
- def containsPoint(self, x: float, y: float) -> bool:
- """检查是否包含点"""
- if self._path is None:
- return False
- # 使用简单矩形包含检查
- return 0.0 <= x <= self._width and 0.0 <= y <= self._height
-
- def clone(self) -> PathShape:
- p = PathShape(self._path, self._std_width, self._std_height)
- p._width = self._width
- p._height = self._height
- p._alpha = self._alpha
- p._fill_color = self._fill_color
- p._stroke_color = self._stroke_color
- p._stroke_width = self._stroke_width
- p._scale_x = self._scale_x
- p._scale_y = self._scale_y
- p._bounds = self._bounds
- return p
-
- def toString(self) -> str:
- return f"PathShape(std={self._std_width:.1f}x{self._std_height:.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RoundRectShape
-# ═══════════════════════════════════════════════════════════════
-
-class RoundRectShape(RectShape):
- """RoundRectShape — 圆角矩形形状"""
-
- def __init__(self, outer_radii: Optional[Tuple[float, float, float, float]] = None,
- inner_radii: Optional[Tuple[float, float, float, float]] = None,
- inset: Optional[Tuple[float, float, float, float]] = None):
- super().__init__()
- self._outer_radii = outer_radii or (0.0, 0.0, 0.0, 0.0)
- self._inner_radii = inner_radii or (0.0, 0.0, 0.0, 0.0)
- self._inset = inset or (0.0, 0.0, 0.0, 0.0)
-
- def draw(self, canvas: Any, paint: Any):
- """绘制圆角矩形"""
- pass
-
- def getOuterRadii(self) -> Tuple[float, float, float, float]:
- return self._outer_radii
-
- def setOuterRadii(self, radii: Tuple[float, float, float, float]):
- self._outer_radii = radii
-
- def getInnerRadii(self) -> Tuple[float, float, float, float]:
- return self._inner_radii
-
- def setInnerRadii(self, radii: Tuple[float, float, float, float]):
- self._inner_radii = radii
-
- def getInset(self) -> Tuple[float, float, float, float]:
- return self._inset
-
- def setInset(self, inset: Tuple[float, float, float, float]):
- self._inset = inset
-
- def getOuterRect(self) -> Tuple[float, float, float, float]:
- left, top, right, bottom = self._bounds
- return (left + self._inset[0], top + self._inset[1],
- right - self._inset[2], bottom - self._inset[3])
-
- def getInnerRect(self) -> Tuple[float, float, float, float]:
- outer = self.getOuterRect()
- r = max(self._outer_radii)
- return (outer[0] + r, outer[1] + r,
- outer[2] - r, outer[3] - r)
-
- def hasInnerShape(self) -> bool:
- """检查是否有内部形状"""
- return any(r > 0 for r in self._inner_radii)
-
- def getCornerRadius(self) -> float:
- """获取统一圆角半径 (所有角相同)"""
- if all(abs(r - self._outer_radii[0]) < 0.001 for r in self._outer_radii):
- return self._outer_radii[0]
- return -1.0
-
- def setCornerRadius(self, radius: float):
- self._outer_radii = (radius, radius, radius, radius)
-
- def isRect(self) -> bool:
- """检查是否为普通矩形"""
- return all(r == 0.0 for r in self._outer_radii)
-
- def clone(self) -> RoundRectShape:
- rr = RoundRectShape(self._outer_radii, self._inner_radii, self._inset)
- rr._width = self._width
- rr._height = self._height
- rr._alpha = self._alpha
- rr._fill_color = self._fill_color
- rr._stroke_color = self._stroke_color
- rr._stroke_width = self._stroke_width
- rr._bounds = self._bounds
- return rr
-
- def toString(self) -> str:
- return f"RoundRectShape(radius={self._outer_radii[0]:.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ShapeUtils
-# ═══════════════════════════════════════════════════════════════
-
-class ShapeUtils(Stub):
- """ShapeUtils — 形状工具类"""
-
- @staticmethod
- def createRect(width: float, height: float) -> RectShape:
- r = RectShape()
- r.resize(width, height)
- return r
-
- @staticmethod
- def createOval(width: float, height: float) -> OvalShape:
- o = OvalShape()
- o.resize(width, height)
- return o
-
- @staticmethod
- def createCircle(radius: float) -> OvalShape:
- o = OvalShape()
- o.resize(radius * 2, radius * 2)
- return o
-
- @staticmethod
- def createArc(start_angle: float, sweep_angle: float,
- width: float, height: float) -> ArcShape:
- a = ArcShape(start_angle, sweep_angle)
- a.resize(width, height)
- return a
-
- @staticmethod
- def createRoundRect(width: float, height: float,
- corner_radius: float) -> RoundRectShape:
- rr = RoundRectShape((corner_radius, corner_radius,
- corner_radius, corner_radius))
- rr.resize(width, height)
- return rr
-
- @staticmethod
- def createPathShape(path: Any, std_width: float, std_height: float) -> PathShape:
- return PathShape(path, std_width, std_height)
-
- @staticmethod
- def createSquare(size: float) -> RectShape:
- r = RectShape()
- r.resize(size, size)
- return r
-
- @staticmethod
- def applyFill(shape: Shape, color: int):
- if isinstance(shape, RectShape):
- shape.setFillColor(color)
- elif isinstance(shape, OvalShape):
- shape.setFillColor(color)
- elif isinstance(shape, PathShape):
- shape.setFillColor(color)
-
- @staticmethod
- def applyStroke(shape: Shape, color: int, width: float):
- if isinstance(shape, RectShape):
- shape.setStrokeColor(color)
- shape.setStrokeWidth(width)
- elif isinstance(shape, OvalShape):
- shape.setStrokeColor(color)
- shape.setStrokeWidth(width)
- elif isinstance(shape, PathShape):
- shape.setStrokeColor(color)
- shape.setStrokeWidth(width)
-
- @staticmethod
- def getShapeCenter(shape: Shape) -> Tuple[float, float]:
- return (shape.getWidth() / 2.0, shape.getHeight() / 2.0)
-
- @staticmethod
- def shapeEquals(a: Shape, b: Shape) -> bool:
- if type(a) is not type(b):
- return False
- return (abs(a.getWidth() - b.getWidth()) < 0.001 and
- abs(a.getHeight() - b.getHeight()) < 0.001 and
- a.getAlpha() == b.getAlpha())
-
- @staticmethod
- def scaleShape(shape: Shape, scale_x: float, scale_y: float):
- shape.resize(shape.getWidth() * scale_x, shape.getHeight() * scale_y)
-
- @staticmethod
- def translateShape(shape: Shape, dx: float, dy: float):
- b = shape.getBounds()
- shape.setBounds(b[0] + dx, b[1] + dy, b[2] + dx, b[3] + dy)
\ No newline at end of file
diff --git a/android_pyapi/android/graphics_fonts.py b/android_pyapi/android/graphics_fonts.py
deleted file mode 100644
index f32295f..0000000
--- a/android_pyapi/android/graphics_fonts.py
+++ /dev/null
@@ -1,298 +0,0 @@
-"""
-Android graphics.fonts 包 — Font, FontFamily, FontStyle, FontVariationAxis, Typeface
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "Font",
- "FontFamily",
- "FontStyle",
- "FontVariationAxis",
- "Typeface",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# FontStyle
-# ═══════════════════════════════════════════════════════════════
-
-class FontStyle(Stub):
- """FontStyle — 字体样式"""
-
- FONT_SLANT_UPRIGHT = 0
- FONT_SLANT_ITALIC = 1
- FONT_WIDTH_NORMAL = 100
- FONT_WIDTH_CONDENSED = 75
- FONT_WIDTH_EXTENDED = 125
-
- def __init__(self, weight: int = 400, slant: int = FONT_SLANT_UPRIGHT,
- width: int = FONT_WIDTH_NORMAL):
- super().__init__()
- self._weight = weight
- self._slant = slant
- self._width = width
-
- def getWeight(self) -> int:
- """获取字重"""
- return self._weight
-
- def getSlant(self) -> int:
- """获取倾斜"""
- return self._slant
-
- def getWidth(self) -> int:
- """获取宽度"""
- return self._width
-
- def toString(self) -> str:
- return f"FontStyle(weight={self._weight}, slant={self._slant}, width={self._width})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FontVariationAxis
-# ═══════════════════════════════════════════════════════════════
-
-class FontVariationAxis(Stub):
- """FontVariationAxis — 字体变体轴"""
-
- def __init__(self, tag: str = "", style_value: float = 0.0):
- super().__init__()
- self._tag = tag
- self._style_value = style_value
-
- def getTag(self) -> str:
- """获取标签"""
- return self._tag
-
- def getStyleValue(self) -> float:
- """获取样式值"""
- return self._style_value
-
- def toString(self) -> str:
- return f"FontVariationAxis(tag={self._tag}, value={self._style_value})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, FontVariationAxis):
- return False
- return self._tag == other._tag and self._style_value == other._style_value
-
- def hashCode(self) -> int:
- return hash((self._tag, self._style_value)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# Font
-# ═══════════════════════════════════════════════════════════════
-
-class Font(Stub):
- """Font — 字体 (桌面存根,包装系统字体)"""
-
- _SYSTEM_FONT_DIRS = [
- "/usr/share/fonts",
- "/System/Library/Fonts",
- "C:\\Windows\\Fonts",
- ]
-
- def __init__(self, file: Optional[str] = None, buffer: Optional[Any] = None,
- weight: int = 400, italic: bool = False, ttc_index: int = 0,
- axes: Optional[List[FontVariationAxis]] = None):
- super().__init__()
- self._file = file
- self._buffer = buffer
- self._weight = weight
- self._italic = italic
- self._ttc_index = ttc_index
- self._axes = axes or []
- self._native_ptr = 0
- self._font_size = 12.0
- self._obb = None
- self._source = file or "default"
-
- def getStyle(self) -> FontStyle:
- """获取字体样式"""
- return FontStyle(self._weight, FontStyle.FONT_SLANT_ITALIC if self._italic else FontStyle.FONT_SLANT_UPRIGHT)
-
- def getBuffer(self) -> Optional[Any]:
- """获取缓冲区"""
- return self._buffer
-
- def getNativePtr(self) -> int:
- """获取原生指针"""
- return self._native_ptr
-
- def getFontSize(self) -> float:
- """获取字号"""
- return self._font_size
-
- def getObb(self) -> Optional[Any]:
- """获取 OBB"""
- return self._obb
-
- def getSource(self) -> str:
- """获取来源"""
- return self._source
-
- def getTtcIndex(self) -> int:
- """获取 TTC 索引"""
- return self._ttc_index
-
- def getWeight(self) -> int:
- """获取字重"""
- return self._weight
-
- def getItalic(self) -> bool:
- """获取斜体"""
- return self._italic
-
- def getAxes(self) -> List[FontVariationAxis]:
- """获取变体轴列表"""
- return self._axes.copy()
-
- def getFile(self) -> Optional[str]:
- """获取文件路径"""
- return self._file
-
- @staticmethod
- def buildNativeTypeface(font: "Font") -> int:
- """构建原生字体类型"""
- return 0
-
- @staticmethod
- def load(file: str, weight: int = 400, italic: bool = False,
- ttc_index: int = 0) -> Optional["Font"]:
- """从文件加载字体"""
- if os.path.exists(file):
- return Font(file=file, weight=weight, italic=italic, ttc_index=ttc_index)
- return None
-
- def toString(self) -> str:
- return f"Font(file={self._file}, weight={self._weight}, italic={self._italic})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FontFamily
-# ═══════════════════════════════════════════════════════════════
-
-class FontFamily(Stub):
- """FontFamily — 字体家族"""
-
- def __init__(self, fonts: Optional[List[Font]] = None):
- super().__init__()
- self._fonts = fonts or []
-
- def addFont(self, font: Font) -> None:
- """添加字体"""
- self._fonts.append(font)
-
- def getFont(self, index: int) -> Optional[Font]:
- """获取指定索引的字体"""
- if 0 <= index < len(self._fonts):
- return self._fonts[index]
- return None
-
- def getSize(self) -> int:
- """获取字体数量"""
- return len(self._fonts)
-
- def toString(self) -> str:
- return f"FontFamily(size={len(self._fonts)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Typeface (fonts package version)
-# ═══════════════════════════════════════════════════════════════
-
-class Typeface(Stub):
- """Typeface — 字体类型 (图形字体包版本)"""
-
- DEFAULT: "Typeface" = None
- DEFAULT_BOLD: "Typeface" = None
- MONOSPACE: "Typeface" = None
- SANS_SERIF: "Typeface" = None
- SERIF: "Typeface" = None
-
- NORMAL = 0
- BOLD = 1
- ITALIC = 2
- BOLD_ITALIC = 3
-
- def __init__(self, family_name: str = "sans-serif", style: int = NORMAL):
- super().__init__()
- self._family_name = family_name
- self._style = style
- self._weight = 400
- if style in (Typeface.BOLD, Typeface.BOLD_ITALIC):
- self._weight = 700
-
- @staticmethod
- def defaultFromStyle(style: int) -> "Typeface":
- """从样式获取默认字体"""
- names = {0: "sans-serif", 1: "sans-serif", 2: "serif", 3: "serif"}
- return Typeface(names.get(style, "sans-serif"), style)
-
- @staticmethod
- def create(family_name: str, style: int) -> "Typeface":
- """创建字体"""
- return Typeface(family_name, style)
-
- @staticmethod
- def load(file_path: str, style: int = NORMAL) -> "Typeface":
- """从文件加载字体"""
- return Typeface("custom", style)
-
- def getStyle(self) -> int:
- """获取字体样式"""
- return self._style
-
- def isBold(self) -> bool:
- """检查是否粗体"""
- return self._style in (Typeface.BOLD, Typeface.BOLD_ITALIC)
-
- def isItalic(self) -> bool:
- """检查是否斜体"""
- return self._style in (Typeface.ITALIC, Typeface.BOLD_ITALIC)
-
- def getWeight(self) -> int:
- """获取字重"""
- return self._weight
-
- @staticmethod
- def getSystemFontMap() -> Dict[str, "Typeface"]:
- """获取系统字体映射"""
- return {
- "sans-serif": Typeface.SANS_SERIF,
- "serif": Typeface.SERIF,
- "monospace": Typeface.MONOSPACE,
- }
-
- @staticmethod
- def getSystemFontSettings(weight: int, italic: bool) -> Optional[Font]:
- """获取系统字体设置"""
- return Font(weight=weight, italic=italic)
-
- @staticmethod
- def setSystemFontSettings(font: Font) -> None:
- """设置系统字体设置"""
- pass
-
- def toString(self) -> str:
- return f"Typeface({self._family_name}, style={self._style})"
-
-
-# Initialize Typeface constants
-Typeface.DEFAULT = Typeface("sans-serif", Typeface.NORMAL)
-Typeface.DEFAULT_BOLD = Typeface("sans-serif", Typeface.BOLD)
-Typeface.MONOSPACE = Typeface("monospace", Typeface.NORMAL)
-Typeface.SANS_SERIF = Typeface("sans-serif", Typeface.NORMAL)
-Typeface.SERIF = Typeface("serif", Typeface.NORMAL)
\ No newline at end of file
diff --git a/android_pyapi/android/graphics_pdf.py b/android_pyapi/android/graphics_pdf.py
deleted file mode 100644
index ea06db5..0000000
--- a/android_pyapi/android/graphics_pdf.py
+++ /dev/null
@@ -1,335 +0,0 @@
-"""
-Android Graphics PDF 组件 — PdfDocument, PdfRenderer, ParcelFileDescriptor
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import io
-import tempfile
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError, android_context, HAS_PIL, HAS_PYMUPDF, HAS_PDF2IMAGE, resolve_android_path
-
-
-# ═══════════════════════════════════════════════════════════════
-# ParcelFileDescriptor
-# ═══════════════════════════════════════════════════════════════
-
-class ParcelFileDescriptor(Stub):
- """ParcelFileDescriptor — 文件描述符"""
-
- MODE_READ_ONLY = 0x10000000
- MODE_WRITE_ONLY = 0x20000000
- MODE_READ_WRITE = 0x30000000
- MODE_CREATE = 0x08000000
- MODE_TRUNCATE = 0x04000000
- MODE_APPEND = 0x02000000
-
- def __init__(self, fd: int = -1, file_path: str = ""):
- super().__init__()
- self._fd = fd
- self._file_path = file_path
- self._closed = False
- self._file_obj = None
- if file_path and fd < 0:
- resolved = resolve_android_path(file_path)
- self._file_path = resolved
-
- @staticmethod
- def open(file_path: str, mode: int) -> "ParcelFileDescriptor":
- resolved = resolve_android_path(file_path)
- fmode = "rb"
- if mode & ParcelFileDescriptor.MODE_WRITE_ONLY:
- fmode = "wb"
- elif mode & ParcelFileDescriptor.MODE_READ_WRITE:
- fmode = "r+b"
- if mode & ParcelFileDescriptor.MODE_CREATE:
- if not os.path.exists(os.path.dirname(resolved)):
- os.makedirs(os.path.dirname(resolved), exist_ok=True)
- if not os.path.exists(resolved):
- open(resolved, "w").close()
- return ParcelFileDescriptor(-1, file_path)
-
- @staticmethod
- def parseFromFd(fd: int) -> "ParcelFileDescriptor":
- return ParcelFileDescriptor(fd)
-
- @staticmethod
- def parseFromString(path: str) -> "ParcelFileDescriptor":
- resolved = resolve_android_path(path)
- return ParcelFileDescriptor(-1, resolved)
-
- @staticmethod
- def adoptFd(fd: int) -> "ParcelFileDescriptor":
- return ParcelFileDescriptor(fd)
-
- @staticmethod
- def createPipe() -> List["ParcelFileDescriptor"]:
- r, w = os.pipe()
- return [ParcelFileDescriptor(r), ParcelFileDescriptor(w)]
-
- def getFileDescriptor(self) -> int:
- return self._fd
-
- def getStatSize(self) -> int:
- if self._file_path and os.path.exists(self._file_path):
- return os.path.getsize(self._file_path)
- return 0
-
- def getFd(self) -> int:
- return self._fd
-
- def close(self):
- if not self._closed:
- self._closed = True
- if self._file_obj:
- self._file_obj.close()
- elif self._fd >= 0:
- try:
- os.close(self._fd)
- except OSError:
- pass
-
- def getFilePath(self) -> str:
- return self._file_path
-
- def toString(self) -> str:
- return f"ParcelFileDescriptor(fd={self._fd})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PdfDocument
-# ═══════════════════════════════════════════════════════════════
-
-class PdfDocument(Stub):
- """PdfDocument — PDF 文档"""
-
- class Page(Stub):
- """PdfDocument.Page — PDF 页面"""
-
- def __init__(self, page_number: int, width: int, height: int):
- super().__init__()
- self._page_number = page_number
- self._width = width
- self._height = height
- self._canvas = None
-
- def getCanvas(self) -> "Canvas":
- from .graphics import Canvas
- if self._canvas is None:
- self._canvas = Canvas(self._width, self._height)
- return self._canvas
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def start(self):
- pass
-
- def finish(self):
- pass
-
- def __init__(self):
- super().__init__()
- self._pages: List[PdfDocument.Page] = []
-
- def startPage(self, page_size: "Page") -> "Canvas":
- width = page_size.getWidth() if hasattr(page_size, "getWidth") else 595
- height = page_size.getHeight() if hasattr(page_size, "getHeight") else 842
- page = PdfDocument.Page(len(self._pages), width, height)
- self._pages.append(page)
- return page.getCanvas()
-
- def finishPage(self, page: "Page"):
- page.finish()
-
- def getPages(self) -> List["Page"]:
- return list(self._pages)
-
- def writeTo(self, out_stream, close: bool = True):
- if HAS_PYMUPDF:
- import fitz
- doc = fitz.open()
- for p in self._pages:
- page = doc.new_page(width=p._width, height=p._height)
- if HAS_PIL and hasattr(p._canvas, "_image") and p._canvas._image:
- img_bytes = io.BytesIO()
- p._canvas._image.save(img_bytes, format="PNG")
- img_bytes.seek(0)
- rect = page.rect
- page.insert_image(rect, stream=img_bytes.read())
- doc.save(out_stream)
- doc.close()
- elif HAS_PIL:
- from PIL import Image
- images = []
- for p in self._pages:
- if hasattr(p._canvas, "_image") and p._canvas._image:
- images.append(p._canvas._image.convert("RGB"))
- if images:
- images[0].save(out_stream, format="PDF", save_all=True,
- append_images=images[1:])
- else:
- blank = Image.new("RGB", (595, 842), (255, 255, 255))
- blank.save(out_stream, format="PDF")
- else:
- if close:
- out_stream.close()
-
- def close(self):
- self._pages.clear()
-
- def __enter__(self):
- return self
-
- def __exit__(self, *args):
- self.close()
-
-
-# ═══════════════════════════════════════════════════════════════
-# PdfRenderer
-# ═══════════════════════════════════════════════════════════════
-
-class PdfRenderer(Stub):
- """PdfRenderer — PDF 渲染器"""
-
- RENDER_MODE_FOR_DISPLAY = 1
- RENDER_MODE_FOR_PRINT = 2
- RENDER_MODE_FOR_ALL = 3
-
- class Page(Stub):
- """PdfRenderer.Page — PDF 渲染页面"""
-
- def __init__(self, renderer: "PdfRenderer", index: int):
- super().__init__()
- self._renderer = renderer
- self._index = index
- self._opened = True
- if renderer._doc:
- self._fitz_page = renderer._doc[index]
- rect = self._fitz_page.rect
- self._width = int(rect.width)
- self._height = int(rect.height)
- else:
- self._fitz_page = None
- self._width = 595
- self._height = 842
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getIndex(self) -> int:
- return self._index
-
- def render(self, canvas: "Canvas", destLeft: int, destTop: int,
- destRight: int, destBottom: int, flags: int = 0):
- if not self._opened:
- return
- if HAS_PYMUPDF and self._fitz_page:
- from .graphics import Bitmap
- mat = fitz.Matrix(2, 2) # 2x zoom for quality
- pix = self._fitz_page.get_pixmap(matrix=mat)
- img_data = pix.tobytes("png")
- if HAS_PIL and hasattr(canvas, "_image") and canvas._image:
- from PIL import Image
- import io as _io
- img = Image.open(io.BytesIO(img_data))
- img = img.resize((destRight - destLeft, destBottom - destTop))
- canvas._image.paste(img, (destLeft, destTop))
- elif HAS_PDF2IMAGE and HAS_PIL and hasattr(canvas, "_image"):
- from pdf2image import convert_from_bytes
- if self._renderer._pdf_bytes:
- images = convert_from_bytes(
- self._renderer._pdf_bytes,
- first_page=self._index + 1,
- last_page=self._index + 1
- )
- if images:
- img = images[0].resize((destRight - destLeft, destBottom - destTop))
- canvas._image.paste(img.convert("RGBA"), (destLeft, destTop))
-
- def start(self):
- self._opened = True
-
- def finish(self):
- self._opened = False
-
- def close(self):
- self._opened = False
-
- def __init__(self, pfd: ParcelFileDescriptor, closePfd: bool = True):
- super().__init__()
- self._pfd = pfd
- self._close_pfd = closePfd
- self._page_count = 0
- self._pdf_bytes = None
- self._doc = None
-
- file_path = pfd.getFilePath()
- if file_path and os.path.exists(file_path):
- with open(file_path, "rb") as f:
- self._pdf_bytes = f.read()
- elif pfd._fd >= 0:
- try:
- self._pdf_bytes = os.read(pfd._fd, 10 * 1024 * 1024)
- except OSError:
- self._pdf_bytes = None
-
- if HAS_PYMUPDF and self._pdf_bytes:
- import fitz
- self._doc = fitz.open(stream=self._pdf_bytes, filetype="pdf")
- self._page_count = len(self._doc)
- elif self._pdf_bytes:
- self._page_count = 1 # fallback
- else:
- self._page_count = 0
-
- def openPage(self, index: int) -> "Page":
- if 0 <= index < self._page_count:
- return PdfRenderer.Page(self, index)
- raise IndexError(f"Page index {index} out of range (0-{self._page_count - 1})")
-
- def close(self):
- if self._doc and HAS_PYMUPDF:
- self._doc.close()
- self._doc = None
- if self._close_pfd and self._pfd:
- self._pfd.close()
- self._pdf_bytes = None
-
- def getPageCount(self) -> int:
- return self._page_count
-
- def shouldScale(self) -> bool:
- return False
-
- def __enter__(self):
- return self
-
- def __exit__(self, *args):
- self.close()
-
-
-# ═══════════════════════════════════════════════════════════════
-# PdfDocumentPage (alias for PdfDocument.Page)
-# ═══════════════════════════════════════════════════════════════
-
-PdfDocumentPage = PdfDocument.Page
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "PdfDocument",
- "PdfDocumentPage",
- "PdfRenderer",
- "ParcelFileDescriptor",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/graphics_surface.py b/android_pyapi/android/graphics_surface.py
deleted file mode 100644
index dd10992..0000000
--- a/android_pyapi/android/graphics_surface.py
+++ /dev/null
@@ -1,699 +0,0 @@
-"""
-Android Graphics Surface 组件 — SurfaceTexture, SurfaceHolder, SurfaceView, GLSurfaceView
-方法签名完全对齐 Android SDK (android.graphics.surface 包 和 android.view.Surface)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurfaceTexture
-# ═══════════════════════════════════════════════════════════════
-
-class SurfaceTexture(Stub):
- """SurfaceTexture — 表面纹理"""
-
- # 纹理目标常量
- TEXTURE_TARGET_2D = 3553
- TEXTURE_TARGET_EXTERNAL = 36197
-
- # Transform 矩阵常量
- TRANSFORM_MATRIX_SIZE = 16
-
- def __init__(self, tex_name: int = 0, allow_high_performance: bool = True):
- super().__init__()
- self._tex_name = tex_name
- self._tex_target: int = SurfaceTexture.TEXTURE_TARGET_EXTERNAL
- self._timestamp: int = 0
- self._frame_available_listener: Optional[Callable] = None
- self._frame_available_listener_handler: Any = None
- self._default_buffer_size: Tuple[int, int] = (0, 0)
- self._is_abandoned: bool = False
- self._is_released: bool = False
- self._transform_matrix: List[float] = [
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0,
- ]
- self._buffer_count: int = 0
- self._frame_count: int = 0
- self._width: int = 0
- self._height: int = 0
-
- def getTexName(self) -> int:
- return self._tex_name
-
- def getTimestamp(self) -> int:
- """获取时间戳 (纳秒)"""
- return self._timestamp
-
- def updateTexImage(self):
- """更新纹理图像"""
- self._timestamp = int(time.time() * 1000000000)
- self._frame_count += 1
-
- def getTransformMatrix(self, matrix: Optional[List[float]] = None) -> List[float]:
- """获取变换矩阵"""
- if matrix is not None and len(matrix) >= 16:
- for i in range(16):
- matrix[i] = self._transform_matrix[i]
- return list(self._transform_matrix)
-
- def setDefaultBufferSize(self, width: int, height: int):
- """设置默认缓冲区大小"""
- self._default_buffer_size = (width, height)
- self._width = width
- self._height = height
-
- def getDefaultBufferSize(self) -> Tuple[int, int]:
- return self._default_buffer_size
-
- def setOnFrameAvailableListener(self, listener: Optional[Callable],
- handler: Any = None):
- """设置帧可用监听器"""
- self._frame_available_listener = listener
- self._frame_available_listener_handler = handler
- if listener:
- listener(self)
-
- def getOnFrameAvailableListener(self) -> Optional[Callable]:
- return self._frame_available_listener
-
- def detachFromGLContext(self):
- """从 GL 上下文分离"""
- pass
-
- def attachToGLContext(self, tex_name: int):
- """附加到 GL 上下文"""
- self._tex_name = tex_name
-
- def release(self):
- """释放表面纹理"""
- self._is_released = True
- self._frame_available_listener = None
-
- def releaseTexImage(self):
- """释放纹理图像"""
- pass
-
- def abandon(self):
- """废弃表面纹理"""
- self._is_abandoned = True
- self._frame_available_listener = None
-
- def isReleased(self) -> bool:
- return self._is_released
-
- def isAbandoned(self) -> bool:
- return self._is_abandoned
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getFrameCount(self) -> int:
- return self._frame_count
-
- def getBufferCount(self) -> int:
- return self._buffer_count
-
- def toString(self) -> str:
- return f"SurfaceTexture(tex={self._tex_name}, {self._width}x{self._height})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurfaceHolder
-# ═══════════════════════════════════════════════════════════════
-
-class SurfaceHolder(Stub):
- """SurfaceHolder — 表面持有者"""
-
- SURFACE_TYPE_NORMAL = 0
- SURFACE_TYPE_HARDWARE = 1
- SURFACE_TYPE_GPU = 2
- SURFACE_TYPE_PUSH_BUFFERS = 3
-
- # 表面变更类型
- CHANGE_TYPE_NONE = 0
- CHANGE_TYPE_SIZE_CHANGED = 1
- CHANGE_TYPE_FORMAT_CHANGED = 2
- CHANGE_TYPE_SURFACE_CREATED = 3
- CHANGE_TYPE_SURFACE_DESTROYED = 4
- CHANGE_TYPE_SURFACE_REDRAW = 5
-
- class Callback(Stub):
- """SurfaceHolder.Callback — 表面回调"""
-
- def surfaceCreated(self, holder: SurfaceHolder):
- pass
-
- def surfaceChanged(self, holder: SurfaceHolder, format: int,
- width: int, height: int):
- pass
-
- def surfaceDestroyed(self, holder: SurfaceHolder):
- pass
-
- def surfaceRedrawNeeded(self, holder: SurfaceHolder):
- pass
-
- class Callback2(Callback):
- """SurfaceHolder.Callback2 — 表面回调 (扩展)"""
-
- def surfaceRedrawNeeded(self, holder: SurfaceHolder):
- pass
-
- def __init__(self, surface: Any = None):
- super().__init__()
- self._surface = surface
- self._is_creating: bool = False
- self._type: int = SurfaceHolder.SURFACE_TYPE_NORMAL
- self._width: int = 0
- self._height: int = 0
- self._format: int = 0
- self._callbacks: List[SurfaceHolder.Callback] = []
- self._callback2: Optional[SurfaceHolder.Callback2] = None
- self._fixed_size: Tuple[int, int] = (-1, -1)
- self._keep_screen_on: bool = False
-
- def getSurface(self) -> Any:
- return self._surface
-
- def setSurface(self, surface: Any):
- self._surface = surface
-
- def addCallback(self, callback: Callback):
- if callback not in self._callbacks:
- self._callbacks.append(callback)
-
- def removeCallback(self, callback: Callback):
- self._callbacks = [c for c in self._callbacks if c is not callback]
-
- def getCallbacks(self) -> List[Callback]:
- return list(self._callbacks)
-
- def setType(self, type_: int):
- self._type = type_
-
- def getType(self) -> int:
- return self._type
-
- def setFixedSize(self, width: int, height: int):
- self._fixed_size = (width, height)
- self._width = width
- self._height = height
-
- def getFixedSize(self) -> Tuple[int, int]:
- return self._fixed_size
-
- def setSizeFromLayout(self):
- """从布局获取大小"""
- pass
-
- def isCreating(self) -> bool:
- return self._is_creating
-
- def setCreating(self, creating: bool):
- self._is_creating = creating
- if creating:
- for cb in self._callbacks:
- cb.surfaceCreated(self)
-
- def setFormat(self, format: int):
- self._format = format
-
- def getFormat(self) -> int:
- return self._format
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def setKeepScreenOn(self, keep_on: bool):
- self._keep_screen_on = keep_on
-
- def isKeepScreenOn(self) -> bool:
- return self._keep_screen_on
-
- def lockCanvas(self) -> Any:
- """锁定画布"""
- return None
-
- def lockCanvas(Rect: Any) -> Any:
- """锁定画布指定区域"""
- return None
-
- def unlockCanvasAndPost(self, canvas: Any):
- """解锁画布并提交"""
- pass
-
- def notifySurfaceCreated(self):
- for cb in self._callbacks:
- cb.surfaceCreated(self)
-
- def notifySurfaceChanged(self, format: int, width: int, height: int):
- for cb in self._callbacks:
- cb.surfaceChanged(self, format, width, height)
-
- def notifySurfaceDestroyed(self):
- for cb in self._callbacks:
- cb.surfaceDestroyed(self)
-
- def toString(self) -> str:
- return f"SurfaceHolder({self._width}x{self._height}, type={self._type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurfaceView
-# ═══════════════════════════════════════════════════════════════
-
-class SurfaceView(Stub):
- """SurfaceView — 表面视图"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._holder: Optional[SurfaceHolder] = SurfaceHolder()
- self._is_visible: bool = False
- self._is_created: bool = False
- self._width: int = 0
- self._height: int = 0
- self._format: int = 0
- self._z_order: int = 0
- self._is_securable: bool = False
- self._transparent_region: Optional[Any] = None
- self._surface_frame: Optional[Any] = None
- self._window_token: Any = None
-
- def getHolder(self) -> SurfaceHolder:
- return self._holder
-
- def setZOrderOnTop(self, on_top: bool):
- """设置 Z 轴顺序在顶层"""
- self._z_order = 1 if on_top else 0
-
- def setZOrderMediaOverlay(self, is_media_overlay: bool):
- """设置媒体覆盖 Z 轴顺序"""
- self._z_order = 2 if is_media_overlay else 0
-
- def setVisibility(self, visible: bool):
- self._is_visible = visible
-
- def isVisible(self) -> bool:
- return self._is_visible
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def setSecure(self, secure: bool):
- self._is_securable = secure
-
- def isSecure(self) -> bool:
- return self._is_securable
-
- def getContext(self) -> Any:
- return self._context
-
- def getWindowToken(self) -> Any:
- return self._window_token
-
- def setWindowToken(self, token: Any):
- self._window_token = token
-
- def onWindowVisibilityChanged(self, visibility: int):
- """窗口可见性变化回调"""
- pass
-
- def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
- """测量回调"""
- pass
-
- def onLayout(self, changed: bool, left: int, top: int,
- right: int, bottom: int):
- """布局回调"""
- self._width = right - left
- self._height = bottom - top
- if self._holder:
- self._holder.notifySurfaceChanged(self._format,
- self._width, self._height)
-
- def draw(self, canvas: Any):
- """绘制"""
- pass
-
- def toString(self) -> str:
- return f"SurfaceView({self._width}x{self._height}, visible={self._is_visible})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GLSurfaceView
-# ═══════════════════════════════════════════════════════════════
-
-class GLSurfaceView(SurfaceView):
- """GLSurfaceView — OpenGL ES 表面视图"""
-
- RENDERMODE_CONTINUOUSLY = 1
- RENDERMODE_WHEN_DIRTY = 0
-
- DEBUG_CHECK_GL_ERROR = 1
- DEBUG_LOG_GL_CALLS = 2
-
- class Renderer(Stub):
- """GLSurfaceView.Renderer — OpenGL 渲染器"""
-
- def onSurfaceCreated(self, gl: Any, config: Any):
- pass
-
- def onSurfaceChanged(self, gl: Any, width: int, height: int):
- pass
-
- def onDrawFrame(self, gl: Any):
- pass
-
- def __init__(self, context: Any = None):
- super().__init__(context)
- self._renderer: Optional[GLSurfaceView.Renderer] = None
- self._render_mode: int = GLSurfaceView.RENDERMODE_CONTINUOUSLY
- self._egl_context_client_version: int = 2
- self._preserve_egl_context_on_pause: bool = False
- self._debug_flags: int = 0
- self._is_running: bool = False
- self._is_paused: bool = False
- self._frame_count: int = 0
- self._request_render: bool = False
-
- def setRenderer(self, renderer: Renderer):
- """设置渲染器"""
- self._renderer = renderer
-
- def getRenderer(self) -> Optional[Renderer]:
- return self._renderer
-
- def setRenderMode(self, mode: int):
- """设置渲染模式"""
- self._render_mode = mode
-
- def getRenderMode(self) -> int:
- return self._render_mode
-
- def requestRender(self):
- """请求渲染"""
- self._request_render = True
- if self._render_mode == GLSurfaceView.RENDERMODE_WHEN_DIRTY:
- self._frame_count += 1
-
- def queueEvent(self, r: Callable):
- """队列事件"""
- r()
-
- def onPause(self):
- """暂停"""
- self._is_paused = True
- self._is_running = False
-
- def onResume(self):
- """恢复"""
- self._is_paused = False
- self._is_running = True
-
- def setPreserveEGLContextOnPause(self, preserve: bool):
- self._preserve_egl_context_on_pause = preserve
-
- def getPreserveEGLContextOnPause(self) -> bool:
- return self._preserve_egl_context_on_pause
-
- def setEGLContextClientVersion(self, version: int):
- self._egl_context_client_version = version
-
- def getEGLContextClientVersion(self) -> int:
- return self._egl_context_client_version
-
- def setDebugFlags(self, flags: int):
- self._debug_flags = flags
-
- def getDebugFlags(self) -> int:
- return self._debug_flags
-
- def isRunning(self) -> bool:
- return self._is_running
-
- def isPaused(self) -> bool:
- return self._is_paused
-
- def getFrameCount(self) -> int:
- return self._frame_count
-
- def onSurfaceCreated(self, gl: Any, config: Any):
- if self._renderer:
- self._renderer.onSurfaceCreated(gl, config)
-
- def onSurfaceChanged(self, gl: Any, width: int, height: int):
- if self._renderer:
- self._renderer.onSurfaceChanged(gl, width, height)
-
- def onDrawFrame(self, gl: Any):
- if self._renderer:
- self._renderer.onDrawFrame(gl)
-
- def destroyDrawingCache(self):
- pass
-
- def toString(self) -> str:
- return f"GLSurfaceView(renderMode={self._render_mode}, running={self._is_running})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Surface (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class Surface(Stub):
- """Surface — 表面 (android.view.Surface)"""
-
- ROTATION_0 = 0
- ROTATION_90 = 1
- ROTATION_180 = 2
- ROTATION_270 = 3
-
- SCALING_MODE_FREEZE = 0
- SCALING_MODE_SCALE_TO_WINDOW = 1
- SCALING_MODE_SCALE_CROP = 2
- SCALING_MODE_NO_SCALE_CROP = 3
-
- def __init__(self, surface_texture: Optional[SurfaceTexture] = None):
- super().__init__()
- self._surface_texture = surface_texture
- self._is_valid: bool = True
- self._is_released: bool = False
- self._width: int = 0
- self._height: int = 0
- self._format: int = 0
- self._name: str = ""
-
- def isValid(self) -> bool:
- return self._is_valid and not self._is_released
-
- def isReleased(self) -> bool:
- return self._is_released
-
- def release(self):
- self._is_released = True
-
- def getSurfaceTexture(self) -> Optional[SurfaceTexture]:
- return self._surface_texture
-
- def setSurfaceTexture(self, st: SurfaceTexture):
- self._surface_texture = st
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def setWidth(self, width: int):
- self._width = width
-
- def setHeight(self, height: int):
- self._height = height
-
- def getFormat(self) -> int:
- return self._format
-
- def setName(self, name: str):
- self._name = name
-
- def getName(self) -> str:
- return self._name
-
- def lockCanvas(self, in_out_dirty_rect: Any = None) -> Any:
- """锁定画布"""
- if self._is_released:
- return None
- return None
-
- def unlockCanvasAndPost(self, canvas: Any):
- """解锁画布并提交"""
- pass
-
- def toString(self) -> str:
- return f"Surface(name={self._name}, valid={self._is_valid}, released={self._is_released})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurfaceControl (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class SurfaceControl(Stub):
- """SurfaceControl — 表面控制"""
-
- BUFFER_TRANSFORM_IDENTITY = 0
- BUFFER_TRANSFORM_MIRROR_HORIZONTAL = 1
- BUFFER_TRANSFORM_MIRROR_VERTICAL = 2
- BUFFER_TRANSFORM_ROTATE_90 = 4
- BUFFER_TRANSFORM_ROTATE_180 = 3
- BUFFER_TRANSFORM_ROTATE_270 = 7
-
- def __init__(self, surface: Optional[Surface] = None):
- super().__init__()
- self._surface = surface
- self._alpha: float = 1.0
- self._layer: int = 0
- self._z_order: int = 0
- self._is_visible: bool = True
- self._transform: int = SurfaceControl.BUFFER_TRANSFORM_IDENTITY
- self._crop: Tuple[int, int, int, int] = (0, 0, 0, 0)
-
- def getSurface(self) -> Optional[Surface]:
- return self._surface
-
- def setSurface(self, surface: Surface):
- self._surface = surface
-
- def setAlpha(self, alpha: float):
- self._alpha = max(0.0, min(1.0, alpha))
-
- def getAlpha(self) -> float:
- return self._alpha
-
- def setLayer(self, layer: int):
- self._layer = layer
-
- def getLayer(self) -> int:
- return self._layer
-
- def setVisibility(self, visible: bool):
- self._is_visible = visible
-
- def isVisible(self) -> bool:
- return self._is_visible
-
- def setTransform(self, transform: int):
- self._transform = transform
-
- def getTransform(self) -> int:
- return self._transform
-
- def setCrop(self, left: int, top: int, right: int, bottom: int):
- self._crop = (left, top, right, bottom)
-
- def getCrop(self) -> Tuple[int, int, int, int]:
- return self._crop
-
- def release(self):
- if self._surface:
- self._surface.release()
-
- def toString(self) -> str:
- return f"SurfaceControl(layer={self._layer}, alpha={self._alpha})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurfaceUtils
-# ═══════════════════════════════════════════════════════════════
-
-class SurfaceUtils(Stub):
- """SurfaceUtils — 表面工具类"""
-
- @staticmethod
- def createSurfaceFromTexture(texture: SurfaceTexture) -> Surface:
- return Surface(texture)
-
- @staticmethod
- def createSurfaceTexture(tex_name: int = 0) -> SurfaceTexture:
- return SurfaceTexture(tex_name)
-
- @staticmethod
- def createGLSurfaceView(context: Any) -> GLSurfaceView:
- return GLSurfaceView(context)
-
- @staticmethod
- def createSurfaceView(context: Any) -> SurfaceView:
- return SurfaceView(context)
-
- @staticmethod
- def createSurfaceHolder(surface: Any) -> SurfaceHolder:
- return SurfaceHolder(surface)
-
- @staticmethod
- def isSurfaceValid(surface: Surface) -> bool:
- return surface is not None and surface.isValid()
-
- @staticmethod
- def releaseSurface(surface: Surface):
- if surface:
- surface.release()
-
- @staticmethod
- def releaseSurfaceTexture(texture: SurfaceTexture):
- if texture:
- texture.release()
-
- @staticmethod
- def getDefaultRenderer(context: Any) -> GLSurfaceView.Renderer:
- class DefaultRenderer(GLSurfaceView.Renderer):
- def onSurfaceCreated(self, gl, config):
- pass
- def onSurfaceChanged(self, gl, width, height):
- pass
- def onDrawFrame(self, gl):
- pass
- return DefaultRenderer()
-
- @staticmethod
- def createSimpleRenderer() -> GLSurfaceView.Renderer:
- class SimpleRenderer(GLSurfaceView.Renderer):
- def __init__(self):
- super().__init__()
- self._background_color: Tuple[float, float, float, float] = (0.0, 0.0, 0.0, 1.0)
-
- def onSurfaceCreated(self, gl, config):
- pass
-
- def onSurfaceChanged(self, gl, width, height):
- pass
-
- def onDrawFrame(self, gl):
- pass
-
- def setBackgroundColor(self, r: float, g: float, b: float, a: float):
- self._background_color = (r, g, b, a)
-
- return SimpleRenderer()
-
- @staticmethod
- def getSurfaceRotationDegrees(rotation: int) -> int:
- return rotation * 90
\ No newline at end of file
diff --git a/android_pyapi/android/graphics_text.py b/android_pyapi/android/graphics_text.py
deleted file mode 100644
index f59d88e..0000000
--- a/android_pyapi/android/graphics_text.py
+++ /dev/null
@@ -1,779 +0,0 @@
-"""
-Android Graphics Text 组件 — TextRunShaper, LineBreaker, MeasuredText, PositionedGlyphs, TextLayout 等
-方法签名完全对齐 Android SDK (android.graphics.text 包)
-"""
-
-from __future__ import annotations
-
-import math
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# PositionedGlyphs
-# ═══════════════════════════════════════════════════════════════
-
-class PositionedGlyphs(Stub):
- """PositionedGlyphs — 定位字形"""
-
- def __init__(self):
- super().__init__()
- self._glyph_ids: List[int] = []
- self._positions_x: List[float] = []
- self._positions_y: List[float] = []
- self._advances_x: List[float] = []
- self._advances_y: List[float] = []
- self._width: float = 0.0
- self._height: float = 0.0
- self._ascent: float = 0.0
- self._descent: float = 0.0
- self._glyph_count: int = 0
-
- def getGlyphCount(self) -> int:
- return self._glyph_count
-
- def getGlyphId(self, index: int) -> int:
- return self._glyph_ids[index] if 0 <= index < len(self._glyph_ids) else 0
-
- def getGlyphX(self, index: int) -> float:
- return self._positions_x[index] if 0 <= index < len(self._positions_x) else 0.0
-
- def getGlyphY(self, index: int) -> float:
- return self._positions_y[index] if 0 <= index < len(self._positions_y) else 0.0
-
- def getGlyphAdvanceX(self, index: int) -> float:
- return self._advances_x[index] if 0 <= index < len(self._advances_x) else 0.0
-
- def getGlyphAdvanceY(self, index: int) -> float:
- return self._advances_y[index] if 0 <= index < len(self._advances_y) else 0.0
-
- def getWidth(self) -> float:
- return self._width
-
- def getHeight(self) -> float:
- return self._height
-
- def getAscent(self) -> float:
- return self._ascent
-
- def getDescent(self) -> float:
- return self._descent
-
- def addGlyph(self, glyph_id: int, x: float, y: float,
- advance_x: float, advance_y: float):
- self._glyph_ids.append(glyph_id)
- self._positions_x.append(x)
- self._positions_y.append(y)
- self._advances_x.append(advance_x)
- self._advances_y.append(advance_y)
- self._glyph_count += 1
-
- def setBounds(self, width: float, height: float):
- self._width = width
- self._height = height
-
- def setMetrics(self, ascent: float, descent: float):
- self._ascent = ascent
- self._descent = descent
-
- def clear(self):
- self._glyph_ids.clear()
- self._positions_x.clear()
- self._positions_y.clear()
- self._advances_x.clear()
- self._advances_y.clear()
- self._glyph_count = 0
- self._width = 0.0
- self._height = 0.0
- self._ascent = 0.0
- self._descent = 0.0
-
- def toString(self) -> str:
- return f"PositionedGlyphs(count={self._glyph_count}, w={self._width:.1f}, h={self._height:.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextRunShaper
-# ═══════════════════════════════════════════════════════════════
-
-class TextRunShaper(Stub):
- """TextRunShaper — 文本运行重塑器"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def shapeTextRun(text: str, start: int, count: int, context_start: int,
- context_count: int, x_offset: float, y_offset: float,
- is_rtl: bool, paint: Any) -> PositionedGlyphs:
- """重塑文本运行"""
- glyphs = PositionedGlyphs()
- for i in range(count):
- if start + i < len(text):
- char_code = ord(text[start + i])
- glyphs.addGlyph(char_code, x_offset + i * 12.0, y_offset, 12.0, 0.0)
- glyphs.setBounds(count * 12.0, 16.0)
- glyphs.setMetrics(-12.0, 3.0)
- return glyphs
-
- @staticmethod
- def shapeTextRunWithFont(text: str, start: int, count: int,
- context_start: int, context_count: int,
- x_offset: float, y_offset: float,
- is_rtl: bool, paint: Any,
- font: Any) -> PositionedGlyphs:
- """使用指定字体重塑文本运行"""
- return TextRunShaper.shapeTextRun(text, start, count, context_start,
- context_count, x_offset, y_offset,
- is_rtl, paint)
-
- @staticmethod
- def shapeTextRunOnPath(text: str, start: int, count: int,
- path: Any, paint: Any) -> PositionedGlyphs:
- """沿路径重塑文本运行"""
- glyphs = PositionedGlyphs()
- for i in range(count):
- if start + i < len(text):
- char_code = ord(text[start + i])
- glyphs.addGlyph(char_code, i * 12.0, 0.0, 12.0, 0.0)
- glyphs.setBounds(count * 12.0, 16.0)
- glyphs.setMetrics(-12.0, 3.0)
- return glyphs
-
- @staticmethod
- def getGlyphBounds(glyphs: PositionedGlyphs, index: int) -> Tuple[float, float, float, float]:
- """获取字形边界"""
- x = glyphs.getGlyphX(index)
- y = glyphs.getGlyphY(index)
- return (x, y, x + 12.0, y + 16.0)
-
-
-# ═══════════════════════════════════════════════════════════════
-# LineBreaker
-# ═══════════════════════════════════════════════════════════════
-
-class LineBreaker(Stub):
- """LineBreaker — 换行器"""
-
- BREAK_STRATEGY_SIMPLE = 0
- BREAK_STRATEGY_HIGH_QUALITY = 1
- BREAK_STRATEGY_BALANCED = 2
-
- HYPHENATION_FREQUENCY_NONE = 0
- HYPHENATION_FREQUENCY_NORMAL = 1
- HYPHENATION_FREQUENCY_FULL = 2
-
- WORD_BREAK_NORMAL = 0
- WORD_BREAK_BREAK_ALL = 1
- WORD_BREAK_KEEP_ALL = 2
-
- TAB_STRATEGY_NONE = 0
- TAB_STRATEGY_ORIGIN = 1
- TAB_STRATEGY_DESTINATION = 2
-
- JUSTIFICATION_MODE_NONE = 0
- JUSTIFICATION_MODE_INTER_WORD = 1
- JUSTIFICATION_MODE_CHARACTER = 2
-
- LINE_LIMIT_UNLIMITED = 0
-
- class Result(Stub):
- """LineBreaker.Result — 换行结果"""
-
- def __init__(self):
- super().__init__()
- self._line_counts: int = 0
- self._line_breaks: List[Tuple[int, float]] = []
- self._line_widths: List[float] = []
- self._line_ascent: List[float] = []
- self._line_descent: List[float] = []
-
- def getLineCount(self) -> int:
- return self._line_counts
-
- def getLineBreakOffset(self, line_index: int) -> int:
- if 0 <= line_index < len(self._line_breaks):
- return self._line_breaks[line_index][0]
- return 0
-
- def getLineWidth(self, line_index: int) -> float:
- if 0 <= line_index < len(self._line_widths):
- return self._line_widths[line_index]
- return 0.0
-
- def getLineAscent(self, line_index: int) -> float:
- if 0 <= line_index < len(self._line_ascent):
- return self._line_ascent[line_index]
- return 0.0
-
- def getLineDescent(self, line_index: int) -> float:
- if 0 <= line_index < len(self._line_descent):
- return self._line_descent[line_index]
- return 0.0
-
- def addLineBreak(self, offset: int, width: float, ascent: float, descent: float):
- self._line_breaks.append((offset, width))
- self._line_widths.append(width)
- self._line_ascent.append(ascent)
- self._line_descent.append(descent)
- self._line_counts += 1
-
- def toString(self) -> str:
- return f"LineBreaker.Result(lines={self._line_counts})"
-
- def __init__(self, strategy: int = BREAK_STRATEGY_SIMPLE,
- hyphenation: int = HYPHENATION_FREQUENCY_NONE):
- super().__init__()
- self._strategy = strategy
- self._hyphenation_frequency = hyphenation
- self._justification_mode: int = LineBreaker.JUSTIFICATION_MODE_NONE
- self._word_break: int = LineBreaker.WORD_BREAK_NORMAL
- self._tab_strategy: int = LineBreaker.TAB_STRATEGY_NONE
- self._line_limit: int = LineBreaker.LINE_LIMIT_UNLIMITED
-
- def getStrategy(self) -> int:
- return self._strategy
-
- def setStrategy(self, strategy: int):
- self._strategy = strategy
-
- def getHyphenationFrequency(self) -> int:
- return self._hyphenation_frequency
-
- def setHyphenationFrequency(self, freq: int):
- self._hyphenation_frequency = freq
-
- def setJustificationMode(self, mode: int):
- self._justification_mode = mode
-
- def getJustificationMode(self) -> int:
- return self._justification_mode
-
- def setWordBreak(self, word_break: int):
- self._word_break = word_break
-
- def getWordBreak(self) -> int:
- return self._word_break
-
- def setTabStrategy(self, strategy: int):
- self._tab_strategy = strategy
-
- def getTabStrategy(self) -> int:
- return self._tab_strategy
-
- def setLineLimit(self, limit: int):
- self._line_limit = limit
-
- def getLineLimit(self) -> int:
- return self._line_limit
-
- def computeLineBreaks(self, text: str, width: float,
- paint: Any = None) -> Result:
- """计算换行"""
- result = LineBreaker.Result()
- if not text:
- return result
- words = text.split(" ")
- line_start = 0
- line_width = 0.0
- char_width = 12.0 # 粗略估计
- for word in words:
- word_len = len(word) * char_width
- if word_len + line_width > width and len(text[line_start:text.index(word)]) > 0:
- break_offset = text.index(word, line_start) if line_start > 0 else len(word)
- result.addLineBreak(break_offset, line_width, -12.0, 3.0)
- line_start = break_offset
- line_width = word_len
- else:
- line_width += word_len + char_width
- if line_start < len(text):
- result.addLineBreak(len(text), line_width, -12.0, 3.0)
- return result
-
- def computeLineBreaksForMeasuredText(self, measured_text: MeasuredText,
- width: float) -> Result:
- """对度量文本计算换行"""
- return self.computeLineBreaks(measured_text.getText(), width)
-
- def toString(self) -> str:
- return f"LineBreaker(strategy={self._strategy}, hyphen={self._hyphenation_frequency})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MeasuredText
-# ═══════════════════════════════════════════════════════════════
-
-class MeasuredText(Stub):
- """MeasuredText — 度量文本"""
-
- def __init__(self, text: str = ""):
- super().__init__()
- self._text = text
- self._widths: List[float] = []
- self._ascent: float = 0.0
- self._descent: float = 0.0
- self._height: float = 0.0
- self._glyph_count: int = 0
- self._char_spacing: float = 0.0
- self._word_spacing: float = 0.0
- self._scale_x: float = 1.0
- self._advances: List[float] = []
- self._clusters: List[int] = []
- for c in text:
- self._widths.append(12.0)
- self._advances.append(12.0)
- self._clusters.append(1)
-
- def getText(self) -> str:
- return self._text
-
- def getWidth(self, start: int = 0, end: int = -1) -> float:
- if end < 0:
- end = len(self._widths)
- return sum(self._widths[start:end])
-
- def getAscent(self) -> float:
- return self._ascent
-
- def getDescent(self) -> float:
- return self._descent
-
- def getHeight(self) -> float:
- return self._height
-
- def getCharWidthAt(self, index: int) -> float:
- if 0 <= index < len(self._widths):
- return self._widths[index]
- return 0.0
-
- def setWidths(self, widths: List[float]):
- self._widths = list(widths)
-
- def setMetrics(self, ascent: float, descent: float):
- self._ascent = ascent
- self._descent = descent
- self._height = ascent - descent
-
- def getAdvance(self, index: int) -> float:
- if 0 <= index < len(self._advances):
- return self._advances[index]
- return 0.0
-
- def getCluster(self, index: int) -> int:
- if 0 <= index < len(self._clusters):
- return self._clusters[index]
- return 1
-
- def getGlyphCount(self) -> int:
- return self._glyph_count
-
- def setGlyphCount(self, count: int):
- self._glyph_count = count
-
- def getCharSpacing(self) -> float:
- return self._char_spacing
-
- def getWordSpacing(self) -> float:
- return self._word_spacing
-
- def getScaleX(self) -> float:
- return self._scale_x
-
- def toString(self) -> str:
- return f"MeasuredText(text={self._text[:20]}, w={self.getWidth():.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextLayout
-# ═══════════════════════════════════════════════════════════════
-
-class TextLayout(Stub):
- """TextLayout — 文本布局"""
-
- DIRECTION_LEFT_TO_RIGHT = 0
- DIRECTION_RIGHT_TO_LEFT = 1
-
- ALIGN_NORMAL = 0
- ALIGN_CENTER = 1
- ALIGN_OPPOSITE = 2
-
- TEXT_DIRECTION_FIRST_STRONG_LTR = 0
- TEXT_DIRECTION_FIRST_STRONG_RTL = 1
- TEXT_DIRECTION_ANY_LTR = 2
- TEXT_DIRECTION_ANY_RTL = 3
- TEXT_DIRECTION_LTR = 4
- TEXT_DIRECTION_RTL = 5
- TEXT_DIRECTION_LOCALE = 6
- TEXT_DIRECTION_FIRST_STRONG = 7
-
- def __init__(self, text: str = "", width: float = 0.0, paint: Any = None):
- super().__init__()
- self._text = text
- self._width = width
- self._paint = paint
- self._lines: List[TextLayout.LineInfo] = []
- self._alignment: int = TextLayout.ALIGN_NORMAL
- self._direction: int = TextLayout.DIRECTION_LEFT_TO_RIGHT
- self._text_direction: int = TextLayout.TEXT_DIRECTION_FIRST_STRONG_LTR
- self._max_lines: int = 0
- self._include_padding: bool = True
- self._spacing_mult: float = 1.0
- self._spacing_add: float = 0.0
- self._ellipsized_width: float = 0.0
- self._is_ellipsized: bool = False
-
- def getText(self) -> str:
- return self._text
-
- def getWidth(self) -> float:
- return self._width
-
- def getHeight(self) -> float:
- if not self._lines:
- return 0.0
- return sum(l.getHeight() for l in self._lines)
-
- def getLineCount(self) -> int:
- return len(self._lines)
-
- def getLineInfo(self, line_index: int) -> Optional[TextLayout.LineInfo]:
- if 0 <= line_index < len(self._lines):
- return self._lines[line_index]
- return None
-
- def getLineStart(self, line_index: int) -> int:
- if 0 <= line_index < len(self._lines):
- return self._lines[line_index].getStart()
- return 0
-
- def getLineEnd(self, line_index: int) -> int:
- if 0 <= line_index < len(self._lines):
- return self._lines[line_index].getEnd()
- return 0
-
- def getLineMax(self, line_index: int) -> float:
- if 0 <= line_index < len(self._lines):
- return self._lines[line_index].getMax()
- return 0.0
-
- def getLineAscent(self, line_index: int) -> float:
- if 0 <= line_index < len(self._lines):
- return self._lines[line_index].getAscent()
- return 0.0
-
- def getLineDescent(self, line_index: int) -> float:
- if 0 <= line_index < len(self._lines):
- return self._lines[line_index].getDescent()
- return 0.0
-
- def getMaxLines(self) -> int:
- return self._max_lines
-
- def setMaxLines(self, max_lines: int):
- self._max_lines = max_lines
-
- def getAlignment(self) -> int:
- return self._alignment
-
- def setAlignment(self, alignment: int):
- self._alignment = alignment
-
- def getDirection(self) -> int:
- return self._direction
-
- def setDirection(self, direction: int):
- self._direction = direction
-
- def getTextDirection(self) -> int:
- return self._text_direction
-
- def setTextDirection(self, direction: int):
- self._text_direction = direction
-
- def setIncludePadding(self, include: bool):
- self._include_padding = include
-
- def isIncludePadding(self) -> bool:
- return self._include_padding
-
- def setSpacingMultiplier(self, mult: float):
- self._spacing_mult = mult
-
- def getSpacingMultiplier(self) -> float:
- return self._spacing_mult
-
- def setSpacingAdd(self, add: float):
- self._spacing_add = add
-
- def getSpacingAdd(self) -> float:
- return self._spacing_add
-
- def isEllipsized(self) -> bool:
- return self._is_ellipsized
-
- def setEllipsizedWidth(self, width: float):
- self._ellipsized_width = width
-
- def getEllipsizedWidth(self) -> float:
- return self._ellipsized_width
-
- def addLine(self, start: int, end: int, max_width: float,
- ascent: float, descent: float):
- line = TextLayout.LineInfo(start, end, max_width, ascent, descent)
- self._lines.append(line)
-
- def clearLines(self):
- self._lines.clear()
-
- def buildSimpleLayout(self, char_width: float = 12.0, line_height: float = 16.0):
- """构建简单布局"""
- self._lines.clear()
- if not self._text:
- return
- chars_per_line = int(self._width / char_width) if char_width > 0 else 10
- if chars_per_line <= 0:
- chars_per_line = 10
- start = 0
- while start < len(self._text):
- end = min(start + chars_per_line, len(self._text))
- line_text = self._text[start:end]
- line_width = len(line_text) * char_width
- self.addLine(start, end, line_width, -12.0, 3.0)
- start = end
-
- def toString(self) -> str:
- return f"TextLayout(lines={len(self._lines)}, w={self._width:.1f})"
-
- # ═══════════════════════════════════════════════════════
- # TextLayout.LineInfo
- # ═══════════════════════════════════════════════════════
-
- class LineInfo(Stub):
- """TextLayout.LineInfo — 行信息"""
-
- def __init__(self, start: int = 0, end: int = 0,
- max_width: float = 0.0, ascent: float = 0.0,
- descent: float = 0.0):
- super().__init__()
- self._start = start
- self._end = end
- self._max_width = max_width
- self._ascent = ascent
- self._descent = descent
- self._height = ascent - descent if descent > 0 else 16.0
- self._direction: int = TextLayout.DIRECTION_LEFT_TO_RIGHT
- self._is_ellipsized: bool = False
-
- def getStart(self) -> int:
- return self._start
-
- def getEnd(self) -> int:
- return self._end
-
- def getMax(self) -> float:
- return self._max_width
-
- def getAscent(self) -> float:
- return self._ascent
-
- def getDescent(self) -> float:
- return self._descent
-
- def getHeight(self) -> float:
- return self._height
-
- def getDirection(self) -> int:
- return self._direction
-
- def setDirection(self, direction: int):
- self._direction = direction
-
- def isEllipsized(self) -> bool:
- return self._is_ellipsized
-
- def setEllipsized(self, ellipsized: bool):
- self._is_ellipsized = ellipsized
-
- def toString(self) -> str:
- return f"LineInfo({self._start}-{self._end}, w={self._max_width:.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FontShaper
-# ═══════════════════════════════════════════════════════════════
-
-class FontShaper(Stub):
- """FontShaper — 字体重塑器"""
-
- def __init__(self, font: Any = None):
- super().__init__()
- self._font = font
- self._variations: Dict[str, float] = {}
- self._features: Dict[str, int] = {}
- self._is_ready: bool = True
-
- def getFont(self) -> Any:
- return self._font
-
- def setFont(self, font: Any):
- self._font = font
-
- def setVariation(self, tag: str, value: float):
- self._variations[tag] = value
-
- def getVariation(self, tag: str) -> Optional[float]:
- return self._variations.get(tag)
-
- def getVariations(self) -> Dict[str, float]:
- return dict(self._variations)
-
- def setFeature(self, tag: str, value: int):
- self._features[tag] = value
-
- def getFeature(self, tag: str) -> int:
- return self._features.get(tag, 0)
-
- def getFeatures(self) -> Dict[str, int]:
- return dict(self._features)
-
- def shapeText(self, text: str, paint: Any = None) -> PositionedGlyphs:
- """重塑文本"""
- glyphs = PositionedGlyphs()
- for i, c in enumerate(text):
- glyphs.addGlyph(ord(c), i * 12.0, 0.0, 12.0, 0.0)
- glyphs.setBounds(len(text) * 12.0, 16.0)
- glyphs.setMetrics(-12.0, 3.0)
- return glyphs
-
- def shapeTextRun(self, text: str, start: int, count: int,
- context_start: int, context_count: int,
- is_rtl: bool, paint: Any) -> PositionedGlyphs:
- """重塑文本运行"""
- glyphs = PositionedGlyphs()
- for i in range(count):
- idx = start + i
- if idx < len(text):
- glyphs.addGlyph(ord(text[idx]), i * 12.0, 0.0, 12.0, 0.0)
- glyphs.setBounds(count * 12.0, 16.0)
- glyphs.setMetrics(-12.0, 3.0)
- return glyphs
-
- def getGlyphMetrics(self, glyph_id: int) -> Tuple[float, float, float, float]:
- """获取字形度量"""
- return (0.0, 0.0, 12.0, 16.0)
-
- def isReady(self) -> bool:
- return self._is_ready
-
- def toString(self) -> str:
- return f"FontShaper(variations={len(self._variations)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextRunShaperResult (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class TextRunShaperResult(Stub):
- """TextRunShaperResult — 文本运行重塑结果"""
-
- def __init__(self):
- super().__init__()
- self._glyphs: PositionedGlyphs = PositionedGlyphs()
- self._char_offset: int = 0
- self._char_count: int = 0
- self._is_rtl: bool = False
- self._font_size: float = 12.0
-
- def getGlyphs(self) -> PositionedGlyphs:
- return self._glyphs
-
- def setGlyphs(self, glyphs: PositionedGlyphs):
- self._glyphs = glyphs
-
- def getCharOffset(self) -> int:
- return self._char_offset
-
- def setCharOffset(self, offset: int):
- self._char_offset = offset
-
- def getCharCount(self) -> int:
- return self._char_count
-
- def setCharCount(self, count: int):
- self._char_count = count
-
- def isRtl(self) -> bool:
- return self._is_rtl
-
- def setRtl(self, rtl: bool):
- self._is_rtl = rtl
-
- def toString(self) -> str:
- return f"TextRunShaperResult(glyphs={self._glyphs.getGlyphCount()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextShaperUtils
-# ═══════════════════════════════════════════════════════════════
-
-class TextShaperUtils(Stub):
- """TextShaperUtils — 文本重塑工具类"""
-
- @staticmethod
- def estimateCharWidth(paint: Any = None) -> float:
- return 12.0
-
- @staticmethod
- def estimateLineHeight(paint: Any = None) -> float:
- return 16.0
-
- @staticmethod
- def measureText(text: str, paint: Any = None) -> float:
- return len(text) * 12.0
-
- @staticmethod
- def wordWrap(text: str, max_width: float, char_width: float = 12.0) -> List[str]:
- lines = []
- chars_per_line = int(max_width / char_width) if char_width > 0 else 10
- if chars_per_line <= 0:
- chars_per_line = 10
- words = text.split(" ")
- current_line = ""
- for word in words:
- if len(current_line) + len(word) + 1 <= chars_per_line:
- if current_line:
- current_line += " "
- current_line += word
- else:
- if current_line:
- lines.append(current_line)
- current_line = word
- if current_line:
- lines.append(current_line)
- return lines
-
- @staticmethod
- def truncateText(text: str, max_width: float, char_width: float = 12.0) -> str:
- max_chars = int(max_width / char_width)
- if max_chars <= 0:
- return ""
- if len(text) <= max_chars:
- return text
- return text[:max_chars - 1] + "..."
-
- @staticmethod
- def isRtlCharacter(c: str) -> bool:
- cp = ord(c)
- return (0x0590 <= cp <= 0x05FF or 0x0600 <= cp <= 0x06FF or
- 0x0700 <= cp <= 0x074F or 0x07C0 <= cp <= 0x07FF or
- 0xFB1D <= cp <= 0xFDFF or 0xFE70 <= cp <= 0xFEFF)
-
- @staticmethod
- def getTextDirection(text: str) -> int:
- for c in text[:100]:
- if TextShaperUtils.isRtlCharacter(c):
- return TextLayout.TEXT_DIRECTION_FIRST_STRONG_RTL
- return TextLayout.TEXT_DIRECTION_FIRST_STRONG_LTR
\ No newline at end of file
diff --git a/android_pyapi/android/hardware.py b/android_pyapi/android/hardware.py
deleted file mode 100644
index c0f54c6..0000000
--- a/android_pyapi/android/hardware.py
+++ /dev/null
@@ -1,746 +0,0 @@
-"""
-Android Hardware 组件 — Sensor, SensorManager, SensorEvent, 等
-方法签名完全对齐 Android SDK
-"""
-
-import math
-import time
-import random
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError, android_context, HAS_PIL
-
-# Linux 真实实现导入
-try:
- from .._linux_impl import IS_LINUX, LinuxBluetooth, LinuxSensors, HAS_BLUETOOTHCTL, LinuxPower
- _USE_LINUX = IS_LINUX
-except ImportError:
- try:
- from .._linux_impl import IS_LINUX, LinuxBluetooth, LinuxSensors, HAS_BLUETOOTHCTL
- _USE_LINUX = IS_LINUX
- LinuxPower = None
- except ImportError:
- _USE_LINUX = False
- LinuxPower = None
-
-
-# ═══════════════════════════════════════════════════════════════
-# Sensor
-# ═══════════════════════════════════════════════════════════════
-
-class Sensor(Stub):
- """Sensor — 传感器"""
-
- TYPE_ACCELEROMETER = 1
- TYPE_MAGNETIC_FIELD = 2
- TYPE_ORIENTATION = 3
- TYPE_GYROSCOPE = 4
- TYPE_LIGHT = 5
- TYPE_PRESSURE = 6
- TYPE_PROXIMITY = 8
- TYPE_GRAVITY = 9
- TYPE_LINEAR_ACCELERATION = 10
- TYPE_ROTATION_VECTOR = 11
- TYPE_RELATIVE_HUMIDITY = 12
- TYPE_AMBIENT_TEMPERATURE = 13
- TYPE_STEP_COUNTER = 19
- TYPE_STEP_DETECTOR = 18
- TYPE_HEART_RATE = 21
- TYPE_LOW_LATENCY_OFFBODY_DETECT = 34
- TYPE_ACCELEROMETER_LIMITED_AXES = 35
- TYPE_DEVICE_ORIENTATION = 27
- TYPE_STATIONARY_DETECT = 28
-
- REPORTING_MODE_CONTINUOUS = 0
- REPORTING_MODE_ON_CHANGE = 1
- REPORTING_MODE_ONE_SHOT = 2
- REPORTING_MODE_SPECIAL_TRIGGER = 3
-
- def __init__(self, type_: int, name: str = "Simulated Sensor",
- vendor: str = "Android-pyApi", version: int = 1,
- resolution: float = 1.0, max_range: float = 100.0,
- power: float = 0.5, min_delay: int = 10000):
- super().__init__()
- self._type = type_
- self._name = name
- self._vendor = vendor
- self._version = version
- self._resolution = resolution
- self._max_range = max_range
- self._power = power
- self._min_delay = min_delay
-
- # Assign default values based on sensor type
- type_defaults = {
- Sensor.TYPE_ACCELEROMETER: ("Accelerometer", 0.01, 39.24, 3.0, 10000),
- Sensor.TYPE_GYROSCOPE: ("Gyroscope", 0.001, 34.91, 6.1, 10000),
- Sensor.TYPE_MAGNETIC_FIELD: ("Magnetic Field", 0.01, 2000.0, 4.0, 10000),
- Sensor.TYPE_LIGHT: ("Light", 1.0, 40000.0, 0.5, 10000),
- Sensor.TYPE_PROXIMITY: ("Proximity", 1.0, 10.0, 0.5, 10000),
- Sensor.TYPE_PRESSURE: ("Pressure", 0.01, 1100.0, 1.0, 10000),
- Sensor.TYPE_GRAVITY: ("Gravity", 0.01, 39.24, 3.0, 10000),
- Sensor.TYPE_LINEAR_ACCELERATION: ("Linear Acceleration", 0.01, 39.24, 3.0, 10000),
- Sensor.TYPE_ROTATION_VECTOR: ("Rotation Vector", 0.0001, 1.0, 5.0, 10000),
- Sensor.TYPE_RELATIVE_HUMIDITY: ("Relative Humidity", 0.1, 100.0, 0.5, 10000),
- Sensor.TYPE_AMBIENT_TEMPERATURE: ("Ambient Temperature", 0.01, 80.0, 0.5, 10000),
- Sensor.TYPE_STEP_COUNTER: ("Step Counter", 1.0, 100000.0, 0.1, 100000),
- Sensor.TYPE_STEP_DETECTOR: ("Step Detector", 1.0, 1.0, 0.1, 100000),
- Sensor.TYPE_HEART_RATE: ("Heart Rate", 1.0, 220.0, 0.5, 100000),
- }
-
- if type_ in type_defaults:
- n, res, mr, p, md = type_defaults[type_]
- self._name = name if name != "Simulated Sensor" else n
- self._resolution = resolution if resolution != 1.0 else res
- self._max_range = max_range if max_range != 100.0 else mr
- self._power = power if power != 0.5 else p
- self._min_delay = min_delay if min_delay != 10000 else md
-
- def getType(self) -> int:
- return self._type
-
- def getName(self) -> str:
- return self._name
-
- def getVendor(self) -> str:
- return self._vendor
-
- def getVersion(self) -> int:
- return self._version
-
- def getMaximumRange(self) -> float:
- return self._max_range
-
- def getMinDelay(self) -> int:
- return self._min_delay
-
- def getPower(self) -> float:
- return self._power
-
- def getResolution(self) -> float:
- return self._resolution
-
- def getFifoMaxEventCount(self) -> int:
- return 0
-
- def getFifoReservedEventCount(self) -> int:
- return 0
-
- def getReportingMode(self) -> int:
- return Sensor.REPORTING_MODE_CONTINUOUS
-
- def isWakeUpSensor(self) -> bool:
- return False
-
- def getStringType(self) -> str:
- type_names = {
- Sensor.TYPE_ACCELEROMETER: "android.sensor.accelerometer",
- Sensor.TYPE_MAGNETIC_FIELD: "android.sensor.magnetic_field",
- Sensor.TYPE_GYROSCOPE: "android.sensor.gyroscope",
- Sensor.TYPE_LIGHT: "android.sensor.light",
- Sensor.TYPE_PRESSURE: "android.sensor.pressure",
- Sensor.TYPE_PROXIMITY: "android.sensor.proximity",
- Sensor.TYPE_GRAVITY: "android.sensor.gravity",
- Sensor.TYPE_LINEAR_ACCELERATION: "android.sensor.linear_acceleration",
- Sensor.TYPE_ROTATION_VECTOR: "android.sensor.rotation_vector",
- Sensor.TYPE_RELATIVE_HUMIDITY: "android.sensor.relative_humidity",
- Sensor.TYPE_AMBIENT_TEMPERATURE: "android.sensor.ambient_temperature",
- Sensor.TYPE_STEP_COUNTER: "android.sensor.step_counter",
- Sensor.TYPE_STEP_DETECTOR: "android.sensor.step_detector",
- Sensor.TYPE_HEART_RATE: "android.sensor.heart_rate",
- }
- return type_names.get(self._type, "android.sensor.unknown")
-
- def toString(self) -> str:
- return f"{self._name} (type={self._type}, vendor={self._vendor}, ver={self._version})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorEvent
-# ═══════════════════════════════════════════════════════════════
-
-class SensorEvent(Stub):
- """SensorEvent — 传感器事件"""
-
- def __init__(self, sensor: Sensor, accuracy: int = 3):
- super().__init__()
- self.sensor = sensor
- self.accuracy = accuracy
- self.timestamp = int(time.time() * 1_000_000_000) # nanoseconds
- self.values: List[float] = []
-
- # Generate appropriate values based on sensor type
- if sensor.getType() == Sensor.TYPE_ACCELEROMETER:
- self.values = [random.uniform(-1, 1), random.uniform(-1, 1),
- 9.8 + random.uniform(-0.5, 0.5)]
- elif sensor.getType() == Sensor.TYPE_GYROSCOPE:
- self.values = [random.uniform(-0.1, 0.1)] * 3
- elif sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD:
- self.values = [random.uniform(-50, 50)] * 3
- elif sensor.getType() == Sensor.TYPE_LIGHT:
- self.values = [random.uniform(100, 1000)]
- elif sensor.getType() == Sensor.TYPE_PROXIMITY:
- self.values = [5.0 if random.random() > 0.5 else 0.0]
- elif sensor.getType() == Sensor.TYPE_PRESSURE:
- self.values = [random.uniform(980, 1050)]
- elif sensor.getType() in (Sensor.TYPE_GRAVITY, Sensor.TYPE_LINEAR_ACCELERATION):
- self.values = [random.uniform(-1, 1)] * 3
- elif sensor.getType() == Sensor.TYPE_ROTATION_VECTOR:
- self.values = [random.uniform(-1, 1)] * 5
- elif sensor.getType() == Sensor.TYPE_RELATIVE_HUMIDITY:
- self.values = [random.uniform(30, 70)]
- elif sensor.getType() == Sensor.TYPE_AMBIENT_TEMPERATURE:
- self.values = [random.uniform(15, 35)]
- elif sensor.getType() == Sensor.TYPE_STEP_COUNTER:
- self.values = [float(random.randint(0, 10000))]
- elif sensor.getType() == Sensor.TYPE_STEP_DETECTOR:
- self.values = [1.0 if random.random() > 0.95 else 0.0]
- elif sensor.getType() == Sensor.TYPE_HEART_RATE:
- self.values = [random.uniform(60, 100)]
- else:
- self.values = [0.0]
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorEventListener
-# ═══════════════════════════════════════════════════════════════
-
-class SensorEventListener(Stub):
- """SensorEventListener — 传感器事件监听器"""
-
- def onSensorChanged(self, event: SensorEvent):
- pass
-
- def onAccuracyChanged(self, sensor: Sensor, accuracy: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorDelay
-# ═══════════════════════════════════════════════════════════════
-
-class SensorDelay(Stub):
- """SensorDelay — 传感器采样延迟常量"""
- FASTEST = 0
- GAME = 1
- UI = 2
- NORMAL = 3
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorManager
-# ═══════════════════════════════════════════════════════════════
-
-class SensorManager(Stub):
- """SensorManager — 传感器管理器"""
-
- SENSOR_DELAY_FASTEST = 0
- SENSOR_DELAY_GAME = 1
- SENSOR_DELAY_UI = 2
- SENSOR_DELAY_NORMAL = 3
-
- AXIS_X = 1
- AXIS_Y = 2
- AXIS_Z = 3
- AXIS_MINUS_X = 129
- AXIS_MINUS_Y = 130
- AXIS_MINUS_Z = 131
-
- def __init__(self):
- super().__init__()
- self._sensors: Dict[int, Sensor] = {}
- self._listeners: Dict[int, List[Tuple[SensorEventListener, Sensor, int]]] = {}
-
- # Create default sensors
- for type_ in [
- Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_GYROSCOPE,
- Sensor.TYPE_MAGNETIC_FIELD, Sensor.TYPE_LIGHT,
- Sensor.TYPE_PROXIMITY, Sensor.TYPE_PRESSURE,
- Sensor.TYPE_GRAVITY, Sensor.TYPE_LINEAR_ACCELERATION,
- Sensor.TYPE_ROTATION_VECTOR, Sensor.TYPE_RELATIVE_HUMIDITY,
- Sensor.TYPE_AMBIENT_TEMPERATURE, Sensor.TYPE_STEP_COUNTER,
- Sensor.TYPE_STEP_DETECTOR, Sensor.TYPE_HEART_RATE,
- ]:
- self._sensors[type_] = Sensor(type_)
-
- def getDefaultSensor(self, type_: int) -> Optional[Sensor]:
- if _USE_LINUX:
- sensor = self._build_linux_sensor(type_)
- if sensor is not None:
- return sensor
- return self._sensors.get(type_)
-
- def _build_linux_sensor(self, type_: int) -> Optional[Sensor]:
- """根据 Linux 真实传感器数据构造 Sensor 对象"""
- try:
- if type_ == Sensor.TYPE_AMBIENT_TEMPERATURE:
- temps = LinuxSensors.get_temperatures()
- if temps:
- t = temps[0]
- return Sensor(Sensor.TYPE_AMBIENT_TEMPERATURE,
- name=t.get("name", "Linux Temperature"),
- vendor="Linux", resolution=0.01,
- max_range=125.0, power=0.0, min_delay=1000)
- return None
- if type_ == Sensor.TYPE_LIGHT:
- light = LinuxSensors.get_light_level()
- if light is not None:
- return Sensor(Sensor.TYPE_LIGHT, name="Linux Light Sensor",
- vendor="Linux", resolution=0.001,
- max_range=40000.0, power=0.0, min_delay=1000)
- return None
- except Exception:
- return None
- return None
-
- def getSensorList(self, type_: int) -> List[Sensor]:
- if _USE_LINUX:
- return self._get_linux_sensor_list(type_)
- if type_ == -1: # ALL
- return list(self._sensors.values())
- sensor = self._sensors.get(type_)
- return [sensor] if sensor else []
-
- def _get_linux_sensor_list(self, type_: int) -> List[Sensor]:
- """从 Linux 真实传感器数据生成传感器列表"""
- sensors: List[Sensor] = []
- try:
- if type_ == -1 or type_ == Sensor.TYPE_AMBIENT_TEMPERATURE:
- for t in LinuxSensors.get_temperatures():
- sensors.append(Sensor(
- Sensor.TYPE_AMBIENT_TEMPERATURE,
- name=t.get("name", "Linux Temperature"),
- vendor="Linux", resolution=0.01,
- max_range=125.0, power=0.0, min_delay=1000))
- if type_ == -1 or type_ == Sensor.TYPE_LIGHT:
- light = LinuxSensors.get_light_level()
- if light is not None:
- sensors.append(Sensor(
- Sensor.TYPE_LIGHT, name="Linux Light Sensor",
- vendor="Linux", resolution=0.001,
- max_range=40000.0, power=0.0, min_delay=1000))
- # CPU 频率作为附加传感器 (映射到压力传感器类型以承载真实数据)
- if type_ == -1 or type_ == Sensor.TYPE_PRESSURE:
- for f in LinuxSensors.get_cpu_frequency():
- sensors.append(Sensor(
- Sensor.TYPE_PRESSURE,
- name=f"CPU{f.get('cpu', 0)} Frequency",
- vendor="Linux", resolution=1.0,
- max_range=10000.0, power=0.0, min_delay=1000))
- # 风扇转速作为附加传感器 (映射到相对湿度类型以承载真实数据)
- if type_ == -1 or type_ == Sensor.TYPE_RELATIVE_HUMIDITY:
- for fan in LinuxSensors.get_fan_speeds():
- sensors.append(Sensor(
- Sensor.TYPE_RELATIVE_HUMIDITY,
- name=f"Fan {fan.get('name', '')}",
- vendor="Linux", resolution=1.0,
- max_range=10000.0, power=0.0, min_delay=1000))
- except Exception:
- pass
- # 若未取到真实数据则回退到模拟传感器
- if not sensors:
- if type_ == -1:
- sensors = list(self._sensors.values())
- else:
- sensor = self._sensors.get(type_)
- if sensor:
- sensors = [sensor]
- return sensors
-
- def getSensors(self) -> List[Sensor]:
- return list(self._sensors.values())
-
- def registerListener(self, listener: SensorEventListener, sensor: Sensor,
- samplingPeriodUs: int, maxReportLatencyUs: int = 0) -> bool:
- if sensor.getType() not in self._sensors:
- return False
- if listener not in self._listeners:
- self._listeners[id(listener)] = []
- self._listeners[id(listener)].append((listener, sensor, samplingPeriodUs))
- return True
-
- def unregisterListener(self, listener: SensorEventListener, sensor: Sensor = None) -> bool:
- lid = id(listener)
- if lid in self._listeners:
- if sensor:
- self._listeners[lid] = [
- (l, s, d) for l, s, d in self._listeners[lid]
- if s.getType() != sensor.getType()
- ]
- if not self._listeners[lid]:
- del self._listeners[lid]
- else:
- del self._listeners[lid]
- return True
- return False
-
- @staticmethod
- def getOrientation(R: List[float], values: List[float]) -> List[float]:
- if len(R) >= 9 and len(values) >= 3:
- values[0] = math.degrees(math.atan2(R[1], R[4])) # azimuth
- values[1] = math.degrees(math.asin(-R[7])) # pitch
- values[2] = math.degrees(math.atan2(-R[6], R[8])) # roll
- return values
-
- @staticmethod
- def getRotationMatrix(R: List[float], I: List[float],
- gravity: List[float], geomagnetic: List[float]) -> bool:
- """根据重力和地磁向量计算旋转矩阵 R 和倾斜矩阵 I。
- 算法对齐 Android SensorManager.getRotationMatrix。"""
- if len(R) < 9:
- R.extend([0.0] * (9 - len(R)))
- gx, gy, gz = gravity[0], gravity[1], gravity[2]
- mx, my, mz = geomagnetic[0], geomagnetic[1], geomagnetic[2]
- # 归一化重力向量 -> H
- g_len = math.sqrt(gx * gx + gy * gy + gz * gz)
- if g_len < 1e-10:
- return False
- hx = gx / g_len
- hy = gy / g_len
- hz = gz / g_len
- # 叉积 A = H x M (东方向)
- ax = hy * mz - hz * my
- ay = hz * mx - hx * mz
- az = hx * my - hy * mx
- a_len = math.sqrt(ax * ax + ay * ay + az * az)
- if a_len < 1e-10:
- return False
- ax /= a_len
- ay /= a_len
- az /= a_len
- # 重新计算 M = A x H
- ex = ay * hz - az * hy
- ey = az * hx - ax * hz
- ez = ax * hy - ay * hx
- # 填充旋转矩阵 R (列优先,Android 格式)
- R[0] = ax
- R[1] = ay
- R[2] = az
- R[3] = ex
- R[4] = ey
- R[5] = ez
- R[6] = hx
- R[7] = hy
- R[8] = hz
- # 填充倾斜矩阵 I
- if I is not None and len(I) >= 9:
- inv_h = 1.0 / g_len
- inv_m = 1.0 / math.sqrt(mx * mx + my * my + mz * mz) if (mx * mx + my * my + mz * mz) > 0 else 0
- I[0] = inv_h * hx
- I[1] = inv_h * hy
- I[2] = inv_h * hz
- I[3] = inv_m * mx
- I[4] = inv_m * my
- I[5] = inv_m * mz
- I[6] = inv_h * ex
- I[7] = inv_h * ey
- I[8] = inv_h * ez
- return True
-
- @staticmethod
- def getAltitude(p0: float, p: float) -> float:
- return 44330.0 * (1.0 - math.pow(p / p0, 1.0 / 5.255))
-
- @staticmethod
- def getInclination(I: List[float]) -> float:
- """根据倾斜矩阵 I 计算地磁倾角(弧度)。"""
- if len(I) >= 9:
- # I[5] = cos(el), I[2] = sin(el)
- # 倾角 = atan2(I[2], I[5])
- return math.atan2(I[2], I[5])
- return 0.0
-
- @staticmethod
- def remapCoordinateSystem(inR: List[float], X: int, Y: int,
- outR: List[float]) -> bool:
- """根据指定的 X/Y 轴重映射坐标系。"""
- if len(inR) < 9 or len(outR) < 9:
- return False
- # Android 轴常量
- AXIS_X = 1
- AXIS_Y = 2
- AXIS_Z = 3
- AXIS_MINUS_X = -1
- AXIS_MINUS_Y = -2
- AXIS_MINUS_Z = -3
- # 将轴常量映射到列索引和符号
- axis_map = {
- AXIS_X: (0, 1), AXIS_Y: (1, 1), AXIS_Z: (2, 1),
- AXIS_MINUS_X: (0, -1), AXIS_MINUS_Y: (1, -1), AXIS_MINUS_Z: (2, -1),
- }
- if X not in axis_map or Y not in axis_map:
- return False
- x_col, x_sign = axis_map[X]
- y_col, y_sign = axis_map[Y]
- # Z = X x Y
- z_col = 3 - x_col - y_col
- z_sign = x_sign * y_sign
- # 如果 X 和 Y 不正交
- if abs(x_col - y_col) != 1 and not (x_col == 0 and y_col == 2) and not (x_col == 2 and y_col == 0):
- z_sign = -z_sign
- # 填充输出矩阵(列优先)
- for row in range(3):
- outR[row * 3 + 0] = inR[row * 3 + x_col] * x_sign
- outR[row * 3 + 1] = inR[row * 3 + y_col] * y_sign
- outR[row * 3 + 2] = inR[row * 3 + z_col] * z_sign
- return True
-
- def getDeviceId(self) -> str:
- """返回传感器设备 ID。尝试从 /sys 读取真实设备标识。"""
- import os as _os
- # 尝试从 /sys/class/sensor 读取
- try:
- base = "/sys/class/sensor"
- if _os.path.isdir(base):
- names = _os.listdir(base)
- if names:
- return names[0]
- except (OSError, IOError):
- pass
- # 尝试从 /sys/bus/iio/devices 读取
- try:
- base = "/sys/bus/iio/devices"
- if _os.path.isdir(base):
- names = _os.listdir(base)
- if names:
- return names[0]
- except (OSError, IOError):
- pass
- return "sensor_hub_0"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HardwareBuffer
-# ═══════════════════════════════════════════════════════════════
-
-class HardwareBuffer(Stub):
- """HardwareBuffer — 硬件缓冲 (API 26+)"""
-
- USAGE_CPU_READ_OFTEN = 0x00000003
- USAGE_CPU_WRITE_OFTEN = 0x00000030
- USAGE_GPU_SAMPLED_IMAGE = 0x00000100
- USAGE_GPU_COLOR_OUTPUT = 0x00000200
- USAGE_GPU_DATA_BUFFER = 0x00001000
- USAGE_SENSOR_DIRECT_DATA = 0x00400000
- USAGE_PROTECTED_CONTENT = 0x00004000
- USAGE_VIDEO_ENCODE = 0x00010000
- USAGE_GPU_FRAMEBUFFER = 0x00020000
- USAGE_COMPOSER_OVERLAY = 0x00000800
- USAGE_FRONT_BUFFER_QUEUE = 0x00008000
-
- BLOB = 0x21
- RGBA_8888 = 1
- RGBA_FP16 = 22
- RGBA_1010102 = 43
- RGBX_8888 = 2
- RGB_888 = 3
- RGB_565 = 4
- YCBCR_420_888 = 35
-
- def __init__(self, width: int, height: int, format: int, layers: int,
- usage: int, buffer_size: int = 0):
- super().__init__()
- self._width = width
- self._height = height
- self._format = format
- self._layers = layers
- self._usage = usage
- self._buffer_size = buffer_size
- self._closed = False
-
- @property
- def width(self) -> int:
- return self._width
-
- @property
- def height(self) -> int:
- return self._height
-
- @property
- def format(self) -> int:
- return self._format
-
- @property
- def layers(self) -> int:
- return self._layers
-
- @property
- def usage(self) -> int:
- return self._usage
-
- def destroy(self):
- self.close()
-
- def close(self):
- self._closed = True
-
- def isClosed(self) -> bool:
- return self._closed
-
- def isEmpty(self) -> bool:
- return self._width == 0 or self._height == 0
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getFormat(self) -> int:
- return self._format
-
- def getLayers(self) -> int:
- return self._layers
-
- def getUsage(self) -> int:
- return self._usage
-
- def getStride(self) -> int:
- return self._width
-
-
-# ═══════════════════════════════════════════════════════════════
-# BatteryManager (Constants)
-# ═══════════════════════════════════════════════════════════════
-
-class BatteryManager(Stub):
- """BatteryManager — 电池管理器常量 (实际实现在 android.os)"""
-
- BATTERY_PROPERTY_CHARGE_COUNTER = 1
- BATTERY_PROPERTY_CURRENT_NOW = 2
- BATTERY_PROPERTY_CURRENT_AVERAGE = 3
- BATTERY_PROPERTY_CAPACITY = 4
- BATTERY_PROPERTY_STATUS = 5
- BATTERY_PROPERTY_ENERGY_COUNTER = 6
-
- BATTERY_STATUS_UNKNOWN = 1
- BATTERY_STATUS_CHARGING = 2
- BATTERY_STATUS_DISCHARGING = 3
- BATTERY_STATUS_NOT_CHARGING = 4
- BATTERY_STATUS_FULL = 5
-
- BATTERY_HEALTH_UNKNOWN = 1
- BATTERY_HEALTH_GOOD = 2
- BATTERY_HEALTH_OVERHEAT = 3
- BATTERY_HEALTH_DEAD = 4
- BATTERY_HEALTH_OVER_VOLTAGE = 5
- BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6
- BATTERY_HEALTH_COLD = 7
-
- BATTERY_PLUGGED_AC = 1
- BATTERY_PLUGGED_USB = 2
- BATTERY_PLUGGED_WIRELESS = 4
-
- ACTION_CHARGING = "android.intent.action.ACTION_CHARGING"
- ACTION_DISCHARGING = "android.intent.action.ACTION_DISCHARGING"
- EXTRA_STATUS = "status"
- EXTRA_HEALTH = "health"
- EXTRA_LEVEL = "level"
- EXTRA_SCALE = "scale"
- EXTRA_PLUGGED = "plugged"
- EXTRA_TEMPERATURE = "temperature"
- EXTRA_VOLTAGE = "voltage"
- EXTRA_TECHNOLOGY = "technology"
- EXTRA_CHARGE_COUNTER = "charge_counter"
- EXTRA_PRESENT = "present"
-
- def __init__(self):
- super().__init__()
-
- def getIntProperty(self, id: int) -> int:
- """返回电池整型属性。优先使用 LinuxPower 读取真实数据。"""
- if _USE_LINUX and LinuxPower is not None:
- try:
- info = LinuxPower.get_battery_info() or {}
- if id == BatteryManager.BATTERY_PROPERTY_CAPACITY:
- level = info.get("level", -1)
- return int(level) if isinstance(level, (int, float)) and level >= 0 else -1
- if id == BatteryManager.BATTERY_PROPERTY_STATUS:
- status_map = {
- "charging": BatteryManager.BATTERY_STATUS_CHARGING,
- "discharging": BatteryManager.BATTERY_STATUS_DISCHARGING,
- "not charging": BatteryManager.BATTERY_STATUS_NOT_CHARGING,
- "full": BatteryManager.BATTERY_STATUS_FULL,
- "unknown": BatteryManager.BATTERY_STATUS_UNKNOWN,
- }
- return status_map.get(str(info.get("status", "unknown")).lower(),
- BatteryManager.BATTERY_STATUS_UNKNOWN)
- if id == BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
- voltage = info.get("voltage", 0)
- return int(voltage * 1000) if isinstance(voltage, (int, float)) else 0
- except Exception:
- pass
- # 回退到默认值
- id_values = {
- BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER: 3500,
- BatteryManager.BATTERY_PROPERTY_CAPACITY: 85,
- BatteryManager.BATTERY_PROPERTY_STATUS: BatteryManager.BATTERY_STATUS_DISCHARGING,
- }
- return id_values.get(id, 0)
-
- def getLongProperty(self, id: int) -> int:
- """返回电池长整型属性。优先使用 LinuxPower 读取真实数据。"""
- if _USE_LINUX and LinuxPower is not None:
- try:
- info = LinuxPower.get_battery_info() or {}
- if id == BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
- current = info.get("current_now", 0)
- return int(current) if isinstance(current, (int, float)) else 0
- if id == BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
- voltage = info.get("voltage", 0)
- return int(voltage * 3600000) if isinstance(voltage, (int, float)) else 0
- except Exception:
- pass
- return self.getIntProperty(id)
-
-
-# ═══════════════════════════════════════════════════════════════
-# BiometricManager (lightweight)
-# ═══════════════════════════════════════════════════════════════
-
-class BiometricManager(Stub):
- """BiometricManager — 生物识别管理器 (轻量)"""
-
- BIOMETRIC_SUCCESS = 0
- BIOMETRIC_ERROR_HW_UNAVAILABLE = 1
- BIOMETRIC_ERROR_NONE_ENROLLED = 11
- BIOMETRIC_ERROR_NO_HARDWARE = 12
- BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15
-
- def __init__(self):
- super().__init__()
-
- def canAuthenticate(self) -> int:
- return BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE
-
-
-# ═══════════════════════════════════════════════════════════════
-# Flashlight support
-# ═══════════════════════════════════════════════════════════════
-
-class CameraFlashlight(Stub):
- """CameraFlashlight — 手电筒支持"""
-
- def __init__(self):
- super().__init__()
- self._on = False
-
- def setTorchMode(self, cameraId: str, enabled: bool):
- self._on = enabled
-
- def isTorchModeEnabled(self, cameraId: str) -> bool:
- return self._on
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Sensor", "SensorManager", "SensorEvent", "SensorEventListener",
- "SensorDelay",
- "HardwareBuffer",
- "BatteryManager",
- "BiometricManager",
- "CameraFlashlight",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_biometrics.py b/android_pyapi/android/hardware_biometrics.py
deleted file mode 100644
index 8567b80..0000000
--- a/android_pyapi/android/hardware_biometrics.py
+++ /dev/null
@@ -1,291 +0,0 @@
-"""
-Android Biometrics 组件 — BiometricManager, BiometricPrompt, 等
-方法签名完全对齐 Android SDK
-"""
-
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError, android_context
-
-
-# ═══════════════════════════════════════════════════════════════
-# BiometricConstants
-# ═══════════════════════════════════════════════════════════════
-
-class BiometricConstants(Stub):
- """BiometricConstants — 生物识别常量"""
-
- BIOMETRIC_SUCCESS = 0
- BIOMETRIC_ERROR_HW_UNAVAILABLE = 1
- BIOMETRIC_ERROR_VENDOR = 8
- BIOMETRIC_ERROR_LOCKOUT = 7
- BIOMETRIC_ERROR_LOCKOUT_PERMANENT = 9
- BIOMETRIC_ERROR_USER_CANCELED = 10
- BIOMETRIC_ERROR_NO_BIOMETRIC = 11
- BIOMETRIC_ERROR_HW_NOT_PRESENT = 12
- BIOMETRIC_ERROR_NEGATIVE_BUTTON = 13
- BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14
- BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15
- BIOMETRIC_ERROR_UNSUPPORTED = 65536
- BIOMETRIC_ERROR_CANCELED = 5
- BIOMETRIC_ERROR_TIMEOUT = 3
- BIOMETRIC_ERROR_NONE_ENROLLED = 11
- BIOMETRIC_ERROR_NO_HARDWARE = 12
- BIOMETRIC_STATUS_OK = 0
-
- # Authenticator types
- BIOMETRIC_STRONG = 0x0F
- BIOMETRIC_WEAK = 0xFF
- DEVICE_CREDENTIAL = 0x8000
-
-
-# ═══════════════════════════════════════════════════════════════
-# BiometricPrompt
-# ═══════════════════════════════════════════════════════════════
-
-class BiometricPrompt(Stub):
- """BiometricPrompt — 生物识别提示 (API 28+)"""
-
- class AuthenticationCallback(Stub):
- """BiometricPrompt.AuthenticationCallback — 认证回调"""
-
- def onAuthenticationError(self, errorCode: int, errString: str):
- pass
-
- def onAuthenticationSucceeded(self, result: "BiometricPrompt.AuthenticationResult"):
- pass
-
- def onAuthenticationFailed(self):
- pass
-
- def onAuthenticationAcquired(self, acquireInfo: int):
- pass
-
- class AuthenticationResult(Stub):
- """BiometricPrompt.AuthenticationResult — 认证结果"""
-
- def __init__(self, cryptoObject: "BiometricPromptCryptoObject" = None,
- authenticationType: int = BiometricConstants.BIOMETRIC_STRONG):
- super().__init__()
- self._crypto_object = cryptoObject
- self._authentication_type = authenticationType
-
- def getCryptoObject(self) -> Optional["BiometricPromptCryptoObject"]:
- return self._crypto_object
-
- def getAuthenticationType(self) -> int:
- return self._authentication_type
-
- class PromptInfo(Stub):
- """BiometricPrompt.PromptInfo — 提示信息"""
-
- class Builder(Stub):
- """BiometricPrompt.PromptInfo.Builder — 提示信息构建器"""
-
- def __init__(self):
- super().__init__()
- self._title = ""
- self._subtitle = ""
- self._description = ""
- self._device_credential_allowed = False
- self._allowed_authenticators = 0
- self._confirmation_required = True
- self._negative_button_text = ""
-
- def setTitle(self, title: str) -> "BiometricPrompt.PromptInfo.Builder":
- self._title = title
- return self
-
- def setSubtitle(self, subtitle: str) -> "BiometricPrompt.PromptInfo.Builder":
- self._subtitle = subtitle
- return self
-
- def setDescription(self, description: str) -> "BiometricPrompt.PromptInfo.Builder":
- self._description = description
- return self
-
- def setDeviceCredentialAllowed(self, allowed: bool) -> "BiometricPrompt.PromptInfo.Builder":
- self._device_credential_allowed = allowed
- return self
-
- def setAllowedAuthenticators(self, authenticators: int) -> "BiometricPrompt.PromptInfo.Builder":
- self._allowed_authenticators = authenticators
- return self
-
- def setConfirmationRequired(self, required: bool) -> "BiometricPrompt.PromptInfo.Builder":
- self._confirmation_required = required
- return self
-
- def setNegativeButtonText(self, text: str) -> "BiometricPrompt.PromptInfo.Builder":
- self._negative_button_text = text
- return self
-
- def build(self) -> "BiometricPrompt.PromptInfo":
- info = BiometricPrompt.PromptInfo()
- info._title = self._title
- info._subtitle = self._subtitle
- info._description = self._description
- info._device_credential_allowed = self._device_credential_allowed
- info._allowed_authenticators = self._allowed_authenticators
- info._confirmation_required = self._confirmation_required
- info._negative_button_text = self._negative_button_text
- return info
-
- def __init__(self):
- super().__init__()
- self._title = ""
- self._subtitle = ""
- self._description = ""
- self._device_credential_allowed = False
- self._allowed_authenticators = 0
- self._confirmation_required = True
- self._negative_button_text = ""
-
- def getTitle(self) -> str:
- return self._title
-
- def getSubtitle(self) -> str:
- return self._subtitle
-
- def getDescription(self) -> str:
- return self._description
-
- def isDeviceCredentialAllowed(self) -> bool:
- return self._device_credential_allowed
-
- def getAllowedAuthenticators(self) -> int:
- return self._allowed_authenticators
-
- def isConfirmationRequired(self) -> bool:
- return self._confirmation_required
-
- def getNegativeButtonText(self) -> str:
- return self._negative_button_text
-
- def __init__(self, context, callback: AuthenticationCallback = None,
- handler=None):
- super().__init__()
- self._context = context
- self._callback = callback
- self._cancelled = False
-
- def authenticate(self, crypto: "BiometricPromptCryptoObject" = None,
- cancel: Any = None, executor=None,
- callback: AuthenticationCallback = None):
- self._cancelled = False
- if callback:
- self._callback = callback
- if self._callback:
- # Simulate failed authentication on desktop
- self._callback.onAuthenticationError(
- BiometricConstants.BIOMETRIC_ERROR_NO_HARDWARE,
- "No biometric hardware available on this device"
- )
-
- def authenticate(self, promptInfo: PromptInfo, crypto: "BiometricPromptCryptoObject" = None):
- self._cancelled = False
- if self._callback:
- self._callback.onAuthenticationError(
- BiometricConstants.BIOMETRIC_ERROR_NO_HARDWARE,
- "No biometric hardware available on this device"
- )
-
- def cancelAuthentication(self):
- self._cancelled = True
- if self._callback:
- self._callback.onAuthenticationError(
- BiometricConstants.BIOMETRIC_ERROR_CANCELED,
- "Authentication cancelled"
- )
-
- def cancel(self):
- self.cancelAuthentication()
-
- def isCancelled(self) -> bool:
- return self._cancelled
-
-
-# ═══════════════════════════════════════════════════════════════
-# BiometricPromptCryptoObject
-# ═══════════════════════════════════════════════════════════════
-
-class BiometricPromptCryptoObject(Stub):
- """BiometricPromptCryptoObject — 加密对象"""
-
- def __init__(self, signature=None, cipher=None, mac=None):
- super().__init__()
- self._signature = signature
- self._cipher = cipher
- self._mac = mac
-
- def getSignature(self):
- return self._signature
-
- def getCipher(self):
- return self._cipher
-
- def getMac(self):
- return self._mac
-
-
-# ═══════════════════════════════════════════════════════════════
-# BiometricPromptAuthenticationResult
-# ═══════════════════════════════════════════════════════════════
-
-BiometricPromptAuthenticationResult = BiometricPrompt.AuthenticationResult
-
-
-# ═══════════════════════════════════════════════════════════════
-# BiometricManager
-# ═══════════════════════════════════════════════════════════════
-
-class BiometricManager(Stub):
- """BiometricManager — 生物识别管理器 (API 29+)"""
-
- BIOMETRIC_SUCCESS = BiometricConstants.BIOMETRIC_SUCCESS
- BIOMETRIC_ERROR_HW_UNAVAILABLE = BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE
- BIOMETRIC_ERROR_NONE_ENROLLED = BiometricConstants.BIOMETRIC_ERROR_NONE_ENROLLED
- BIOMETRIC_ERROR_NO_HARDWARE = BiometricConstants.BIOMETRIC_ERROR_NO_HARDWARE
- BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED
- BIOMETRIC_ERROR_UNSUPPORTED = BiometricConstants.BIOMETRIC_ERROR_UNSUPPORTED
- BIOMETRIC_STATUS_OK = BiometricConstants.BIOMETRIC_STATUS_OK
- BIOMETRIC_ERROR_VENDOR = BiometricConstants.BIOMETRIC_ERROR_VENDOR
- BIOMETRIC_ERROR_USER_CANCELED = BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED
- BIOMETRIC_ERROR_CANCELED = BiometricConstants.BIOMETRIC_ERROR_CANCELED
- BIOMETRIC_ERROR_TIMEOUT = BiometricConstants.BIOMETRIC_ERROR_TIMEOUT
- BIOMETRIC_ERROR_LOCKOUT = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
- BIOMETRIC_ERROR_LOCKOUT_PERMANENT = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT
-
- # Authenticators
- AUTHENTICATOR_BIOMETRIC_STRONG = BiometricConstants.BIOMETRIC_STRONG
- AUTHENTICATOR_BIOMETRIC_WEAK = BiometricConstants.BIOMETRIC_WEAK
- AUTHENTICATOR_DEVICE_CREDENTIAL = BiometricConstants.DEVICE_CREDENTIAL
-
- def __init__(self, context=None):
- super().__init__()
- self._context = context
-
- def canAuthenticate(self, authenticators: int = AUTHENTICATOR_BIOMETRIC_STRONG) -> int:
- """Check if biometric authentication is available"""
- return BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE
-
- @staticmethod
- def fromContext(context) -> "BiometricManager":
- """Get BiometricManager from context"""
- return BiometricManager(context)
-
- def toString(self) -> str:
- return "BiometricManager(desktop - no hardware)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "BiometricManager",
- "BiometricPrompt",
- "BiometricPromptAuthenticationResult",
- "BiometricPromptCryptoObject",
- "BiometricConstants",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_camera2.py b/android_pyapi/android/hardware_camera2.py
deleted file mode 100644
index 4025211..0000000
--- a/android_pyapi/android/hardware_camera2.py
+++ /dev/null
@@ -1,761 +0,0 @@
-"""
-Android Camera2 组件 — CameraManager, CameraDevice, CaptureRequest 等
-方法签名完全对齐 Android SDK
-"""
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError, android_context, HAS_PIL
-
-
-# ═══════════════════════════════════════════════════════════════
-# CameraMetadata
-# ═══════════════════════════════════════════════════════════════
-
-class CameraMetadata(Stub):
- """CameraMetadata — 相机元数据基类"""
-
- # CONTROL_AE modes
- CONTROL_AE_MODE_OFF = 0
- CONTROL_AE_MODE_ON = 1
- CONTROL_AE_MODE_ON_AUTO_FLASH = 2
- CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3
- CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4
- CONTROL_AE_MODE_EXTERNAL_FLASH = 5
-
- # CONTROL_AF modes
- CONTROL_AF_MODE_OFF = 0
- CONTROL_AF_MODE_AUTO = 1
- CONTROL_AF_MODE_MACRO = 2
- CONTROL_AF_MODE_CONTINUOUS_VIDEO = 3
- CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4
- CONTROL_AF_MODE_EDOF = 5
-
- # CONTROL_AWB modes
- CONTROL_AWB_MODE_OFF = 0
- CONTROL_AWB_MODE_AUTO = 1
- CONTROL_AWB_MODE_INCANDESCENT = 2
- CONTROL_AWB_MODE_FLUORESCENT = 3
- CONTROL_AWB_MODE_WARM_FLUORESCENT = 4
- CONTROL_AWB_MODE_DAYLIGHT = 5
- CONTROL_AWB_MODE_CLOUDY_DAYLIGHT = 6
- CONTROL_AWB_MODE_TWILIGHT = 7
- CONTROL_AWB_MODE_SHADE = 8
-
- # CONTROL modes
- CONTROL_MODE_OFF = 0
- CONTROL_MODE_AUTO = 1
- CONTROL_MODE_USE_SCENE_MODE = 2
- CONTROL_MODE_OFF_KEEP_STATE = 3
-
- # FLASH modes
- FLASH_MODE_OFF = 0
- FLASH_MODE_SINGLE = 1
- FLASH_MODE_TORCH = 2
-
- # STATISTICS_FACE_DETECT modes
- STATISTICS_FACE_DETECT_MODE_OFF = 0
- STATISTICS_FACE_DETECT_MODE_SIMPLE = 1
- STATISTICS_FACE_DETECT_MODE_FULL = 2
-
- # EDGE modes
- EDGE_MODE_OFF = 0
- EDGE_MODE_FAST = 1
- EDGE_MODE_HIGH_QUALITY = 2
- EDGE_MODE_ZERO_SHUTTER_LAG = 3
-
- # NOISE_REDUCTION modes
- NOISE_REDUCTION_MODE_OFF = 0
- NOISE_REDUCTION_MODE_FAST = 1
- NOISE_REDUCTION_MODE_HIGH_QUALITY = 2
- NOISE_REDUCTION_MODE_MINIMAL = 3
- NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG = 4
-
- # TONEMAP modes
- TONEMAP_MODE_CONTRAST_CURVE = 0
- TONEMAP_MODE_FAST = 1
- TONEMAP_MODE_HIGH_QUALITY = 2
- TONEMAP_MODE_GAMMA_VALUE = 3
- TONEMAP_MODE_PRESET_CURVE = 4
-
- # COLOR_CORRECTION modes
- COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0
- COLOR_CORRECTION_MODE_FAST = 1
- COLOR_CORRECTION_MODE_HIGH_QUALITY = 2
-
- # COLOR_CORRECTION_ABERRATION modes
- COLOR_CORRECTION_ABERRATION_MODE_OFF = 0
- COLOR_CORRECTION_ABERRATION_MODE_FAST = 1
- COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2
-
- # CONTROL_AE_PRECAPTURE_TRIGGER
- CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0
- CONTROL_AE_PRECAPTURE_TRIGGER_START = 1
- CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2
-
- # CONTROL_EFFECT modes
- CONTROL_EFFECT_MODE_OFF = 0
- CONTROL_EFFECT_MODE_MONO = 1
- CONTROL_EFFECT_MODE_NEGATIVE = 2
- CONTROL_EFFECT_MODE_SOLARIZE = 3
- CONTROL_EFFECT_MODE_SEPIA = 4
- CONTROL_EFFECT_MODE_POSTERIZE = 5
- CONTROL_EFFECT_MODE_WHITEBOARD = 6
- CONTROL_EFFECT_MODE_BLACKBOARD = 7
- CONTROL_EFFECT_MODE_AQUA = 8
-
- # CONTROL_SCENE modes
- CONTROL_SCENE_MODE_DISABLED = 0
- CONTROL_SCENE_MODE_FACE_PRIORITY = 1
- CONTROL_SCENE_MODE_ACTION = 2
- CONTROL_SCENE_MODE_PORTRAIT = 3
- CONTROL_SCENE_MODE_LANDSCAPE = 4
- CONTROL_SCENE_MODE_NIGHT = 5
- CONTROL_SCENE_MODE_NIGHT_PORTRAIT = 6
- CONTROL_SCENE_MODE_THEATRE = 7
- CONTROL_SCENE_MODE_BEACH = 8
- CONTROL_SCENE_MODE_SNOW = 9
- CONTROL_SCENE_MODE_SUNSET = 10
- CONTROL_SCENE_MODE_STEADYPHOTO = 11
- CONTROL_SCENE_MODE_FIREWORKS = 12
- CONTROL_SCENE_MODE_SPORTS = 13
- CONTROL_SCENE_MODE_PARTY = 14
- CONTROL_SCENE_MODE_CANDLELIGHT = 15
- CONTROL_SCENE_MODE_BARCODE = 16
- CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17
- CONTROL_SCENE_MODE_HDR = 18
-
- # CONTROL_VIDEO_STABILIZATION modes
- CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0
- CONTROL_VIDEO_STABILIZATION_MODE_ON = 1
-
- # DISTORTION_CORRECTION modes
- DISTORTION_CORRECTION_MODE_OFF = 0
- DISTORTION_CORRECTION_MODE_FAST = 1
- DISTORTION_CORRECTION_MODE_HIGH_QUALITY = 2
-
- # HOT_PIXEL modes
- HOT_PIXEL_MODE_OFF = 0
- HOT_PIXEL_MODE_FAST = 1
- HOT_PIXEL_MODE_HIGH_QUALITY = 2
-
- # LENS_OPTICAL_STABILIZATION modes
- LENS_OPTICAL_STABILIZATION_MODE_OFF = 0
- LENS_OPTICAL_STABILIZATION_MODE_ON = 1
-
- # LENS_FACING
- LENS_FACING_FRONT = 0
- LENS_FACING_BACK = 1
- LENS_FACING_EXTERNAL = 2
-
- # INFO_SUPPORTED_HARDWARE_LEVEL
- INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0
- INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1
- INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2
- INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3
- INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL = 4
-
-
-# ═══════════════════════════════════════════════════════════════
-# CameraCharacteristics
-# ═══════════════════════════════════════════════════════════════
-
-class CameraCharacteristics(CameraMetadata):
- """CameraCharacteristics — 相机特性"""
-
- LENS_FACING = "android.lens.facing"
- SENSOR_ORIENTATION = "android.sensor.orientation"
- FLASH_INFO_AVAILABLE = "android.flash.info.available"
- INFO_SUPPORTED_HARDWARE_LEVEL = "android.info.supportedHardwareLevel"
- SCALER_STREAM_CONFIGURATION_MAP = "android.scaler.streamConfigurationMap"
- CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES = "android.control.aeAvailableTargetFpsRanges"
- CONTROL_AE_AVAILABLE_MODES = "android.control.aeAvailableModes"
- CONTROL_AF_AVAILABLE_MODES = "android.control.afAvailableModes"
- CONTROL_AVAILABLE_EFFECTS = "android.control.availableEffects"
- CONTROL_AVAILABLE_SCENE_MODES = "android.control.availableSceneModes"
- CONTROL_MAX_REGIONS_AE = "android.control.maxRegionsAe"
- CONTROL_MAX_REGIONS_AF = "android.control.maxRegionsAf"
- CONTROL_MAX_REGIONS_AWB = "android.control.maxRegionsAwb"
- JPEG_AVAILABLE_THUMBNAIL_SIZES = "android.jpeg.availableThumbnailSizes"
- JPEG_MAX_SIZE = "android.jpeg.maxSize"
- SENSOR_INFO_PIXEL_ARRAY_SIZE = "android.sensor.info.pixelArraySize"
- SENSOR_INFO_ACTIVE_ARRAY_SIZE = "android.sensor.info.activeArraySize"
- FLASH_MODE = "android.flash.mode"
-
- def __init__(self, camera_id: str = "0"):
- super().__init__()
- self._properties: Dict[str, Any] = {
- CameraCharacteristics.LENS_FACING: CameraCharacteristics.LENS_FACING_BACK,
- CameraCharacteristics.SENSOR_ORIENTATION: 90,
- CameraCharacteristics.FLASH_INFO_AVAILABLE: True,
- CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL:
- CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
- CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP: {
- "output_sizes": [(1920, 1080), (1280, 720), (640, 480)],
- "input_sizes": [(1920, 1080)],
- },
- CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES: [(15, 30), (30, 30)],
- CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES: [0, 1, 2, 3, 4],
- CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES: [0, 1, 2, 3, 4, 5],
- CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS: list(range(9)),
- CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES: list(range(19)),
- CameraCharacteristics.CONTROL_MAX_REGIONS_AE: 1,
- CameraCharacteristics.CONTROL_MAX_REGIONS_AF: 1,
- CameraCharacteristics.CONTROL_MAX_REGIONS_AWB: 0,
- CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES: [(320, 240), (160, 120)],
- CameraCharacteristics.JPEG_MAX_SIZE: 5000000,
- CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE: (4032, 3024),
- CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE: (4032, 3024),
- }
-
- def get(self, key: str) -> Any:
- return self._properties.get(key)
-
- def keys(self) -> Set[str]:
- return set(self._properties.keys())
-
- def query(self, key: str) -> Any:
- return self._properties.get(key)
-
-
-# ═══════════════════════════════════════════════════════════════
-# CameraId
-# ═══════════════════════════════════════════════════════════════
-
-class CameraId(Stub):
- """CameraId — 相机ID封装"""
-
- def __init__(self, id_string: str):
- super().__init__()
- self._id = id_string
-
- def getId(self) -> str:
- return self._id
-
- def toString(self) -> str:
- return self._id
-
- def equals(self, other) -> bool:
- if isinstance(other, CameraId):
- return self._id == other._id
- if isinstance(other, str):
- return self._id == other
- return False
-
- def hashCode(self) -> int:
- return hash(self._id)
-
-
-# ═══════════════════════════════════════════════════════════════
-# CameraCharacteristicsKey
-# ═══════════════════════════════════════════════════════════════
-
-class CameraCharacteristicsKey(Stub):
- """CameraCharacteristicsKey — 相机特性键"""
-
- def __init__(self, name: str, native_type: type = object):
- super().__init__()
- self._name = name
- self._native_type = native_type
-
- def getName(self) -> str:
- return self._name
-
- def getNativeType(self) -> type:
- return self._native_type
-
- def equals(self, other) -> bool:
- if isinstance(other, CameraCharacteristicsKey):
- return self._name == other._name
- return False
-
- def hashCode(self) -> int:
- return hash(self._name)
-
- def toString(self) -> str:
- return f"CameraCharacteristicsKey({self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CaptureRequest
-# ═══════════════════════════════════════════════════════════════
-
-class CaptureRequest(CameraMetadata):
- """CaptureRequest — 捕获请求"""
-
- CONTROL_AE_MODE = "android.control.aeMode"
- CONTROL_AF_MODE = "android.control.afMode"
- CONTROL_AWB_MODE = "android.control.awbMode"
- CONTROL_MODE = "android.control.mode"
- FLASH_MODE = "android.flash.mode"
- SENSOR_EXPOSURE_TIME = "android.sensor.exposureTime"
- SENSOR_SENSITIVITY = "android.sensor.sensitivity"
- LENS_FOCUS_DISTANCE = "android.lens.focusDistance"
- STATISTICS_FACE_DETECT_MODE = "android.statistics.faceDetectMode"
- JPEG_QUALITY = "android.jpeg.quality"
- JPEG_ORIENTATION = "android.jpeg.orientation"
- JPEG_THUMBNAIL_QUALITY = "android.jpeg.thumbnailQuality"
- JPEG_THUMBNAIL_SIZE = "android.jpeg.thumbnailSize"
- SCALER_CROP_REGION = "android.scaler.cropRegion"
- EDGE_MODE = "android.edge.mode"
- NOISE_REDUCTION_MODE = "android.noiseReduction.mode"
- TONEMAP_MODE = "android.tonemap.mode"
- BLACK_LEVEL_LOCK = "android.blackLevel.lock"
- CONTROL_AE_TARGET_FPS_RANGE = "android.control.aeTargetFpsRange"
- CONTROL_AE_EXPOSURE_COMPENSATION = "android.control.aeExposureCompensation"
- CONTROL_AE_LOCK = "android.control.aeLock"
- CONTROL_AE_PRECAPTURE_TRIGGER = "android.control.aePrecaptureTrigger"
- CONTROL_AWB_LOCK = "android.control.awbLock"
- CONTROL_EFFECT_MODE = "android.control.effectMode"
- CONTROL_SCENE_MODE = "android.control.sceneMode"
- CONTROL_VIDEO_STABILIZATION_MODE = "android.control.videoStabilizationMode"
- COLOR_CORRECTION_MODE = "android.colorCorrection.mode"
- COLOR_CORRECTION_GAINS = "android.colorCorrection.gains"
- COLOR_CORRECTION_TRANSFORM = "android.colorCorrection.transform"
- COLOR_CORRECTION_ABERRATION_MODE = "android.colorCorrection.aberrationMode"
- CONTROL_POST_RAW_SENSITIVITY_BOOST = "android.control.postRawSensitivityBoost"
- DISTORTION_CORRECTION_MODE = "android.distortionCorrection.mode"
- HOT_PIXEL_MODE = "android.hotPixel.mode"
- LENS_OPTICAL_STABILIZATION_MODE = "android.lens.opticalStabilizationMode"
- REQUEST_PIPELINE_MAX_DEPTH = "android.request.pipelineMaxDepth"
- SENSOR_TIMESTAMP = "android.sensor.timestamp"
- STATISTICS_LENS_SHADING_MAP_MODE = "android.statistics.lensShadingMapMode"
- STATISTICS_OIS_DATA_MODE = "android.statistics.oisDataMode"
- STATISTICS_SECTION = "android.statistics.section"
- TONEMAP_CURVE = "android.tonemap.curve"
- TONEMAP_GAMMA = "android.tonemap.gamma"
-
- class Builder(Stub):
- """CaptureRequest.Builder — 捕获请求构建器"""
-
- def __init__(self, camera_device: "CameraDevice"):
- super().__init__()
- self._parameters: Dict[str, Any] = {}
- self._tag = None
- self._camera_device = camera_device
-
- def set(self, key: str, value: Any):
- self._parameters[key] = value
-
- def get(self, key: str) -> Any:
- return self._parameters.get(key)
-
- def setTag(self, tag: Any):
- self._tag = tag
-
- def build(self) -> "CaptureRequest":
- req = CaptureRequest()
- req._parameters = dict(self._parameters)
- req._tag = self._tag
- return req
-
- def addTarget(self, surface):
- pass
-
- def removeTarget(self, surface):
- pass
-
- def __init__(self):
- super().__init__()
- self._parameters: Dict[str, Any] = {
- CaptureRequest.CONTROL_AE_MODE: CameraMetadata.CONTROL_AE_MODE_ON,
- CaptureRequest.CONTROL_AF_MODE: CameraMetadata.CONTROL_AF_MODE_AUTO,
- CaptureRequest.CONTROL_AWB_MODE: CameraMetadata.CONTROL_AWB_MODE_AUTO,
- CaptureRequest.CONTROL_MODE: CameraMetadata.CONTROL_MODE_AUTO,
- CaptureRequest.FLASH_MODE: CameraMetadata.FLASH_MODE_OFF,
- CaptureRequest.JPEG_QUALITY: 95,
- CaptureRequest.JPEG_ORIENTATION: 0,
- }
- self._tag = None
- self._targets: List[Any] = []
-
- def get(self, key: str) -> Any:
- return self._parameters.get(key)
-
- def keys(self) -> Set[str]:
- return set(self._parameters.keys())
-
- def getTag(self) -> Any:
- return self._tag
-
-
-# ═══════════════════════════════════════════════════════════════
-# CaptureResult
-# ═══════════════════════════════════════════════════════════════
-
-class CaptureResult(CameraMetadata):
- """CaptureResult — 捕获结果"""
-
- # Same keys as CaptureRequest
- CONTROL_AE_MODE = CaptureRequest.CONTROL_AE_MODE
- CONTROL_AF_MODE = CaptureRequest.CONTROL_AF_MODE
- CONTROL_AWB_MODE = CaptureRequest.CONTROL_AWB_MODE
- CONTROL_MODE = CaptureRequest.CONTROL_MODE
- FLASH_MODE = CaptureRequest.FLASH_MODE
- SENSOR_EXPOSURE_TIME = CaptureRequest.SENSOR_EXPOSURE_TIME
- SENSOR_SENSITIVITY = CaptureRequest.SENSOR_SENSITIVITY
- LENS_FOCUS_DISTANCE = CaptureRequest.LENS_FOCUS_DISTANCE
- STATISTICS_FACE_DETECT_MODE = CaptureRequest.STATISTICS_FACE_DETECT_MODE
- JPEG_QUALITY = CaptureRequest.JPEG_QUALITY
- JPEG_ORIENTATION = CaptureRequest.JPEG_ORIENTATION
- JPEG_THUMBNAIL_QUALITY = CaptureRequest.JPEG_THUMBNAIL_QUALITY
- JPEG_THUMBNAIL_SIZE = CaptureRequest.JPEG_THUMBNAIL_SIZE
- SCALER_CROP_REGION = CaptureRequest.SCALER_CROP_REGION
- EDGE_MODE = CaptureRequest.EDGE_MODE
- NOISE_REDUCTION_MODE = CaptureRequest.NOISE_REDUCTION_MODE
- TONEMAP_MODE = CaptureRequest.TONEMAP_MODE
- BLACK_LEVEL_LOCK = CaptureRequest.BLACK_LEVEL_LOCK
- CONTROL_AE_TARGET_FPS_RANGE = CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE
- CONTROL_AE_EXPOSURE_COMPENSATION = CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION
- CONTROL_AE_LOCK = CaptureRequest.CONTROL_AE_LOCK
- CONTROL_AE_PRECAPTURE_TRIGGER = CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER
- CONTROL_AWB_LOCK = CaptureRequest.CONTROL_AWB_LOCK
- CONTROL_EFFECT_MODE = CaptureRequest.CONTROL_EFFECT_MODE
- CONTROL_SCENE_MODE = CaptureRequest.CONTROL_SCENE_MODE
- CONTROL_VIDEO_STABILIZATION_MODE = CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE
- COLOR_CORRECTION_MODE = CaptureRequest.COLOR_CORRECTION_MODE
- COLOR_CORRECTION_GAINS = CaptureRequest.COLOR_CORRECTION_GAINS
- COLOR_CORRECTION_TRANSFORM = CaptureRequest.COLOR_CORRECTION_TRANSFORM
- COLOR_CORRECTION_ABERRATION_MODE = CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE
- CONTROL_POST_RAW_SENSITIVITY_BOOST = CaptureRequest.CONTROL_POST_RAW_SENSITIVITY_BOOST
- DISTORTION_CORRECTION_MODE = CaptureRequest.DISTORTION_CORRECTION_MODE
- HOT_PIXEL_MODE = CaptureRequest.HOT_PIXEL_MODE
- LENS_OPTICAL_STABILIZATION_MODE = CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE
- REQUEST_PIPELINE_MAX_DEPTH = CaptureRequest.REQUEST_PIPELINE_MAX_DEPTH
- SENSOR_TIMESTAMP = CaptureRequest.SENSOR_TIMESTAMP
- STATISTICS_LENS_SHADING_MAP_MODE = CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE
- STATISTICS_OIS_DATA_MODE = CaptureRequest.STATISTICS_OIS_DATA_MODE
- STATISTICS_SECTION = CaptureRequest.STATISTICS_SECTION
- TONEMAP_CURVE = CaptureRequest.TONEMAP_CURVE
- TONEMAP_GAMMA = CaptureRequest.TONEMAP_GAMMA
-
- def __init__(self, request: CaptureRequest = None):
- super().__init__()
- self._results: Dict[str, Any] = {
- CaptureResult.CONTROL_AE_MODE: CameraMetadata.CONTROL_AE_MODE_ON,
- CaptureResult.CONTROL_AF_MODE: CameraMetadata.CONTROL_AF_MODE_AUTO,
- CaptureResult.CONTROL_AWB_MODE: CameraMetadata.CONTROL_AWB_MODE_AUTO,
- CaptureResult.CONTROL_MODE: CameraMetadata.CONTROL_MODE_AUTO,
- CaptureResult.FLASH_MODE: CameraMetadata.FLASH_MODE_OFF,
- CaptureResult.SENSOR_EXPOSURE_TIME: 33333333,
- CaptureResult.SENSOR_SENSITIVITY: 100,
- CaptureResult.SENSOR_TIMESTAMP: int(time.time() * 1e9),
- }
- self._request = request
- self._sequence_id = -1
- self._frame_number = -1
-
- def get(self, key: str) -> Any:
- return self._results.get(key)
-
- def keys(self) -> Set[str]:
- return set(self._results.keys())
-
- def getRequest(self) -> Optional[CaptureRequest]:
- return self._request
-
- def getSequenceId(self) -> int:
- return self._sequence_id
-
- def getFrameNumber(self) -> int:
- return self._frame_number
-
-
-# ═══════════════════════════════════════════════════════════════
-# TotalCaptureResult
-# ═══════════════════════════════════════════════════════════════
-
-class TotalCaptureResult(CaptureResult):
- """TotalCaptureResult — 完整捕获结果"""
-
- def __init__(self, request: CaptureRequest = None,
- partial_results: List[CaptureResult] = None):
- super().__init__(request)
- self._partial_results = partial_results or []
-
- def getPartialResults(self) -> List[CaptureResult]:
- return list(self._partial_results)
-
-
-# ═══════════════════════════════════════════════════════════════
-# CameraCaptureSession
-# ═══════════════════════════════════════════════════════════════
-
-class CameraCaptureSession(Stub):
- """CameraCaptureSession — 捕获会话"""
-
- class StateCallback(Stub):
- """CameraCaptureSession.StateCallback — 会话状态回调"""
-
- def onConfigured(self, session: "CameraCaptureSession"):
- pass
-
- def onConfigureFailed(self, session: "CameraCaptureSession"):
- pass
-
- def onReady(self, session: "CameraCaptureSession"):
- pass
-
- def onActive(self, session: "CameraCaptureSession"):
- pass
-
- def onClosed(self, session: "CameraCaptureSession"):
- pass
-
- def onSurfacePrepared(self, session: "CameraCaptureSession", surface):
- pass
-
- class CaptureCallback(Stub):
- """CameraCaptureSession.CaptureCallback — 捕获回调"""
-
- def onCaptureStarted(self, session: "CameraCaptureSession", request: CaptureRequest,
- timestamp: int, frameNumber: int):
- pass
-
- def onCaptureCompleted(self, session: "CameraCaptureSession", request: CaptureRequest,
- result: TotalCaptureResult):
- pass
-
- def onCaptureFailed(self, session: "CameraCaptureSession", request: CaptureRequest,
- failure):
- pass
-
- def onCaptureProgressed(self, session: "CameraCaptureSession", request: CaptureRequest,
- result: CaptureResult):
- pass
-
- def onCaptureSequenceCompleted(self, session: "CameraCaptureSession",
- sequenceId: int, frameNumber: int):
- pass
-
- def onCaptureSequenceAborted(self, session: "CameraCaptureSession", sequenceId: int):
- pass
-
- def onCaptureBufferLost(self, session: "CameraCaptureSession", request: CaptureRequest,
- target, frameNumber: int):
- pass
-
- def __init__(self, device: "CameraDevice"):
- super().__init__()
- self._device = device
- self._closed = False
- self._repeating_request = None
- self._state_callback = None
- self._session_id = int(time.time() * 1000)
-
- def capture(self, request: CaptureRequest, callback: CaptureCallback = None,
- handler=None) -> int:
- seq_id = int(time.time() * 1000)
- result = TotalCaptureResult(request)
- if callback:
- callback.onCaptureStarted(self, request, int(time.time() * 1e9), 0)
- callback.onCaptureCompleted(self, request, result)
- callback.onCaptureSequenceCompleted(self, seq_id, 0)
- return seq_id
-
- def setRepeatingRequest(self, request: CaptureRequest, callback: CaptureCallback = None,
- handler=None) -> int:
- self._repeating_request = request
- seq_id = int(time.time() * 1000)
- result = TotalCaptureResult(request)
- if callback:
- callback.onCaptureStarted(self, request, int(time.time() * 1e9), 0)
- callback.onCaptureCompleted(self, request, result)
- return seq_id
-
- def stopRepeatingRequest(self) -> None:
- self._repeating_request = None
-
- def abortCaptures(self) -> None:
- pass
-
- def close(self):
- self._closed = True
-
- def getDevice(self) -> "CameraDevice":
- return self._device
-
- def isClosed(self) -> bool:
- return self._closed
-
-
-# ═══════════════════════════════════════════════════════════════
-# CameraDevice
-# ═══════════════════════════════════════════════════════════════
-
-class CameraDevice(Stub):
- """CameraDevice — 相机设备"""
-
- STATE_OPENED = 0
- STATE_CLOSED = 3
- STATE_DISCONNECTED = 1
- STATE_ERROR = 2
-
- class StateCallback(Stub):
- """CameraDevice.StateCallback — 设备状态回调"""
-
- def onOpened(self, device: "CameraDevice"):
- pass
-
- def onClosed(self, device: "CameraDevice"):
- pass
-
- def onDisconnected(self, device: "CameraDevice"):
- pass
-
- def onError(self, device: "CameraDevice", error: int):
- pass
-
- def __init__(self, camera_id: str = "0"):
- super().__init__()
- self._id = camera_id
- self._state = CameraDevice.STATE_OPENED
- self._state_callback = None
- self._sessions: List[CameraCaptureSession] = []
-
- def getId(self) -> str:
- return self._id
-
- def createCaptureRequest(self, templateType: int) -> CaptureRequest.Builder:
- return CaptureRequest.Builder(self)
-
- def createCaptureSession(self, outputs: List[Any],
- callback: CameraCaptureSession.StateCallback,
- handler=None):
- session = CameraCaptureSession(self)
- session._state_callback = callback
- self._sessions.append(session)
- if callback:
- callback.onConfigured(session)
- return session
-
- def close(self):
- self._state = CameraDevice.STATE_CLOSED
- for session in self._sessions:
- session.close()
-
- def getState(self) -> int:
- return self._state
-
- def toString(self) -> str:
- return f"CameraDevice@{self._id}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CameraManager
-# ═══════════════════════════════════════════════════════════════
-
-class CameraManager(Stub):
- """CameraManager — 相机管理器"""
-
- def __init__(self):
- super().__init__()
- self._cameras: Dict[str, CameraCharacteristics] = {
- "0": CameraCharacteristics("0"),
- }
- self._open_devices: Dict[str, CameraDevice] = {}
- self._availability_callbacks: List[Any] = []
- self._torch_callbacks: List[Any] = []
-
- def getCameraIdList(self) -> List[str]:
- return list(self._cameras.keys())
-
- def getCameraCharacteristics(self, cameraId: str) -> CameraCharacteristics:
- if cameraId not in self._cameras:
- raise AndroidOnlyError(f"Camera {cameraId} not available")
- return self._cameras[cameraId]
-
- def openCamera(self, cameraId: str, callback: CameraDevice.StateCallback,
- handler=None):
- if cameraId not in self._cameras:
- if callback:
- callback.onError(None, CameraDevice.STATE_ERROR)
- return
- device = CameraDevice(cameraId)
- self._open_devices[cameraId] = device
- if callback:
- callback.onOpened(device)
-
- def registerAvailabilityCallback(self, callback):
- self._availability_callbacks.append(callback)
-
- def unregisterAvailabilityCallback(self, callback):
- if callback in self._availability_callbacks:
- self._availability_callbacks.remove(callback)
-
- def registerTorchCallback(self, callback, handler=None):
- self._torch_callbacks.append(callback)
-
- def unregisterTorchCallback(self, callback):
- if callback in self._torch_callbacks:
- self._torch_callbacks.remove(callback)
-
- def setTorchMode(self, cameraId: str, enabled: bool):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# CameraOfflineSession
-# ═══════════════════════════════════════════════════════════════
-
-class CameraOfflineSession(CameraCaptureSession):
- """CameraOfflineSession — 离线会话 (API 30+)"""
-
- def __init__(self, device: CameraDevice):
- super().__init__(device)
-
- def switchToOffline(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# CameraExtensionSession
-# ═══════════════════════════════════════════════════════════════
-
-class CameraExtensionSession(Stub):
- """CameraExtensionSession — 扩展会话 (API 31+)"""
-
- class StateCallback(Stub):
- def onConfigured(self, session: "CameraExtensionSession"):
- pass
-
- def onConfigureFailed(self, session: "CameraExtensionSession"):
- pass
-
- def onClosed(self, session: "CameraExtensionSession"):
- pass
-
- class ExtensionCaptureCallback(Stub):
- def onCaptureStarted(self, session: "CameraExtensionSession", request: CaptureRequest,
- timestamp: int):
- pass
-
- def onCaptureProcessStarted(self, session: "CameraExtensionSession", request: CaptureRequest):
- pass
-
- def onCaptureFailed(self, session: "CameraExtensionSession", request: CaptureRequest):
- pass
-
- def onCaptureResultAvailable(self, session: "CameraExtensionSession",
- request: CaptureRequest, result: TotalCaptureResult):
- pass
-
- def __init__(self):
- super().__init__()
- self._closed = False
-
- def close(self):
- self._closed = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "CameraManager", "CameraDevice", "CameraCaptureSession",
- "CaptureRequest", "CaptureResult", "CameraCharacteristics",
- "CameraMetadata", "CameraId", "CameraCharacteristicsKey",
- "TotalCaptureResult", "CameraOfflineSession", "CameraExtensionSession",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_camera2_params.py b/android_pyapi/android/hardware_camera2_params.py
deleted file mode 100644
index c3da2f8..0000000
--- a/android_pyapi/android/hardware_camera2_params.py
+++ /dev/null
@@ -1,854 +0,0 @@
-"""
-Android Hardware Camera2 Params 组件 — RggbChannelVector, BlackLevelPattern, StreamConfigurationMap 等
-方法签名完全对齐 Android SDK (android.hardware.camera2.params 包)
-"""
-
-from __future__ import annotations
-
-import math
-from typing import Any, Dict, List, Optional, Sequence, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# RggbChannelVector
-# ═══════════════════════════════════════════════════════════════
-
-class RggbChannelVector(Stub):
- """RggbChannelVector — RGGB 通道向量"""
-
- COUNT = 4
-
- def __init__(self, red: float, green_even: float, green_odd: float, blue: float):
- super().__init__()
- self._red = red
- self._green_even = green_even
- self._green_odd = green_odd
- self._blue = blue
-
- def getRed(self) -> float:
- return self._red
-
- def getGreenEven(self) -> float:
- return self._green_even
-
- def getGreenOdd(self) -> float:
- return self._green_odd
-
- def getBlue(self) -> float:
- return self._blue
-
- def getComponent(self, i: int) -> float:
- components = [self._red, self._green_even, self._green_odd, self._blue]
- return components[i]
-
- def toFloatArray(self) -> List[float]:
- return [self._red, self._green_even, self._green_odd, self._blue]
-
- def copyTo(self, destination: List[float], offset: int = 0):
- for i, v in enumerate([self._red, self._green_even, self._green_odd, self._blue]):
- destination[offset + i] = v
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, RggbChannelVector):
- return (abs(self._red - other._red) < 1e-6 and
- abs(self._green_even - other._green_even) < 1e-6 and
- abs(self._green_odd - other._green_odd) < 1e-6 and
- abs(self._blue - other._blue) < 1e-6)
- return False
-
- def hashCode(self) -> int:
- return hash((self._red, self._green_even, self._green_odd, self._blue)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"RggbChannelVector(R={self._red:.3f}, Ge={self._green_even:.3f}, Go={self._green_odd:.3f}, B={self._blue:.3f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BlackLevelPattern
-# ═══════════════════════════════════════════════════════════════
-
-class BlackLevelPattern(Stub):
- """BlackLevelPattern — 黑电平模式"""
-
- COUNT = 4
-
- def __init__(self, red: int = 0, green_even: int = 0,
- green_odd: int = 0, blue: int = 0):
- super().__init__()
- self._offsets = [red, green_even, green_odd, blue]
-
- def getOffsetForIndex(self, column: int, row: int) -> int:
- idx = (row % 2) * 2 + (column % 2)
- return self._offsets[idx]
-
- def copyTo(self, destination: List[int], offset: int = 0):
- for i, v in enumerate(self._offsets):
- destination[offset + i] = v
-
- def getRed(self) -> int:
- return self._offsets[0]
-
- def getGreenEven(self) -> int:
- return self._offsets[1]
-
- def getGreenOdd(self) -> int:
- return self._offsets[2]
-
- def getBlue(self) -> int:
- return self._offsets[3]
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, BlackLevelPattern):
- return self._offsets == other._offsets
- return False
-
- def hashCode(self) -> int:
- return hash(tuple(self._offsets)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"BlackLevelPattern(R={self._offsets[0]}, Ge={self._offsets[1]}, Go={self._offsets[2]}, B={self._offsets[3]})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ColorSpaceTransform
-# ═══════════════════════════════════════════════════════════════
-
-class ColorSpaceTransform(Stub):
- """ColorSpaceTransform — 色彩空间变换 (3x3 矩阵)"""
-
- COUNT = 9
- ELEMENTS_PER_ROW = 3
- ROWS = 3
- COLUMNS = 3
-
- def __init__(self, elements: Optional[List[Rational]] = None):
- super().__init__()
- if elements is not None and len(elements) == 9:
- self._elements = list(elements)
- else:
- self._elements = [Rational(1, 1) if i % 4 == 0 else Rational(0, 1) for i in range(9)]
-
- def getElement(self, column: int, row: int) -> Rational:
- return self._elements[row * 3 + column]
-
- def setElement(self, column: int, row: int, element: Rational):
- self._elements[row * 3 + column] = element
-
- def copyTo(self, destination: List[Rational], offset: int = 0):
- for i, v in enumerate(self._elements):
- destination[offset + i] = v
-
- def getElements(self) -> List[Rational]:
- return list(self._elements)
-
- def transform(self, r: float, g: float, b: float) -> Tuple[float, float, float]:
- e = self._elements
- r_out = e[0].toFloat() * r + e[1].toFloat() * g + e[2].toFloat() * b
- g_out = e[3].toFloat() * r + e[4].toFloat() * g + e[5].toFloat() * b
- b_out = e[6].toFloat() * r + e[7].toFloat() * g + e[8].toFloat() * b
- return (r_out, g_out, b_out)
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, ColorSpaceTransform):
- return all(abs(a.toFloat() - b.toFloat()) < 1e-6
- for a, b in zip(self._elements, other._elements))
- return False
-
- def hashCode(self) -> int:
- return hash(tuple(self._elements)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return (f"ColorSpaceTransform([{self._elements[0]}, {self._elements[1]}, {self._elements[2]},"
- f" {self._elements[3]}, {self._elements[4]}, {self._elements[5]},"
- f" {self._elements[6]}, {self._elements[7]}, {self._elements[8]}])")
-
-
-# ═══════════════════════════════════════════════════════════════
-# Rational
-# ═══════════════════════════════════════════════════════════════
-
-class Rational(Stub):
- """Rational — 有理数"""
-
- def __init__(self, numerator: int = 0, denominator: int = 1):
- super().__init__()
- if denominator < 0:
- numerator = -numerator
- denominator = -denominator
- gcd = math.gcd(abs(numerator), abs(denominator)) if denominator != 0 else 1
- self._numerator = numerator // gcd
- self._denominator = denominator // gcd
-
- def getNumerator(self) -> int:
- return self._numerator
-
- def getDenominator(self) -> int:
- return self._denominator
-
- def toFloat(self) -> float:
- if self._denominator == 0:
- return float('inf') if self._numerator >= 0 else float('-inf')
- return self._numerator / self._denominator
-
- def toDouble(self) -> float:
- return self.toFloat()
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, Rational):
- return (self._numerator * other._denominator ==
- other._numerator * self._denominator)
- return False
-
- def hashCode(self) -> int:
- return hash((self._numerator, self._denominator)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"{self._numerator}/{self._denominator}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# StreamConfigurationMap
-# ═══════════════════════════════════════════════════════════════
-
-class StreamConfigurationMap(Stub):
- """StreamConfigurationMap — 流配置映射"""
-
- def __init__(self):
- super().__init__()
- self._output_formats: Dict[int, List[Tuple[int, int]]] = {}
- self._input_formats: Dict[int, List[Tuple[int, int]]] = {}
- self._high_speed_video_sizes: Dict[int, List[Tuple[int, int]]] = {}
- self._output_min_frame_durations: Dict[Tuple[int, int, int], int] = {}
- self._output_stall_durations: Dict[Tuple[int, int, int], int] = {}
- self._input_min_frame_durations: Dict[Tuple[int, int, int], int] = {}
- self._input_stall_durations: Dict[Tuple[int, int, int], int] = {}
- self._mutable: bool = True
-
- def getOutputFormats(self) -> List[int]:
- return list(self._output_formats.keys())
-
- def getInputFormats(self) -> List[int]:
- return list(self._input_formats.keys())
-
- def getOutputSizes(self, format: int) -> List[Tuple[int, int]]:
- return list(self._output_formats.get(format, []))
-
- def getInputSizes(self, format: int) -> List[Tuple[int, int]]:
- return list(self._input_formats.get(format, []))
-
- def getHighSpeedVideoSizes(self) -> List[Tuple[int, int]]:
- result = set()
- for sizes in self._high_speed_video_sizes.values():
- result.update(sizes)
- return list(result)
-
- def getHighSpeedVideoFpsRangeFor(self, size: Tuple[int, int]) -> List[Tuple[int, int]]:
- return [(30, 30), (60, 60), (120, 120)]
-
- def getHighSpeedVideoFpsRanges(self) -> List[Tuple[int, int]]:
- return [(30, 30), (60, 60), (120, 120), (240, 240)]
-
- def getOutputMinFrameDuration(self, format: int, size: Tuple[int, int]) -> int:
- return self._output_min_frame_durations.get((format, size[0], size[1]), 33333333)
-
- def getOutputStallDuration(self, format: int, size: Tuple[int, int]) -> int:
- return self._output_stall_durations.get((format, size[0], size[1]), 0)
-
- def getInputMinFrameDuration(self, format: int, size: Tuple[int, int]) -> int:
- return self._input_min_frame_durations.get((format, size[0], size[1]), 33333333)
-
- def getInputStallDuration(self, format: int, size: Tuple[int, int]) -> int:
- return self._input_stall_durations.get((format, size[0], size[1]), 0)
-
- def isOutputSupportedFor(self, size: Tuple[int, int]) -> bool:
- for sizes in self._output_formats.values():
- if size in sizes:
- return True
- return False
-
- def isValid(self) -> bool:
- return len(self._output_formats) > 0
-
- def setMutable(self, mutable: bool):
- self._mutable = mutable
-
- def isMutable(self) -> bool:
- return self._mutable
-
- def addOutputFormat(self, format: int, sizes: List[Tuple[int, int]]):
- self._output_formats[format] = list(sizes)
-
- def addInputFormat(self, format: int, sizes: List[Tuple[int, int]]):
- self._input_formats[format] = list(sizes)
-
- def toString(self) -> str:
- return f"StreamConfigurationMap(outputFormats={len(self._output_formats)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TonemapCurve
-# ═══════════════════════════════════════════════════════════════
-
-class TonemapCurve(Stub):
- """TonemapCurve — 色调映射曲线"""
-
- LEVEL_BLACK = 0
- LEVEL_WHITE = 1
-
- CHANNEL_RED = 0
- CHANNEL_GREEN = 1
- CHANNEL_BLUE = 2
-
- POINT_SIZE = 2
-
- def __init__(self, red_curve: Optional[List[float]] = None,
- green_curve: Optional[List[float]] = None,
- blue_curve: Optional[List[float]] = None):
- super().__init__()
- self._curves = {
- TonemapCurve.CHANNEL_RED: list(red_curve or [0.0, 0.0, 1.0, 1.0]),
- TonemapCurve.CHANNEL_GREEN: list(green_curve or [0.0, 0.0, 1.0, 1.0]),
- TonemapCurve.CHANNEL_BLUE: list(blue_curve or [0.0, 0.0, 1.0, 1.0]),
- }
-
- def getPointCount(self, channel: int) -> int:
- return len(self._curves.get(channel, [])) // 2
-
- def getPoint(self, channel: int, index: int, out_point: List[float] = None) -> Tuple[float, float]:
- curve = self._curves.get(channel, [])
- if out_point is None:
- out_point = [0.0, 0.0]
- out_point[0] = curve[index * 2]
- out_point[1] = curve[index * 2 + 1]
- return (out_point[0], out_point[1])
-
- def setPoint(self, channel: int, index: int, x: float, y: float):
- curve = self._curves[channel]
- while len(curve) < (index * 2 + 2):
- curve.extend([0.0, 0.0])
- curve[index * 2] = x
- curve[index * 2 + 1] = y
-
- def getCurve(self, channel: int) -> Optional[List[float]]:
- return list(self._curves.get(channel, []))
-
- def estimateCurve(self, channel: int, x: float) -> float:
- curve = self._curves.get(channel, [])
- if not curve or len(curve) < 4:
- return x
- for i in range(0, len(curve) - 2, 2):
- x0, y0 = curve[i], curve[i + 1]
- x1, y1 = curve[i + 2], curve[i + 3]
- if x0 <= x <= x1 or (x1 <= x <= x0):
- if abs(x1 - x0) < 1e-10:
- return y0
- t = (x - x0) / (x1 - x0)
- return y0 + t * (y1 - y0)
- return curve[-1] if curve else x
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, TonemapCurve):
- return all(abs(self._curves[c][i] - other._curves[c][i]) < 1e-6
- for c in range(3) for i in range(len(self._curves[c])))
- return False
-
- def hashCode(self) -> int:
- return hash(tuple(tuple(v) for v in self._curves.values())) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"TonemapCurve(points={self.getPointCount(0)}, {self.getPointCount(1)}, {self.getPointCount(2)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LensShadingMap
-# ═══════════════════════════════════════════════════════════════
-
-class LensShadingMap(Stub):
- """LensShadingMap — 镜头阴影映射"""
-
- def __init__(self, columns: int = 1, rows: int = 1):
- super().__init__()
- self._columns = columns
- self._rows = rows
- self._gain_map: Dict[Tuple[int, int, int], float] = {}
-
- def getGainFactor(self, channel: int, column: int, row: int) -> float:
- return self._gain_map.get((channel, column, row), 1.0)
-
- def setGainFactor(self, channel: int, column: int, row: int, gain: float):
- self._gain_map[(channel, column, row)] = gain
-
- def getGainFactorVector(self, column: int, row: int) -> RggbChannelVector:
- r = self.getGainFactor(0, column, row)
- ge = self.getGainFactor(1, column, row)
- go = self.getGainFactor(2, column, row)
- b = self.getGainFactor(3, column, row)
- return RggbChannelVector(r, ge, go, b)
-
- def getColumnCount(self) -> int:
- return self._columns
-
- def getRowCount(self) -> int:
- return self._rows
-
- def copyGainFactors(self, destination: List[float], offset: int = 0):
- for (ch, col, row), gain in self._gain_map.items():
- idx = offset + (row * self._columns + col) * 4 + ch
- if idx < len(destination):
- destination[idx] = gain
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, LensShadingMap):
- return (self._columns == other._columns and self._rows == other._rows
- and self._gain_map == other._gain_map)
- return False
-
- def hashCode(self) -> int:
- return hash((self._columns, self._rows, tuple(sorted(self._gain_map.items())))) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"LensShadingMap({self._columns}x{self._rows})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MeteringRectangle
-# ═══════════════════════════════════════════════════════════════
-
-class MeteringRectangle(Stub):
- """MeteringRectangle — 测光矩形"""
-
- def __init__(self, x: int = 0, y: int = 0, width: int = 0,
- height: int = 0, metering_weight: int = 1):
- super().__init__()
- self._x = x
- self._y = y
- self._width = width
- self._height = height
- self._metering_weight = metering_weight
-
- def getX(self) -> int:
- return self._x
-
- def getY(self) -> int:
- return self._y
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getMeteringWeight(self) -> int:
- return self._metering_weight
-
- def getRect(self) -> Tuple[int, int, int, int]:
- return (self._x, self._y, self._x + self._width, self._y + self._height)
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, MeteringRectangle):
- return (self._x == other._x and self._y == other._y
- and self._width == other._width
- and self._height == other._height
- and self._metering_weight == other._metering_weight)
- return False
-
- def hashCode(self) -> int:
- return hash((self._x, self._y, self._width, self._height, self._metering_weight)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"MeteringRectangle({self._x},{self._y} {self._width}x{self._height} w={self._metering_weight})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# OutputConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class OutputConfiguration(Stub):
- """OutputConfiguration — 输出配置"""
-
- SURFACE_TYPE_UNKNOWN = -1
- SURFACE_TYPE_SURFACE_VIEW = 0
- SURFACE_TYPE_SURFACE_TEXTURE = 1
- SURFACE_TYPE_IMAGE_READER = 2
- SURFACE_TYPE_MEDIA_CODEC = 3
- SURFACE_TYPE_MEDIA_RECORDER = 4
-
- ROTATION_0 = 0
- ROTATION_90 = 1
- ROTATION_180 = 2
- ROTATION_270 = 3
-
- def __init__(self, surface: Any = None, surface_type: int = SURFACE_TYPE_UNKNOWN):
- super().__init__()
- self._surface = surface
- self._surface_type = surface_type
- self._rotation: int = OutputConfiguration.ROTATION_0
- self._width: int = 0
- self._height: int = 0
- self._format: int = 0
- self._is_deferred: bool = False
- self._physical_camera_id: str = ""
- self._surface_set: List[Any] = []
- self._shared_surfaces: List[Any] = []
- self._capture_stage: int = 0
-
- def getSurface(self) -> Any:
- return self._surface
-
- def setSurface(self, surface: Any):
- self._surface = surface
-
- def getSurfaceType(self) -> int:
- return self._surface_type
-
- def setSurfaceType(self, type_: int):
- self._surface_type = type_
-
- def getRotation(self) -> int:
- return self._rotation
-
- def setRotation(self, rotation: int):
- self._rotation = rotation
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getFormat(self) -> int:
- return self._format
-
- def setDimensions(self, width: int, height: int):
- self._width = width
- self._height = height
-
- def setFormat(self, format: int):
- self._format = format
-
- def isDeferred(self) -> bool:
- return self._is_deferred
-
- def setDeferred(self, deferred: bool):
- self._is_deferred = deferred
-
- def getPhysicalCameraId(self) -> str:
- return self._physical_camera_id
-
- def setPhysicalCameraId(self, camera_id: str):
- self._physical_camera_id = camera_id
-
- def addSurface(self, surface: Any):
- self._surface_set.append(surface)
-
- def removeSurface(self, surface: Any):
- self._surface_set = [s for s in self._surface_set if s is not surface]
-
- def getSurfaces(self) -> List[Any]:
- return list(self._surface_set)
-
- def toString(self) -> str:
- return f"OutputConfiguration({self._width}x{self._height}, rot={self._rotation})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SessionConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class SessionConfiguration(Stub):
- """SessionConfiguration — 会话配置"""
-
- SESSION_TYPE_REGULAR = 0
- SESSION_TYPE_VENDOR = 1
- SESSION_TYPE_HIGH_SPEED = 2
- SESSION_TYPE_LOW_LATENCY = 3
- SESSION_TYPE_OFFLINE_PROCESSING = 4
-
- def __init__(self, session_type: int = SESSION_TYPE_REGULAR,
- outputs: Optional[List[OutputConfiguration]] = None,
- callback: Any = None):
- super().__init__()
- self._session_type = session_type
- self._outputs = list(outputs or [])
- self._callback = callback
- self._input_config: Optional[OutputConfiguration] = None
- self._session_params: Any = None
- self._implementation: Any = None
- self._color_space: int = 0
- self._is_global_session: bool = False
-
- def getSessionType(self) -> int:
- return self._session_type
-
- def getOutputConfigurations(self) -> List[OutputConfiguration]:
- return list(self._outputs)
-
- def addOutputConfiguration(self, output: OutputConfiguration):
- self._outputs.append(output)
-
- def removeOutputConfiguration(self, output: OutputConfiguration):
- self._outputs = [o for o in self._outputs if o is not output]
-
- def setInputConfiguration(self, input_config: OutputConfiguration):
- self._input_config = input_config
-
- def getInputConfiguration(self) -> Optional[OutputConfiguration]:
- return self._input_config
-
- def setSessionParameters(self, params: Any):
- self._session_params = params
-
- def getSessionParameters(self) -> Any:
- return self._session_params
-
- def setColorSpace(self, color_space: int):
- self._color_space = color_space
-
- def getColorSpace(self) -> int:
- return self._color_space
-
- def getCallback(self) -> Any:
- return self._callback
-
- def toString(self) -> str:
- return f"SessionConfiguration(type={self._session_type}, outputs={len(self._outputs)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MultiResolutionStreamConfigurationMap
-# ═══════════════════════════════════════════════════════════════
-
-class MultiResolutionStreamConfigurationMap(Stub):
- """MultiResolutionStreamConfigurationMap — 多分辨率流配置映射"""
-
- def __init__(self):
- super().__init__()
- self._configs: Dict[int, List[OutputConfiguration]] = {}
-
- def getOutputConfigurations(self, format: int) -> List[OutputConfiguration]:
- return list(self._configs.get(format, []))
-
- def getFormats(self) -> List[int]:
- return list(self._configs.keys())
-
- def addConfiguration(self, format: int, config: OutputConfiguration):
- if format not in self._configs:
- self._configs[format] = []
- self._configs[format].append(config)
-
- def removeConfiguration(self, format: int, config: OutputConfiguration):
- if format in self._configs:
- self._configs[format] = [c for c in self._configs[format] if c is not config]
-
- def getMaxResolution(self, format: int) -> Optional[OutputConfiguration]:
- configs = self._configs.get(format, [])
- if not configs:
- return None
- return max(configs, key=lambda c: c.getWidth() * c.getHeight())
-
- def toString(self) -> str:
- return f"MultiResolutionStreamConfigurationMap(formats={len(self._configs)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# OisSample
-# ═══════════════════════════════════════════════════════════════
-
-class OisSample(Stub):
- """OisSample — OIS 样本数据"""
-
- def __init__(self, timestamp_ns: int = 0, x_shift: float = 0.0, y_shift: float = 0.0):
- super().__init__()
- self._timestamp_ns = timestamp_ns
- self._x_shift = x_shift
- self._y_shift = y_shift
-
- def getTimestampNanos(self) -> int:
- return self._timestamp_ns
-
- def getXshift(self) -> float:
- return self._x_shift
-
- def getYshift(self) -> float:
- return self._y_shift
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, OisSample):
- return (self._timestamp_ns == other._timestamp_ns
- and abs(self._x_shift - other._x_shift) < 1e-6
- and abs(self._y_shift - other._y_shift) < 1e-6)
- return False
-
- def hashCode(self) -> int:
- return hash((self._timestamp_ns, self._x_shift, self._y_shift)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"OisSample(ts={self._timestamp_ns}, x={self._x_shift:.3f}, y={self._y_shift:.3f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RecommendedStreamConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class RecommendedStreamConfiguration(Stub):
- """RecommendedStreamConfiguration — 推荐流配置"""
-
- USECASE_PREVIEW = 0
- USECASE_RECORD = 1
- USECASE_STILL_CAPTURE = 2
- USECASE_VIDEO_SNAPSHOT = 3
- USECASE_ZSL = 4
- USECASE_RAW = 5
- USECASE_LOW_LATENCY_SNAPSHOT = 6
- USECASE_10BIT_OUTPUT = 7
- USECASE_ANALYSIS = 8
- USECASE_CUSTOM = 9
- USECASE_VENDOR_START = 0x1000
-
- def __init__(self, width: int = 0, height: int = 0, format: int = 0,
- input_output: bool = False, usecase: int = USECASE_PREVIEW):
- super().__init__()
- self._width = width
- self._height = height
- self._format = format
- self._input_output = input_output
- self._usecase = usecase
- self._fps_range: Tuple[int, int] = (30, 30)
- self._is_high_speed: bool = False
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getFormat(self) -> int:
- return self._format
-
- def isInput(self) -> bool:
- return self._input_output
-
- def isOutput(self) -> bool:
- return not self._input_output
-
- def getUsecase(self) -> int:
- return self._usecase
-
- def getFpsRange(self) -> Tuple[int, int]:
- return self._fps_range
-
- def setFpsRange(self, min_fps: int, max_fps: int):
- self._fps_range = (min_fps, max_fps)
-
- def isHighSpeed(self) -> bool:
- return self._is_high_speed
-
- def setHighSpeed(self, high_speed: bool):
- self._is_high_speed = high_speed
-
- def toString(self) -> str:
- return f"RecommendedStreamConfiguration({self._width}x{self._height}, fmt={self._format})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RecommendedStreamConfigurationMap
-# ═══════════════════════════════════════════════════════════════
-
-class RecommendedStreamConfigurationMap(Stub):
- """RecommendedStreamConfigurationMap — 推荐流配置映射"""
-
- def __init__(self):
- super().__init__()
- self._recommendations: Dict[int, List[RecommendedStreamConfiguration]] = {}
- self._max_resolutions: Dict[int, Tuple[int, int]] = {}
-
- def getRecommendedStreamConfigurations(self, usecase: int) -> List[RecommendedStreamConfiguration]:
- return list(self._recommendations.get(usecase, []))
-
- def getAllUsecases(self) -> List[int]:
- return list(self._recommendations.keys())
-
- def addRecommendation(self, usecase: int, config: RecommendedStreamConfiguration):
- if usecase not in self._recommendations:
- self._recommendations[usecase] = []
- self._recommendations[usecase].append(config)
-
- def removeRecommendation(self, usecase: int, config: RecommendedStreamConfiguration):
- if usecase in self._recommendations:
- self._recommendations[usecase] = [
- c for c in self._recommendations[usecase] if c is not config
- ]
-
- def getMaxResolution(self, usecase: int) -> Optional[Tuple[int, int]]:
- return self._max_resolutions.get(usecase)
-
- def setMaxResolution(self, usecase: int, width: int, height: int):
- self._max_resolutions[usecase] = (width, height)
-
- def toString(self) -> str:
- return f"RecommendedStreamConfigurationMap(usecases={len(self._recommendations)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TotalCaptureResultExt — TotalCaptureResult 的扩展
-# ═══════════════════════════════════════════════════════════════
-
-class TotalCaptureResultExt(Stub):
- """TotalCaptureResultExt — TotalCaptureResult 的 params 扩展"""
-
- def __init__(self):
- super().__init__()
- self._results: Dict[str, Any] = {}
- self._partial_results: List[Any] = []
- self._session_id: int = 0
- self._frame_number: int = 0
- self._sequence_id: int = 0
- self._af_trigger_id: int = 0
- self._ae_trigger_id: int = 0
- self._sensor_timestamp: int = 0
- self._physical_camera_results: Dict[str, Any] = {}
-
- def getResult(self, key: str) -> Optional[Any]:
- return self._results.get(key)
-
- def setResult(self, key: str, value: Any):
- self._results[key] = value
-
- def getAllResults(self) -> Dict[str, Any]:
- return dict(self._results)
-
- def getPartialResults(self) -> List[Any]:
- return list(self._partial_results)
-
- def addPartialResult(self, result: Any):
- self._partial_results.append(result)
-
- def getSessionId(self) -> int:
- return self._session_id
-
- def setSessionId(self, session_id: int):
- self._session_id = session_id
-
- def getFrameNumber(self) -> int:
- return self._frame_number
-
- def setFrameNumber(self, frame: int):
- self._frame_number = frame
-
- def getSequenceId(self) -> int:
- return self._sequence_id
-
- def setSequenceId(self, seq: int):
- self._sequence_id = seq
-
- def getPhysicalCameraResult(self, camera_id: str) -> Optional[Any]:
- return self._physical_camera_results.get(camera_id)
-
- def setPhysicalCameraResult(self, camera_id: str, result: Any):
- self._physical_camera_results[camera_id] = result
-
- def toString(self) -> str:
- return f"TotalCaptureResultExt(frame={self._frame_number}, seq={self._sequence_id})"
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_consumerir.py b/android_pyapi/android/hardware_consumerir.py
deleted file mode 100644
index 68ceaae..0000000
--- a/android_pyapi/android/hardware_consumerir.py
+++ /dev/null
@@ -1,93 +0,0 @@
-"""
-Android hardware.consumerir 组件 — ConsumerIrManager, CarrierFrequencyRange 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import threading
-from typing import Any, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# ConsumerIrManager
-# ═══════════════════════════════════════════════════════════════
-
-class ConsumerIrManager(Stub):
- """ConsumerIrManager — 红外遥控管理器"""
-
- def __init__(self):
- super().__init__()
- self._has_emitter: bool = False
- self._carrier_frequencies: List[ConsumerIrManager.CarrierFrequencyRange] = [
- ConsumerIrManager.CarrierFrequencyRange(30000, 60000),
- ]
- self._learned_ir: Optional[List[int]] = None
-
- class CarrierFrequencyRange(Stub):
- """ConsumerIrManager.CarrierFrequencyRange — 载波频率范围"""
-
- def __init__(self, min_freq: int, max_freq: int):
- super().__init__()
- self._min_frequency = min_freq
- self._max_frequency = max_freq
-
- def getMinFrequency(self) -> int:
- return self._min_frequency
-
- def getMaxFrequency(self) -> int:
- return self._max_frequency
-
- def toString(self) -> str:
- return f"CarrierFrequencyRange{{min={self._min_frequency}, max={self._max_frequency}}}"
-
- def hashCode(self) -> int:
- return hash((self._min_frequency, self._max_frequency)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, ConsumerIrManager.CarrierFrequencyRange):
- return False
- return (self._min_frequency == other._min_frequency and
- self._max_frequency == other._max_frequency)
-
- # ── Main methods ──
-
- def hasIrEmitter(self) -> bool:
- return self._has_emitter
-
- def transmit(self, carrierFrequency: int, pattern: List[int]):
- if not self._has_emitter:
- raise AndroidOnlyError("No IR emitter available on this device")
- self._last_pattern = (carrierFrequency, pattern)
-
- def getCarrierFrequencyRange(self) -> List[CarrierFrequencyRange]:
- return list(self._carrier_frequencies)
-
- # ── Learning (stub) ──
-
- def isLearnedIR(self) -> bool:
- return self._learned_ir is not None
-
- def learnIR(self, timeout: int) -> Optional[List[int]]:
- self._learned_ir = [9000, 4500, 560, 560, 560, 560, 560, 1690]
- return self._learned_ir
-
- def cancelLearning(self):
- self._learned_ir = None
-
- def toString(self) -> str:
- return f"ConsumerIrManager{{hasEmitter={self._has_emitter}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "ConsumerIrManager",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_display.py b/android_pyapi/android/hardware_display.py
deleted file mode 100644
index d199a51..0000000
--- a/android_pyapi/android/hardware_display.py
+++ /dev/null
@@ -1,299 +0,0 @@
-"""
-Android hardware.display 组件 — DisplayManager, VirtualDisplay, WifiDisplay 等
-方法签名完全对齐 Android SDK
-"""
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# DisplayManager
-# ═══════════════════════════════════════════════════════════════
-
-class DisplayManager(Stub):
- """DisplayManager — 显示管理器"""
-
- VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1
- VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 4
- VIRTUAL_DISPLAY_FLAG_PUBLIC_DISPLAY = 8
- VIRTUAL_DISPLAY_FLAG_PRESENTATION = 2
- VIRTUAL_DISPLAY_FLAG_SECURE = 16
- VIRTUAL_DISPLAY_FLAG_SUPPORTS_HDR = 32
-
- MATCH_DEFAULT_DISPLAY = -1
- MATCH_ALL_DISPLAYS = 0
-
- # ═══════════════════════════════════════════════════════════
- # DisplayListener
- # ═══════════════════════════════════════════════════════════
-
- class DisplayListener(Stub):
- """DisplayManager.DisplayListener — 显示监听器"""
-
- def onDisplayAdded(self, displayId: int):
- pass
-
- def onDisplayRemoved(self, displayId: int):
- pass
-
- def onDisplayChanged(self, displayId: int):
- pass
-
- def __init__(self):
- super().__init__()
- self._displays: Dict[int, Display] = {}
- self._listeners: Dict[int, DisplayManager.DisplayListener] = {}
- self._next_display_id = 1
- # Create default display
- self._displays[0] = Display(0, "Built-in Display")
-
- def getDisplay(self, displayId: int) -> Optional["Display"]:
- return self._displays.get(displayId)
-
- def getDisplays(self) -> List["Display"]:
- if DisplayManager.MATCH_ALL_DISPLAYS:
- return list(self._displays.values())
- return []
-
- def registerDisplayListener(self, listener: DisplayListener, handler: Any = None):
- lid = id(listener)
- self._listeners[lid] = listener
-
- def unregisterDisplayListener(self, listener: DisplayListener):
- lid = id(listener)
- self._listeners.pop(lid, None)
-
- def createVirtualDisplay(self, name: str, width: int, height: int, densityDpi: int,
- surface: Any, flags: int, callback: Callable = None,
- handler: Any = None) -> "VirtualDisplay":
- display_id = self._next_display_id
- self._next_display_id += 1
- vd = VirtualDisplay(display_id, name, width, height, densityDpi, surface, flags)
- return vd
-
- def getStableDisplay(self) -> Optional["Display"]:
- return self._displays.get(0)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Display
-# ═══════════════════════════════════════════════════════════════
-
-class Display(Stub):
- """Display — 显示信息"""
-
- DEFAULT_DISPLAY = 0
-
- STATE_UNKNOWN = 0
- STATE_OFF = 1
- STATE_ON = 2
- STATE_DOZE = 3
- STATE_DOZE_SUSPEND = 4
-
- FLAG_PRESENTATION = 2
- FLAG_PRIVATE = 4
- FLAG_ROUND = 8
- FLAG_CAN_SHOW_WITH_INSETS = 16
- FLAG_SECURE = 32
- FLAG_SUPPORTS_HDR = 64
-
- def __init__(self, displayId: int = 0, name: str = "Display",
- width: int = 1920, height: int = 1080,
- densityDpi: int = 420, refreshRate: float = 60.0):
- super().__init__()
- self._display_id = displayId
- self._name = name
- self._width = width
- self._height = height
- self._density_dpi = densityDpi
- self._refresh_rate = refreshRate
- self._state = Display.STATE_ON
- self._flags = 0
- self._app_width = width
- self._app_height = height
-
- def getDisplayId(self) -> int:
- return self._display_id
-
- def getName(self) -> str:
- return self._name
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getRotation(self) -> int:
- return 0
-
- def getState(self) -> int:
- return self._state
-
- def getRefreshRate(self) -> float:
- return self._refresh_rate
-
- def isHdr(self) -> bool:
- return bool(self._flags & Display.FLAG_SUPPORTS_HDR)
-
- def getFlags(self) -> int:
- return self._flags
-
- def getMode(self) -> Any:
- return None
-
- def getSupportedModes(self) -> List[Any]:
- return []
-
- def getSupportedHdrTypes(self) -> List[int]:
- return []
-
- def getAppWidth(self) -> int:
- return self._app_width
-
- def getAppHeight(self) -> int:
- return self._app_height
-
- def getDensityDpi(self) -> int:
- return self._density_dpi
-
- def toString(self) -> str:
- return f"Display(id={self._display_id}, name={self._name}, {self._width}x{self._height}," \
- f" dpi={self._density_dpi})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# VirtualDisplay
-# ═══════════════════════════════════════════════════════════════
-
-class VirtualDisplay(Stub):
- """VirtualDisplay — 虚拟显示"""
-
- def __init__(self, displayId: int, name: str, width: int, height: int,
- densityDpi: int, surface: Any, flags: int):
- super().__init__()
- self._display_id = displayId
- self._name = name
- self._width = width
- self._height = height
- self._density_dpi = densityDpi
- self._surface = surface
- self._flags = flags
- self._display = Display(displayId, name, width, height, densityDpi)
- self._released = False
-
- def setSurface(self, surface: Any):
- self._surface = surface
-
- def resize(self, width: int, height: int, densityDpi: int):
- self._width = width
- self._height = height
- self._density_dpi = densityDpi
-
- def release(self):
- self._released = True
-
- def getDisplay(self) -> Display:
- return self._display
-
- def getSurface(self) -> Any:
- return self._surface
-
- def getFlags(self) -> int:
- return self._flags
-
- def toString(self) -> str:
- return f"VirtualDisplay(id={self._display_id}, name={self._name}," \
- f" {self._width}x{self._height}, released={self._released})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiDisplayStatus
-# ═══════════════════════════════════════════════════════════════
-
-class WifiDisplayStatus(Stub):
- """WifiDisplayStatus — Wi-Fi 显示状态"""
-
- FEATURE_STATE_DISABLED = 0
- FEATURE_STATE_ON = 1
- FEATURE_STATE_OFF = 2
- FEATURE_STATE_UNAVAILABLE = 3
-
- def __init__(self):
- super().__init__()
- self._active_display: Optional[WifiDisplay] = None
- self._scan_results: List[WifiDisplay] = []
- self._feature_state = WifiDisplayStatus.FEATURE_STATE_DISABLED
-
- def getActiveDisplay(self) -> Optional["WifiDisplay"]:
- return self._active_display
-
- def getScanResults(self) -> List["WifiDisplay"]:
- return self._scan_results
-
- def getFeatureState(self) -> int:
- return self._feature_state
-
- def toString(self) -> str:
- return f"WifiDisplayStatus(featureState={self._feature_state})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiDisplay
-# ═══════════════════════════════════════════════════════════════
-
-class WifiDisplay(Stub):
- """WifiDisplay — Wi-Fi 显示设备"""
-
- def __init__(self, deviceAddress: str = "", deviceName: str = "",
- deviceAlias: str = "", available: bool = False,
- remembered: bool = False):
- super().__init__()
- self._device_address = deviceAddress
- self._device_name = deviceName
- self._device_alias = deviceAlias
- self._available = available
- self._remembered = remembered
-
- def getDeviceAddress(self) -> str:
- return self._device_address
-
- def getDeviceName(self) -> str:
- return self._device_name
-
- def getDeviceAlias(self) -> str:
- return self._device_alias
-
- def isAvailable(self) -> bool:
- return self._available
-
- def isRemembered(self) -> bool:
- return self._remembered
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, WifiDisplay):
- return False
- return self._device_address == other._device_address
-
- def hashCode(self) -> int:
- return hash(self._device_address) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"WifiDisplay(address={self._device_address}, name={self._device_name}," \
- f" available={self._available})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "DisplayManager",
- "Display",
- "VirtualDisplay",
- "WifiDisplayStatus",
- "WifiDisplay",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_fingerprint.py b/android_pyapi/android/hardware_fingerprint.py
deleted file mode 100644
index b3fb524..0000000
--- a/android_pyapi/android/hardware_fingerprint.py
+++ /dev/null
@@ -1,179 +0,0 @@
-"""
-Android hardware.fingerprint 组件 — FingerprintManager, Fingerprint 等
-方法签名完全对齐 Android SDK
-"""
-
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# FingerprintManager
-# ═══════════════════════════════════════════════════════════════
-
-class FingerprintManager(Stub):
- """FingerprintManager — 指纹管理器"""
-
- FINGERPRINT_ACQUIRED_GOOD = 0
- FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3
- FINGERPRINT_ACQUIRED_INSUFFICIENT = 2
- FINGERPRINT_ACQUIRED_PARTIAL = 1
- FINGERPRINT_ACQUIRED_TOO_FAST = 5
- FINGERPRINT_ACQUIRED_TOO_SLOW = 4
-
- FINGERPRINT_ERROR_HW_UNAVAILABLE = 1
- FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2
- FINGERPRINT_ERROR_TIMEOUT = 3
- FINGERPRINT_ERROR_NO_SPACE = 4
- FINGERPRINT_ERROR_CANCELED = 5
- FINGERPRINT_ERROR_LOCKOUT = 7
- FINGERPRINT_ERROR_VENDOR = 8
- FINGERPRINT_ERROR_USER_CANCELED = 10
- FINGERPRINT_ERROR_BAD_CALIBRATION = 11
- FINGERPRINT_ERROR_POWER_PRESS = 12
- FINGERPRINT_ERROR_IDLE_NOT_ENROLLED = 13
-
- # ═══════════════════════════════════════════════════════════
- # AuthenticationCallback
- # ═══════════════════════════════════════════════════════════
-
- class AuthenticationCallback(Stub):
- """FingerprintManager.AuthenticationCallback — 认证回调"""
-
- def onAuthenticationError(self, errorCode: int, errString: str):
- pass
-
- def onAuthenticationHelp(self, helpCode: int, helpString: str):
- pass
-
- def onAuthenticationSucceeded(self, result: "FingerprintManager.AuthenticationResult"):
- pass
-
- def onAuthenticationFailed(self):
- pass
-
- def onAuthenticationAcquired(self, acquireInfo: int):
- pass
-
- # ═══════════════════════════════════════════════════════════
- # AuthenticationResult
- # ═══════════════════════════════════════════════════════════
-
- class AuthenticationResult(Stub):
- """FingerprintManager.AuthenticationResult — 认证结果"""
-
- def __init__(self, fingerprint: "Fingerprint" = None,
- cryptoObject: "FingerprintManager.CryptoObject" = None):
- super().__init__()
- self._fingerprint = fingerprint
- self._crypto_object = cryptoObject
-
- def getFingerprint(self) -> Optional["Fingerprint"]:
- return self._fingerprint
-
- def getCryptoObject(self) -> Optional["FingerprintManager.CryptoObject"]:
- return self._crypto_object
-
- # ═══════════════════════════════════════════════════════════
- # CryptoObject
- # ═══════════════════════════════════════════════════════════
-
- class CryptoObject(Stub):
- """FingerprintManager.CryptoObject — 加密对象"""
-
- def __init__(self, cipher: Any = None, signature: Any = None, mac: Any = None):
- super().__init__()
- self._cipher = cipher
- self._signature = signature
- self._mac = mac
-
- def getCipher(self) -> Any:
- return self._cipher
-
- def getSignature(self) -> Any:
- return self._signature
-
- def getMac(self) -> Any:
- return self._mac
-
- def __init__(self):
- super().__init__()
- self._enrolled_fingerprints: List[Fingerprint] = []
- self._callbacks: Dict[int, FingerprintManager.AuthenticationCallback] = {}
-
- def isHardwareDetected(self) -> bool:
- return False
-
- def hasEnrolledFingerprints(self) -> bool:
- return len(self._enrolled_fingerprints) > 0
-
- def authenticate(self, crypto: Optional[CryptoObject] = None,
- cancel: Any = None, flags: int = 0,
- callback: Optional[AuthenticationCallback] = None,
- handler: Any = None):
- if callback:
- callback.onAuthenticationError(
- FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
- "Fingerprint hardware not available on desktop"
- )
-
- def enroll(self, token: Any, userId: int = 0,
- callback: Optional[AuthenticationCallback] = None):
- raise AndroidOnlyError("FingerprintManager.enroll() is not available on desktop")
-
- def remove(self, fingerprint: "Fingerprint", userId: int = 0):
- if fingerprint in self._enrolled_fingerprints:
- self._enrolled_fingerprints.remove(fingerprint)
-
- def rename(self, fingerprint: "Fingerprint", newName: str):
- if fingerprint:
- fingerprint._name = newName
-
- def getEnrolledFingerprints(self) -> List["Fingerprint"]:
- return list(self._enrolled_fingerprints)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Fingerprint
-# ═══════════════════════════════════════════════════════════════
-
-class Fingerprint(Stub):
- """Fingerprint — 指纹数据"""
-
- def __init__(self, name: str = "", fingerId: int = 0, groupId: int = 0,
- deviceId: int = 0):
- super().__init__()
- self._name = name
- self._finger_id = fingerId
- self._group_id = groupId
- self._device_id = deviceId
-
- def getName(self) -> str:
- return self._name
-
- def getFingerId(self) -> int:
- return self._finger_id
-
- def getGroupId(self) -> int:
- return self._group_id
-
- def getDeviceId(self) -> int:
- return self._device_id
-
- def toString(self) -> str:
- return f"Fingerprint(name={self._name}, fingerId={self._finger_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "FingerprintManager",
- "Fingerprint",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_hdmi.py b/android_pyapi/android/hardware_hdmi.py
deleted file mode 100644
index 343fc63..0000000
--- a/android_pyapi/android/hardware_hdmi.py
+++ /dev/null
@@ -1,775 +0,0 @@
-"""
-Android HDMI API — HdmiControlManager, HdmiDeviceInfo, HdmiPortInfo, etc.
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import time
-import uuid
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# DEVICE_* 常量
-DEVICE_TYPE_TV = 0
-DEVICE_TYPE_RECORDER = 1
-DEVICE_TYPE_TUNER = 2
-DEVICE_TYPE_PLAYBACK = 3
-DEVICE_TYPE_AUDIO_SYSTEM = 4
-DEVICE_TYPE_PURE_CEC_SWITCH = 5
-DEVICE_TYPE_VIDEO_PROCESSOR = 6
-DEVICE_TYPE_RESERVED = 7
-DEVICE_TYPE_INACTIVE = 15
-DEVICE_TYPE_CEC_AUTO = 16
-
-# CONTROL_* 常量
-CONTROL_STATE_CHANGED_REASON_UNKNOWN = 0
-CONTROL_STATE_CHANGED_REASON_ENABLED = 1
-CONTROL_STATE_CHANGED_REASON_DISABLED = 2
-CONTROL_STATE_CHANGED_REASON_WAKE_UP = 3
-CONTROL_STATE_CHANGED_REASON_SLEEP = 4
-CONTROL_STATE_CHANGED_REASON_STANDBY = 5
-CONTROL_STATE_CHANGED_REASON_HDMI_CEC_ENABLED = 6
-CONTROL_STATE_CHANGED_REASON_HDMI_CEC_DISABLED = 7
-CONTROL_STATE_CHANGED_REASON_HDMI_MHL_ENABLED = 8
-CONTROL_STATE_CHANGED_REASON_HDMI_MHL_DISABLED = 9
-CONTROL_STATE_CHANGED_REASON_INVALID = -1
-
-# CEC_* 常量
-CEC_VERSION_1_1 = 0x11
-CEC_VERSION_1_2 = 0x12
-CEC_VERSION_1_3 = 0x13
-CEC_VERSION_1_4 = 0x14
-CEC_VERSION_2_0 = 0x20
-CEC_VERSION_UNKNOWN = 0x00
-
-# POWER_STATUS 常量
-POWER_STATUS_ON = 0
-POWER_STATUS_STANDBY = 1
-POWER_STATUS_TO_ON = 2
-POWER_STATUS_TO_STANDBY = 3
-POWER_STATUS_UNKNOWN = -1
-
-# PORT_TYPE 常量
-PORT_TYPE_INPUT = 0
-PORT_TYPE_OUTPUT = 1
-PORT_TYPE_BIDIRECTIONAL = 2
-PORT_TYPE_ARC = 3
-PORT_TYPE_EARC = 4
-
-# RESULT 常量
-RESULT_SUCCESS = 0
-RESULT_FAILURE = -1
-RESULT_TIMEOUT = -2
-RESULT_NOT_SUPPORTED = -3
-RESULT_BUSY = -4
-RESULT_ALREADY_IN_PROGRESS = -5
-
-# CEC_MESSAGE_TYPE 常量
-CEC_MESSAGE_TYPE_FEATURE_ABORT = 0x00
-CEC_MESSAGE_TYPE_ACTIVE_SOURCE = 0x82
-CEC_MESSAGE_TYPE_IMAGE_VIEW_ON = 0x04
-CEC_MESSAGE_TYPE_TEXT_VIEW_ON = 0x0D
-CEC_MESSAGE_TYPE_INACTIVE_SOURCE = 0x9D
-CEC_MESSAGE_TYPE_REQUEST_ACTIVE_SOURCE = 0x85
-CEC_MESSAGE_TYPE_STANDBY = 0x36
-CEC_MESSAGE_TYPE_SET_MENU_LANGUAGE = 0x32
-CEC_MESSAGE_TYPE_USER_CONTROL_PRESSED = 0x44
-CEC_MESSAGE_TYPE_USER_CONTROL_RELEASED = 0x45
-CEC_MESSAGE_TYPE_GIVE_PHYSICAL_ADDRESS = 0x83
-CEC_MESSAGE_TYPE_REPORT_PHYSICAL_ADDRESS = 0x84
-CEC_MESSAGE_TYPE_GIVE_DEVICE_VENDOR_ID = 0x8C
-CEC_MESSAGE_TYPE_DEVICE_VENDOR_ID = 0x87
-CEC_MESSAGE_TYPE_GIVE_OSD_NAME = 0x46
-CEC_MESSAGE_TYPE_SET_OSD_NAME = 0x47
-CEC_MESSAGE_TYPE_GIVE_FEATURES = 0x88
-CEC_MESSAGE_TYPE_REPORT_FEATURES = 0x89
-CEC_MESSAGE_TYPE_VENDOR_COMMAND = 0x89
-CEC_MESSAGE_TYPE_VENDOR_REMOTE_BUTTON_DOWN = 0x8A
-CEC_MESSAGE_TYPE_VENDOR_REMOTE_BUTTON_UP = 0x8B
-
-# HDMI_RECORD_SOURCE 常量
-RECORD_SOURCE_OWN_SOURCE = 1
-RECORD_SOURCE_DIGITAL_SERVICE = 2
-RECORD_SOURCE_ANALOGUE_SERVICE = 3
-RECORD_SOURCE_EXTERNAL_PHYSICAL_ADDRESS = 4
-RECORD_SOURCE_EXTERNAL_PLUG = 5
-RECORD_SOURCE_PROGRAM_NUMBER = 6
-
-
-# ═══════════════════════════════════════════════════════════════
-# HdmiDeviceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class HdmiDeviceInfo(Stub):
- """HdmiDeviceInfo — HDMI 设备信息"""
-
- def __init__(
- self,
- logicalAddress: int = -1,
- physicalAddress: int = 0xFFFF,
- portId: int = -1,
- deviceType: int = DEVICE_TYPE_INACTIVE,
- vendorId: int = 0,
- displayName: str = "",
- ):
- super().__init__()
- self._logical_address = logicalAddress
- self._physical_address = physicalAddress
- self._port_id = portId
- self._device_type = deviceType
- self._vendor_id = vendorId
- self._display_name = displayName
- self._device_id = str(uuid.uuid4())
- self._osd_name: Optional[str] = None
- self._cec_version = CEC_VERSION_2_0
- self._power_status = POWER_STATUS_ON
- self._is_cec_device = True
- self._is_mhl_device = False
- self._is_arc_supported = False
- self._is_earc_supported = False
- self._is_audio_return_channel = False
- self._physical_address_str: Optional[str] = None
- self._adopter_id = 0
- self._logical_addresses: List[int] = []
- self._supports_cec = True
- self._vendor_name: Optional[str] = None
- self._menu_language: Optional[str] = None
- self._features: List[int] = []
- self._is_active_source = False
- self._discovery_time = time.time()
-
- def getLogicalAddress(self) -> int:
- return self._logical_address
-
- def getPhysicalAddress(self) -> int:
- return self._physical_address
-
- def getPhysicalAddressString(self) -> str:
- if self._physical_address_str:
- return self._physical_address_str
- pa = self._physical_address
- return f"{(pa >> 12) & 0xF}.{(pa >> 8) & 0xF}.{(pa >> 4) & 0xF}.{pa & 0xF}"
-
- def getPortId(self) -> int:
- return self._port_id
-
- def getDeviceType(self) -> int:
- return self._device_type
-
- def getDeviceTypeString(self) -> str:
- type_names = {
- DEVICE_TYPE_TV: "TV",
- DEVICE_TYPE_RECORDER: "Recorder",
- DEVICE_TYPE_TUNER: "Tuner",
- DEVICE_TYPE_PLAYBACK: "Playback",
- DEVICE_TYPE_AUDIO_SYSTEM: "AudioSystem",
- DEVICE_TYPE_PURE_CEC_SWITCH: "Switch",
- DEVICE_TYPE_VIDEO_PROCESSOR: "VideoProcessor",
- DEVICE_TYPE_INACTIVE: "Inactive",
- }
- return type_names.get(self._device_type, "Unknown")
-
- def getVendorId(self) -> int:
- return self._vendor_id
-
- def getDisplayName(self) -> str:
- return self._display_name
-
- def getOsdName(self) -> Optional[str]:
- return self._osd_name
-
- def setOsdName(self, name: str) -> None:
- self._osd_name = name
-
- def getCecVersion(self) -> int:
- return self._cec_version
-
- def getPowerStatus(self) -> int:
- return self._power_status
-
- def setPowerStatus(self, status: int) -> None:
- self._power_status = status
-
- def isCecDevice(self) -> bool:
- return self._is_cec_device
-
- def isMhlDevice(self) -> bool:
- return self._is_mhl_device
-
- def isArcSupported(self) -> bool:
- return self._is_arc_supported
-
- def isEarcSupported(self) -> bool:
- return self._is_earc_supported
-
- def isActiveSource(self) -> bool:
- return self._is_active_source
-
- def setActiveSource(self, active: bool) -> None:
- self._is_active_source = active
-
- def toString(self) -> str:
- return (
- f"HdmiDeviceInfo(logical={self._logical_address}, "
- f"physical={self.getPhysicalAddressString()}, "
- f"type={self.getDeviceTypeString()}, "
- f"name={self._display_name})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# HdmiPortInfo
-# ═══════════════════════════════════════════════════════════════
-
-class HdmiPortInfo(Stub):
- """HdmiPortInfo — HDMI 端口信息"""
-
- def __init__(self, id: int = 0, type: int = PORT_TYPE_INPUT, address: int = 0x0000):
- super().__init__()
- self._id = id
- self._type = type
- self._physical_address = address
- self._is_cec_supported = True
- self._is_arc_supported = False
- self._is_earc_supported = False
- self._is_mhl_supported = False
- self._supports_4k = False
- self._supports_hdr = False
- self._supports_dolby_vision = False
- self._max_tmds_character_rate = 6000
- self._num_edid_blocks = 0
- self._edid: Optional[bytes] = None
- self._port_name: Optional[str] = None
- self._connected_device: Optional[HdmiDeviceInfo] = None
- self._is_connected = False
-
- def getId(self) -> int:
- return self._id
-
- def getType(self) -> int:
- return self._type
-
- def getPhysicalAddress(self) -> int:
- return self._physical_address
-
- def isCecSupported(self) -> bool:
- return self._is_cec_supported
-
- def setCecSupported(self, supported: bool) -> None:
- self._is_cec_supported = supported
-
- def isArcSupported(self) -> bool:
- return self._is_arc_supported
-
- def setArcSupported(self, supported: bool) -> None:
- self._is_arc_supported = supported
-
- def isEarcSupported(self) -> bool:
- return self._is_earc_supported
-
- def setEarcSupported(self, supported: bool) -> None:
- self._is_earc_supported = supported
-
- def isMhlSupported(self) -> bool:
- return self._is_mhl_supported
-
- def supports4k(self) -> bool:
- return self._supports_4k
-
- def setSupports4k(self, supported: bool) -> None:
- self._supports_4k = supported
-
- def supportsHdr(self) -> bool:
- return self._supports_hdr
-
- def supportsDolbyVision(self) -> bool:
- return self._supports_dolby_vision
-
- def getMaxTmdsCharacterRate(self) -> int:
- return self._max_tmds_character_rate
-
- def getPortName(self) -> Optional[str]:
- return self._port_name
-
- def setPortName(self, name: str) -> None:
- self._port_name = name
-
- def isConnected(self) -> bool:
- return self._is_connected
-
- def setConnected(self, connected: bool, device: Optional[HdmiDeviceInfo] = None) -> None:
- self._is_connected = connected
- self._connected_device = device
-
- def getConnectedDevice(self) -> Optional[HdmiDeviceInfo]:
- return self._connected_device
-
- def toString(self) -> str:
- return (
- f"HdmiPortInfo(id={self._id}, type={self._type}, "
- f"cec={self._is_cec_supported}, arc={self._is_arc_supported}, "
- f"connected={self._is_connected})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# HdmiCecDeviceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class HdmiCecDeviceInfo(Stub):
- """HdmiCecDeviceInfo — CEC 设备信息"""
-
- def __init__(self):
- super().__init__()
- self._logical_address = -1
- self._physical_address = 0xFFFF
- self._device_type = DEVICE_TYPE_INACTIVE
- self._vendor_id = 0
- self._osd_name: Optional[str] = None
- self._cec_version = CEC_VERSION_2_0
- self._language: Optional[str] = None
- self._features: List[int] = []
- self._is_active = False
-
- def getLogicalAddress(self) -> int:
- return self._logical_address
-
- def getPhysicalAddress(self) -> int:
- return self._physical_address
-
- def getDeviceType(self) -> int:
- return self._device_type
-
- def getVendorId(self) -> int:
- return self._vendor_id
-
- def getOsdName(self) -> Optional[str]:
- return self._osd_name
-
- def getCecVersion(self) -> int:
- return self._cec_version
-
- def getLanguage(self) -> Optional[str]:
- return self._language
-
- def getFeatures(self) -> List[int]:
- return list(self._features)
-
- def isActive(self) -> bool:
- return self._is_active
-
- def toString(self) -> str:
- return (
- f"HdmiCecDeviceInfo(logical={self._logical_address}, "
- f"type={self._device_type}, name={self._osd_name})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# HdmiRecordSources
-# ═══════════════════════════════════════════════════════════════
-
-class HdmiRecordSources(Stub):
- """HdmiRecordSources — HDMI 录制源"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def createDigitalSource(serviceId: int, source: int) -> Any:
- return {"type": "digital", "serviceId": serviceId, "source": source}
-
- @staticmethod
- def createAnalogueSource(serviceType: int, frequency: int, system: int) -> Any:
- return {"type": "analogue", "serviceType": serviceType, "frequency": frequency, "system": system}
-
- @staticmethod
- def createExternalPlug(plugNumber: int) -> Any:
- return {"type": "external_plug", "plugNumber": plugNumber}
-
- @staticmethod
- def createExternalPhysicalAddress(physicalAddress: int) -> Any:
- return {"type": "external_physical", "physicalAddress": physicalAddress}
-
- @staticmethod
- def createOwnSource() -> Any:
- return {"type": "own"}
-
- @staticmethod
- def createProgramNumber(programNumber: int) -> Any:
- return {"type": "program", "programNumber": programNumber}
-
- def toString(self) -> str:
- return "HdmiRecordSources"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HdmiRecordListener
-# ═══════════════════════════════════════════════════════════════
-
-class HdmiRecordListener(Stub):
- """HdmiRecordListener — HDMI 录制监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onRecordStarted(self, source: Any, result: int) -> None:
- pass
-
- def onRecordStopped(self, source: Any) -> None:
- pass
-
- def onRecordScheduleStarted(self, source: Any, result: int) -> None:
- pass
-
- def onRecordScheduleStopped(self, source: Any) -> None:
- pass
-
- def onClearTimerStarted(self, source: Any, result: int) -> None:
- pass
-
- def onClearTimerStopped(self, source: Any) -> None:
- pass
-
- def onOneTouchRecordStarted(self, source: Any) -> None:
- pass
-
- def onOneTouchRecordStopped(self, source: Any) -> None:
- pass
-
- def onTimerRecordStarted(self, source: Any, result: int) -> None:
- pass
-
- def onTimerRecordStopped(self, source: Any) -> None:
- pass
-
- def toString(self) -> str:
- return "HdmiRecordListener"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HdmiPlaybackClient
-# ═══════════════════════════════════════════════════════════════
-
-class HdmiPlaybackClient(Stub):
- """HdmiPlaybackClient — HDMI 播放客户端"""
-
- def __init__(self, manager: "HdmiControlManager"):
- super().__init__()
- self._manager = manager
- self._callback: Optional[Callable] = None
-
- def sendKeyEvent(self, keyCode: int, isPressed: bool) -> None:
- pass
-
- def oneTouchPlay(self, callback: Optional[Callable] = None) -> None:
- if callback:
- callback(RESULT_SUCCESS)
-
- def queryDeviceType(self, callback: Optional[Callable] = None) -> None:
- if callback:
- callback(DEVICE_TYPE_PLAYBACK)
-
- def setCallback(self, callback: Callable) -> None:
- self._callback = callback
-
- def clearCallback(self) -> None:
- self._callback = None
-
- def toString(self) -> str:
- return "HdmiPlaybackClient"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HdmiSwitchClient
-# ═══════════════════════════════════════════════════════════════
-
-class HdmiSwitchClient(Stub):
- """HdmiSwitchClient — HDMI 切换客户端"""
-
- def __init__(self, manager: "HdmiControlManager"):
- super().__init__()
- self._manager = manager
- self._callback: Optional[Callable] = None
-
- def selectDevice(self, logicalAddress: int, callback: Optional[Callable] = None) -> None:
- if callback:
- callback(RESULT_SUCCESS)
-
- def setCallback(self, callback: Callable) -> None:
- self._callback = callback
-
- def clearCallback(self) -> None:
- self._callback = None
-
- def getDeviceList(self) -> List[HdmiDeviceInfo]:
- return self._manager.getDeviceList()
-
- def toString(self) -> str:
- return "HdmiSwitchClient"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HdmiTvClient
-# ═══════════════════════════════════════════════════════════════
-
-class HdmiTvClient(Stub):
- """HdmiTvClient — HDMI TV 客户端"""
-
- def __init__(self, manager: "HdmiControlManager"):
- super().__init__()
- self._manager = manager
- self._callback: Optional[Callable] = None
- self._record_listener: Optional[HdmiRecordListener] = None
-
- def deviceSelect(self, logicalAddress: int, callback: Optional[Callable] = None) -> None:
- if callback:
- callback(RESULT_SUCCESS)
-
- def sendStandby(self, deviceId: int, callback: Optional[Callable] = None) -> None:
- if callback:
- callback(RESULT_SUCCESS)
-
- def setSystemAudioMode(self, enabled: bool, callback: Optional[Callable] = None) -> None:
- if callback:
- callback(RESULT_SUCCESS)
-
- def setArcEnabled(self, enabled: bool) -> None:
- pass
-
- def setEarcEnabled(self, enabled: bool) -> None:
- pass
-
- def startOneTouchRecord(self, address: int, source: Any) -> None:
- if self._record_listener:
- self._record_listener.onOneTouchRecordStarted(source)
-
- def stopOneTouchRecord(self, address: int) -> None:
- if self._record_listener:
- self._record_listener.onOneTouchRecordStopped(address)
-
- def startTimerRecording(self, address: int, source: Any, duration: int) -> None:
- if self._record_listener:
- self._record_listener.onTimerRecordStarted(source, RESULT_SUCCESS)
-
- def clearTimerRecording(self, address: int, source: Any) -> None:
- if self._record_listener:
- self._record_listener.onClearTimerStarted(source, RESULT_SUCCESS)
-
- def setRecordListener(self, listener: HdmiRecordListener) -> None:
- self._record_listener = listener
-
- def setCallback(self, callback: Callable) -> None:
- self._callback = callback
-
- def clearCallback(self) -> None:
- self._callback = None
-
- def startPlayback(self, address: int) -> None:
- pass
-
- def stopPlayback(self, address: int) -> None:
- pass
-
- def toString(self) -> str:
- return "HdmiTvClient"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HdmiControlManager
-# ═══════════════════════════════════════════════════════════════
-
-class HdmiControlManager(Stub):
- """HdmiControlManager — HDMI 控制管理器 (桌面存根)"""
-
- DEVICE_TYPE_TV = DEVICE_TYPE_TV
- DEVICE_TYPE_RECORDER = DEVICE_TYPE_RECORDER
- DEVICE_TYPE_TUNER = DEVICE_TYPE_TUNER
- DEVICE_TYPE_PLAYBACK = DEVICE_TYPE_PLAYBACK
- DEVICE_TYPE_AUDIO_SYSTEM = DEVICE_TYPE_AUDIO_SYSTEM
- DEVICE_TYPE_PURE_CEC_SWITCH = DEVICE_TYPE_PURE_CEC_SWITCH
- DEVICE_TYPE_VIDEO_PROCESSOR = DEVICE_TYPE_VIDEO_PROCESSOR
- DEVICE_TYPE_RESERVED = DEVICE_TYPE_RESERVED
- DEVICE_TYPE_INACTIVE = DEVICE_TYPE_INACTIVE
-
- CONTROL_STATE_CHANGED_REASON_UNKNOWN = CONTROL_STATE_CHANGED_REASON_UNKNOWN
- CONTROL_STATE_CHANGED_REASON_ENABLED = CONTROL_STATE_CHANGED_REASON_ENABLED
- CONTROL_STATE_CHANGED_REASON_DISABLED = CONTROL_STATE_CHANGED_REASON_DISABLED
- CONTROL_STATE_CHANGED_REASON_WAKE_UP = CONTROL_STATE_CHANGED_REASON_WAKE_UP
- CONTROL_STATE_CHANGED_REASON_SLEEP = CONTROL_STATE_CHANGED_REASON_SLEEP
- CONTROL_STATE_CHANGED_REASON_STANDBY = CONTROL_STATE_CHANGED_REASON_STANDBY
-
- POWER_STATUS_ON = POWER_STATUS_ON
- POWER_STATUS_STANDBY = POWER_STATUS_STANDBY
- POWER_STATUS_TO_ON = POWER_STATUS_TO_ON
- POWER_STATUS_TO_STANDBY = POWER_STATUS_TO_STANDBY
- POWER_STATUS_UNKNOWN = POWER_STATUS_UNKNOWN
-
- RESULT_SUCCESS = RESULT_SUCCESS
- RESULT_FAILURE = RESULT_FAILURE
- RESULT_TIMEOUT = RESULT_TIMEOUT
- RESULT_NOT_SUPPORTED = RESULT_NOT_SUPPORTED
- RESULT_BUSY = RESULT_BUSY
-
- CEC_VERSION_1_4 = CEC_VERSION_1_4
- CEC_VERSION_2_0 = CEC_VERSION_2_0
-
- _instance: Optional["HdmiControlManager"] = None
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._lock = threading.Lock()
- self._devices: Dict[int, HdmiDeviceInfo] = {}
- self._ports: Dict[int, HdmiPortInfo] = {}
- self._is_available = True
- self._hdmi_cec_enabled = True
- self._hdmi_mhl_enabled = True
- self._system_audio_mode = False
- self._arc_enabled = False
- self._earc_enabled = False
- self._active_source: Optional[HdmiDeviceInfo] = None
- self._playback_client: Optional[HdmiPlaybackClient] = None
- self._tv_client: Optional[HdmiTvClient] = None
- self._switch_client: Optional[HdmiSwitchClient] = None
- self._hotplug_listeners: List[Callable] = []
- self._cec_message_listeners: List[Callable] = []
- self._control_state_listeners: List[Callable] = []
-
- def getPlaybackClient(self) -> Optional[HdmiPlaybackClient]:
- if self._playback_client is None:
- self._playback_client = HdmiPlaybackClient(self)
- return self._playback_client
-
- def getTvClient(self) -> Optional[HdmiTvClient]:
- if self._tv_client is None:
- self._tv_client = HdmiTvClient(self)
- return self._tv_client
-
- def getSwitchClient(self) -> Optional[HdmiSwitchClient]:
- if self._switch_client is None:
- self._switch_client = HdmiSwitchClient(self)
- return self._switch_client
-
- def getDeviceList(self) -> List[HdmiDeviceInfo]:
- with self._lock:
- return list(self._devices.values())
-
- def getDeviceInfo(self, logicalAddress: int) -> Optional[HdmiDeviceInfo]:
- with self._lock:
- return self._devices.get(logicalAddress)
-
- def getPortInfo(self, portId: int) -> Optional[HdmiPortInfo]:
- with self._lock:
- return self._ports.get(portId)
-
- def getPorts(self) -> List[HdmiPortInfo]:
- with self._lock:
- return list(self._ports.values())
-
- def addDevice(self, device: HdmiDeviceInfo) -> None:
- with self._lock:
- self._devices[device.getLogicalAddress()] = device
- if device.isActiveSource():
- self._active_source = device
-
- def removeDevice(self, logicalAddress: int) -> Optional[HdmiDeviceInfo]:
- with self._lock:
- device = self._devices.pop(logicalAddress, None)
- if device and self._active_source is device:
- self._active_source = None
- return device
-
- def clearDevices(self) -> None:
- with self._lock:
- self._devices.clear()
- self._active_source = None
-
- def isCecEnabled(self) -> bool:
- return self._hdmi_cec_enabled
-
- def setCecEnabled(self, enabled: bool) -> None:
- self._hdmi_cec_enabled = enabled
-
- def isMhlEnabled(self) -> bool:
- return self._hdmi_mhl_enabled
-
- def setMhlEnabled(self, enabled: bool) -> None:
- self._hdmi_mhl_enabled = enabled
-
- def isSystemAudioMode(self) -> bool:
- return self._system_audio_mode
-
- def setSystemAudioMode(self, mode: bool) -> None:
- self._system_audio_mode = mode
-
- def isArcEnabled(self) -> bool:
- return self._arc_enabled
-
- def setArcEnabled(self, enabled: bool) -> None:
- self._arc_enabled = enabled
-
- def isEarcEnabled(self) -> bool:
- return self._earc_enabled
-
- def setEarcEnabled(self, enabled: bool) -> None:
- self._earc_enabled = enabled
-
- def getActiveSource(self) -> Optional[HdmiDeviceInfo]:
- with self._lock:
- return self._active_source
-
- def setActiveSource(self, device: HdmiDeviceInfo) -> None:
- with self._lock:
- self._active_source = device
-
- def addHotplugEventListener(self, listener: Callable) -> None:
- if listener not in self._hotplug_listeners:
- self._hotplug_listeners.append(listener)
-
- def removeHotplugEventListener(self, listener: Callable) -> None:
- if listener in self._hotplug_listeners:
- self._hotplug_listeners.remove(listener)
-
- def addCecMessageListener(self, listener: Callable) -> None:
- if listener not in self._cec_message_listeners:
- self._cec_message_listeners.append(listener)
-
- def removeCecMessageListener(self, listener: Callable) -> None:
- if listener in self._cec_message_listeners:
- self._cec_message_listeners.remove(listener)
-
- def addControlStateChangeListener(self, listener: Callable) -> None:
- if listener not in self._control_state_listeners:
- self._control_state_listeners.append(listener)
-
- def removeControlStateChangeListener(self, listener: Callable) -> None:
- if listener in self._control_state_listeners:
- self._control_state_listeners.remove(listener)
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def sendCecMessage(self, message: Any) -> int:
- return RESULT_SUCCESS
-
- def toString(self) -> str:
- with self._lock:
- return (
- f"HdmiControlManager(devices={len(self._devices)}, "
- f"ports={len(self._ports)}, "
- f"cec={self._hdmi_cec_enabled})"
- )
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_input.py b/android_pyapi/android/hardware_input.py
deleted file mode 100644
index 0410fec..0000000
--- a/android_pyapi/android/hardware_input.py
+++ /dev/null
@@ -1,254 +0,0 @@
-"""
-Android hardware.input 组件 — InputManager, InputDevice, MotionRange 等
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputManager
-# ═══════════════════════════════════════════════════════════════
-
-class InputManager(Stub):
- """InputManager — 输入管理器"""
-
- ACTION_QUERY_KEYBOARD_LAYOUTS = "android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS"
-
- # ═══════════════════════════════════════════════════════════
- # InputDeviceListener
- # ═══════════════════════════════════════════════════════════
-
- class InputDeviceListener(Stub):
- """InputManager.InputDeviceListener — 输入设备监听器"""
-
- def onInputDeviceAdded(self, deviceId: int):
- pass
-
- def onInputDeviceRemoved(self, deviceId: int):
- pass
-
- def onInputDeviceChanged(self, deviceId: int):
- pass
-
- def __init__(self):
- super().__init__()
- self._devices: Dict[int, InputDevice] = {}
- self._listeners: Dict[int, InputManager.InputDeviceListener] = {}
- self._next_id = 1
- self._init_default_devices()
-
- def _init_default_devices(self):
- # Keyboard
- kb = InputDevice(
- deviceId=0, name="Virtual Keyboard",
- descriptor="keyboard_v1", sources=InputDevice.SOURCE_KEYBOARD,
- vendorId=0x1, productId=0x1,
- keyboardType=InputDevice.KEYBOARD_TYPE_ALPHABETIC,
- hasMicrophone=False, isVirtual=True
- )
- self._devices[0] = kb
-
- # Mouse
- mouse = InputDevice(
- deviceId=1, name="Virtual Mouse",
- descriptor="mouse_v1", sources=InputDevice.SOURCE_MOUSE,
- vendorId=0x2, productId=0x2,
- keyboardType=InputDevice.KEYBOARD_TYPE_NONE,
- hasMicrophone=False, isVirtual=True
- )
- self._devices[1] = mouse
-
- # Trackpad
- tp = InputDevice(
- deviceId=2, name="Virtual Trackpad",
- descriptor="trackpad_v1", sources=InputDevice.SOURCE_TOUCHPAD,
- vendorId=0x3, productId=0x3,
- keyboardType=InputDevice.KEYBOARD_TYPE_NONE,
- hasMicrophone=False, isVirtual=False
- )
- self._devices[2] = tp
-
- def getDevice(self, deviceId: int) -> Optional["InputDevice"]:
- return self._devices.get(deviceId)
-
- def getDeviceIds(self) -> List[int]:
- return list(self._devices.keys())
-
- def registerInputDeviceListener(self, listener: InputDeviceListener, handler: Any = None):
- lid = id(listener)
- self._listeners[lid] = listener
-
- def unregisterInputDeviceListener(self, listener: InputDeviceListener):
- lid = id(listener)
- self._listeners.pop(lid, None)
-
- def getInputDevice(self, deviceId: int) -> Optional["InputDevice"]:
- return self.getDevice(deviceId)
-
- def isInTabletMode(self) -> bool:
- return False
-
- def getCurrentKeyboardLayoutForInputDevice(self, device: "InputDevice") -> Optional[str]:
- return None
-
- def setKeyboardLayoutForInputDevice(self, device: "InputDevice",
- keyboardLayoutDescriptor: str):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputDevice
-# ═══════════════════════════════════════════════════════════════
-
-class InputDevice(Stub):
- """InputDevice — 输入设备"""
-
- KEYBOARD_TYPE_ALPHABETIC = 2
- KEYBOARD_TYPE_NON_ALPHABETIC = 1
- KEYBOARD_TYPE_NONE = 0
-
- SOURCE_CLASS_JOYSTICK = 16
- SOURCE_CLASS_MASK = 0x000000FF
- SOURCE_CLASS_NONE = 0x00000000
- SOURCE_CLASS_POINTER = 0x00000002
- SOURCE_CLASS_POSITION = 0x00000008
- SOURCE_CLASS_TRACKBALL = 0x00000004
- SOURCE_CLASS_BUTTON = 0x00000001
-
- SOURCE_GAMEPAD = 0x00000401
- SOURCE_HDMI = 0x02000000
- SOURCE_JOYSTICK = 0x01000010
- SOURCE_KEYBOARD = 0x00000101
- SOURCE_MOUSE = 0x00002002
- SOURCE_MOUSE_RELATIVE = 0x00002000
- SOURCE_ROTARY_ENCODER = 0x00800000
- SOURCE_STYLUS = 0x00004002
- SOURCE_TOUCHPAD = 0x00100008
- SOURCE_TOUCHSCREEN = 0x00001002
- SOURCE_TOUCH_NAVIGATION = 0x00200008
- SOURCE_TRACKBALL = 0x00010004
- SOURCE_UNKNOWN = 0x00000000
- SOURCE_ANY = 0xFFFFFFFE
-
- # ═══════════════════════════════════════════════════════════
- # MotionRange
- # ═══════════════════════════════════════════════════════════
-
- class MotionRange(Stub):
- """InputDevice.MotionRange — 运动范围"""
-
- def __init__(self, axis: int = 0, source: int = 0,
- min: float = 0.0, max: float = 1.0,
- flat: float = 0.0, fuzz: float = 0.0,
- resolution: float = 0.0):
- super().__init__()
- self._axis = axis
- self._source = source
- self._min = min
- self._max = max
- self._flat = flat
- self._fuzz = fuzz
- self._resolution = resolution
-
- def getAxis(self) -> int:
- return self._axis
-
- def getSource(self) -> int:
- return self._source
-
- def getMin(self) -> float:
- return self._min
-
- def getMax(self) -> float:
- return self._max
-
- def getFlat(self) -> float:
- return self._flat
-
- def getFuzz(self) -> float:
- return self._fuzz
-
- def getRange(self) -> float:
- return self._max - self._min
-
- def getResolution(self) -> float:
- return self._resolution
-
- def toString(self) -> str:
- return f"MotionRange(axis={self._axis}, source={self._source}," \
- f" range=[{self._min}, {self._max}])"
-
- def __init__(self, deviceId: int = 0, name: str = "", descriptor: str = "",
- sources: int = 0, vendorId: int = 0, productId: int = 0,
- controllerNumber: int = 0, keyboardType: int = KEYBOARD_TYPE_NONE,
- hasMicrophone: bool = False, isVirtual: bool = False):
- super().__init__()
- self._device_id = deviceId
- self._name = name
- self._descriptor = descriptor
- self._sources = sources
- self._vendor_id = vendorId
- self._product_id = productId
- self._controller_number = controllerNumber
- self._keyboard_type = keyboardType
- self._has_microphone = hasMicrophone
- self._is_virtual = isVirtual
- self._motion_ranges: List[InputDevice.MotionRange] = []
-
- def getId(self) -> int:
- return self._device_id
-
- def getName(self) -> str:
- return self._name
-
- def getDescriptor(self) -> str:
- return self._descriptor
-
- def getSources(self) -> int:
- return self._sources
-
- def getVendorId(self) -> int:
- return self._vendor_id
-
- def getProductId(self) -> int:
- return self._product_id
-
- def getControllerNumber(self) -> int:
- return self._controller_number
-
- def getKeyCharacterMap(self) -> Any:
- return None
-
- def getMotionRange(self, axis: int = -1, source: int = -1) -> List[MotionRange]:
- results = []
- for mr in self._motion_ranges:
- if axis >= 0 and mr.getAxis() != axis:
- continue
- if source >= 0 and mr.getSource() != source:
- continue
- results.append(mr)
- return results
-
- def hasMicrophone(self) -> bool:
- return self._has_microphone
-
- def isVirtual(self) -> bool:
- return self._is_virtual
-
- def toString(self) -> str:
- return f"InputDevice(id={self._device_id}, name={self._name}," \
- f" sources={self._sources:#x})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "InputManager",
- "InputDevice",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_light.py b/android_pyapi/android/hardware_light.py
deleted file mode 100644
index 4851f08..0000000
--- a/android_pyapi/android/hardware_light.py
+++ /dev/null
@@ -1,660 +0,0 @@
-"""
-Android Lights API — LightsManager, Light, LightState, LightSession, LightsRequest
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import time
-import uuid
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-from enum import IntEnum
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# LIGHT_ID_* 常量
-LIGHT_ID_BACKLIGHT = 0
-LIGHT_ID_KEYBOARD = 1
-LIGHT_ID_BUTTONS = 2
-LIGHT_ID_BATTERY = 3
-LIGHT_ID_NOTIFICATIONS = 4
-LIGHT_ID_ATTENTION = 5
-LIGHT_ID_BLUETOOTH = 6
-LIGHT_ID_WIFI = 7
-LIGHT_ID_MICROPHONE = 8
-LIGHT_ID_CAMERA = 9
-LIGHT_ID_COUNT = 10
-LIGHT_ID_MICROPHONE_MUTE = 11
-LIGHT_ID_CAMERA_MUTE = 12
-LIGHT_ID_POWER = 13
-LIGHT_ID_ADAPTIVE_BACKLIGHT = 14
-LIGHT_ID_CHARGING = 15
-LIGHT_ID_ERROR = 16
-LIGHT_ID_MANUAL_BACKLIGHT = 17
-LIGHT_ID_MAX = 31
-
-# BRIGHTNESS_* 常量
-BRIGHTNESS_MIN = 0
-BRIGHTNESS_LOW = 25
-BRIGHTNESS_MEDIUM = 127
-BRIGHTNESS_HIGH = 200
-BRIGHTNESS_MAX = 255
-BRIGHTNESS_OFF = 0
-BRIGHTNESS_FULL = 255
-BRIGHTNESS_DEFAULT = 127
-
-# LIGHT_TYPE_* 常量
-LIGHT_TYPE_MANUAL = 0
-LIGHT_TYPE_AUTOMATIC = 1
-LIGHT_TYPE_MICROPHONE = 2
-LIGHT_TYPE_CAMERA = 3
-LIGHT_TYPE_NOTIFICATION = 4
-LIGHT_TYPE_ATTENTION = 5
-LIGHT_TYPE_RGB = 6
-LIGHT_TYPE_MONOCHROME = 7
-LIGHT_TYPE_POWER = 8
-LIGHT_TYPE_BATTERY = 9
-LIGHT_TYPE_ADAPTIVE = 10
-LIGHT_TYPE_BLINKING = 11
-
-# LIGHT_CAPABILITY 常量
-LIGHT_CAPABILITY_NONE = 0
-LIGHT_CAPABILITY_BRIGHTNESS = 1
-LIGHT_CAPABILITY_RGB = 2
-LIGHT_CAPABILITY_COLOR_TEMPERATURE = 4
-LIGHT_CAPABILITY_BLINKING = 8
-LIGHT_CAPABILITY_DIMMABLE = 16
-LIGHT_CAPABILITY_ADAPTIVE = 32
-LIGHT_CAPABILITY_MICROPHONE = 64
-LIGHT_CAPABILITY_CAMERA = 128
-
-# FLASH_MODE 常量
-FLASH_MODE_NONE = 0
-FLASH_MODE_HARDWARE = 1
-FLASH_MODE_SOFTWARE = 2
-FLASH_MODE_TIMED = 3
-FLASH_MODE_INFINITE = 4
-
-# LIGHT_STATE 常量
-LIGHT_STATE_ON = 1
-LIGHT_STATE_OFF = 0
-LIGHT_STATE_BLINKING = 2
-LIGHT_STATE_BREATHING = 3
-LIGHT_STATE_PULSING = 4
-
-
-# ═══════════════════════════════════════════════════════════════
-# LightState
-# ═══════════════════════════════════════════════════════════════
-
-class LightState(Stub):
- """LightState — 灯光状态"""
-
- def __init__(self):
- super().__init__()
- self._color = 0
- self._brightness = 0
- self._brightness_mode = LIGHT_TYPE_MANUAL
- self._flash_mode = FLASH_MODE_NONE
- self._flash_on_ms = 0
- self._flash_off_ms = 0
- self._state = LIGHT_STATE_OFF
- self._rgb_color = (0, 0, 0)
- self._color_temperature = 6500
- self._is_hardware = False
- self._pulse_duration = 0
- self._breathing_enabled = False
- self._fade_in_time = 0
- self._fade_out_time = 0
- self._brightness_float = 0.0
- self._brightness_nits = 0.0
-
- def getColor(self) -> int:
- return self._color
-
- def setColor(self, color: int) -> None:
- self._color = color
- self._rgb_color = ((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF)
-
- def getBrightness(self) -> int:
- return self._brightness
-
- def setBrightness(self, brightness: int) -> None:
- self._brightness = max(0, min(255, brightness))
- self._brightness_float = self._brightness / 255.0
-
- def getBrightnessMode(self) -> int:
- return self._brightness_mode
-
- def setBrightnessMode(self, mode: int) -> None:
- self._brightness_mode = mode
-
- def getFlashMode(self) -> int:
- return self._flash_mode
-
- def setFlashMode(self, mode: int) -> None:
- self._flash_mode = mode
-
- def getFlashOnMs(self) -> int:
- return self._flash_on_ms
-
- def setFlashOnMs(self, onMs: int) -> None:
- self._flash_on_ms = onMs
-
- def getFlashOffMs(self) -> int:
- return self._flash_off_ms
-
- def setFlashOffMs(self, offMs: int) -> None:
- self._flash_off_ms = offMs
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int) -> None:
- self._state = state
-
- def isOn(self) -> bool:
- return self._state != LIGHT_STATE_OFF
-
- def getRgbColor(self) -> Tuple[int, int, int]:
- return self._rgb_color
-
- def setRgbColor(self, r: int, g: int, b: int) -> None:
- self._rgb_color = (r & 0xFF, g & 0xFF, b & 0xFF)
- self._color = (r << 16) | (g << 8) | b
-
- def getColorTemperature(self) -> int:
- return self._color_temperature
-
- def setColorTemperature(self, temperature: int) -> None:
- self._color_temperature = max(1000, min(20000, temperature))
-
- def isHardwareControlled(self) -> bool:
- return self._is_hardware
-
- def setFadeInTime(self, ms: int) -> None:
- self._fade_in_time = ms
-
- def setFadeOutTime(self, ms: int) -> None:
- self._fade_out_time = ms
-
- def getBrightnessFloat(self) -> float:
- return self._brightness_float
-
- def getBrightnessNits(self) -> float:
- return self._brightness_nits
-
- def setBrightnessNits(self, nits: float) -> None:
- self._brightness_nits = nits
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, LightState):
- return (self._color == other._color and self._brightness == other._brightness)
- return False
-
- def hashCode(self) -> int:
- return hash((self._color, self._brightness)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return (
- f"LightState(color=0x{self._color:06x}, "
- f"brightness={self._brightness}, "
- f"state={self._state})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# Light
-# ═══════════════════════════════════════════════════════════════
-
-class Light(Stub):
- """Light — 灯光设备"""
-
- LIGHT_TYPE_MANUAL = LIGHT_TYPE_MANUAL
- LIGHT_TYPE_AUTOMATIC = LIGHT_TYPE_AUTOMATIC
- LIGHT_TYPE_MICROPHONE = LIGHT_TYPE_MICROPHONE
- LIGHT_TYPE_CAMERA = LIGHT_TYPE_CAMERA
- LIGHT_TYPE_NOTIFICATION = LIGHT_TYPE_NOTIFICATION
- LIGHT_TYPE_ATTENTION = LIGHT_TYPE_ATTENTION
- LIGHT_TYPE_RGB = LIGHT_TYPE_RGB
- LIGHT_TYPE_ADAPTIVE = LIGHT_TYPE_ADAPTIVE
- LIGHT_TYPE_BLINKING = LIGHT_TYPE_BLINKING
-
- def __init__(self, light_id: int = 0, light_type: int = LIGHT_TYPE_MANUAL):
- super().__init__()
- self._id = light_id
- self._type = light_type
- self._ordinal = light_id
- self._capabilities = LIGHT_CAPABILITY_BRIGHTNESS
- self._name: Optional[str] = None
- self._is_available = True
- self._default_brightness = BRIGHTNESS_DEFAULT
- self._max_brightness = BRIGHTNESS_MAX
- self._min_brightness = BRIGHTNESS_MIN
- self._supports_rgb = False
- self._supports_color_temperature = False
- self._supports_blinking = False
- self._supports_dimming = True
- self._supports_adaptive = False
- self._default_color = 0xFFFFFF
- self._default_color_temperature = 6500
- self._blink_supported = False
- self._pulse_supported = False
- self._breathing_supported = False
- self._fade_supported = False
- self._current_state = LightState()
- self._rgb_support = light_type == LIGHT_TYPE_RGB
- self._adaptive_support = light_type == LIGHT_TYPE_ADAPTIVE
- self._blink_support = light_type == LIGHT_TYPE_BLINKING
-
- def getId(self) -> int:
- return self._id
-
- def getType(self) -> int:
- return self._type
-
- def getOrdinal(self) -> int:
- return self._ordinal
-
- def getCapabilities(self) -> int:
- return self._capabilities
-
- def setCapabilities(self, caps: int) -> None:
- self._capabilities = caps
-
- def getName(self) -> Optional[str]:
- return self._name
-
- def setName(self, name: str) -> None:
- self._name = name
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def setAvailable(self, available: bool) -> None:
- self._is_available = available
-
- def getDefaultBrightness(self) -> int:
- return self._default_brightness
-
- def getMaxBrightness(self) -> int:
- return self._max_brightness
-
- def getMinBrightness(self) -> int:
- return self._min_brightness
-
- def supportsRgb(self) -> bool:
- return self._supports_rgb
-
- def supportsColorTemperature(self) -> bool:
- return self._supports_color_temperature
-
- def supportsBlinking(self) -> bool:
- return self._supports_blinking
-
- def supportsDimming(self) -> bool:
- return self._supports_dimming
-
- def supportsAdaptive(self) -> bool:
- return self._supports_adaptive
-
- def getDefaultColor(self) -> int:
- return self._default_color
-
- def getDefaultColorTemperature(self) -> int:
- return self._default_color_temperature
-
- def getCurrentState(self) -> LightState:
- return self._current_state
-
- def setCurrentState(self, state: LightState) -> None:
- self._current_state = state
-
- def canSetBrightness(self) -> bool:
- return self._capabilities & LIGHT_CAPABILITY_BRIGHTNESS != 0
-
- def canSetColor(self) -> bool:
- return self._capabilities & LIGHT_CAPABILITY_RGB != 0
-
- def canSetColorTemperature(self) -> bool:
- return self._capabilities & LIGHT_CAPABILITY_COLOR_TEMPERATURE != 0
-
- def canBlink(self) -> bool:
- return self._capabilities & LIGHT_CAPABILITY_BLINKING != 0
-
- def isDimmable(self) -> bool:
- return self._capabilities & LIGHT_CAPABILITY_DIMMABLE != 0
-
- def isAdaptive(self) -> bool:
- return self._capabilities & LIGHT_CAPABILITY_ADAPTIVE != 0
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, Light):
- return self._id == other._id
- return False
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"Light(id={self._id}, type={self._type}, name={self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LightSession
-# ═══════════════════════════════════════════════════════════════
-
-class LightSession(Stub):
- """LightSession — 灯光会话"""
-
- def __init__(self, light_id: int):
- super().__init__()
- self._session_id = str(uuid.uuid4())
- self._light_id = light_id
- self._state = LightState()
- self._is_active = False
- self._created_at = time.time()
- self._last_update = time.time()
- self._priority = 0
- self._owner: Optional[str] = None
- self._transient = False
- self._timeout_ms = 0
- self._fade_duration_ms = 0
-
- def getSessionId(self) -> str:
- return self._session_id
-
- def getLightId(self) -> int:
- return self._light_id
-
- def getState(self) -> LightState:
- return self._state
-
- def setState(self, state: LightState) -> None:
- self._state = state
- self._last_update = time.time()
-
- def isActive(self) -> bool:
- return self._is_active
-
- def setActive(self, active: bool) -> None:
- self._is_active = active
-
- def getCreatedAt(self) -> float:
- return self._created_at
-
- def getLastUpdate(self) -> float:
- return self._last_update
-
- def getPriority(self) -> int:
- return self._priority
-
- def setPriority(self, priority: int) -> None:
- self._priority = priority
-
- def getOwner(self) -> Optional[str]:
- return self._owner
-
- def setOwner(self, owner: str) -> None:
- self._owner = owner
-
- def isTransient(self) -> bool:
- return self._transient
-
- def setTransient(self, transient: bool) -> None:
- self._transient = transient
-
- def getTimeoutMs(self) -> int:
- return self._timeout_ms
-
- def setTimeoutMs(self, timeoutMs: int) -> None:
- self._timeout_ms = timeoutMs
-
- def getFadeDurationMs(self) -> int:
- return self._fade_duration_ms
-
- def setFadeDurationMs(self, ms: int) -> None:
- self._fade_duration_ms = ms
-
- def toString(self) -> str:
- return (
- f"LightSession(id={self._session_id[:8]}..., "
- f"light={self._light_id}, "
- f"active={self._is_active})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# LightsRequest
-# ═══════════════════════════════════════════════════════════════
-
-class LightsRequest(Stub):
- """LightsRequest — 灯光请求"""
-
- def __init__(self):
- super().__init__()
- self._light_states: Dict[int, LightState] = {}
- self._light_sessions: List[LightSession] = []
- self._request_id = str(uuid.uuid4())
- self._created_at = time.time()
- self._priority = 0
- self._is_urgent = False
- self._callback: Optional[Callable] = None
- self._completed = False
-
- def addLightState(self, light_id: int, state: LightState) -> "LightsRequest":
- self._light_states[light_id] = state
- return self
-
- def addLightSession(self, session: LightSession) -> "LightsRequest":
- self._light_sessions.append(session)
- return self
-
- def removeLightState(self, light_id: int) -> None:
- self._light_states.pop(light_id, None)
-
- def getLightStates(self) -> Dict[int, LightState]:
- return dict(self._light_states)
-
- def getLightSessions(self) -> List[LightSession]:
- return list(self._light_sessions)
-
- def getRequestId(self) -> str:
- return self._request_id
-
- def getPriority(self) -> int:
- return self._priority
-
- def setPriority(self, priority: int) -> None:
- self._priority = priority
-
- def isUrgent(self) -> bool:
- return self._is_urgent
-
- def setUrgent(self, urgent: bool) -> None:
- self._is_urgent = urgent
-
- def isCompleted(self) -> bool:
- return self._completed
-
- def setCompleted(self, completed: bool) -> None:
- self._completed = completed
-
- def getLightCount(self) -> int:
- return len(self._light_states)
-
- def toString(self) -> str:
- return (
- f"LightsRequest(id={self._request_id[:8]}..., "
- f"lights={len(self._light_states)}, "
- f"sessions={len(self._light_sessions)})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# LightsManager
-# ═══════════════════════════════════════════════════════════════
-
-class LightsManager(Stub):
- """LightsManager — 灯光管理器 (桌面存根)"""
-
- LIGHT_ID_BACKLIGHT = LIGHT_ID_BACKLIGHT
- LIGHT_ID_KEYBOARD = LIGHT_ID_KEYBOARD
- LIGHT_ID_BUTTONS = LIGHT_ID_BUTTONS
- LIGHT_ID_BATTERY = LIGHT_ID_BATTERY
- LIGHT_ID_NOTIFICATIONS = LIGHT_ID_NOTIFICATIONS
- LIGHT_ID_ATTENTION = LIGHT_ID_ATTENTION
- LIGHT_ID_BLUETOOTH = LIGHT_ID_BLUETOOTH
- LIGHT_ID_WIFI = LIGHT_ID_WIFI
- LIGHT_ID_MICROPHONE = LIGHT_ID_MICROPHONE
- LIGHT_ID_CAMERA = LIGHT_ID_CAMERA
- LIGHT_ID_MICROPHONE_MUTE = LIGHT_ID_MICROPHONE_MUTE
- LIGHT_ID_CAMERA_MUTE = LIGHT_ID_CAMERA_MUTE
- LIGHT_ID_POWER = LIGHT_ID_POWER
- LIGHT_ID_ADAPTIVE_BACKLIGHT = LIGHT_ID_ADAPTIVE_BACKLIGHT
- LIGHT_ID_CHARGING = LIGHT_ID_CHARGING
-
- BRIGHTNESS_MIN = BRIGHTNESS_MIN
- BRIGHTNESS_LOW = BRIGHTNESS_LOW
- BRIGHTNESS_MEDIUM = BRIGHTNESS_MEDIUM
- BRIGHTNESS_HIGH = BRIGHTNESS_HIGH
- BRIGHTNESS_MAX = BRIGHTNESS_MAX
- BRIGHTNESS_OFF = BRIGHTNESS_OFF
- BRIGHTNESS_FULL = BRIGHTNESS_FULL
- BRIGHTNESS_DEFAULT = BRIGHTNESS_DEFAULT
-
- LIGHT_TYPE_MANUAL = LIGHT_TYPE_MANUAL
- LIGHT_TYPE_AUTOMATIC = LIGHT_TYPE_AUTOMATIC
- LIGHT_TYPE_MICROPHONE = LIGHT_TYPE_MICROPHONE
- LIGHT_TYPE_CAMERA = LIGHT_TYPE_CAMERA
- LIGHT_TYPE_NOTIFICATION = LIGHT_TYPE_NOTIFICATION
- LIGHT_TYPE_ATTENTION = LIGHT_TYPE_ATTENTION
- LIGHT_TYPE_RGB = LIGHT_TYPE_RGB
- LIGHT_TYPE_ADAPTIVE = LIGHT_TYPE_ADAPTIVE
- LIGHT_TYPE_BLINKING = LIGHT_TYPE_BLINKING
-
- _instance: Optional["LightsManager"] = None
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._lock = threading.Lock()
- self._lights: Dict[int, Light] = {}
- self._sessions: Dict[str, LightSession] = {}
- self._active_requests: List[LightsRequest] = []
- self._default_brightness = 127
- self._max_brightness = 255
- self._min_brightness = 0
- self._lights_available = True
- self._initialize_default_lights()
-
- def _initialize_default_lights(self) -> None:
- default_lights = [
- (LIGHT_ID_BACKLIGHT, "backlight", LIGHT_TYPE_AUTOMATIC),
- (LIGHT_ID_KEYBOARD, "keyboard", LIGHT_TYPE_MANUAL),
- (LIGHT_ID_BUTTONS, "buttons", LIGHT_TYPE_MANUAL),
- (LIGHT_ID_BATTERY, "battery", LIGHT_TYPE_BATTERY),
- (LIGHT_ID_NOTIFICATIONS, "notifications", LIGHT_TYPE_NOTIFICATION),
- (LIGHT_ID_ATTENTION, "attention", LIGHT_TYPE_ATTENTION),
- (LIGHT_ID_BLUETOOTH, "bluetooth", LIGHT_TYPE_MANUAL),
- (LIGHT_ID_WIFI, "wifi", LIGHT_TYPE_MANUAL),
- (LIGHT_ID_MICROPHONE, "microphone", LIGHT_TYPE_MICROPHONE),
- (LIGHT_ID_CAMERA, "camera", LIGHT_TYPE_CAMERA),
- (LIGHT_ID_MICROPHONE_MUTE, "microphone_mute", LIGHT_TYPE_MICROPHONE),
- (LIGHT_ID_CAMERA_MUTE, "camera_mute", LIGHT_TYPE_CAMERA),
- (LIGHT_ID_POWER, "power", LIGHT_TYPE_POWER),
- (LIGHT_ID_ADAPTIVE_BACKLIGHT, "adaptive_backlight", LIGHT_TYPE_ADAPTIVE),
- (LIGHT_ID_CHARGING, "charging", LIGHT_TYPE_BATTERY),
- ]
- for lid, name, ltype in default_lights:
- light = Light(lid, ltype)
- light.setName(name)
- self._lights[lid] = light
-
- def getLight(self, lightId: int) -> Optional[Light]:
- with self._lock:
- return self._lights.get(lightId)
-
- def getLights(self) -> List[Light]:
- with self._lock:
- return list(self._lights.values())
-
- def openSession(self, lightId: int) -> LightSession:
- session = LightSession(lightId)
- with self._lock:
- self._sessions[session.getSessionId()] = session
- return session
-
- def closeSession(self, session: LightSession) -> None:
- with self._lock:
- sid = session.getSessionId()
- if sid in self._sessions:
- session.setActive(False)
- del self._sessions[sid]
-
- def setLightState(self, lightId: int, state: LightState) -> None:
- with self._lock:
- light = self._lights.get(lightId)
- if light:
- light.setCurrentState(state)
-
- def setLightStates(self, states: Dict[int, LightState]) -> None:
- with self._lock:
- for lid, state in states.items():
- light = self._lights.get(lid)
- if light:
- light.setCurrentState(state)
-
- def submitRequest(self, request: LightsRequest) -> None:
- with self._lock:
- self._active_requests.append(request)
- for lid, state in request.getLightStates().items():
- light = self._lights.get(lid)
- if light:
- light.setCurrentState(state)
- for session in request.getLightSessions():
- session.setActive(True)
- self._sessions[session.getSessionId()] = session
- request.setCompleted(True)
-
- def getActiveRequests(self) -> List[LightsRequest]:
- with self._lock:
- return list(self._active_requests)
-
- def getActiveSessions(self, lightId: int) -> List[LightSession]:
- with self._lock:
- return [s for s in self._sessions.values() if s.getLightId() == lightId and s.isActive()]
-
- def getDefaultBrightness(self) -> int:
- return self._default_brightness
-
- def setDefaultBrightness(self, brightness: int) -> None:
- self._default_brightness = max(0, min(255, brightness))
-
- def getMaxBrightness(self) -> int:
- return self._max_brightness
-
- def getMinBrightness(self) -> int:
- return self._min_brightness
-
- def isAvailable(self) -> bool:
- return self._lights_available
-
- def toString(self) -> str:
- with self._lock:
- return (
- f"LightsManager(lights={len(self._lights)}, "
- f"sessions={len(self._sessions)}, "
- f"requests={len(self._active_requests)})"
- )
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_location.py b/android_pyapi/android/hardware_location.py
deleted file mode 100644
index 6ad2450..0000000
--- a/android_pyapi/android/hardware_location.py
+++ /dev/null
@@ -1,848 +0,0 @@
-"""
-Android hardware.location 包 — ContextHubManager, ContextHubClient,
-ContextHubInfo, NanoApp, NanoAppInstanceInfo, NanoAppFilter 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "ContextHubManager", "ContextHubClient", "ContextHubInfo",
- "ContextHubTransaction", "ContextHubIntentEvent",
- "ContextHubService", "ContextHubServiceCallback",
- "NanoApp", "NanoAppInstanceInfo", "NanoAppFilter",
- "NanoAppMessage", "NanoAppRpcService", "NanoAppStateInfo",
- "ContextHubManagerCallback",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-HUB_TYPE_PRIMARY = 0
-HUB_TYPE_SECONDARY = 1
-HUB_TYPE_VIRTUAL = 2
-
-HUB_STATUS_OK = 0
-HUB_STATUS_ERROR = -1
-HUB_STATUS_TIMEOUT = -2
-HUB_STATUS_BUSY = -3
-HUB_STATUS_NOT_FOUND = -4
-HUB_STATUS_INVALID_PARAM = -5
-HUB_STATUS_UNSUPPORTED = -6
-HUB_STATUS_DISABLED = -7
-HUB_STATUS_RESTARTING = -8
-HUB_STATUS_LOW_POWER = -9
-
-TRANSACTION_SUCCESS = 0
-TRANSACTION_FAILURE = -1
-TRANSACTION_PENDING = 1
-TRANSACTION_CANCELLED = -2
-
-TRANSACTION_TYPE_LOAD_NANOAPP = 0
-TRANSACTION_TYPE_UNLOAD_NANOAPP = 1
-TRANSACTION_TYPE_QUERY_NANOAPPS = 2
-TRANSACTION_TYPE_QUERY_MEMORY = 3
-TRANSACTION_TYPE_RESET_HUB = 4
-TRANSACTION_TYPE_ENABLE_NANOAPP = 5
-TRANSACTION_TYPE_DISABLE_NANOAPP = 6
-TRANSACTION_TYPE_QUERY_NANOAPP_DETAILS = 7
-TRANSACTION_TYPE_CONFIGURE_HUB = 8
-TRANSACTION_TYPE_SET_NANOAPP_LOADED = 9
-
-NANOAPP_STATE_NOT_LOADED = 0
-NANOAPP_STATE_LOADING = 1
-NANOAPP_STATE_LOADED = 2
-NANOAPP_STATE_UNLOADING = 3
-NANOAPP_STATE_RUNNING = 4
-NANOAPP_STATE_SUSPENDED = 5
-NANOAPP_STATE_ERROR = 6
-NANOAPP_STATE_STOPPED = 7
-NANOAPP_STATE_CRASHED = 8
-
-NANOAPP_FLAG_ENABLED = 1
-NANOAPP_FLAG_DISABLED = 2
-NANOAPP_FLAG_SYSTEM = 4
-NANOAPP_FLAG_VENDOR = 8
-NANOAPP_FLAG_SIGNED = 16
-NANOAPP_FLAG_DEBUG = 32
-
-NANOAPP_TYPE_ANY = -1
-NANOAPP_TYPE_SENSOR = 0
-NANOAPP_TYPE_AUDIO = 1
-NANOAPP_TYPE_LOCATION = 2
-NANOAPP_TYPE_ACTIVITY = 3
-NANOAPP_TYPE_CONTEXT = 4
-NANOAPP_TYPE_COMMUNICATION = 5
-NANOAPP_TYPE_SECURITY = 6
-NANOAPP_TYPE_CUSTOM = 100
-
-
-# ═══════════════════════════════════════════════════════════════
-# NanoApp
-# ═══════════════════════════════════════════════════════════════
-
-class NanoApp(Stub):
- """NanoApp — Nano 应用程序"""
-
- def __init__(self, id: int = 0, name: str = "", vendor: str = "",
- version: int = 1, size: int = 0,
- type_: int = NANOAPP_TYPE_CUSTOM,
- binary: bytes = b"",
- flags: int = 0, description: str = ""):
- super().__init__()
- self._id = id
- self._name = name
- self._vendor = vendor
- self._version = version
- self._size = size if size > 0 else len(binary)
- self._type = type_
- self._binary = binary
- self._flags = flags
- self._description = description
-
- def getId(self) -> int:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getVendor(self) -> str:
- return self._vendor
-
- def getVersion(self) -> int:
- return self._version
-
- def getSize(self) -> int:
- return self._size
-
- def getType(self) -> int:
- return self._type
-
- def getBinary(self) -> bytes:
- return self._binary
-
- def getFlags(self) -> int:
- return self._flags
-
- def getDescription(self) -> str:
- return self._description
-
- def toString(self) -> str:
- return f"NanoApp(id={self._id}, name={self._name}, version={self._version})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, NanoApp):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# NanoAppMessage
-# ═══════════════════════════════════════════════════════════════
-
-class NanoAppMessage(Stub):
- """NanoAppMessage — NanoApp 消息"""
-
- def __init__(self, nanoAppId: int = 0, messageType: int = 0,
- data: bytes = b"", isReliable: bool = False,
- isSequenced: bool = True):
- super().__init__()
- self._nano_app_id = nanoAppId
- self._message_type = messageType
- self._data = data
- self._is_reliable = isReliable
- self._is_sequenced = isSequenced
-
- def getNanoAppId(self) -> int:
- return self._nano_app_id
-
- def getMessageType(self) -> int:
- return self._message_type
-
- def getData(self) -> bytes:
- return self._data
-
- def isReliable(self) -> bool:
- return self._is_reliable
-
- def isSequenced(self) -> bool:
- return self._is_sequenced
-
- def toString(self) -> str:
- return f"NanoAppMessage(appId={self._nano_app_id}, type={self._message_type})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, NanoAppMessage):
- return False
- return self._nano_app_id == other._nano_app_id and self._message_type == other._message_type
-
- def hashCode(self) -> int:
- return hash((self._nano_app_id, self._message_type)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# NanoAppInstanceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class NanoAppInstanceInfo(Stub):
- """NanoAppInstanceInfo — NanoApp 实例信息"""
-
- def __init__(self, id: int = 0, name: str = "", vendor: str = "",
- version: int = 1, state: int = NANOAPP_STATE_NOT_LOADED,
- type_: int = NANOAPP_TYPE_CUSTOM,
- flags: int = 0, memUsage: int = 0,
- handle: int = 0, isEnabled: bool = True):
- super().__init__()
- self._id = id
- self._name = name
- self._vendor = vendor
- self._version = version
- self._state = state
- self._type = type_
- self._flags = flags
- self._mem_usage = memUsage
- self._handle = handle
- self._is_enabled = isEnabled
-
- def getId(self) -> int:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getVendor(self) -> str:
- return self._vendor
-
- def getVersion(self) -> int:
- return self._version
-
- def getState(self) -> int:
- return self._state
-
- def getType(self) -> int:
- return self._type
-
- def getFlags(self) -> int:
- return self._flags
-
- def getMemUsage(self) -> int:
- return self._mem_usage
-
- def getHandle(self) -> int:
- return self._handle
-
- def isEnabled(self) -> bool:
- return self._is_enabled
-
- def toString(self) -> str:
- return f"NanoAppInstanceInfo(id={self._id}, name={self._name}, state={self._state})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, NanoAppInstanceInfo):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# NanoAppFilter
-# ═══════════════════════════════════════════════════════════════
-
-class NanoAppFilter(Stub):
- """NanoAppFilter — NanoApp 过滤器"""
-
- def __init__(self, nanoAppId: int = -1, type_: int = NANOAPP_TYPE_ANY,
- vendor: str = "", name: str = "",
- minVersion: int = 0, maxVersion: int = -1,
- flags: int = 0):
- super().__init__()
- self._nano_app_id = nanoAppId
- self._type = type_
- self._vendor = vendor
- self._name = name
- self._min_version = minVersion
- self._max_version = maxVersion
- self._flags = flags
-
- def getNanoAppId(self) -> int:
- return self._nano_app_id
-
- def getType(self) -> int:
- return self._type
-
- def getVendor(self) -> str:
- return self._vendor
-
- def getName(self) -> str:
- return self._name
-
- def getMinVersion(self) -> int:
- return self._min_version
-
- def getMaxVersion(self) -> int:
- return self._max_version
-
- def getFlags(self) -> int:
- return self._flags
-
- def matches(self, info: NanoAppInstanceInfo) -> bool:
- if self._nano_app_id != -1 and info.getId() != self._nano_app_id:
- return False
- if self._type != NANOAPP_TYPE_ANY and info.getType() != self._type:
- return False
- if self._vendor and self._vendor != info.getVendor():
- return False
- return True
-
- class Builder(Stub):
- """NanoAppFilter.Builder — 过滤器构建器"""
-
- def __init__(self):
- super().__init__()
- self._nano_app_id = -1
- self._type = NANOAPP_TYPE_ANY
- self._vendor = ""
- self._name = ""
- self._min_version = 0
- self._max_version = -1
- self._flags = 0
-
- def setNanoAppId(self, id: int) -> "NanoAppFilter.Builder":
- self._nano_app_id = id
- return self
-
- def setType(self, type_: int) -> "NanoAppFilter.Builder":
- self._type = type_
- return self
-
- def setVendor(self, vendor: str) -> "NanoAppFilter.Builder":
- self._vendor = vendor
- return self
-
- def build(self) -> "NanoAppFilter":
- return NanoAppFilter(
- nanoAppId=self._nano_app_id, type_=self._type,
- vendor=self._vendor, name=self._name,
- minVersion=self._min_version, maxVersion=self._max_version,
- flags=self._flags,
- )
-
- def toString(self) -> str:
- return f"NanoAppFilter(id={self._nano_app_id}, type={self._type})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, NanoAppFilter):
- return False
- return (self._nano_app_id == other._nano_app_id and
- self._type == other._type)
-
- def hashCode(self) -> int:
- return hash((self._nano_app_id, self._type)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# NanoAppRpcService
-# ═══════════════════════════════════════════════════════════════
-
-class NanoAppRpcService(Stub):
- """NanoAppRpcService — NanoApp RPC 服务"""
-
- def __init__(self, id: int = 0, name: str = "", version: int = 1,
- description: str = "", methods: List[str] = None):
- super().__init__()
- self._id = id
- self._name = name
- self._version = version
- self._description = description
- self._methods = methods or []
-
- def getId(self) -> int:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getVersion(self) -> int:
- return self._version
-
- def getDescription(self) -> str:
- return self._description
-
- def getMethods(self) -> List[str]:
- return list(self._methods)
-
- def toString(self) -> str:
- return f"NanoAppRpcService(id={self._id}, name={self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NanoAppStateInfo
-# ═══════════════════════════════════════════════════════════════
-
-class NanoAppStateInfo(Stub):
- """NanoAppStateInfo — NanoApp 状态信息"""
-
- def __init__(self, nanoAppId: int = 0, state: int = NANOAPP_STATE_NOT_LOADED,
- isEnabled: bool = False, memUsage: int = 0,
- uptimeMs: int = 0, lastError: int = 0,
- errorMessage: str = ""):
- super().__init__()
- self._nano_app_id = nanoAppId
- self._state = state
- self._is_enabled = isEnabled
- self._mem_usage = memUsage
- self._uptime_ms = uptimeMs
- self._last_error = lastError
- self._error_message = errorMessage
-
- def getNanoAppId(self) -> int:
- return self._nano_app_id
-
- def getState(self) -> int:
- return self._state
-
- def isEnabled(self) -> bool:
- return self._is_enabled
-
- def getMemUsage(self) -> int:
- return self._mem_usage
-
- def getUptimeMs(self) -> int:
- return self._uptime_ms
-
- def getLastError(self) -> int:
- return self._last_error
-
- def getErrorMessage(self) -> str:
- return self._error_message
-
- def toString(self) -> str:
- return f"NanoAppStateInfo(id={self._nano_app_id}, state={self._state})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContextHubInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ContextHubInfo(Stub):
- """ContextHubInfo — 上下文 Hub 信息"""
-
- def __init__(self, id: int = 0, name: str = "",
- vendor: str = "", version: int = 1,
- type_: int = HUB_TYPE_PRIMARY,
- maxSensors: int = 32, maxNanoApps: int = 16,
- memorySize: int = 256 * 1024,
- supportedSensors: List[int] = None,
- isAvailable: bool = True):
- super().__init__()
- self._id = id
- self._name = name
- self._vendor = vendor
- self._version = version
- self._type = type_
- self._max_sensors = maxSensors
- self._max_nano_apps = maxNanoApps
- self._memory_size = memorySize
- self._supported_sensors = supportedSensors or []
- self._is_available = isAvailable
-
- def getId(self) -> int:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getVendor(self) -> str:
- return self._vendor
-
- def getVersion(self) -> int:
- return self._version
-
- def getHubType(self) -> int:
- return self._type
-
- def getMaxSensors(self) -> int:
- return self._max_sensors
-
- def getMaxNanoApps(self) -> int:
- return self._max_nano_apps
-
- def getMemorySize(self) -> int:
- return self._memory_size
-
- def getSupportedSensors(self) -> List[int]:
- return list(self._supported_sensors)
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def toString(self) -> str:
- return f"ContextHubInfo(id={self._id}, name={self._name})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, ContextHubInfo):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContextHubTransaction
-# ═══════════════════════════════════════════════════════════════
-
-class ContextHubTransaction(Stub):
- """ContextHubTransaction — ContextHub 事务"""
-
- def __init__(self, id: int = 0, type_: int = TRANSACTION_TYPE_QUERY_NANOAPPS,
- status: int = TRANSACTION_PENDING,
- result: Any = None):
- super().__init__()
- self._id = id
- self._type = type_
- self._status = status
- self._result = result
-
- def getId(self) -> int:
- return self._id
-
- def getType(self) -> int:
- return self._type
-
- def getStatus(self) -> int:
- return self._status
-
- def getResult(self) -> Any:
- return self._result
-
- def setResult(self, result: Any):
- self._result = result
-
- def waitForResult(self, timeoutMs: int = 0) -> Any:
- return self._result
-
- def cancel(self):
- self._status = TRANSACTION_CANCELLED
-
- def toString(self) -> str:
- return f"ContextHubTransaction(id={self._id}, type={self._type}, status={self._status})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, ContextHubTransaction):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContextHubIntentEvent
-# ═══════════════════════════════════════════════════════════════
-
-class ContextHubIntentEvent(Stub):
- """ContextHubIntentEvent — ContextHub 意图事件"""
-
- EVENT_HUB_RESTARTED = 0
- EVENT_HUB_ERROR = 1
- EVENT_NANOAPP_LOADED = 2
- EVENT_NANOAPP_UNLOADED = 3
- EVENT_NANOAPP_STARTED = 4
- EVENT_NANOAPP_STOPPED = 5
- EVENT_NANOAPP_ERROR = 6
- EVENT_NANOAPP_MESSAGE = 7
- EVENT_NANOAPP_CRASHED = 8
-
- def __init__(self, eventType: int = EVENT_HUB_RESTARTED,
- hubId: int = 0, nanoAppId: int = 0,
- timestamp: int = 0, data: bytes = b""):
- super().__init__()
- self._event_type = eventType
- self._hub_id = hubId
- self._nano_app_id = nanoAppId
- self._timestamp = timestamp
- self._data = data
-
- def getEventType(self) -> int:
- return self._event_type
-
- def getHubId(self) -> int:
- return self._hub_id
-
- def getNanoAppId(self) -> int:
- return self._nano_app_id
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def getData(self) -> bytes:
- return self._data
-
- def toString(self) -> str:
- return f"ContextHubIntentEvent(type={self._event_type}, hub={self._hub_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContextHubManagerCallback
-# ═══════════════════════════════════════════════════════════════
-
-class ContextHubManagerCallback(Stub):
- """ContextHubManagerCallback — ContextHub 管理器回调"""
-
- def onHubStarted(self, hubInfo: ContextHubInfo):
- pass
-
- def onHubStopped(self, hubInfo: ContextHubInfo):
- pass
-
- def onHubError(self, hubInfo: ContextHubInfo, errorCode: int):
- pass
-
- def onNanoAppLoaded(self, hubId: int, nanoAppId: int):
- pass
-
- def onNanoAppUnloaded(self, hubId: int, nanoAppId: int):
- pass
-
- def onNanoAppStarted(self, hubId: int, nanoAppId: int):
- pass
-
- def onNanoAppStopped(self, hubId: int, nanoAppId: int):
- pass
-
- def onNanoAppCrashed(self, hubId: int, nanoAppId: int):
- pass
-
- def onNanoAppMessage(self, hubId: int, message: NanoAppMessage):
- pass
-
- def toString(self) -> str:
- return f"ContextHubManagerCallback@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContextHubClient
-# ═══════════════════════════════════════════════════════════════
-
-class ContextHubClient(Stub):
- """ContextHubClient — ContextHub 客户端"""
-
- def __init__(self, hubInfo: Optional[ContextHubInfo] = None,
- callback: Optional[ContextHubManagerCallback] = None):
- super().__init__()
- self._hub_info = hubInfo
- self._callback = callback
-
- def getHubInfo(self) -> Optional[ContextHubInfo]:
- return self._hub_info
-
- def sendMessageToNanoApp(self, nanoAppId: int, message: NanoAppMessage) -> int:
- return TRANSACTION_SUCCESS
-
- def sendMessageToHub(self, message: NanoAppMessage) -> int:
- return TRANSACTION_SUCCESS
-
- def requestNanoAppState(self, nanoAppId: int) -> Optional[NanoAppStateInfo]:
- return None
-
- def enableNanoApp(self, nanoAppId: int) -> int:
- return TRANSACTION_SUCCESS
-
- def disableNanoApp(self, nanoAppId: int) -> int:
- return TRANSACTION_SUCCESS
-
- def close(self):
- pass
-
- def setCallback(self, callback: ContextHubManagerCallback):
- self._callback = callback
-
- def getCallback(self) -> Optional[ContextHubManagerCallback]:
- return self._callback
-
- def toString(self) -> str:
- return f"ContextHubClient(hub={self._hub_info})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContextHubService / ContextHubServiceCallback
-# ═══════════════════════════════════════════════════════════════
-
-class ContextHubService(Stub):
- """ContextHubService — ContextHub 服务"""
-
- SERVICE_NAME = "contexthub"
-
- def __init__(self):
- super().__init__()
-
- def startHub(self, hubInfo: ContextHubInfo) -> int:
- return TRANSACTION_SUCCESS
-
- def stopHub(self, hubInfo: ContextHubInfo) -> int:
- return TRANSACTION_SUCCESS
-
- def resetHub(self, hubInfo: ContextHubInfo) -> int:
- return TRANSACTION_SUCCESS
-
- def configureHub(self, hubInfo: ContextHubInfo, config: bytes) -> int:
- return TRANSACTION_SUCCESS
-
- def toString(self) -> str:
- return "ContextHubService()"
-
-
-class ContextHubServiceCallback(Stub):
- """ContextHubServiceCallback — ContextHub 服务回调"""
-
- def onHubStarted(self, hubId: int):
- pass
-
- def onHubStopped(self, hubId: int):
- pass
-
- def onHubReset(self, hubId: int):
- pass
-
- def onHubError(self, hubId: int, errorCode: int):
- pass
-
- def toString(self) -> str:
- return f"ContextHubServiceCallback@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContextHubManager
-# ═══════════════════════════════════════════════════════════════
-
-class ContextHubManager(Stub):
- """ContextHubManager — ContextHub 管理器"""
-
- def __init__(self):
- super().__init__()
- self._hubs: Dict[int, ContextHubInfo] = {}
- self._clients: Dict[int, ContextHubClient] = {}
- self._callbacks: Dict[int, ContextHubManagerCallback] = {}
-
- def getHubs(self, filter_: Optional[NanoAppFilter] = None) -> List[ContextHubInfo]:
- if filter_ is None:
- return list(self._hubs.values())
- return [h for h in self._hubs.values() if h.getId() == filter_.getNanoAppId()]
-
- def createClient(self, hubInfo: ContextHubInfo,
- callback: ContextHubManagerCallback) -> ContextHubClient:
- client = ContextHubClient(hubInfo=hubInfo, callback=callback)
- cid = id(client)
- self._clients[cid] = client
- if callback:
- cb_id = id(callback)
- self._callbacks[cb_id] = callback
- return client
-
- def destroyClient(self, client: ContextHubClient):
- cid = id(client)
- self._clients.pop(cid, None)
- cb = client.getCallback()
- if cb:
- self._callbacks.pop(id(cb), None)
-
- def registerCallback(self, hubInfo: ContextHubInfo,
- callback: ContextHubManagerCallback):
- cb_id = id(callback)
- self._callbacks[cb_id] = callback
-
- def unregisterCallback(self, hubInfo: ContextHubInfo,
- callback: ContextHubManagerCallback):
- cb_id = id(callback)
- self._callbacks.pop(cb_id, None)
-
- def loadNanoApp(self, hubInfo: ContextHubInfo, nanoApp: NanoApp) -> ContextHubTransaction:
- tx = ContextHubTransaction(type_=TRANSACTION_TYPE_LOAD_NANOAPP)
- tx.setResult(TRANSACTION_SUCCESS)
- return tx
-
- def unloadNanoApp(self, hubInfo: ContextHubInfo, nanoAppId: int) -> ContextHubTransaction:
- tx = ContextHubTransaction(type_=TRANSACTION_TYPE_UNLOAD_NANOAPP)
- tx.setResult(TRANSACTION_SUCCESS)
- return tx
-
- def queryNanoApps(self, hubInfo: ContextHubInfo) -> ContextHubTransaction:
- tx = ContextHubTransaction(type_=TRANSACTION_TYPE_QUERY_NANOAPPS)
- tx.setResult([])
- return tx
-
- def queryNanoAppDetails(self, hubInfo: ContextHubInfo, nanoAppId: int) -> ContextHubTransaction:
- tx = ContextHubTransaction(type_=TRANSACTION_TYPE_QUERY_NANOAPP_DETAILS)
- tx.setResult(NanoAppInstanceInfo(id=nanoAppId))
- return tx
-
- def queryHubMemory(self, hubInfo: ContextHubInfo) -> ContextHubTransaction:
- tx = ContextHubTransaction(type_=TRANSACTION_TYPE_QUERY_MEMORY)
- tx.setResult({"total": 262144, "free": 131072})
- return tx
-
- def resetHub(self, hubInfo: ContextHubInfo) -> ContextHubTransaction:
- tx = ContextHubTransaction(type_=TRANSACTION_TYPE_RESET_HUB)
- tx.setResult(TRANSACTION_SUCCESS)
- return tx
-
- def enableNanoApp(self, hubInfo: ContextHubInfo, nanoAppId: int) -> int:
- return TRANSACTION_SUCCESS
-
- def disableNanoApp(self, hubInfo: ContextHubInfo, nanoAppId: int) -> int:
- return TRANSACTION_SUCCESS
-
- def findNanoAppByFilter(self, filter_: NanoAppFilter) -> List[NanoAppInstanceInfo]:
- return []
-
- def getNanoAppInstanceInfo(self, hubInfo: ContextHubInfo,
- nanoAppId: int) -> Optional[NanoAppInstanceInfo]:
- return None
-
- def addHub(self, hubInfo: ContextHubInfo):
- self._hubs[hubInfo.getId()] = hubInfo
-
- def removeHub(self, hubId: int):
- self._hubs.pop(hubId, None)
-
- def toString(self) -> str:
- return f"ContextHubManager(hubs={len(self._hubs)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_radio.py b/android_pyapi/android/hardware_radio.py
deleted file mode 100644
index b365a41..0000000
--- a/android_pyapi/android/hardware_radio.py
+++ /dev/null
@@ -1,417 +0,0 @@
-"""
-Android hardware.radio 组件 — RadioManager, RadioTuner, RadioMetadata 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# RadioMetadata
-# ═══════════════════════════════════════════════════════════════
-
-class RadioMetadata(Stub):
- """RadioMetadata — 收音机元数据"""
-
- METADATA_KEY_ART = 0x00000001
- METADATA_KEY_ARTIST = 0x00000002
- METADATA_KEY_TITLE = 0x00000003
- METADATA_KEY_ALBUM = 0x00000004
- METADATA_KEY_GENRE = 0x00000005
- METADATA_KEY_CLOCK = 0x00000006
- METADATA_KEY_ICON = 0x00000007
- METADATA_KEY_RDS_PI = 0x00000008
- METADATA_KEY_RDS_PS = 0x00000009
- METADATA_KEY_RDS_RT = 0x0000000A
- METADATA_KEY_DAB_ENSEMBLE_NAME = 0x0000000B
- METADATA_KEY_DAB_ECC = 0x0000000C
- METADATA_KEY_DAB_IDENTIFIER = 0x0000000D
- METADATA_KEY_DAB_SERVICE_NAME = 0x0000000E
-
- def __init__(self):
- super().__init__()
- self._data: Dict[int, Any] = {}
-
- def getString(self, key: int) -> Optional[str]:
- val = self._data.get(key)
- return str(val) if val is not None else None
-
- def getInt(self, key: int) -> int:
- return int(self._data.get(key, 0))
-
- def getLong(self, key: int) -> int:
- return int(self._data.get(key, 0))
-
- def getBitmap(self, key: int) -> Any:
- return self._data.get(key)
-
- def getText(self, key: int) -> Optional[str]:
- return self.getString(key)
-
- def containsKey(self, key: int) -> bool:
- return key in self._data
-
- def keySet(self) -> Set[int]:
- return set(self._data.keys())
-
- def putString(self, key: int, value: str):
- self._data[key] = value
-
- def putInt(self, key: int, value: int):
- self._data[key] = value
-
- def toString(self) -> str:
- return f"RadioMetadata{{{len(self._data)} entries}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RadioManager.ProgramInfo
-# ═══════════════════════════════════════════════════════════════
-
-class RadioManager:
- """RadioManager — 收音机管理器(命名空间)"""
-
- STATUS_SUCCESS = 0
- STATUS_ERROR = -1
- STATUS_INVALID_ARGUMENTS = -2
- STATUS_INVALID_OPERATION = -3
- STATUS_NO_ENTRY = -4
- STATUS_PERMISSION_DENIED = -5
- STATUS_NOT_SUPPORTED = -6
- STATUS_NOT_INITIALIZED = -7
- STATUS_BUSY = -8
- STATUS_TIMED_OUT = -9
- STATUS_DEAD_OBJECT = -10
-
-
-class RadioManager_ProgramInfo(Stub):
- """RadioManager.ProgramInfo — 节目信息"""
-
- INFO_TYPE_MIN = 0
- INFO_TYPE_MAX = 1
-
- def __init__(self):
- super().__init__()
- self._metadata = RadioMetadata()
- self._info_type: int = 0
- self._channel: int = 0
- self._tuning_frequency: int = 0
- self._program_type: int = 0
- self._digital: bool = False
- self._emergency: bool = False
- self._traffic: bool = False
- self._music: bool = False
- self._news: bool = False
- self._talk: bool = False
- self._sport: bool = False
- self._weather: bool = False
- self._classical: bool = False
-
- def getRadioMetadata(self) -> RadioMetadata:
- return self._metadata
-
- def getInfoType(self) -> int:
- return self._info_type
-
- def getChannel(self) -> int:
- return self._channel
-
- def getTuningFrequency(self) -> int:
- return self._tuning_frequency
-
- def getProgramType(self) -> int:
- return self._program_type
-
- def isDigital(self) -> bool:
- return self._digital
-
- def isEmergency(self) -> bool:
- return self._emergency
-
- def isTraffic(self) -> bool:
- return self._traffic
-
- def isMusic(self) -> bool:
- return self._music
-
- def isNews(self) -> bool:
- return self._news
-
- def isTalk(self) -> bool:
- return self._talk
-
- def isSport(self) -> bool:
- return self._sport
-
- def isWeather(self) -> bool:
- return self._weather
-
- def isClassical(self) -> bool:
- return self._classical
-
- def toString(self) -> str:
- return f"ProgramInfo{{channel={self._channel}, digital={self._digital}}}"
-
-
-RadioManager.ProgramInfo = RadioManager_ProgramInfo
-
-
-# ═══════════════════════════════════════════════════════════════
-# RadioManager.ModuleProperties
-# ═══════════════════════════════════════════════════════════════
-
-class RadioManager_ModuleProperties(Stub):
- """RadioManager.ModuleProperties — 模块属性"""
-
- def __init__(self, id_: int = 0, service_name: str = "radio",
- class_id: int = 0, implementor: str = "Android-pyApi",
- hal_version: int = 2,
- supported_program_types: Optional[List[int]] = None,
- supported_sound_bands: Optional[List[int]] = None,
- supported_deemphasis: Optional[List[int]] = None,
- supported_regions: Optional[List[int]] = None,
- min_freq: int = 87500, max_freq: int = 108000,
- freq_step: int = 100):
- super().__init__()
- self._id = id_
- self._service_name = service_name
- self._class_id = class_id
- self._implementor = implementor
- self._hal_version = hal_version
- self._supported_program_types = supported_program_types or [0, 1]
- self._supported_sound_bands = supported_sound_bands or [0]
- self._supported_deemphasis = supported_deemphasis or [50]
- self._supported_regions = supported_regions or [0]
- self._min_freq = min_freq
- self._max_freq = max_freq
- self._freq_step = freq_step
- self._vendor_info: Dict[str, str] = {}
- self._initialization_complete: bool = True
- self._bg_scan_available: bool = True
- self._program_info_available: bool = True
- self._antenna_connected: bool = True
-
- def getId(self) -> int:
- return self._id
-
- def getServiceName(self) -> str:
- return self._service_name
-
- def getClassId(self) -> int:
- return self._class_id
-
- def getImplementor(self) -> str:
- return self._implementor
-
- def getHALVersion(self) -> int:
- return self._hal_version
-
- def getSupportedProgramTypes(self) -> List[int]:
- return list(self._supported_program_types)
-
- def getSupportedSoundBands(self) -> List[int]:
- return list(self._supported_sound_bands)
-
- def getSupportedDeemphasis(self) -> List[int]:
- return list(self._supported_deemphasis)
-
- def getSupportedRegions(self) -> List[int]:
- return list(self._supported_regions)
-
- def getMinTuningFrequency(self) -> int:
- return self._min_freq
-
- def getMaxTuningFrequency(self) -> int:
- return self._max_freq
-
- def getTuningFrequencyStep(self) -> int:
- return self._freq_step
-
- def getVendorInfo(self) -> Dict[str, str]:
- return dict(self._vendor_info)
-
- def isInitializationComplete(self) -> bool:
- return self._initialization_complete
-
- def isBgScanAvailable(self) -> bool:
- return self._bg_scan_available
-
- def isProgramInfoAvailable(self) -> bool:
- return self._program_info_available
-
- def isAntennaConnected(self) -> bool:
- return self._antenna_connected
-
- def toString(self) -> str:
- return f"ModuleProperties{{id={self._id}, name={self._service_name}}}"
-
-
-RadioManager.ModuleProperties = RadioManager_ModuleProperties
-
-
-# ═══════════════════════════════════════════════════════════════
-# RadioTuner
-# ═══════════════════════════════════════════════════════════════
-
-class RadioTuner(Stub):
- """RadioTuner — 收音机调谐器"""
-
- DIRECTION_DOWN = 0
- DIRECTION_UP = 1
-
- def __init__(self):
- super().__init__()
- self._frequency: int = 100000 # 100 MHz
- self._muted: bool = False
- self._configuration: Optional[Dict[str, Any]] = None
-
- def scan(self, direction: int, skipSubChannel: bool = False) -> int:
- step = 100 if direction == self.DIRECTION_UP else -100
- self._frequency += step
- return RadioManager.STATUS_SUCCESS
-
- def step(self, direction: int, skipSubChannel: bool = False) -> int:
- return self.scan(direction, skipSubChannel)
-
- def tune(self, frequency: int, programType: int = -1) -> int:
- self._frequency = frequency
- return RadioManager.STATUS_SUCCESS
-
- def cancel(self) -> int:
- return RadioManager.STATUS_SUCCESS
-
- def cancelAnnouncement(self) -> int:
- return RadioManager.STATUS_SUCCESS
-
- def getConfiguration(self) -> Optional[Dict[str, Any]]:
- return self._configuration
-
- def setConfiguration(self, configuration: Dict[str, Any]) -> int:
- self._configuration = dict(configuration)
- return RadioManager.STATUS_SUCCESS
-
- def getMute(self) -> bool:
- return self._muted
-
- def setMute(self, mute: bool) -> int:
- self._muted = mute
- return RadioManager.STATUS_SUCCESS
-
- def getProgramInformation(self, fullInfo: bool = True) -> Optional[RadioManager.ProgramInfo]:
- info = RadioManager.ProgramInfo()
- info._tuning_frequency = self._frequency
- return info
-
- def isAntennaConnected(self) -> bool:
- return True
-
- def hasControl(self) -> bool:
- return True
-
- def getParameters(self, keys: List[str]) -> Dict[str, str]:
- return {}
-
- def setParameters(self, parameters: Dict[str, str]) -> int:
- return RadioManager.STATUS_SUCCESS
-
- def close(self):
- pass
-
- def toString(self) -> str:
- return f"RadioTuner{{frequency={self._frequency}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RadioManager (main class)
-# ═══════════════════════════════════════════════════════════════
-
-class RadioManager(Stub):
- """RadioManager — 收音机管理器"""
-
- STATUS_SUCCESS = 0
- STATUS_ERROR = -1
- STATUS_INVALID_ARGUMENTS = -2
- STATUS_INVALID_OPERATION = -3
- STATUS_NO_ENTRY = -4
- STATUS_PERMISSION_DENIED = -5
- STATUS_NOT_SUPPORTED = -6
- STATUS_NOT_INITIALIZED = -7
- STATUS_BUSY = -8
- STATUS_TIMED_OUT = -9
- STATUS_DEAD_OBJECT = -10
-
- def __init__(self):
- super().__init__()
- self._lock = threading.Lock()
- self._modules: List[RadioManager.ModuleProperties] = [
- RadioManager.ModuleProperties(id_=0, service_name="FM Radio"),
- ]
- self._tuner: Optional[RadioTuner] = None
- self._enabled: bool = False
- self._callbacks: List[Any] = []
-
- def listModules(self, modules: List[Any]) -> int:
- modules.clear()
- modules.extend(self._modules)
- return self.STATUS_SUCCESS
-
- def open(self, moduleId: int, tunerCallback: Any) -> Optional[RadioTuner]:
- self._tuner = RadioTuner()
- return self._tuner
-
- def close(self, tuner: RadioTuner):
- tuner.close()
- self._tuner = None
-
- def getModuleProperties(self, moduleId: int) -> Optional[RadioManager.ModuleProperties]:
- for m in self._modules:
- if m.getId() == moduleId:
- return m
- return None
-
- def getParameters(self, moduleId: int, keys: List[str]) -> Dict[str, str]:
- return {}
-
- def setParameters(self, moduleId: int, parameters: Dict[str, str]) -> int:
- return self.STATUS_SUCCESS
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def registerCallback(self, callback: Any, handler: Any = None) -> int:
- if callback not in self._callbacks:
- self._callbacks.append(callback)
- return self.STATUS_SUCCESS
-
- def unregisterCallback(self, callback: Any) -> int:
- if callback in self._callbacks:
- self._callbacks.remove(callback)
- return self.STATUS_SUCCESS
-
- def registerClient(self, packageName: str, callback: Any) -> int:
- return self.STATUS_SUCCESS
-
- def unregisterClient(self, packageName: str) -> int:
- return self.STATUS_SUCCESS
-
- def toString(self) -> str:
- return f"RadioManager@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "RadioManager",
- "RadioTuner",
- "RadioMetadata",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_sensor_ext.py b/android_pyapi/android/hardware_sensor_ext.py
deleted file mode 100644
index 651b3d8..0000000
--- a/android_pyapi/android/hardware_sensor_ext.py
+++ /dev/null
@@ -1,831 +0,0 @@
-"""
-Android hardware sensor 扩展组件 — Sensor (扩展), SensorEvent,
-SensorDirectChannel, SensorPrivacyManager, SensorOffload,
-SensorRequest 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import time
-import random
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from .hardware import SensorManager as _BaseSensorManager
-from .hardware import Sensor as _BaseSensor
-from .hardware import SensorEvent as _BaseSensorEvent
-from .hardware import SensorEventListener as _BaseSensorEventListener
-
-__all__ = [
- "Sensor", "SensorEvent", "SensorEventListener",
- "SensorManager", "SensorDirectChannel",
- "SensorDirectChannelConfig", "SensorPrivacyManager",
- "SensorAvailability", "SensorAdditionalInfo",
- "SensorDynamicSensorCallback", "SensorOffload",
- "SensorOffloadSession", "SensorRequest",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 传感器常量
-# ═══════════════════════════════════════════════════════════════
-
-TYPE_ACCELEROMETER = 1
-TYPE_MAGNETIC_FIELD = 2
-TYPE_ORIENTATION = 3
-TYPE_GYROSCOPE = 4
-TYPE_LIGHT = 5
-TYPE_PRESSURE = 6
-TYPE_TEMPERATURE = 7
-TYPE_PROXIMITY = 8
-TYPE_GRAVITY = 9
-TYPE_LINEAR_ACCELERATION = 10
-TYPE_ROTATION_VECTOR = 11
-TYPE_RELATIVE_HUMIDITY = 12
-TYPE_AMBIENT_TEMPERATURE = 13
-TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14
-TYPE_GAME_ROTATION_VECTOR = 15
-TYPE_GYROSCOPE_UNCALIBRATED = 16
-TYPE_SIGNIFICANT_MOTION = 17
-TYPE_STEP_DETECTOR = 18
-TYPE_STEP_COUNTER = 19
-TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20
-TYPE_HEART_RATE = 21
-TYPE_TILT_DETECTOR = 22
-TYPE_WAKE_GESTURE = 23
-TYPE_GLANCE_GESTURE = 24
-TYPE_PICK_UP_GESTURE = 25
-TYPE_WRIST_TILT_GESTURE = 26
-TYPE_DEVICE_ORIENTATION = 27
-TYPE_STATIONARY_DETECT = 28
-TYPE_POSE_6DOF = 28
-TYPE_STATIONARY_DETECT_EXT = 29
-TYPE_MOTION_DETECT = 30
-TYPE_HEART_BEAT = 31
-TYPE_LOW_LATENCY_OFFBODY_DETECT = 34
-TYPE_ACCELEROMETER_LIMITED_AXES = 35
-TYPE_GYROSCOPE_LIMITED_AXES = 36
-TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 37
-TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 38
-TYPE_HEAD_TRACKER = 39
-TYPE_ACCELEROMETER_UNCALIBRATED = 40
-TYPE_HINGE_ANGLE = 41
-
-REPORTING_MODE_CONTINUOUS = 0
-REPORTING_MODE_ON_CHANGE = 1
-REPORTING_MODE_ONE_SHOT = 2
-REPORTING_MODE_SPECIAL_TRIGGER = 3
-
-DIRECT_RATE_NONE = 0
-DIRECT_RATE_NORMAL = 1
-DIRECT_RATE_FAST = 2
-DIRECT_RATE_VERY_FAST = 3
-
-DIRECT_CHANNEL_TYPE_HARDWARE = 1
-DIRECT_CHANNEL_TYPE_SOFTWARE = 2
-DIRECT_CHANNEL_SENSOR_NONE = 0
-
-SENSOR_STATUS_NO_CONTACT = -1
-SENSOR_STATUS_UNRELIABLE = 0
-SENSOR_STATUS_ACCURACY_LOW = 1
-SENSOR_STATUS_ACCURACY_MEDIUM = 2
-SENSOR_STATUS_ACCURACY_HIGH = 3
-
-AXIS_X = 1
-AXIS_Y = 2
-AXIS_Z = 3
-AXIS_MINUS_X = 4
-AXIS_MINUS_Y = 5
-AXIS_MINUS_Z = 6
-
-
-# ═══════════════════════════════════════════════════════════════
-# Sensor (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class Sensor(_BaseSensor):
- """Sensor — 传感器 (完整版,继承 hardware.Sensor 的所有方法)"""
-
- TYPE_ACCELEROMETER = TYPE_ACCELEROMETER
- TYPE_MAGNETIC_FIELD = TYPE_MAGNETIC_FIELD
- TYPE_ORIENTATION = TYPE_ORIENTATION
- TYPE_GYROSCOPE = TYPE_GYROSCOPE
- TYPE_LIGHT = TYPE_LIGHT
- TYPE_PRESSURE = TYPE_PRESSURE
- TYPE_PROXIMITY = TYPE_PROXIMITY
- TYPE_GRAVITY = TYPE_GRAVITY
- TYPE_LINEAR_ACCELERATION = TYPE_LINEAR_ACCELERATION
- TYPE_ROTATION_VECTOR = TYPE_ROTATION_VECTOR
- TYPE_RELATIVE_HUMIDITY = TYPE_RELATIVE_HUMIDITY
- TYPE_AMBIENT_TEMPERATURE = TYPE_AMBIENT_TEMPERATURE
- TYPE_STEP_COUNTER = TYPE_STEP_COUNTER
- TYPE_STEP_DETECTOR = TYPE_STEP_DETECTOR
- TYPE_HEART_RATE = TYPE_HEART_RATE
- TYPE_SIGNIFICANT_MOTION = TYPE_SIGNIFICANT_MOTION
- TYPE_GAME_ROTATION_VECTOR = TYPE_GAME_ROTATION_VECTOR
- TYPE_GEOMAGNETIC_ROTATION_VECTOR = TYPE_GEOMAGNETIC_ROTATION_VECTOR
- TYPE_DEVICE_ORIENTATION = TYPE_DEVICE_ORIENTATION
- TYPE_STATIONARY_DETECT = TYPE_STATIONARY_DETECT
- TYPE_MOTION_DETECT = TYPE_MOTION_DETECT
- TYPE_HEART_BEAT = TYPE_HEART_BEAT
- TYPE_LOW_LATENCY_OFFBODY_DETECT = TYPE_LOW_LATENCY_OFFBODY_DETECT
- TYPE_HINGE_ANGLE = TYPE_HINGE_ANGLE
- TYPE_HEAD_TRACKER = TYPE_HEAD_TRACKER
-
- REPORTING_MODE_CONTINUOUS = REPORTING_MODE_CONTINUOUS
- REPORTING_MODE_ON_CHANGE = REPORTING_MODE_ON_CHANGE
- REPORTING_MODE_ONE_SHOT = REPORTING_MODE_ONE_SHOT
- REPORTING_MODE_SPECIAL_TRIGGER = REPORTING_MODE_SPECIAL_TRIGGER
-
- SENSOR_STATUS_NO_CONTACT = SENSOR_STATUS_NO_CONTACT
- SENSOR_STATUS_UNRELIABLE = SENSOR_STATUS_UNRELIABLE
- SENSOR_STATUS_ACCURACY_LOW = SENSOR_STATUS_ACCURACY_LOW
- SENSOR_STATUS_ACCURACY_MEDIUM = SENSOR_STATUS_ACCURACY_MEDIUM
- SENSOR_STATUS_ACCURACY_HIGH = SENSOR_STATUS_ACCURACY_HIGH
-
- def __init__(self, type_: int = TYPE_ACCELEROMETER,
- name: str = "Simulated Sensor",
- vendor: str = "Android-pyApi", version: int = 1,
- resolution: float = 1.0, max_range: float = 100.0,
- power: float = 0.5, min_delay: int = 10000,
- max_delay: int = 1000000,
- reporting_mode: int = REPORTING_MODE_CONTINUOUS,
- is_wake_up: bool = False,
- is_dynamic: bool = False,
- fifo_reserved_event_count: int = 0,
- fifo_max_event_count: int = 0,
- id_: int = 0):
- super().__init__(type_, name, vendor, version, resolution,
- max_range, power, min_delay)
- self._type = type_
- self._name = name
- self._vendor = vendor
- self._version = version
- self._resolution = resolution
- self._max_range = max_range
- self._power = power
- self._min_delay = min_delay
- self._max_delay = max_delay
- self._reporting_mode = reporting_mode
- self._is_wake_up = is_wake_up
- self._is_dynamic = is_dynamic
- self._fifo_reserved_event_count = fifo_reserved_event_count
- self._fifo_max_event_count = fifo_max_event_count
- self._id = id_
- self._string_type = ""
-
- def getType(self) -> int:
- return self._type
-
- def getName(self) -> str:
- return self._name
-
- def getVendor(self) -> str:
- return self._vendor
-
- def getVersion(self) -> int:
- return self._version
-
- def getMaximumRange(self) -> float:
- return self._max_range
-
- def getResolution(self) -> float:
- return self._resolution
-
- def getPower(self) -> float:
- return self._power
-
- def getMinDelay(self) -> int:
- return self._min_delay
-
- def getMaxDelay(self) -> int:
- return self._max_delay
-
- def getReportingMode(self) -> int:
- return self._reporting_mode
-
- def isWakeUpSensor(self) -> bool:
- return self._is_wake_up
-
- def isDynamicSensor(self) -> bool:
- return self._is_dynamic
-
- def getFifoReservedEventCount(self) -> int:
- return self._fifo_reserved_event_count
-
- def getFifoMaxEventCount(self) -> int:
- return self._fifo_max_event_count
-
- def getId(self) -> int:
- return self._id
-
- def getStringType(self) -> str:
- if self._string_type:
- return self._string_type
- type_names = {
- 1: "android.sensor.accelerometer", 2: "android.sensor.magnetic_field",
- 3: "android.sensor.orientation", 4: "android.sensor.gyroscope",
- 5: "android.sensor.light", 6: "android.sensor.pressure",
- 8: "android.sensor.proximity", 9: "android.sensor.gravity",
- 10: "android.sensor.linear_acceleration", 11: "android.sensor.rotation_vector",
- 12: "android.sensor.relative_humidity", 13: "android.sensor.ambient_temperature",
- 19: "android.sensor.step_counter", 18: "android.sensor.step_detector",
- 21: "android.sensor.heart_rate",
- }
- return type_names.get(self._type, f"android.sensor.type_{self._type}")
-
- def toString(self) -> str:
- return (f"Sensor(name={self._name}, type={self._type}, "
- f"vendor={self._vendor})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, Sensor):
- return False
- return self._type == other._type and self._name == other._name
-
- def hashCode(self) -> int:
- return hash((self._type, self._name)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorEvent
-# ═══════════════════════════════════════════════════════════════
-
-class SensorEvent(_BaseSensorEvent):
- """SensorEvent — 传感器事件 (继承 hardware.SensorEvent 的所有方法)"""
-
- def __init__(self, sensor: Optional[Sensor] = None,
- values: List[float] = None,
- accuracy: int = SENSOR_STATUS_ACCURACY_HIGH,
- timestamp: int = 0):
- if sensor is not None:
- super().__init__(sensor, accuracy)
- else:
- Stub.__init__(self)
- self.sensor = sensor
- self.values = values or [0.0, 0.0, 0.0]
- self.accuracy = accuracy
- self.timestamp = timestamp or int(time.time() * 1000000)
-
- def getSensor(self) -> Optional[Sensor]:
- return self.sensor
-
- def getValues(self) -> List[float]:
- return list(self.values)
-
- def getAccuracy(self) -> int:
- return self.accuracy
-
- def getTimestamp(self) -> int:
- return self.timestamp
-
- def toString(self) -> str:
- return (f"SensorEvent(sensor={self.sensor}, "
- f"values={self.values}, accuracy={self.accuracy})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, SensorEvent):
- return False
- return self.timestamp == other.timestamp
-
- def hashCode(self) -> int:
- return self.timestamp & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorEventListener
-# ═══════════════════════════════════════════════════════════════
-
-class SensorEventListener(_BaseSensorEventListener):
- """SensorEventListener — 传感器事件监听器 (继承 hardware.SensorEventListener 的所有方法)"""
-
- def onSensorChanged(self, event: SensorEvent):
- pass
-
- def onAccuracyChanged(self, sensor: Sensor, accuracy: int):
- pass
-
- def toString(self) -> str:
- return f"SensorEventListener@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class SensorManager(_BaseSensorManager):
- """SensorManager — 传感器管理器 (完整版,继承 hardware.SensorManager)"""
-
- AXIS_X = AXIS_X
- AXIS_Y = AXIS_Y
- AXIS_Z = AXIS_Z
- AXIS_MINUS_X = AXIS_MINUS_X
- AXIS_MINUS_Y = AXIS_MINUS_Y
- AXIS_MINUS_Z = AXIS_MINUS_Z
-
- SENSOR_DELAY_FASTEST = 0
- SENSOR_DELAY_GAME = 1
- SENSOR_DELAY_UI = 2
- SENSOR_DELAY_NORMAL = 3
-
- DIRECT_RATE_NONE = DIRECT_RATE_NONE
- DIRECT_RATE_NORMAL = DIRECT_RATE_NORMAL
- DIRECT_RATE_FAST = DIRECT_RATE_FAST
- DIRECT_RATE_VERY_FAST = DIRECT_RATE_VERY_FAST
-
- def __init__(self):
- super().__init__()
- self._sensors: Dict[int, Sensor] = {}
- self._listeners: Dict[int, Tuple[SensorEventListener, Sensor, int]] = {}
- self._dynamic_sensor_callbacks: Dict[int, SensorDynamicSensorCallback] = {}
- self._privacy_manager = SensorPrivacyManager()
- self._direct_channels: Dict[int, SensorDirectChannel] = {}
- self._platform_sensors()
-
- def _platform_sensors(self):
- types = [
- (Sensor.TYPE_ACCELEROMETER, "Accelerometer", 0.01, 39.24, 3.0, 10000),
- (Sensor.TYPE_GYROSCOPE, "Gyroscope", 0.001, 34.91, 6.1, 10000),
- (Sensor.TYPE_MAGNETIC_FIELD, "Magnetic Field", 0.01, 2000.0, 4.0, 10000),
- (Sensor.TYPE_LIGHT, "Light", 1.0, 40000.0, 0.5, 10000),
- (Sensor.TYPE_PROXIMITY, "Proximity", 1.0, 10.0, 0.5, 10000),
- (Sensor.TYPE_PRESSURE, "Pressure", 0.01, 1100.0, 1.0, 10000),
- (Sensor.TYPE_GRAVITY, "Gravity", 0.01, 39.24, 3.0, 10000),
- (Sensor.TYPE_LINEAR_ACCELERATION, "Linear Acceleration", 0.01, 39.24, 3.0, 10000),
- (Sensor.TYPE_ROTATION_VECTOR, "Rotation Vector", 0.0001, 1.0, 5.0, 10000),
- (Sensor.TYPE_RELATIVE_HUMIDITY, "Relative Humidity", 0.1, 100.0, 0.5, 10000),
- (Sensor.TYPE_AMBIENT_TEMPERATURE, "Ambient Temperature", 0.01, 80.0, 0.5, 10000),
- (Sensor.TYPE_STEP_COUNTER, "Step Counter", 1.0, 100000.0, 0.1, 100000),
- (Sensor.TYPE_STEP_DETECTOR, "Step Detector", 1.0, 1.0, 0.1, 100000),
- (Sensor.TYPE_HEART_RATE, "Heart Rate", 1.0, 220.0, 0.5, 100000),
- (Sensor.TYPE_SIGNIFICANT_MOTION, "Significant Motion", 1.0, 1.0, 0.1, 100000),
- (Sensor.TYPE_DEVICE_ORIENTATION, "Device Orientation", 1.0, 360.0, 0.5, 10000),
- (Sensor.TYPE_STATIONARY_DETECT, "Stationary Detect", 1.0, 1.0, 0.1, 100000),
- (Sensor.TYPE_MOTION_DETECT, "Motion Detect", 1.0, 1.0, 0.1, 100000),
- (Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT, "Off-Body Detect", 1.0, 1.0, 0.1, 100000),
- (Sensor.TYPE_HINGE_ANGLE, "Hinge Angle", 0.1, 360.0, 0.1, 10000),
- (Sensor.TYPE_HEAD_TRACKER, "Head Tracker", 0.01, 360.0, 1.0, 5000),
- ]
- for i, (t, n, r, mr, p, md) in enumerate(types):
- self._sensors[t] = Sensor(
- type_=t, name=n, resolution=r, max_range=mr,
- power=p, min_delay=md, id_=i,
- )
-
- def getDefaultSensor(self, type_: int) -> Optional[Sensor]:
- return self._sensors.get(type_)
-
- def getSensorList(self, type_: int) -> List[Sensor]:
- if type_ == -1:
- return list(self._sensors.values())
- return [s for s in self._sensors.values() if s.getType() == type_]
-
- def registerListener(self, listener: SensorEventListener, sensor: Sensor,
- samplingPeriodUs: int = SENSOR_DELAY_NORMAL,
- maxReportLatencyUs: int = 0) -> bool:
- lid = id(listener)
- self._listeners[lid] = (listener, sensor, samplingPeriodUs)
- return True
-
- def unregisterListener(self, listener: SensorEventListener, sensor: Sensor = None):
- lid = id(listener)
- if sensor and lid in self._listeners:
- _, reg_sensor, _ = self._listeners[lid]
- if reg_sensor == sensor:
- del self._listeners[lid]
- else:
- self._listeners.pop(lid, None)
-
- def registerDynamicSensorCallback(self, callback: SensorDynamicSensorCallback,
- handler: Any = None):
- lid = id(callback)
- self._dynamic_sensor_callbacks[lid] = callback
-
- def unregisterDynamicSensorCallback(self, callback: SensorDynamicSensorCallback):
- lid = id(callback)
- self._dynamic_sensor_callbacks.pop(lid, None)
-
- def createDirectChannel(self, config: "SensorDirectChannelConfig") -> Optional["SensorDirectChannel"]:
- channel = SensorDirectChannel(config=config, manager=self)
- cid = id(channel)
- self._direct_channels[cid] = channel
- return channel
-
- def destroyDirectChannel(self, channel: "SensorDirectChannel"):
- cid = id(channel)
- self._direct_channels.pop(cid, None)
-
- def getSensorPrivacyManager(self) -> "SensorPrivacyManager":
- return self._privacy_manager
-
- def flush(self, listener: SensorEventListener) -> bool:
- return True
-
- def getDynamicSensorList(self, type_: int) -> List[Sensor]:
- return [s for s in self._sensors.values()
- if s.isDynamicSensor() and (type_ == -1 or s.getType() == type_)]
-
- def requestSensor(self, request: "SensorRequest") -> bool:
- return True
-
- def getSensorAvailability(self, type_: int) -> "SensorAvailability":
- return SensorAvailability(available=type_ in self._sensors)
-
- def createOffloadSession(self) -> "SensorOffloadSession":
- return SensorOffloadSession()
-
- def getSensorOffload(self) -> "SensorOffload":
- return SensorOffload()
-
- def toString(self) -> str:
- return f"SensorManager(sensors={len(self._sensors)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorDirectChannelConfig
-# ═══════════════════════════════════════════════════════════════
-
-class SensorDirectChannelConfig(Stub):
- """SensorDirectChannelConfig — 传感器直连通道配置"""
-
- def __init__(self, type_: int = DIRECT_CHANNEL_TYPE_SOFTWARE,
- size: int = 4096, rate: int = DIRECT_RATE_NORMAL,
- shared_mem_fd: int = -1):
- super().__init__()
- self._type = type_
- self._size = size
- self._rate = rate
- self._shared_mem_fd = shared_mem_fd
-
- def getType(self) -> int:
- return self._type
-
- def getSize(self) -> int:
- return self._size
-
- def getRate(self) -> int:
- return self._rate
-
- def getSharedMemFd(self) -> int:
- return self._shared_mem_fd
-
- def toString(self) -> str:
- return f"SensorDirectChannelConfig(type={self._type}, size={self._size})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorDirectChannel
-# ═══════════════════════════════════════════════════════════════
-
-class SensorDirectChannel(Stub):
- """SensorDirectChannel — 传感器直连通道"""
-
- TYPE_HARDWARE = DIRECT_CHANNEL_TYPE_HARDWARE
- TYPE_SOFTWARE = DIRECT_CHANNEL_TYPE_SOFTWARE
-
- RATE_NONE = DIRECT_RATE_NONE
- RATE_NORMAL = DIRECT_RATE_NORMAL
- RATE_FAST = DIRECT_RATE_FAST
- RATE_VERY_FAST = DIRECT_RATE_VERY_FAST
-
- def __init__(self, config: Optional[SensorDirectChannelConfig] = None,
- manager: Optional[SensorManager] = None):
- super().__init__()
- self._config = config
- self._manager = manager
- self._configured_sensors: List[Sensor] = []
- self._is_valid = True
-
- def isOpen(self) -> bool:
- return self._is_valid
-
- def close(self):
- self._is_valid = False
- if self._manager:
- self._manager.destroyDirectChannel(self)
-
- def configure(self, sensor: Sensor, rate: int) -> int:
- if not self._is_valid:
- return -1
- self._configured_sensors.append(sensor)
- return 0
-
- def getConfiguredSensors(self) -> List[Sensor]:
- return list(self._configured_sensors)
-
- def toString(self) -> str:
- return f"SensorDirectChannel(open={self._is_valid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorPrivacyManager
-# ═══════════════════════════════════════════════════════════════
-
-class SensorPrivacyManager(Stub):
- """SensorPrivacyManager — 传感器隐私管理器"""
-
- SOURCE_MICROPHONE = 1
- SOURCE_CAMERA = 2
- SOURCE_LOCATION = 3
- SOURCE_ALL = -1
-
- STATE_DISABLED = 0
- STATE_ENABLED = 1
-
- def __init__(self):
- super().__init__()
- self._mic_muted = False
- self._camera_disabled = False
- self._listeners: Dict[int, Callable] = {}
-
- def isSensorPrivacyEnabled(self, source: int) -> bool:
- if source == SensorPrivacyManager.SOURCE_MICROPHONE:
- return self._mic_muted
- if source == SensorPrivacyManager.SOURCE_CAMERA:
- return self._camera_disabled
- return False
-
- def setSensorPrivacy(self, source: int, enabled: bool):
- if source == SensorPrivacyManager.SOURCE_MICROPHONE:
- self._mic_muted = enabled
- elif source == SensorPrivacyManager.SOURCE_CAMERA:
- self._camera_disabled = enabled
- elif source == SensorPrivacyManager.SOURCE_ALL:
- self._mic_muted = enabled
- self._camera_disabled = enabled
-
- def addSensorPrivacyListener(self, source: int, callback: Callable):
- lid = id(callback)
- self._listeners[lid] = callback
-
- def removeSensorPrivacyListener(self, source: int, callback: Callable):
- lid = id(callback)
- self._listeners.pop(lid, None)
-
- def toString(self) -> str:
- return f"SensorPrivacyManager(micMuted={self._mic_muted})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorAvailability
-# ═══════════════════════════════════════════════════════════════
-
-class SensorAvailability(Stub):
- """SensorAvailability — 传感器可用性"""
-
- def __init__(self, available: bool = True,
- type_: int = TYPE_ACCELEROMETER,
- reason: str = ""):
- super().__init__()
- self._available = available
- self._type = type_
- self._reason = reason
-
- def isAvailable(self) -> bool:
- return self._available
-
- def getType(self) -> int:
- return self._type
-
- def getReason(self) -> str:
- return self._reason
-
- def toString(self) -> str:
- return f"SensorAvailability(type={self._type}, available={self._available})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorAdditionalInfo
-# ═══════════════════════════════════════════════════════════════
-
-class SensorAdditionalInfo(Stub):
- """SensorAdditionalInfo — 传感器附加信息"""
-
- TYPE_FRAME_BEGIN = 0
- TYPE_FRAME_END = 1
- TYPE_UNTRACKED_DELAY = 65536
- TYPE_INTERNAL_TEMPERATURE = 65537
- TYPE_VEC3_CALIBRATION = 65538
- TYPE_SENSOR_PLACEMENT = 65539
- TYPE_SAMPLE_0 = 65540
- TYPE_LOCAL_GEOMAGNETIC_FIELD = 65541
- TYPE_LOCAL_GRAVITY = 65542
- TYPE_DOCK_STATE = 65543
- TYPE_HIGH_LEVEL_EVENT = 65544
- TYPE_MAGNETIC_FIELD_CALIBRATION = 65545
-
- def __init__(self, sensor: Optional[Sensor] = None,
- type_: int = TYPE_FRAME_BEGIN,
- serialized: List[int] = None,
- values: List[float] = None):
- super().__init__()
- self.sensor = sensor
- self.type = type_
- self.serialized = serialized or []
- self.values = values or []
-
- def getSensor(self) -> Optional[Sensor]:
- return self.sensor
-
- def getType(self) -> int:
- return self.type
-
- def getSerialized(self) -> List[int]:
- return list(self.serialized)
-
- def getValues(self) -> List[float]:
- return list(self.values)
-
- def toString(self) -> str:
- return f"SensorAdditionalInfo(type={self.type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorDynamicSensorCallback
-# ═══════════════════════════════════════════════════════════════
-
-class SensorDynamicSensorCallback(Stub):
- """SensorDynamicSensorCallback — 动态传感器回调"""
-
- def onDynamicSensorConnected(self, sensor: Sensor):
- pass
-
- def onDynamicSensorDisconnected(self, sensor: Sensor):
- pass
-
- def toString(self) -> str:
- return f"SensorDynamicSensorCallback@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorOffload / SensorOffloadSession
-# ═══════════════════════════════════════════════════════════════
-
-class SensorOffload(Stub):
- """SensorOffload — 传感器卸载"""
-
- def __init__(self):
- super().__init__()
-
- def createSession(self) -> "SensorOffloadSession":
- return SensorOffloadSession()
-
- def getMaxSensorsPerSession(self) -> int:
- return 16
-
- def isSupported(self) -> bool:
- return True
-
- def toString(self) -> str:
- return "SensorOffload()"
-
-
-class SensorOffloadSession(Stub):
- """SensorOffloadSession — 传感器卸载会话"""
-
- STATE_IDLE = 0
- STATE_ACTIVE = 1
- STATE_SUSPENDED = 2
- STATE_ERROR = 3
-
- def __init__(self):
- super().__init__()
- self._state = SensorOffloadSession.STATE_IDLE
- self._sensors: List[Sensor] = []
- self._sampling_period_us = 0
- self._max_report_latency_us = 0
-
- def getState(self) -> int:
- return self._state
-
- def start(self, sensors: List[Sensor], samplingPeriodUs: int,
- maxReportLatencyUs: int = 0):
- self._sensors = list(sensors)
- self._sampling_period_us = samplingPeriodUs
- self._max_report_latency_us = maxReportLatencyUs
- self._state = SensorOffloadSession.STATE_ACTIVE
-
- def stop(self):
- self._state = SensorOffloadSession.STATE_IDLE
- self._sensors.clear()
-
- def suspend(self):
- self._state = SensorOffloadSession.STATE_SUSPENDED
-
- def resume(self):
- if self._state == SensorOffloadSession.STATE_SUSPENDED:
- self._state = SensorOffloadSession.STATE_ACTIVE
-
- def getSensors(self) -> List[Sensor]:
- return list(self._sensors)
-
- def getSamplingPeriodUs(self) -> int:
- return self._sampling_period_us
-
- def getMaxReportLatencyUs(self) -> int:
- return self._max_report_latency_us
-
- def toString(self) -> str:
- return f"SensorOffloadSession(state={self._state}, sensors={len(self._sensors)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SensorRequest / SensorRequest.Builder
-# ═══════════════════════════════════════════════════════════════
-
-class SensorRequest(Stub):
- """SensorRequest — 传感器请求"""
-
- def __init__(self, sensor: Optional[Sensor] = None,
- samplingPeriodUs: int = 100000,
- maxReportLatencyUs: int = 0,
- isWakeUp: bool = False):
- super().__init__()
- self._sensor = sensor
- self._sampling_period_us = samplingPeriodUs
- self._max_report_latency_us = maxReportLatencyUs
- self._is_wake_up = isWakeUp
-
- def getSensor(self) -> Optional[Sensor]:
- return self._sensor
-
- def getSamplingPeriodUs(self) -> int:
- return self._sampling_period_us
-
- def getMaxReportLatencyUs(self) -> int:
- return self._max_report_latency_us
-
- def isWakeUp(self) -> bool:
- return self._is_wake_up
-
- class Builder(Stub):
- """SensorRequest.Builder — 传感器请求构建器"""
-
- def __init__(self):
- super().__init__()
- self._sensor: Optional[Sensor] = None
- self._sampling_period_us = 100000
- self._max_report_latency_us = 0
- self._is_wake_up = False
-
- def setSensor(self, sensor: Sensor) -> "SensorRequest.Builder":
- self._sensor = sensor
- return self
-
- def setSamplingPeriodUs(self, periodUs: int) -> "SensorRequest.Builder":
- self._sampling_period_us = periodUs
- return self
-
- def setMaxReportLatencyUs(self, latencyUs: int) -> "SensorRequest.Builder":
- self._max_report_latency_us = latencyUs
- return self
-
- def setWakeUp(self, wakeUp: bool) -> "SensorRequest.Builder":
- self._is_wake_up = wakeUp
- return self
-
- def build(self) -> "SensorRequest":
- return SensorRequest(
- sensor=self._sensor, samplingPeriodUs=self._sampling_period_us,
- maxReportLatencyUs=self._max_report_latency_us,
- isWakeUp=self._is_wake_up,
- )
-
- def toString(self) -> str:
- return (f"SensorRequest(sensor={self._sensor}, "
- f"period={self._sampling_period_us}us)")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, SensorRequest):
- return False
- return (self._sensor == other._sensor and
- self._sampling_period_us == other._sampling_period_us)
-
- def hashCode(self) -> int:
- return hash((id(self._sensor), self._sampling_period_us)) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_serial.py b/android_pyapi/android/hardware_serial.py
deleted file mode 100644
index f4ac418..0000000
--- a/android_pyapi/android/hardware_serial.py
+++ /dev/null
@@ -1,513 +0,0 @@
-"""
-Android hardware Serial 组件 — SerialManager, SerialPort, SerialUsb
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import io
-import os
-import time
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-__all__ = [
- "SerialManager",
- "SerialPort",
- "SerialUsb",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 串口常量
-# ═══════════════════════════════════════════════════════════════
-
-SERIAL_PORT_MODE_READ = 0
-SERIAL_PORT_MODE_WRITE = 1
-SERIAL_PORT_MODE_READ_WRITE = 2
-
-SERIAL_PARITY_NONE = 0
-SERIAL_PARITY_ODD = 1
-SERIAL_PARITY_EVEN = 2
-SERIAL_PARITY_MARK = 3
-SERIAL_PARITY_SPACE = 4
-
-SERIAL_STOP_BITS_1 = 1
-SERIAL_STOP_BITS_1_5 = 3
-SERIAL_STOP_BITS_2 = 2
-
-SERIAL_DATA_BITS_5 = 5
-SERIAL_DATA_BITS_6 = 6
-SERIAL_DATA_BITS_7 = 7
-SERIAL_DATA_BITS_8 = 8
-
-SERIAL_FLOW_CONTROL_NONE = 0
-SERIAL_FLOW_CONTROL_RTS_CTS = 1
-SERIAL_FLOW_CONTROL_XON_XOFF = 2
-SERIAL_FLOW_CONTROL_DTR_DSR = 4
-
-SERIAL_BAUD_300 = 300
-SERIAL_BAUD_1200 = 1200
-SERIAL_BAUD_2400 = 2400
-SERIAL_BAUD_4800 = 4800
-SERIAL_BAUD_9600 = 9600
-SERIAL_BAUD_19200 = 19200
-SERIAL_BAUD_38400 = 38400
-SERIAL_BAUD_57600 = 57600
-SERIAL_BAUD_115200 = 115200
-SERIAL_BAUD_230400 = 230400
-SERIAL_BAUD_460800 = 460800
-SERIAL_BAUD_921600 = 921600
-
-SERIAL_ERROR_NONE = 0
-SERIAL_ERROR_PORT_NOT_FOUND = -1
-SERIAL_ERROR_PORT_IN_USE = -2
-SERIAL_ERROR_PERMISSION_DENIED = -3
-SERIAL_ERROR_IO_ERROR = -4
-SERIAL_ERROR_UNSUPPORTED = -5
-SERIAL_ERROR_TIMEOUT = -6
-SERIAL_ERROR_DISCONNECTED = -7
-
-
-# ═══════════════════════════════════════════════════════════════
-# SerialPort
-# ═══════════════════════════════════════════════════════════════
-
-class SerialPort(Stub):
- """SerialPort — 串口"""
-
- def __init__(self, name: str = "", baudRate: int = SERIAL_BAUD_9600,
- dataBits: int = SERIAL_DATA_BITS_8,
- parity: int = SERIAL_PARITY_NONE,
- stopBits: int = SERIAL_STOP_BITS_1,
- flowControl: int = SERIAL_FLOW_CONTROL_NONE,
- mode: int = SERIAL_PORT_MODE_READ_WRITE):
- super().__init__()
- self._name = name
- self._baud_rate = baudRate
- self._data_bits = dataBits
- self._parity = parity
- self._stop_bits = stopBits
- self._flow_control = flowControl
- self._mode = mode
- self._is_open = False
- self._fd: Optional[Any] = None
- self._timeout_ms = 1000
- self._buffer_size = 4096
- self._read_buffer = b""
- self._write_buffer = b""
-
- def getName(self) -> str:
- return self._name
-
- def getBaudRate(self) -> int:
- return self._baud_rate
-
- def setBaudRate(self, baudRate: int):
- self._baud_rate = baudRate
-
- def getDataBits(self) -> int:
- return self._data_bits
-
- def setDataBits(self, dataBits: int):
- self._data_bits = dataBits
-
- def getParity(self) -> int:
- return self._parity
-
- def setParity(self, parity: int):
- self._parity = parity
-
- def getStopBits(self) -> int:
- return self._stop_bits
-
- def setStopBits(self, stopBits: int):
- self._stop_bits = stopBits
-
- def getFlowControl(self) -> int:
- return self._flow_control
-
- def setFlowControl(self, flowControl: int):
- self._flow_control = flowControl
-
- def getMode(self) -> int:
- return self._mode
-
- def setTimeout(self, timeoutMs: int):
- self._timeout_ms = timeoutMs
-
- def getTimeout(self) -> int:
- return self._timeout_ms
-
- def isOpen(self) -> bool:
- return self._is_open
-
- def open(self) -> int:
- if self._is_open:
- return SERIAL_ERROR_NONE
- try:
- self._fd = io.FileIO(self._name, "rb+" if self._mode == SERIAL_PORT_MODE_READ_WRITE
- else "rb" if self._mode == SERIAL_PORT_MODE_READ
- else "wb")
- self._is_open = True
- return SERIAL_ERROR_NONE
- except (IOError, OSError) as e:
- if "Permission denied" in str(e):
- return SERIAL_ERROR_PERMISSION_DENIED
- if "No such file" in str(e):
- return SERIAL_ERROR_PORT_NOT_FOUND
- return SERIAL_ERROR_IO_ERROR
-
- def close(self):
- if self._fd:
- try:
- self._fd.close()
- except Exception:
- pass
- self._fd = None
- self._is_open = False
-
- def read(self, size: int = -1) -> Optional[bytes]:
- if not self._is_open or not self._fd:
- return None
- try:
- if self._mode == SERIAL_PORT_MODE_WRITE:
- return b""
- if size < 0:
- data = self._fd.read()
- else:
- data = self._fd.read(size)
- return data if data else b""
- except Exception:
- return None
-
- def write(self, data: bytes) -> int:
- if not self._is_open or not self._fd:
- return SERIAL_ERROR_PORT_NOT_FOUND
- try:
- if self._mode == SERIAL_PORT_MODE_READ:
- return SERIAL_ERROR_PERMISSION_DENIED
- written = self._fd.write(data)
- return written if written else len(data)
- except Exception:
- return SERIAL_ERROR_IO_ERROR
-
- def flush(self) -> int:
- if not self._is_open:
- return SERIAL_ERROR_PORT_NOT_FOUND
- try:
- if hasattr(self._fd, 'flush'):
- self._fd.flush()
- return SERIAL_ERROR_NONE
- except Exception:
- return SERIAL_ERROR_IO_ERROR
-
- def getAvailableBytes(self) -> int:
- if not self._is_open or not self._fd:
- return 0
- try:
- import os
- if hasattr(self._fd, 'fileno'):
- fd = self._fd.fileno()
- import select
- r, _, _ = select.select([fd], [], [], 0)
- if r:
- import struct
- import fcntl
- try:
- buf = fcntl.ioctl(fd, 0x541B, struct.pack('I', 0)) # FIONREAD
- return struct.unpack('I', buf)[0]
- except Exception:
- pass
- except Exception:
- pass
- return 0
-
- def setDTR(self, value: bool):
- pass
-
- def setRTS(self, value: bool):
- pass
-
- def getDCD(self) -> bool:
- return False
-
- def getDSR(self) -> bool:
- return False
-
- def getCTS(self) -> bool:
- return False
-
- def getRI(self) -> bool:
- return False
-
- def sendBreak(self, durationMs: int = 100):
- pass
-
- def toString(self) -> str:
- return (f"SerialPort(name={self._name}, baud={self._baud_rate}, "
- f"open={self._is_open})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, SerialPort):
- return False
- return self._name == other._name
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SerialUsb
-# ═══════════════════════════════════════════════════════════════
-
-class SerialUsb(Stub):
- """SerialUsb — USB 串口"""
-
- USB_VENDOR_FTDI = 0x0403
- USB_VENDOR_CP210X = 0x10C4
- USB_VENDOR_CH340 = 0x1A86
- USB_VENDOR_PL2303 = 0x067B
- USB_VENDOR_ARDUINO = 0x2341
- USB_VENDOR_SILABS = 0x10C4
-
- USB_PRODUCT_FTDI_FT232 = 0x6001
- USB_PRODUCT_CP2102 = 0xEA60
- USB_PRODUCT_CH340 = 0x7523
- USB_PRODUCT_PL2303 = 0x2303
-
- def __init__(self, vendorId: int = 0, productId: int = 0,
- serialNumber: str = "", manufacturer: str = "",
- product: str = "", devicePort: str = "",
- deviceNode: str = ""):
- super().__init__()
- self._vendor_id = vendorId
- self._product_id = productId
- self._serial_number = serialNumber
- self._manufacturer = manufacturer
- self._product = product
- self._device_port = devicePort
- self._device_node = deviceNode
- self._port: Optional[SerialPort] = None
-
- def getVendorId(self) -> int:
- return self._vendor_id
-
- def getProductId(self) -> int:
- return self._product_id
-
- def getSerialNumber(self) -> str:
- return self._serial_number
-
- def getManufacturer(self) -> str:
- return self._manufacturer
-
- def getProduct(self) -> str:
- return self._product
-
- def getDevicePort(self) -> str:
- return self._device_port
-
- def getDeviceNode(self) -> str:
- return self._device_node
-
- def createSerialPort(self, baudRate: int = SERIAL_BAUD_9600,
- dataBits: int = SERIAL_DATA_BITS_8,
- parity: int = SERIAL_PARITY_NONE,
- stopBits: int = SERIAL_STOP_BITS_1,
- flowControl: int = SERIAL_FLOW_CONTROL_NONE) -> Optional[SerialPort]:
- if not self._device_node and not self._device_port:
- return None
- port_name = self._device_node or f"/dev/{self._device_port}"
- port = SerialPort(name=port_name, baudRate=baud_rate,
- dataBits=dataBits, parity=parity,
- stopBits=stopBits, flowControl=flowControl)
- self._port = port
- return port
-
- def getSerialPort(self) -> Optional[SerialPort]:
- return self._port
-
- def toString(self) -> str:
- return (f"SerialUsb(vendor=0x{self._vendor_id:04X}, "
- f"product=0x{self._product_id:04X})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, SerialUsb):
- return False
- return (self._vendor_id == other._vendor_id and
- self._product_id == other._product_id and
- self._serial_number == other._serial_number)
-
- def hashCode(self) -> int:
- return hash((self._vendor_id, self._product_id, self._serial_number)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SerialManager
-# ═══════════════════════════════════════════════════════════════
-
-class SerialManager(Stub):
- """SerialManager — 串口管理器"""
-
- ACTION_SERIAL_PORT_ADDED = "android.hardware.usb.action.USB_DEVICE_ATTACHED"
- ACTION_SERIAL_PORT_REMOVED = "android.hardware.usb.action.USB_DEVICE_DETACHED"
- EXTRA_SERIAL_PORT = "serial_port"
- EXTRA_USB_DEVICE = "device"
-
- def __init__(self):
- super().__init__()
- self._ports: Dict[str, SerialPort] = {}
- self._usb_devices: Dict[str, SerialUsb] = {}
- self._listeners: Dict[int, Callable] = {}
-
- def getSerialPorts(self) -> List[SerialPort]:
- return list(self._ports.values())
-
- def getSerialPort(self, name: str) -> Optional[SerialPort]:
- return self._ports.get(name)
-
- def openSerialPort(self, name: str, baudRate: int = SERIAL_BAUD_9600,
- dataBits: int = SERIAL_DATA_BITS_8,
- parity: int = SERIAL_PARITY_NONE,
- stopBits: int = SERIAL_STOP_BITS_1,
- flowControl: int = SERIAL_FLOW_CONTROL_NONE,
- mode: int = SERIAL_PORT_MODE_READ_WRITE) -> Optional[SerialPort]:
- if name in self._ports and self._ports[name].isOpen():
- return None
- port = SerialPort(name=name, baudRate=baudRate, dataBits=dataBits,
- parity=parity, stopBits=stopBits,
- flowControl=flowControl, mode=mode)
- err = port.open()
- if err != SERIAL_ERROR_NONE:
- return None
- self._ports[name] = port
- return port
-
- def closeSerialPort(self, name: str):
- port = self._ports.get(name)
- if port:
- port.close()
- self._ports.pop(name, None)
-
- def getUsbDevices(self) -> List[SerialUsb]:
- return list(self._usb_devices.values())
-
- def addUsbDevice(self, device: SerialUsb):
- self._usb_devices[device.getDeviceNode() or device.getDevicePort()] = device
-
- def removeUsbDevice(self, device: SerialUsb):
- key = device.getDeviceNode() or device.getDevicePort()
- self._usb_devices.pop(key, None)
-
- def getAvailableDevices(self) -> List[str]:
- """列出系统可用的串口设备路径"""
- ports = []
- for base in ("/dev/ttyS", "/dev/ttyUSB", "/dev/ttyACM",
- "/dev/ttyAMA", "/dev/ttyO", "/dev/cu.usbserial",
- "/dev/tty.wchusbserial"):
- for i in range(256):
- path = f"{base}{i}"
- if os.path.exists(path):
- ports.append(path)
- return ports + list(self._ports.keys())
-
- def getSerialPortsForDevice(self, usbDevice: SerialUsb) -> List[SerialPort]:
- return [p for n, p in self._ports.items()
- if usbDevice.getDeviceNode() in n or usbDevice.getDevicePort() in n]
-
- def registerListener(self, listener: Callable):
- lid = id(listener)
- self._listeners[lid] = listener
-
- def unregisterListener(self, listener: Callable):
- lid = id(listener)
- self._listeners.pop(lid, None)
-
- def isSerialPortName(self, name: str) -> bool:
- return name.startswith(("ttyS", "ttyUSB", "ttyACM", "ttyAMA"))
-
- def toString(self) -> str:
- return f"SerialManager(ports={len(self._ports)}, usb={len(self._usb_devices)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def getSerialPortCount(self) -> int:
- return len(self._ports)
-
- def getUsbDeviceCount(self) -> int:
- return len(self._usb_devices)
-
- def hasSerialPort(self, name: str) -> bool:
- return name in self._ports
-
- def hasUsbDevice(self, vendorId: int, productId: int) -> bool:
- for dev in self._usb_devices.values():
- if dev.getVendorId() == vendorId and dev.getProductId() == productId:
- return True
- return False
-
- def findUsbDeviceBySerial(self, serialNumber: str) -> Optional[SerialUsb]:
- for dev in self._usb_devices.values():
- if dev.getSerialNumber() == serialNumber:
- return dev
- return None
-
- def findUsbDeviceByVendorProduct(self, vendorId: int, productId: int) -> List[SerialUsb]:
- return [dev for dev in self._usb_devices.values()
- if dev.getVendorId() == vendorId and dev.getProductId() == productId]
-
- def closeAllPorts(self) -> None:
- for name, port in list(self._ports.items()):
- port.close()
- self._ports.pop(name, None)
-
- def getPortStatus(self, name: str) -> int:
- port = self._ports.get(name)
- if port is None:
- return SERIAL_ERROR_PORT_NOT_FOUND
- if not port.isOpen():
- return SERIAL_ERROR_PORT_NOT_FOUND
- return SERIAL_ERROR_NONE
-
- def reconfigurePort(self, name: str, baudRate: int = 0,
- dataBits: int = 0, parity: int = -1,
- stopBits: int = 0, flowControl: int = -1) -> int:
- port = self._ports.get(name)
- if port is None:
- return SERIAL_ERROR_PORT_NOT_FOUND
- if baudRate > 0:
- port.setBaudRate(baudRate)
- if dataBits > 0:
- port.setDataBits(dataBits)
- if parity >= 0:
- port.setParity(parity)
- if stopBits > 0:
- port.setStopBits(stopBits)
- if flowControl >= 0:
- port.setFlowControl(flowControl)
- return SERIAL_ERROR_NONE
-
- def addSerialPort(self, port: SerialPort) -> None:
- self._ports[port.getName()] = port
-
- def removeSerialPort(self, name: str) -> None:
- self._ports.pop(name, None)
-
- def getSerialPortNames(self) -> List[str]:
- return list(self._ports.keys())
-
- def getUsbDeviceSerialNumbers(self) -> List[str]:
- return [dev.getSerialNumber() for dev in self._usb_devices.values()]
-
- def clearAllDevices(self) -> None:
- self._usb_devices.clear()
- for port in self._ports.values():
- if port.isOpen():
- port.close()
- self._ports.clear()
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_thermal.py b/android_pyapi/android/hardware_thermal.py
deleted file mode 100644
index 0dfe0ac..0000000
--- a/android_pyapi/android/hardware_thermal.py
+++ /dev/null
@@ -1,218 +0,0 @@
-"""
-Android hardware.thermal 组件 — ThermalManager, CoolingDevice, Temperature 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import random
-import threading
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError, HAS_PSUTIL
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# Temperature
-# ═══════════════════════════════════════════════════════════════
-
-class Temperature(Stub):
- """Temperature — 温度数据"""
-
- TYPE_SKIN = 0
- TYPE_CPU = 1
- TYPE_GPU = 2
- TYPE_BATTERY = 3
- TYPE_NPU = 4
- TYPE_POWER_AMP = 5
- TYPE_MODEM = 6
- TYPE_AMBIENT = 7
- TYPE_USB_PORT = 8
- TYPE_DISPLAY = 9
- TYPE_BELT = 10
- TYPE_CAMERA = 11
- TYPE_TPU = 12
- TYPE_POGO = 13
-
- def __init__(self, type_: int = TYPE_AMBIENT, name: str = "ambient",
- value: float = 25.0, status: int = 0):
- super().__init__()
- self._type = type_
- self._name = name
- self._value = value
- self._status = status
-
- def getType(self) -> int:
- return self._type
-
- def getName(self) -> str:
- return self._name
-
- def getValue(self) -> float:
- return self._value
-
- def getStatus(self) -> int:
- return self._status
-
- def toString(self) -> str:
- return f"Temperature{{type={self._type}, name={self._name}, value={self._value}, status={self._status}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CoolingDevice
-# ═══════════════════════════════════════════════════════════════
-
-class CoolingDevice(Stub):
- """CoolingDevice — 冷却设备"""
-
- def __init__(self, type_: int = 0, description: str = "cooling_fan",
- current_level: int = 50):
- super().__init__()
- self._type = type_
- self._description = description
- self._current_level = current_level
-
- def getType(self) -> int:
- return self._type
-
- def getDescription(self) -> str:
- return self._description
-
- def getCurrentLevel(self) -> int:
- return self._current_level
-
- def toString(self) -> str:
- return f"CoolingDevice{{type={self._type}, description={self._description}, level={self._current_level}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ThermalStatus
-# ═══════════════════════════════════════════════════════════════
-
-class ThermalStatus(Stub):
- """ThermalStatus — 热状态"""
-
- def __init__(self):
- super().__init__()
- self._status: int = ThermalManager.THERMAL_STATUS_NONE
- self._temperatures: List[Temperature] = []
-
- def getStatus(self) -> int:
- return self._status
-
- def getType(self) -> int:
- return 0
-
- def getName(self) -> str:
- return "thermal_status"
-
- def getTemperatures(self) -> List[Temperature]:
- return list(self._temperatures)
-
- def toString(self) -> str:
- return f"ThermalStatus{{status={self._status}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ThermalManager
-# ═══════════════════════════════════════════════════════════════
-
-class ThermalManager(Stub):
- """ThermalManager — 热管理器"""
-
- THERMAL_STATUS_NONE = 0
- THERMAL_STATUS_LIGHT = 1
- THERMAL_STATUS_MODERATE = 2
- THERMAL_STATUS_SEVERE = 3
- THERMAL_STATUS_CRITICAL = 4
- THERMAL_STATUS_EMERGENCY = 5
- THERMAL_STATUS_SHUTDOWN = 6
-
- def __init__(self):
- super().__init__()
- self._lock = threading.Lock()
- self._listeners: List[Callable[[int], None]] = []
- self._thermal_status = self.THERMAL_STATUS_NONE
- self._status_threshold = self.THERMAL_STATUS_CRITICAL
-
- # Simulated temperatures
- self._temperatures: List[Temperature] = [
- Temperature(Temperature.TYPE_CPU, "cpu0", 45.0, self.THERMAL_STATUS_NONE),
- Temperature(Temperature.TYPE_GPU, "gpu0", 40.0, self.THERMAL_STATUS_NONE),
- Temperature(Temperature.TYPE_BATTERY, "battery", 30.0, self.THERMAL_STATUS_NONE),
- Temperature(Temperature.TYPE_AMBIENT, "ambient", 25.0, self.THERMAL_STATUS_NONE),
- Temperature(Temperature.TYPE_SKIN, "skin", 32.0, self.THERMAL_STATUS_NONE),
- Temperature(Temperature.TYPE_NPU, "npu0", 38.0, self.THERMAL_STATUS_NONE),
- Temperature(Temperature.TYPE_MODEM, "modem", 35.0, self.THERMAL_STATUS_NONE),
- Temperature(Temperature.TYPE_DISPLAY, "display", 36.0, self.THERMAL_STATUS_NONE),
- ]
-
- # Try to get actual CPU temps via psutil
- if HAS_PSUTIL:
- import psutil
- try:
- temps = psutil.sensors_temperatures()
- if temps:
- for name, entries in temps.items():
- for entry in entries:
- temp_type = getattr(Temperature, f"TYPE_{name.upper()}", Temperature.TYPE_AMBIENT)
- self._temperatures.append(
- Temperature(temp_type, entry.label or name,
- entry.current, self.THERMAL_STATUS_NONE)
- )
- except Exception:
- pass
-
- # ── Thermal headroom ──
-
- def getThermalHeadroom(self, forecastSeconds: int) -> float:
- """获取热余量百分比 (0.0 = 过温, 1.0 = 安全)"""
- max_temp = max(t.getValue() for t in self._temperatures) if self._temperatures else 25.0
- headroom = max(0.0, 1.0 - (max_temp - 25.0) / 75.0)
- return min(1.0, headroom)
-
- # ── Status ──
-
- def getThermalStatus(self) -> int:
- return self._thermal_status
-
- def getThermalStatusThreshold(self) -> int:
- return self._status_threshold
-
- # ── Listeners ──
-
- def addThermalStatusListener(self, listener: Callable[[int], None]):
- with self._lock:
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeThermalStatusListener(self, listener: Callable[[int], None]):
- with self._lock:
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def _notify_listeners(self, status: int):
- with self._lock:
- for listener in self._listeners:
- listener(status)
-
- # ── Helper ──
-
- def toString(self) -> str:
- return f"ThermalManager{{status={self._thermal_status}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "ThermalManager",
- "CoolingDevice",
- "ThermalStatus",
- "Temperature",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/hardware_usb.py b/android_pyapi/android/hardware_usb.py
deleted file mode 100644
index 3420944..0000000
--- a/android_pyapi/android/hardware_usb.py
+++ /dev/null
@@ -1,409 +0,0 @@
-from __future__ import annotations
-
-"""
-Android hardware.usb 组件 — UsbManager, UsbDevice, UsbDeviceConnection 等
-方法签名完全对齐 Android SDK
-"""
-
-from typing import Any, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsbConstants
-# ═══════════════════════════════════════════════════════════════
-
-class UsbConstants(Stub):
- """UsbConstants — USB 常量"""
-
- USB_DIR_IN = 0x80
- USB_DIR_OUT = 0
-
- USB_TYPE_MASK = 0x60
- USB_TYPE_CLASS = 0x20
- USB_TYPE_VENDOR = 0x40
- USB_TYPE_STANDARD = 0x00
-
- USB_ENDPOINT_XFER_CONTROL = 0
- USB_ENDPOINT_XFER_ISOC = 1
- USB_ENDPOINT_XFER_BULK = 2
- USB_ENDPOINT_XFER_INT = 3
-
- USB_CLASS_APP_SPEC = 0xFE
- USB_CLASS_AUDIO = 0x01
- USB_CLASS_CDC_DATA = 0x0A
- USB_CLASS_COMM = 0x02
- USB_CLASS_CONTENT_SEC = 0x0D
- USB_CLASS_CSCID = 0x0B
- USB_CLASS_HID = 0x03
- USB_CLASS_HUB = 0x09
- USB_CLASS_MASS_STORAGE = 0x08
- USB_CLASS_MISC = 0xEF
- USB_CLASS_PER_INTERFACE = 0x00
- USB_CLASS_PHYSICA = 0x05
- USB_CLASS_PRINTER = 0x07
- USB_CLASS_STILL_IMAGE = 0x06
- USB_CLASS_VENDOR_SPEC = 0xFF
- USB_CLASS_VIDEO = 0x0E
- USB_CLASS_WIRELESS = 0xE0
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsbManager
-# ═══════════════════════════════════════════════════════════════
-
-class UsbManager(Stub):
- """UsbManager — USB 管理器"""
-
- ACTION_USB_DEVICE_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED"
- ACTION_USB_DEVICE_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED"
- ACTION_USB_ACCESSORY_ATTACHED = "android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
- ACTION_USB_ACCESSORY_DETACHED = "android.hardware.usb.action.USB_ACCESSORY_DETACHED"
-
- EXTRA_DEVICE = "device"
- EXTRA_ACCESSORY = "accessory"
- EXTRA_PERMISSION_GRANTED = "permission"
-
- def __init__(self):
- super().__init__()
- self._devices: Dict[str, UsbDevice] = {}
- self._permissions: Set[str] = set()
- self._accessories: List[UsbAccessory] = []
- self._connections: Dict[str, UsbDeviceConnection] = {}
- # Create some mock devices
- self._devices["001"] = UsbDevice(
- deviceId=1, deviceName="/dev/bus/usb/001/001",
- vendorId=0x18D1, productId=0x4EE1,
- deviceClass=UsbConstants.USB_CLASS_MISC,
- deviceSubclass=0, deviceProtocol=0,
- manufacturerName="Google", productName="Pixel Device",
- version="3.1", serialNumber="ABC123"
- )
-
- def getDeviceList(self) -> Dict[str, UsbDevice]:
- return dict(self._devices)
-
- def openDevice(self, device: "UsbDevice") -> Optional["UsbDeviceConnection"]:
- if not device:
- return None
- conn = UsbDeviceConnection(device)
- self._connections[str(device.getDeviceId())] = conn
- return conn
-
- def hasPermission(self, device: "UsbDevice") -> bool:
- return device.getDeviceName() in self._permissions
-
- def requestPermission(self, device: "UsbDevice"):
- self._permissions.add(device.getDeviceName())
-
- def grantPermission(self, device: "UsbDevice"):
- self._permissions.add(device.getDeviceName())
-
- def revokePermission(self, device: "UsbDevice"):
- self._permissions.discard(device.getDeviceName())
-
- def setCurrentFunction(self, function: str, usbDataUnlocked: bool = False):
- pass
-
- def setUsbDataUnlocked(self, unlocked: bool):
- pass
-
- def getCurrentAccessory(self) -> Optional["UsbAccessory"]:
- return self._accessories[0] if self._accessories else None
-
- def openAccessory(self, accessory: "UsbAccessory") -> Optional["UsbDeviceConnection"]:
- if not accessory:
- return None
- conn = UsbDeviceConnection(accessory)
- return conn
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsbDevice
-# ═══════════════════════════════════════════════════════════════
-
-class UsbDevice(Stub):
- """UsbDevice — USB 设备"""
-
- def __init__(self, deviceId: int = 0, deviceName: str = "",
- vendorId: int = 0, productId: int = 0,
- deviceClass: int = 0, deviceSubclass: int = 0,
- deviceProtocol: int = 0, configurationCount: int = 1,
- interfaceCount: int = 0,
- manufacturerName: str = "", productName: str = "",
- version: str = "", serialNumber: str = ""):
- super().__init__()
- self._device_id = deviceId
- self._device_name = deviceName
- self._vendor_id = vendorId
- self._product_id = productId
- self._device_class = deviceClass
- self._device_subclass = deviceSubclass
- self._device_protocol = deviceProtocol
- self._configuration_count = configurationCount
- self._interface_count = interfaceCount
- self._manufacturer_name = manufacturerName
- self._product_name = productName
- self._version = version
- self._serial_number = serialNumber
- self._interfaces: List[UsbInterface] = []
-
- def getDeviceId(self) -> int:
- return self._device_id
-
- def getDeviceName(self) -> str:
- return self._device_name
-
- def getVendorId(self) -> int:
- return self._vendor_id
-
- def getProductId(self) -> int:
- return self._product_id
-
- def getDeviceClass(self) -> int:
- return self._device_class
-
- def getDeviceSubclass(self) -> int:
- return self._device_subclass
-
- def getDeviceProtocol(self) -> int:
- return self._device_protocol
-
- def getConfigurationCount(self) -> int:
- return self._configuration_count
-
- def getInterfaceCount(self) -> int:
- return len(self._interfaces)
-
- def getInterface(self, index: int) -> Optional["UsbInterface"]:
- if 0 <= index < len(self._interfaces):
- return self._interfaces[index]
- return None
-
- def getInterfaces(self) -> List["UsbInterface"]:
- return list(self._interfaces)
-
- def getManufacturerName(self) -> str:
- return self._manufacturer_name
-
- def getProductName(self) -> str:
- return self._product_name
-
- def getVersion(self) -> str:
- return self._version
-
- def getSerialNumber(self) -> str:
- return self._serial_number
-
- def describeContents(self) -> int:
- return 0
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, UsbDevice):
- return False
- return self._device_id == other._device_id
-
- def hashCode(self) -> int:
- return hash(self._device_id) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"UsbDevice(name={self._device_name}, vid={self._vendor_id:x}," \
- f" pid={self._product_id:x})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsbDeviceConnection
-# ═══════════════════════════════════════════════════════════════
-
-class UsbDeviceConnection(Stub):
- """UsbDeviceConnection — USB 设备连接"""
-
- def __init__(self, device: Any):
- super().__init__()
- self._device = device
- self._claimed_interfaces: Set[int] = set()
- self._fd = -1
-
- def claimInterface(self, intf: "UsbInterface", force: bool = False) -> bool:
- self._claimed_interfaces.add(intf.getId())
- return True
-
- def releaseInterface(self, intf: "UsbInterface") -> bool:
- self._claimed_interfaces.discard(intf.getId())
- return True
-
- def bulkTransfer(self, endpoint: "UsbEndpoint", buffer: bytes,
- length: int, timeout: int) -> int:
- return -1
-
- def controlTransfer(self, requestType: int, request: int,
- value: int, index: int, buffer: bytes,
- length: int, timeout: int) -> int:
- return -1
-
- def getRawDescriptors(self) -> bytes:
- return b""
-
- def getFileDescriptor(self) -> int:
- return self._fd
-
- def serial(self) -> Optional[str]:
- if hasattr(self._device, 'getSerialNumber'):
- return self._device.getSerialNumber()
- return None
-
- def close(self):
- self._claimed_interfaces.clear()
-
- def toString(self) -> str:
- return f"UsbDeviceConnection(device={self._device})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsbInterface
-# ═══════════════════════════════════════════════════════════════
-
-class UsbInterface(Stub):
- """UsbInterface — USB 接口"""
-
- def __init__(self, id: int = 0, alternateSetting: int = 0,
- name: str = "", interfaceClass: int = 0,
- interfaceSubclass: int = 0, interfaceProtocol: int = 0):
- super().__init__()
- self._id = id
- self._alternate_setting = alternateSetting
- self._name = name
- self._interface_class = interfaceClass
- self._interface_subclass = interfaceSubclass
- self._interface_protocol = interfaceProtocol
- self._endpoints: List[UsbEndpoint] = []
-
- def getId(self) -> int:
- return self._id
-
- def getAlternateSetting(self) -> int:
- return self._alternate_setting
-
- def getName(self) -> str:
- return self._name
-
- def getInterfaceClass(self) -> int:
- return self._interface_class
-
- def getInterfaceSubclass(self) -> int:
- return self._interface_subclass
-
- def getInterfaceProtocol(self) -> int:
- return self._interface_protocol
-
- def getEndpointCount(self) -> int:
- return len(self._endpoints)
-
- def getEndpoint(self, index: int) -> Optional["UsbEndpoint"]:
- if 0 <= index < len(self._endpoints):
- return self._endpoints[index]
- return None
-
- def toString(self) -> str:
- return f"UsbInterface(id={self._id}, name={self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsbEndpoint
-# ═══════════════════════════════════════════════════════════════
-
-class UsbEndpoint(Stub):
- """UsbEndpoint — USB 端点"""
-
- def __init__(self, address: int = 0, endpointNumber: int = 0,
- attributes: int = 0, direction: int = 0,
- maxPacketSize: int = 64, interval: int = 0,
- type_: int = 0):
- super().__init__()
- self._address = address
- self._endpoint_number = endpointNumber
- self._attributes = attributes
- self._direction = direction
- self._max_packet_size = maxPacketSize
- self._interval = interval
- self._type = type_
-
- def getAddress(self) -> int:
- return self._address
-
- def getEndpointNumber(self) -> int:
- return self._endpoint_number
-
- def getAttributes(self) -> int:
- return self._attributes
-
- def getDirection(self) -> int:
- return self._direction
-
- def getMaxPacketSize(self) -> int:
- return self._max_packet_size
-
- def getInterval(self) -> int:
- return self._interval
-
- def getType(self) -> int:
- return self._type
-
- def toString(self) -> str:
- return f"UsbEndpoint(addr={self._address:#04x}, type={self._type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# UsbAccessory
-# ═══════════════════════════════════════════════════════════════
-
-class UsbAccessory(Stub):
- """UsbAccessory — USB 附件"""
-
- def __init__(self, manufacturer: str = "", model: str = "",
- description: str = "", version: str = "",
- uri: str = "", serial: str = ""):
- super().__init__()
- self._manufacturer = manufacturer
- self._model = model
- self._description = description
- self._version = version
- self._uri = uri
- self._serial = serial
-
- def getManufacturer(self) -> str:
- return self._manufacturer
-
- def getModel(self) -> str:
- return self._model
-
- def getDescription(self) -> str:
- return self._description
-
- def getVersion(self) -> str:
- return self._version
-
- def getUri(self) -> str:
- return self._uri
-
- def getSerial(self) -> str:
- return self._serial
-
- def toString(self) -> str:
- return f"UsbAccessory(manufacturer={self._manufacturer}, model={self._model})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "UsbManager",
- "UsbDevice",
- "UsbDeviceConnection",
- "UsbInterface",
- "UsbEndpoint",
- "UsbConstants",
- "UsbAccessory",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/inputmethod.py b/android_pyapi/android/inputmethod.py
deleted file mode 100644
index 553deef..0000000
--- a/android_pyapi/android/inputmethod.py
+++ /dev/null
@@ -1,804 +0,0 @@
-"""
-Android InputMethod 组件 — InputMethodService, Keyboard, KeyboardView, Key 等
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError, android_context
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputMethod
-# ═══════════════════════════════════════════════════════════════
-
-class InputMethod(Stub):
- """InputMethod — 输入法接口"""
-
- def __init__(self):
- super().__init__()
-
- def createSession(self, callback: Any) -> Optional["InputMethodSession"]:
- """创建输入法会话"""
- return None
-
- def startInput(self, input_connection: Any, editor_info: Any) -> None:
- """开始输入"""
- pass
-
- def restartInput(self, input_connection: Any, editor_info: Any) -> None:
- """重启输入"""
- pass
-
- def dispatchKeyEvent(self, event: Any) -> None:
- """分发按键事件"""
- pass
-
- def dispatchTrackballEvent(self, event: Any) -> None:
- """分发轨迹球事件"""
- pass
-
- def dispatchGenericMotionEvent(self, event: Any) -> None:
- """分发通用运动事件"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputMethodSession
-# ═══════════════════════════════════════════════════════════════
-
-class InputMethodSession(Stub):
- """InputMethodSession — 输入法会话接口"""
-
- def __init__(self):
- super().__init__()
-
- def finishInput(self):
- """结束输入"""
- pass
-
- def updateSelection(self, old_sel_start: int, old_sel_end: int,
- new_sel_start: int, new_sel_end: int,
- candidates_start: int, candidates_end: int):
- """更新选区"""
- pass
-
- def updateCursor(self, old_cursor: Any, new_cursor: Any):
- """更新光标"""
- pass
-
- def displayCompletions(self, completions: List["CompletionInfo"]):
- """显示补全"""
- pass
-
- def appPrivateCommand(self, action: str, data: Any):
- """应用私有命令"""
- pass
-
- def viewClicked(self, focus_changed: bool):
- """视图点击"""
- pass
-
- def updateExtractedText(self, token: int, extracted_text: Any):
- """更新提取文本"""
- pass
-
- def dispatchKeyEvent(self, key_code: int, event: Any) -> None:
- """分发按键事件"""
- pass
-
- def dispatchTrackballEvent(self, event: Any) -> None:
- pass
-
- def dispatchGenericMotionEvent(self, event: Any) -> None:
- pass
-
- def toggleSoftInput(self, show_flags: int, hide_flags: int):
- """切换软键盘"""
- pass
-
- def notifyImeHidden(self):
- """通知输入法隐藏"""
- pass
-
- def removeImeSurface(self):
- """移除输入法界面"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AbstractInputMethodService
-# ═══════════════════════════════════════════════════════════════
-
-class AbstractInputMethodService(Stub):
- """AbstractInputMethodService — 抽象输入法服务基类"""
-
- def __init__(self):
- super().__init__()
- self._input_method: Optional[InputMethod] = None
- self._input_method_session: Optional[InputMethodSession] = None
-
- def onCreate(self):
- """服务创建"""
- pass
-
- def onDestroy(self):
- """服务销毁"""
- pass
-
- def onBind(self, intent: Any) -> Any:
- """绑定"""
- return None
-
- def onUnbind(self, intent: Any) -> bool:
- """解绑"""
- return False
-
- def onCreateInputMethod(self) -> InputMethod:
- """创建输入法实例"""
- return InputMethod()
-
- def onCreateInputMethodSession(self) -> InputMethodSession:
- """创建输入法会话"""
- return InputMethodSession()
-
- def getKeyDispatcherState(self) -> Any:
- """获取按键调度状态"""
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputMethodImpl
-# ═══════════════════════════════════════════════════════════════
-
-class InputMethodImpl(InputMethod):
- """InputMethodImpl — 输入法实现"""
-
- def __init__(self):
- super().__init__()
- self._session: Optional[InputMethodSession] = None
-
- def createSession(self, callback: Any) -> Optional["InputMethodSession"]:
- self._session = InputMethodSessionImpl()
- return self._session
-
- def startInput(self, input_connection: Any, editor_info: Any):
- sys.stderr.write("[InputMethodImpl] startInput\n")
-
- def restartInput(self, input_connection: Any, editor_info: Any):
- sys.stderr.write("[InputMethodImpl] restartInput\n")
-
- def dispatchKeyEvent(self, event: Any):
- sys.stderr.write("[InputMethodImpl] dispatchKeyEvent\n")
-
- def dispatchTrackballEvent(self, event: Any):
- pass
-
- def dispatchGenericMotionEvent(self, event: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputMethodSessionImpl
-# ═══════════════════════════════════════════════════════════════
-
-class InputMethodSessionImpl(InputMethodSession):
- """InputMethodSessionImpl — 输入法会话实现"""
-
- def __init__(self):
- super().__init__()
-
- def finishInput(self):
- sys.stderr.write("[InputMethodSessionImpl] finishInput\n")
-
- def updateSelection(self, old_sel_start: int, old_sel_end: int,
- new_sel_start: int, new_sel_end: int,
- candidates_start: int, candidates_end: int):
- pass
-
- def displayCompletions(self, completions: List["CompletionInfo"]):
- pass
-
- def dispatchKeyEvent(self, key_code: int, event: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputMethodService
-# ═══════════════════════════════════════════════════════════════
-
-class InputMethodService(AbstractInputMethodService):
- """InputMethodService — 输入法服务"""
-
- SHOW_EXPLICIT = 0x0001
- SHOW_IMPLICIT = 0x0002
-
- def __init__(self):
- super().__init__()
- self._input_view: Optional[Any] = None
- self._candidates_view: Optional[Any] = None
- self._input_connection: Optional[Any] = None
- self._input_editor_info: Optional["EditorInfo"] = None
- self._input_binding: Optional["InputBinding"] = None
- self._input_view_shown: bool = False
- self._fullscreen_mode: bool = False
- self._extract_to_fullscreen_mode: bool = False
- self._is_fullscreen: bool = False
- self._keyboard: Optional["Keyboard"] = None
- self._settings_observer: Any = None
- self._candidates_view_shown: bool = False
- self._show_input_requested: bool = False
- self._token: Any = None
- self._window_visible: bool = False
- self._input_started: bool = False
-
- def onCreate(self):
- """创建服务"""
- sys.stderr.write("[InputMethodService] onCreate\n")
-
- def onCreateInputView(self) -> Optional[Any]:
- """创建输入视图"""
- return None
-
- def onCreateCandidatesView(self) -> Optional[Any]:
- """创建候选视图"""
- return None
-
- def onStartInputView(self, info: "EditorInfo", restarting: bool):
- """开始输入视图"""
- pass
-
- def onFinishInputView(self, finishing_input: bool):
- """结束输入视图"""
- pass
-
- def onStartInput(self, attribute: "EditorInfo", restarting: bool):
- """开始输入"""
- self._input_editor_info = attribute
- self._input_started = True
-
- def onFinishInput(self):
- """结束输入"""
- self._input_started = False
-
- def onBindInput(self, binding: "InputBinding"):
- """绑定输入"""
- self._input_binding = binding
-
- def onUnbindInput(self) -> bool:
- """解绑输入"""
- self._input_binding = None
- return False
-
- def onDestroy(self):
- """销毁"""
- self._input_view = None
- self._candidates_view = None
- self._input_connection = None
-
- def showWindow(self, show_flags: int):
- """显示窗口"""
- self._window_visible = True
- sys.stderr.write(f"[InputMethodService] showWindow: flags={show_flags}\n")
-
- def hideWindow(self):
- """隐藏窗口"""
- self._window_visible = False
-
- def setInputView(self, view: Any):
- """设置输入视图"""
- self._input_view = view
-
- def setCandidatesView(self, view: Any):
- """设置候选视图"""
- self._candidates_view = view
-
- def updateInputViewShown(self):
- """更新输入视图显示状态"""
- pass
-
- def updateFullscreenMode(self):
- """更新全屏模式"""
- pass
-
- def updateExtractToFullscreenMode(self):
- """更新提取全屏模式"""
- pass
-
- def requestHideSelf(self, flags: int):
- """请求隐藏自身"""
- sys.stderr.write(f"[InputMethodService] requestHideSelf: flags={flags}\n")
-
- def switchInputMethod(self, id: str):
- """切换输入法"""
- sys.stderr.write(f"[InputMethodService] switchInputMethod: id={id}\n")
-
- def sendDefaultEditorAction(self, from_enter_key: bool):
- """发送默认编辑器动作"""
- pass
-
- def sendDownUpKeyEvents(self, key_event_code: int):
- """发送按键按下和释放事件"""
- pass
-
- def getCurrentInputBinding(self) -> Optional["InputBinding"]:
- """获取当前输入绑定"""
- return self._input_binding
-
- def getCurrentInputEditorInfo(self) -> Optional["EditorInfo"]:
- """获取当前编辑器信息"""
- return self._input_editor_info
-
- def getCurrentInputConnection(self) -> Optional["InputConnection"]:
- """获取当前输入连接"""
- return self._input_connection
-
- def getTextForImeAction(self, ime_options: int) -> str:
- """获取IME动作的文本"""
- action_map = {
- 0x0001: "None",
- 0x0002: "Go",
- 0x0003: "Search",
- 0x0004: "Send",
- 0x0005: "Next",
- 0x0006: "Done",
- 0x0007: "Previous",
- }
- action = ime_options & 0x000000FF
- return action_map.get(action, "Unknown")
-
- def doStartInput(self, input_connection: Any, editor_info: "EditorInfo", restarting: bool):
- """执行启动输入"""
- self._input_connection = input_connection
- self._input_editor_info = editor_info
- self.onStartInput(editor_info, restarting)
- if self._window_visible:
- self.onStartInputView(editor_info, restarting)
-
- def doFinishInput(self):
- """执行结束输入"""
- self.onFinishInput()
- self.onFinishInputView(True)
-
- def onEvaluateInputViewShown(self) -> bool:
- """评估是否显示输入视图"""
- return self._input_view is not None
-
- def onEvaluateFullscreenMode(self) -> bool:
- """评估是否全屏模式"""
- return self._fullscreen_mode
-
- def onConfigureWindow(self, win: Any, is_fullscreen: bool, is_candidates: bool):
- """配置窗口"""
- pass
-
- def isInputViewShown(self) -> bool:
- """输入视图是否已显示"""
- return self._input_view_shown
-
- def updateWindow(self, show_input: bool = False):
- """更新窗口"""
- pass
-
- def setExtractView(self, view: Any):
- """设置提取视图"""
- pass
-
- def getExtractView(self) -> Optional[Any]:
- """获取提取视图"""
- return None
-
- def getInputView(self) -> Optional[Any]:
- """获取输入视图"""
- return self._input_view
-
- def getCandidatesView(self) -> Optional[Any]:
- """获取候选视图"""
- return self._candidates_view
-
- def isFullscreenMode(self) -> bool:
- """是否全屏模式"""
- return self._is_fullscreen
-
- def onDisplayCompletions(self, completions: List["CompletionInfo"]):
- """显示补全"""
- pass
-
- def onUpdateSelection(self, old_sel_start: int, old_sel_end: int,
- new_sel_start: int, new_sel_end: int,
- candidates_start: int, candidates_end: int):
- """更新选区"""
- pass
-
- def onViewClicked(self, focus_changed: bool):
- """视图点击"""
- pass
-
- def onWindowShown(self):
- """窗口显示"""
- self._window_visible = True
-
- def onWindowHidden(self):
- """窗口隐藏"""
- self._window_visible = False
-
- def setKeyboard(self, keyboard: "Keyboard"):
- """设置键盘"""
- self._keyboard = keyboard
-
- def getKeyboard(self) -> Optional["Keyboard"]:
- """获取键盘"""
- return self._keyboard
-
-
-# ═══════════════════════════════════════════════════════════════
-# Key
-# ═══════════════════════════════════════════════════════════════
-
-class Key(Stub):
- """Key — 键盘按键"""
-
- def __init__(self, row: "KeyboardRow" = None):
- super().__init__()
- self.codes: List[int] = []
- self.label: Optional[str] = None
- self.icon: Any = None
- self.sticky: bool = False
- self.modifier: bool = False
- self.repeatable: bool = False
- self.edgeFlags: int = 0
- self.popupCharacters: Optional[str] = None
- self.popupResId: int = 0
- self._x: int = 0
- self._y: int = 0
- self._width: int = 0
- self._height: int = 0
- self._gap: int = 0
- self._row: Optional["KeyboardRow"] = row
- self._pressed: bool = False
- self._on: bool = False
-
- def getCode(self) -> int:
- """获取按键码"""
- return self.codes[0] if self.codes else 0
-
- def isPressed(self) -> bool:
- """是否按下"""
- return self._pressed
-
- def setPressed(self, pressed: bool):
- """设置按下状态"""
- self._pressed = pressed
-
- def isOn(self) -> bool:
- """是否开启"""
- return self._on
-
- def setOn(self, on_state: bool):
- """设置开启状态"""
- self._on = on_state
-
- def squaredDistance(self, x: int, y: int) -> int:
- """计算距离平方"""
- center_x = self._x + self._width // 2
- center_y = self._y + self._height // 2
- return (x - center_x) ** 2 + (y - center_y) ** 2
-
- def hitTest(self, x: int, y: int) -> bool:
- """命中测试"""
- return (self._x <= x <= self._x + self._width and
- self._y <= y <= self._y + self._height)
-
- def getX(self) -> int:
- return self._x
-
- def getY(self) -> int:
- return self._y
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def toString(self) -> str:
- return f"Key(code={self.getCode()}, label={self.label})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# KeyboardRow
-# ═══════════════════════════════════════════════════════════════
-
-class KeyboardRow(Stub):
- """KeyboardRow — 键盘行"""
-
- def __init__(self, keyboard: "Keyboard" = None):
- super().__init__()
- self._keys: List[Key] = []
- self._keyboard: Optional["Keyboard"] = keyboard
- self._default_width: int = 0
- self._default_height: int = 0
- self._row_edge_flags: int = 0
- self._mode: str = ""
-
- def getKeys(self) -> List[Key]:
- return list(self._keys)
-
- def addKey(self, key: Key):
- self._keys.append(key)
-
- def getKeyboard(self) -> Optional["Keyboard"]:
- return self._keyboard
-
- def getDefaultWidth(self) -> int:
- return self._default_width
-
- def getDefaultHeight(self) -> int:
- return self._default_height
-
- def toString(self) -> str:
- return f"KeyboardRow(keys={len(self._keys)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Keyboard
-# ═══════════════════════════════════════════════════════════════
-
-class Keyboard(Stub):
- """Keyboard — 键盘布局"""
-
- def __init__(self, context: Any = None, xml_layout_res_id: int = 0):
- super().__init__()
- self._keys: List[Key] = []
- self._rows: List[KeyboardRow] = []
- self._modifier_keys: List[Key] = []
- self._height: int = 0
- self._min_width: int = 0
- self._key_width: int = 0
- self._key_height: int = 0
- self._horizontal_gap: int = 0
- self._vertical_gap: int = 0
- self._shift_keys: List[Key] = []
- self._alt_keys: List[Key] = []
-
- def getKeys(self) -> List[Key]:
- return list(self._keys)
-
- def getHeight(self) -> int:
- return self._height
-
- def getMinWidth(self) -> int:
- return self._min_width
-
- def getKeyWidth(self) -> int:
- return self._key_width
-
- def getKeyHeight(self) -> int:
- return self._key_height
-
- def getHorizontalGap(self) -> int:
- return self._horizontal_gap
-
- def getVerticalGap(self) -> int:
- return self._vertical_gap
-
- def getModifierKeys(self) -> List[Key]:
- return list(self._modifier_keys)
-
- def getNearestKeys(self, x: int, y: int) -> List[Key]:
- """获取最近的按键"""
- nearest: List[Key] = []
- for key in self._keys:
- if key.hitTest(x, y):
- nearest.append(key)
- return nearest
-
- def setKeys(self, keys: List[Key]):
- """设置按键列表"""
- self._keys = keys
-
- def getRows(self) -> List[KeyboardRow]:
- return list(self._rows)
-
- def setShifted(self, shift_state: bool):
- """设置Shift状态"""
- pass
-
- def isShifted(self) -> bool:
- """是否Shift状态"""
- return False
-
- def getShiftKeyIndex(self) -> int:
- """获取Shift按键索引"""
- for i, key in enumerate(self._keys):
- if key.modifier:
- return i
- return -1
-
- def setVerticalGap(self, gap: int):
- self._vertical_gap = gap
-
- def setHorizontalGap(self, gap: int):
- self._horizontal_gap = gap
-
- def setKeyWidth(self, width: int):
- self._key_width = width
-
- def setKeyHeight(self, height: int):
- self._key_height = height
-
- def toString(self) -> str:
- return f"Keyboard(keys={len(self._keys)}, rows={len(self._rows)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# KeyboardView
-# ═══════════════════════════════════════════════════════════════
-
-class KeyboardView(Stub):
- """KeyboardView — 键盘视图"""
-
- class OnKeyboardActionListener(Stub):
- """OnKeyboardActionListener — 键盘动作监听器"""
-
- def onKey(self, primary_code: int):
- pass
-
- def onPress(self, primary_code: int):
- pass
-
- def onRelease(self, primary_code: int):
- pass
-
- def onText(self, text: str):
- pass
-
- def swipeLeft(self):
- pass
-
- def swipeRight(self):
- pass
-
- def swipeDown(self):
- pass
-
- def swipeUp(self):
- pass
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__()
- self._keyboard: Optional[Keyboard] = None
- self._on_keyboard_action_listener: Optional["KeyboardView.OnKeyboardActionListener"] = None
- self._preview_enabled: bool = True
- self._proximity_correction_enabled: bool = True
- self._vertical_correction: int = 0
- self._key_text_color: int = 0xFF000000
- self._key_text_size: int = 20
- self._shadow_color: int = 0x00000000
- self._shadow_radius: float = 0.0
- self._background_color: int = 0xFF888888
-
- def setKeyboard(self, keyboard: Keyboard):
- self._keyboard = keyboard
-
- def getKeyboard(self) -> Optional[Keyboard]:
- return self._keyboard
-
- def onDraw(self, canvas: Any):
- """绘制键盘"""
- pass
-
- def setOnKeyboardActionListener(self, listener: "KeyboardView.OnKeyboardActionListener"):
- self._on_keyboard_action_listener = listener
-
- def getOnKeyboardActionListener(self) -> Optional["KeyboardView.OnKeyboardActionListener"]:
- return self._on_keyboard_action_listener
-
- def setPreviewEnabled(self, preview_enabled: bool):
- self._preview_enabled = preview_enabled
-
- def isPreviewEnabled(self) -> bool:
- return self._preview_enabled
-
- def setProximityCorrectionEnabled(self, enabled: bool):
- self._proximity_correction_enabled = enabled
-
- def isProximityCorrectionEnabled(self) -> bool:
- return self._proximity_correction_enabled
-
- def setVerticalCorrection(self, vertical_correction: int):
- self._vertical_correction = vertical_correction
-
- def getVerticalCorrection(self) -> int:
- return self._vertical_correction
-
- def setKeyTextColor(self, color: int):
- self._key_text_color = color
-
- def setKeyTextSize(self, size: int):
- self._key_text_size = size
-
- def setShadowColor(self, color: int):
- self._shadow_color = color
-
- def setShadowRadius(self, radius: float):
- self._shadow_radius = radius
-
- def setBackgroundColor(self, color: int):
- self._background_color = color
-
- def invalidateAllKeys(self):
- """使所有按键失效"""
- pass
-
- def invalidateKey(self, key_index: int):
- """使指定按键失效"""
- pass
-
- def onClick(self, key: Key):
- """点击按键"""
- if self._on_keyboard_action_listener and key.codes:
- self._on_keyboard_action_listener.onKey(key.codes[0])
-
- def onLongPress(self, key: Key) -> bool:
- """长按按键"""
- if key.popupCharacters:
- return True
- return False
-
- def closing(self):
- """关闭"""
- pass
-
- def handleBack(self) -> bool:
- """处理返回键"""
- return False
-
- def setKeys(self, keys: List[Key]):
- """设置按键"""
- if self._keyboard:
- self._keyboard.setKeys(keys)
-
-
-# ═══════════════════════════════════════════════════════════════
-# KeyEventCallback
-# ═══════════════════════════════════════════════════════════════
-
-class KeyEventCallback(Stub):
- """KeyEventCallback — 按键事件回调"""
-
- def onKeyDown(self, key_code: int, event: Any) -> bool:
- """按键按下"""
- return False
-
- def onKeyLongPress(self, key_code: int, event: Any) -> bool:
- """按键长按"""
- return False
-
- def onKeyUp(self, key_code: int, event: Any) -> bool:
- """按键释放"""
- return False
-
- def onKeyMultiple(self, key_code: int, count: int, event: Any) -> bool:
- """按键重复"""
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "InputMethodService",
- "InputMethodImpl",
- "InputMethodSessionImpl",
- "AbstractInputMethodService",
- "InputMethod",
- "InputMethodSession",
- "Keyboard",
- "KeyboardView",
- "Key",
- "KeyEventCallback",
- "KeyboardRow",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/inputmethodservice.py b/android_pyapi/android/inputmethodservice.py
deleted file mode 100644
index ffb09b6..0000000
--- a/android_pyapi/android/inputmethodservice.py
+++ /dev/null
@@ -1,1078 +0,0 @@
-"""
-Android InputMethod Service 组件 — InputMethodService, AbstractInputMethodService, Keyboard, Key, KeyboardView 等
-方法签名完全对齐 Android SDK (android.inputmethodservice 包)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-KEYCODE_UNKNOWN = 0
-KEYCODE_SOFT_LEFT = 1
-KEYCODE_SOFT_RIGHT = 2
-KEYCODE_HOME = 3
-KEYCODE_BACK = 4
-KEYCODE_CALL = 5
-KEYCODE_ENDCALL = 6
-KEYCODE_0 = 7
-KEYCODE_1 = 8
-KEYCODE_2 = 9
-KEYCODE_3 = 10
-KEYCODE_4 = 11
-KEYCODE_5 = 12
-KEYCODE_6 = 13
-KEYCODE_7 = 14
-KEYCODE_8 = 15
-KEYCODE_9 = 16
-KEYCODE_STAR = 17
-KEYCODE_POUND = 18
-KEYCODE_DPAD_UP = 19
-KEYCODE_DPAD_DOWN = 20
-KEYCODE_DPAD_LEFT = 21
-KEYCODE_DPAD_RIGHT = 22
-KEYCODE_DPAD_CENTER = 23
-KEYCODE_VOLUME_UP = 24
-KEYCODE_VOLUME_DOWN = 25
-KEYCODE_POWER = 26
-KEYCODE_CAMERA = 27
-KEYCODE_CLEAR = 28
-KEYCODE_A = 29
-KEYCODE_B = 30
-KEYCODE_C = 31
-KEYCODE_D = 32
-KEYCODE_E = 33
-KEYCODE_F = 34
-KEYCODE_G = 35
-KEYCODE_H = 36
-KEYCODE_I = 37
-KEYCODE_J = 38
-KEYCODE_K = 39
-KEYCODE_L = 40
-KEYCODE_M = 41
-KEYCODE_N = 42
-KEYCODE_O = 43
-KEYCODE_P = 44
-KEYCODE_Q = 45
-KEYCODE_R = 46
-KEYCODE_S = 47
-KEYCODE_T = 48
-KEYCODE_U = 49
-KEYCODE_V = 50
-KEYCODE_W = 51
-KEYCODE_X = 52
-KEYCODE_Y = 53
-KEYCODE_Z = 54
-KEYCODE_COMMA = 55
-KEYCODE_PERIOD = 56
-KEYCODE_ALT_LEFT = 57
-KEYCODE_ALT_RIGHT = 58
-KEYCODE_SHIFT_LEFT = 59
-KEYCODE_SHIFT_RIGHT = 60
-KEYCODE_TAB = 61
-KEYCODE_SPACE = 62
-KEYCODE_SYM = 63
-KEYCODE_EXPLORER = 64
-KEYCODE_ENVELOPE = 65
-KEYCODE_ENTER = 66
-KEYCODE_DEL = 67
-KEYCODE_GRAVE = 68
-KEYCODE_MINUS = 69
-KEYCODE_EQUALS = 70
-KEYCODE_LEFT_BRACKET = 71
-KEYCODE_RIGHT_BRACKET = 72
-KEYCODE_BACKSLASH = 73
-KEYCODE_SEMICOLON = 74
-KEYCODE_APOSTROPHE = 75
-KEYCODE_SLASH = 76
-KEYCODE_AT = 77
-KEYCODE_NUM = 78
-KEYCODE_HEADSETHOOK = 79
-KEYCODE_FOCUS = 80
-KEYCODE_PLUS = 81
-KEYCODE_MENU = 82
-KEYCODE_NOTIFICATION = 83
-KEYCODE_SEARCH = 84
-KEYCODE_MEDIA_PLAY_PAUSE = 85
-KEYCODE_MEDIA_STOP = 86
-KEYCODE_MEDIA_NEXT = 87
-KEYCODE_MEDIA_PREVIOUS = 88
-KEYCODE_MEDIA_REWIND = 89
-KEYCODE_MEDIA_FAST_FORWARD = 90
-KEYCODE_MUTE = 91
-KEYCODE_PAGE_UP = 92
-KEYCODE_PAGE_DOWN = 93
-KEYCODE_PICTSYMBOLS = 94
-KEYCODE_SWITCH_CHARSET = 95
-KEYCODE_BUTTON_A = 96
-KEYCODE_BUTTON_B = 97
-KEYCODE_BUTTON_C = 98
-KEYCODE_BUTTON_X = 99
-KEYCODE_BUTTON_Y = 100
-KEYCODE_BUTTON_Z = 101
-KEYCODE_BUTTON_L1 = 102
-KEYCODE_BUTTON_R1 = 103
-KEYCODE_BUTTON_L2 = 104
-KEYCODE_BUTTON_R2 = 105
-KEYCODE_BUTTON_THUMBL = 106
-KEYCODE_BUTTON_THUMBR = 107
-KEYCODE_BUTTON_START = 108
-KEYCODE_BUTTON_SELECT = 109
-KEYCODE_BUTTON_MODE = 110
-KEYCODE_ESCAPE = 111
-KEYCODE_FORWARD_DEL = 112
-KEYCODE_CTRL_LEFT = 113
-KEYCODE_CTRL_RIGHT = 114
-KEYCODE_CAPS_LOCK = 115
-KEYCODE_SCROLL_LOCK = 116
-KEYCODE_META_LEFT = 117
-KEYCODE_META_RIGHT = 118
-KEYCODE_FUNCTION = 119
-KEYCODE_SYSRQ = 120
-KEYCODE_BREAK = 121
-KEYCODE_MOVE_HOME = 122
-KEYCODE_MOVE_END = 123
-KEYCODE_INSERT = 124
-KEYCODE_FORWARD = 125
-KEYCODE_MEDIA_PLAY = 126
-KEYCODE_MEDIA_PAUSE = 127
-KEYCODE_MEDIA_CLOSE = 128
-KEYCODE_MEDIA_EJECT = 129
-KEYCODE_MEDIA_RECORD = 130
-KEYCODE_F1 = 131
-KEYCODE_F2 = 132
-KEYCODE_F3 = 133
-KEYCODE_F4 = 134
-KEYCODE_F5 = 135
-KEYCODE_F6 = 136
-KEYCODE_F7 = 137
-KEYCODE_F8 = 138
-KEYCODE_F9 = 139
-KEYCODE_F10 = 140
-KEYCODE_F11 = 141
-KEYCODE_F12 = 142
-KEYCODE_NUM_LOCK = 143
-KEYCODE_NUMPAD_0 = 144
-KEYCODE_NUMPAD_1 = 145
-KEYCODE_NUMPAD_2 = 146
-KEYCODE_NUMPAD_3 = 147
-KEYCODE_NUMPAD_4 = 148
-KEYCODE_NUMPAD_5 = 149
-KEYCODE_NUMPAD_6 = 150
-KEYCODE_NUMPAD_7 = 151
-KEYCODE_NUMPAD_8 = 152
-KEYCODE_NUMPAD_9 = 153
-KEYCODE_NUMPAD_DIVIDE = 154
-KEYCODE_NUMPAD_MULTIPLY = 155
-KEYCODE_NUMPAD_SUBTRACT = 156
-KEYCODE_NUMPAD_ADD = 157
-KEYCODE_NUMPAD_DOT = 158
-KEYCODE_NUMPAD_COMMA = 159
-KEYCODE_NUMPAD_ENTER = 160
-KEYCODE_NUMPAD_EQUALS = 161
-KEYCODE_NUMPAD_LEFT_PAREN = 162
-KEYCODE_NUMPAD_RIGHT_PAREN = 163
-KEYCODE_VOLUME_MUTE = 164
-KEYCODE_INFO = 165
-KEYCODE_CHANNEL_UP = 166
-KEYCODE_CHANNEL_DOWN = 167
-KEYCODE_ZOOM_IN = 168
-KEYCODE_ZOOM_OUT = 169
-KEYCODE_TV = 170
-KEYCODE_WINDOW = 171
-KEYCODE_GUIDE = 172
-KEYCODE_DVR = 173
-KEYCODE_BOOKMARK = 174
-KEYCODE_CAPTIONS = 175
-KEYCODE_SETTINGS = 176
-KEYCODE_TV_POWER = 177
-KEYCODE_TV_INPUT = 178
-KEYCODE_STB_POWER = 179
-KEYCODE_STB_INPUT = 180
-KEYCODE_AVR_POWER = 181
-KEYCODE_AVR_INPUT = 182
-KEYCODE_PROG_RED = 183
-KEYCODE_PROG_GREEN = 184
-KEYCODE_PROG_YELLOW = 185
-KEYCODE_PROG_BLUE = 186
-KEYCODE_APP_SWITCH = 187
-KEYCODE_BUTTON_1 = 188
-KEYCODE_BUTTON_2 = 189
-KEYCODE_BUTTON_3 = 190
-KEYCODE_BUTTON_4 = 191
-KEYCODE_BUTTON_5 = 192
-KEYCODE_BUTTON_6 = 193
-KEYCODE_BUTTON_7 = 194
-KEYCODE_BUTTON_8 = 195
-KEYCODE_BUTTON_9 = 196
-KEYCODE_BUTTON_10 = 197
-KEYCODE_BUTTON_11 = 198
-KEYCODE_BUTTON_12 = 199
-KEYCODE_BUTTON_13 = 200
-KEYCODE_BUTTON_14 = 201
-KEYCODE_BUTTON_15 = 202
-KEYCODE_BUTTON_16 = 203
-KEYCODE_LANGUAGE_SWITCH = 204
-KEYCODE_MANNER_MODE = 205
-KEYCODE_3D_MODE = 206
-KEYCODE_CONTACTS = 207
-KEYCODE_CALENDAR = 208
-KEYCODE_MUSIC = 209
-KEYCODE_CALCULATOR = 210
-KEYCODE_ZENKAKU_HANKAKU = 211
-KEYCODE_EISU = 212
-KEYCODE_MUHENKAN = 213
-KEYCODE_HENKAN = 214
-KEYCODE_KATAKANA_HIRAGANA = 215
-KEYCODE_YEN = 216
-KEYCODE_RO = 217
-KEYCODE_KANA = 218
-KEYCODE_ASSIST = 219
-KEYCODE_BRIGHTNESS_DOWN = 220
-KEYCODE_BRIGHTNESS_UP = 221
-KEYCODE_MEDIA_AUDIO_TRACK = 222
-KEYCODE_SLEEP = 223
-KEYCODE_WAKEUP = 224
-KEYCODE_PAIRING = 225
-KEYCODE_MEDIA_TOP_MENU = 226
-KEYCODE_11 = 227
-KEYCODE_12 = 228
-KEYCODE_LAST_CHANNEL = 229
-KEYCODE_TV_DATA_SERVICE = 230
-KEYCODE_VOICE_ASSIST = 231
-KEYCODE_TV_RADIO_SERVICE = 232
-KEYCODE_TV_TELETEXT = 233
-KEYCODE_TV_NUMBER_ENTRY = 234
-KEYCODE_TV_TERRESTRIAL_ANALOG = 235
-KEYCODE_TV_TERRESTRIAL_DIGITAL = 236
-KEYCODE_TV_SATELLITE = 237
-KEYCODE_TV_SATELLITE_BS = 238
-KEYCODE_TV_SATELLITE_CS = 239
-KEYCODE_TV_SATELLITE_SERVICE = 240
-KEYCODE_TV_NETWORK = 241
-KEYCODE_TV_ANTENNA_CABLE = 242
-KEYCODE_TV_INPUT_HDMI_1 = 243
-KEYCODE_TV_INPUT_HDMI_2 = 244
-KEYCODE_TV_INPUT_HDMI_3 = 245
-KEYCODE_TV_INPUT_HDMI_4 = 246
-KEYCODE_TV_INPUT_COMPOSITE_1 = 247
-KEYCODE_TV_INPUT_COMPOSITE_2 = 248
-KEYCODE_TV_INPUT_COMPONENT_1 = 249
-KEYCODE_TV_INPUT_COMPONENT_2 = 250
-KEYCODE_TV_INPUT_VGA_1 = 251
-KEYCODE_TV_AUDIO_DESCRIPTION = 252
-KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253
-KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254
-KEYCODE_TV_ZOOM_MODE = 255
-KEYCODE_TV_CONTENTS_MENU = 256
-KEYCODE_TV_MEDIA_CONTEXT_MENU = 257
-KEYCODE_TV_TIMER_PROGRAMMING = 258
-KEYCODE_HELP = 259
-KEYCODE_NAVIGATE_PREVIOUS = 260
-KEYCODE_NAVIGATE_NEXT = 261
-KEYCODE_NAVIGATE_IN = 262
-KEYCODE_NAVIGATE_OUT = 263
-KEYCODE_STEM_PRIMARY = 264
-KEYCODE_STEM_1 = 265
-KEYCODE_STEM_2 = 266
-KEYCODE_STEM_3 = 267
-KEYCODE_DPAD_UP_LEFT = 268
-KEYCODE_DPAD_DOWN_LEFT = 269
-KEYCODE_DPAD_UP_RIGHT = 270
-KEYCODE_DPAD_DOWN_RIGHT = 271
-KEYCODE_MEDIA_SKIP_FORWARD = 272
-KEYCODE_MEDIA_SKIP_BACKWARD = 273
-KEYCODE_MEDIA_STEP_FORWARD = 274
-KEYCODE_MEDIA_STEP_BACKWARD = 275
-KEYCODE_MEDIA_TOP_MENU_2 = 276
-KEYCODE_SOFT_SLEEP = 277
-KEYCODE_CUT = 278
-KEYCODE_COPY = 279
-KEYCODE_PASTE = 280
-KEYCODE_SYSTEM_NAVIGATION_UP = 281
-KEYCODE_SYSTEM_NAVIGATION_DOWN = 282
-KEYCODE_SYSTEM_NAVIGATION_LEFT = 283
-KEYCODE_SYSTEM_NAVIGATION_RIGHT = 284
-KEYCODE_ALL_APPS = 285
-KEYCODE_REFRESH = 286
-KEYCODE_THUMBS_UP = 287
-KEYCODE_THUMBS_DOWN = 288
-KEYCODE_PROFILE_SWITCH = 289
-KEYCODE_VIDEO_APP_1 = 290
-KEYCODE_VIDEO_APP_2 = 291
-KEYCODE_VIDEO_APP_3 = 292
-KEYCODE_VIDEO_APP_4 = 293
-KEYCODE_VIDEO_APP_5 = 294
-KEYCODE_VIDEO_APP_6 = 295
-KEYCODE_VIDEO_APP_7 = 296
-KEYCODE_VIDEO_APP_8 = 297
-KEYCODE_FEATURED_APP_1 = 298
-KEYCODE_FEATURED_APP_2 = 299
-KEYCODE_FEATURED_APP_3 = 300
-KEYCODE_FEATURED_APP_4 = 301
-KEYCODE_DEMO_APP_1 = 302
-KEYCODE_DEMO_APP_2 = 303
-KEYCODE_DEMO_APP_3 = 304
-KEYCODE_DEMO_APP_4 = 305
-
-
-# ═══════════════════════════════════════════════════════════════
-# Key
-# ═══════════════════════════════════════════════════════════════
-
-class Key(Stub):
- """Key — 键盘按键"""
-
- KEY_FLAG_ALT = 1
- KEY_FLAG_SHIFT = 2
- KEY_FLAG_CAPS_LOCK = 4
- KEY_FLAG_CTRL = 8
- KEY_FLAG_META = 16
- KEY_FLAG_FUNCTION = 32
- KEY_FLAG_MODIFIER = 64
- KEY_FLAG_REPEAT = 128
- KEY_FLAG_LONGPRESS = 256
- KEY_FLAG_CLUSTER = 512
- KEY_FLAG_CANCELED = 1024
- KEY_FLAG_EDGE = 2048
- KEY_FLAG_GESTURE = 4096
- KEY_FLAG_VIRTUAL = 8192
-
- KEY_TYPE_NORMAL = 0
- KEY_TYPE_MODIFIER = 1
- KEY_TYPE_SPACE = 2
- KEY_TYPE_DONE = 3
- KEY_TYPE_DELETE = 4
- KEY_TYPE_ACTION = 5
- KEY_TYPE_CANCEL = 6
- KEY_TYPE_MODE_CHANGE = 7
- KEY_TYPE_SHIFT = 8
- KEY_TYPE_ALT = 9
- KEY_TYPE_CTRL = 10
- KEY_TYPE_FUNCTION = 11
- KEY_TYPE_EMOJI = 12
- KEY_TYPE_LANGUAGE = 13
-
- def __init__(self, key_code: int = KEYCODE_UNKNOWN, label: str = "",
- type: int = KEY_TYPE_NORMAL):
- super().__init__()
- self._key_code = key_code
- self._label = label
- self._type = type
- self._text: str = ""
- self._icon: Any = None
- self._x: int = 0
- self._y: int = 0
- self._width: int = 0
- self._height: int = 0
- self._gap: int = 0
- self._sticky: bool = False
- self._modifier: bool = False
- self._enabled: bool = True
- self._repeating: bool = False
- self._edge_flags: int = 0
- self._popup_characters: str = ""
- self._secondary_labels: List[str] = []
-
- def getKeyCode(self) -> int:
- return self._key_code
-
- def setKeyCode(self, key_code: int):
- self._key_code = key_code
-
- def getLabel(self) -> str:
- return self._label
-
- def setLabel(self, label: str):
- self._label = label
-
- def getType(self) -> int:
- return self._type
-
- def setType(self, type_: int):
- self._type = type_
-
- def getText(self) -> str:
- return self._text
-
- def setText(self, text: str):
- self._text = text
-
- def getIcon(self) -> Any:
- return self._icon
-
- def setIcon(self, icon: Any):
- self._icon = icon
-
- def getX(self) -> int:
- return self._x
-
- def setX(self, x: int):
- self._x = x
-
- def getY(self) -> int:
- return self._y
-
- def setY(self, y: int):
- self._y = y
-
- def getWidth(self) -> int:
- return self._width
-
- def setWidth(self, width: int):
- self._width = width
-
- def getHeight(self) -> int:
- return self._height
-
- def setHeight(self, height: int):
- self._height = height
-
- def getGap(self) -> int:
- return self._gap
-
- def setGap(self, gap: int):
- self._gap = gap
-
- def isSticky(self) -> bool:
- return self._sticky
-
- def setSticky(self, sticky: bool):
- self._sticky = sticky
-
- def isModifier(self) -> bool:
- return self._modifier
-
- def setModifier(self, modifier: bool):
- self._modifier = modifier
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- def isRepeating(self) -> bool:
- return self._repeating
-
- def setRepeating(self, repeating: bool):
- self._repeating = repeating
-
- def getPopupCharacters(self) -> str:
- return self._popup_characters
-
- def setPopupCharacters(self, chars: str):
- self._popup_characters = chars
-
- def getSecondaryLabels(self) -> List[str]:
- return list(self._secondary_labels)
-
- def setSecondaryLabels(self, labels: List[str]):
- self._secondary_labels = list(labels)
-
- def isShiftKey(self) -> bool:
- return self._type == Key.KEY_TYPE_SHIFT
-
- def isAltKey(self) -> bool:
- return self._type == Key.KEY_TYPE_ALT
-
- def isCtrlKey(self) -> bool:
- return self._type == Key.KEY_TYPE_CTRL
-
- def isFunctionKey(self) -> bool:
- return self._type == Key.KEY_TYPE_FUNCTION
-
- def toString(self) -> str:
- return f"Key(code={self._key_code}, label={self._label}, type={self._type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Keyboard
-# ═══════════════════════════════════════════════════════════════
-
-class Keyboard(Stub):
- """Keyboard — 键盘布局"""
-
- KEYBOARD_TYPE_ALPHA = 0
- KEYBOARD_TYPE_NUMERIC = 1
- KEYBOARD_TYPE_PHONE = 2
- KEYBOARD_TYPE_SYMBOLS = 3
- KEYBOARD_TYPE_EMOJI = 4
- KEYBOARD_TYPE_URL = 5
- KEYBOARD_TYPE_EMAIL = 6
- KEYBOARD_TYPE_IME = 7
-
- EDGE_LEFT = 1
- EDGE_RIGHT = 2
- EDGE_TOP = 4
- EDGE_BOTTOM = 8
-
- def __init__(self, context: Any = None, layout_id: int = 0,
- keyboard_type: int = KEYBOARD_TYPE_ALPHA):
- super().__init__()
- self._context = context
- self._layout_id = layout_id
- self._keyboard_type = keyboard_type
- self._keys: List[Key] = []
- self._shift_keys: List[Key] = []
- self._alt_keys: List[Key] = []
- self._ctrl_keys: List[Key] = []
- self._function_keys: List[Key] = []
- self._modifier_keys: List[Key] = []
- self._key_width: int = 0
- self._key_height: int = 0
- self._horizontal_gap: int = 0
- self._vertical_gap: int = 0
- self._default_row_height: int = 0
- self._rows: int = 0
- self._columns: int = 0
- self._label: str = ""
- self._is_shifted: bool = False
- self._is_alt: bool = False
- self._is_ctrl: bool = False
- self._is_function: bool = False
-
- def getKeys(self) -> List[Key]:
- return list(self._keys)
-
- def setKeys(self, keys: List[Key]):
- self._keys = list(keys)
-
- def addKey(self, key: Key):
- self._keys.append(key)
-
- def removeKey(self, key: Key):
- self._keys = [k for k in self._keys if k is not key]
-
- def getKeyByCode(self, key_code: int) -> Optional[Key]:
- for k in self._keys:
- if k.getKeyCode() == key_code:
- return k
- return None
-
- def getShiftKeys(self) -> List[Key]:
- return list(self._shift_keys)
-
- def getAltKeys(self) -> List[Key]:
- return list(self._alt_keys)
-
- def getModifierKeys(self) -> List[Key]:
- return list(self._modifier_keys)
-
- def getKeyWidth(self) -> int:
- return self._key_width
-
- def setKeyWidth(self, width: int):
- self._key_width = width
-
- def getKeyHeight(self) -> int:
- return self._key_height
-
- def setKeyHeight(self, height: int):
- self._key_height = height
-
- def getHorizontalGap(self) -> int:
- return self._horizontal_gap
-
- def setHorizontalGap(self, gap: int):
- self._horizontal_gap = gap
-
- def getVerticalGap(self) -> int:
- return self._vertical_gap
-
- def setVerticalGap(self, gap: int):
- self._vertical_gap = gap
-
- def getRows(self) -> int:
- return self._rows
-
- def setRows(self, rows: int):
- self._rows = rows
-
- def getColumns(self) -> int:
- return self._columns
-
- def setColumns(self, cols: int):
- self._columns = cols
-
- def getLabel(self) -> str:
- return self._label
-
- def setLabel(self, label: str):
- self._label = label
-
- def isShifted(self) -> bool:
- return self._is_shifted
-
- def setShifted(self, shifted: bool):
- self._is_shifted = shifted
-
- def getKeyboardType(self) -> int:
- return self._keyboard_type
-
- def setKeyboardType(self, type_: int):
- self._keyboard_type = type_
-
- def toString(self) -> str:
- return f"Keyboard(keys={len(self._keys)}, type={self._keyboard_type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# KeyboardView
-# ═══════════════════════════════════════════════════════════════
-
-class KeyboardView(Stub):
- """KeyboardView — 键盘视图"""
-
- def __init__(self, context: Any = None, keyboard: Keyboard = None):
- super().__init__()
- self._context = context
- self._keyboard = keyboard
- self._is_visible: bool = False
- self._is_preview_enabled: bool = True
- self._is_proximity_correction_enabled: bool = True
- self._key_text_size: float = 20.0
- self._key_text_color: int = 0xFF000000
- self._background_color: int = 0xFFEEEEEE
- self._preview_background_color: int = 0xFFCCCCCC
- self._on_key_listener: Optional[Callable] = None
- self._on_key_action_listener: Optional[Callable] = None
- self._pressed_keys: Set[Key] = set()
- self._keyboard_width: int = 0
- self._keyboard_height: int = 0
-
- def setKeyboard(self, keyboard: Keyboard):
- self._keyboard = keyboard
-
- def getKeyboard(self) -> Optional[Keyboard]:
- return self._keyboard
-
- def setVisibility(self, visible: bool):
- self._is_visible = visible
-
- def isVisible(self) -> bool:
- return self._is_visible
-
- def setPreviewEnabled(self, enabled: bool):
- self._is_preview_enabled = enabled
-
- def isPreviewEnabled(self) -> bool:
- return self._is_preview_enabled
-
- def setProximityCorrectionEnabled(self, enabled: bool):
- self._is_proximity_correction_enabled = enabled
-
- def isProximityCorrectionEnabled(self) -> bool:
- return self._is_proximity_correction_enabled
-
- def setKeyTextSize(self, size: float):
- self._key_text_size = size
-
- def getKeyTextSize(self) -> float:
- return self._key_text_size
-
- def setKeyTextColor(self, color: int):
- self._key_text_color = color
-
- def getKeyTextColor(self) -> int:
- return self._key_text_color
-
- def setBackgroundColor(self, color: int):
- self._background_color = color
-
- def getBackgroundColor(self) -> int:
- return self._background_color
-
- def setOnKeyboardActionListener(self, listener: Callable):
- self._on_key_listener = listener
-
- def setOnKeyListener(self, listener: Callable):
- self._on_key_action_listener = listener
-
- def simulateKeyPress(self, key: Key):
- """模拟按键按下"""
- self._pressed_keys.add(key)
- if self._on_key_listener:
- self._on_key_listener.onKey(key.getKeyCode(), key)
-
- def simulateKeyRelease(self, key: Key):
- """模拟按键释放"""
- self._pressed_keys.discard(key)
-
- def isKeyPressed(self, key: Key) -> bool:
- return key in self._pressed_keys
-
- def invalidate(self):
- """重绘键盘"""
- pass
-
- def setKeyboardWidth(self, width: int):
- self._keyboard_width = width
-
- def setKeyboardHeight(self, height: int):
- self._keyboard_height = height
-
- def getKeyboardWidth(self) -> int:
- return self._keyboard_width
-
- def getKeyboardHeight(self) -> int:
- return self._keyboard_height
-
- def clampY(self, y: int) -> int:
- return max(0, min(y, self._keyboard_height))
-
- def toString(self) -> str:
- return f"KeyboardView(visible={self._is_visible})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AbstractInputMethodService
-# ═══════════════════════════════════════════════════════════════
-
-class AbstractInputMethodService(Stub):
- """AbstractInputMethodService — 抽象输入法服务基类"""
-
- SERVICE_INTERFACE = "android.inputmethodservice.AbstractInputMethodService"
- SERVICE_META_DATA = "android.inputmethod"
-
- def __init__(self):
- super().__init__()
- self._keyboard_view: Optional[KeyboardView] = None
- self._keyboard: Optional[Keyboard] = None
- self._is_fullscreen: bool = False
- self._is_extracted_view_visible: bool = False
- self._is_input_view_visible: bool = False
- self._is_candidates_view_visible: bool = False
- self._input_view_started: bool = False
-
- def onCreate(self):
- pass
-
- def onDestroy(self):
- self._keyboard = None
- self._keyboard_view = None
-
- def onCreateInputView(self) -> Optional[KeyboardView]:
- return self._keyboard_view
-
- def onCreateCandidatesView(self) -> Any:
- return None
-
- def onStartInputView(self, info: Any, restarting: bool):
- self._is_input_view_visible = True
- self._input_view_started = True
-
- def onFinishInputView(self, finishing_input: bool):
- self._is_input_view_visible = False
-
- def onStartCandidatesView(self, info: Any, restarting: bool):
- self._is_candidates_view_visible = True
-
- def onFinishCandidatesView(self, finishing_input: bool):
- self._is_candidates_view_visible = False
-
- def onStartInput(self, input_connection: Any, editor_info: Any, restarting: bool):
- pass
-
- def onFinishInput(self):
- pass
-
- def setKeyboard(self, keyboard: Keyboard):
- self._keyboard = keyboard
- if self._keyboard_view:
- self._keyboard_view.setKeyboard(keyboard)
-
- def getKeyboard(self) -> Optional[Keyboard]:
- return self._keyboard
-
- def setKeyboardView(self, keyboard_view: KeyboardView):
- self._keyboard_view = keyboard_view
-
- def getKeyboardView(self) -> Optional[KeyboardView]:
- return self._keyboard_view
-
- def sendKeyChar(self, char: str):
- pass
-
- def sendDownUpKeyEvents(self, key_event_code: int):
- pass
-
- def switchToNextKeyboard(self):
- pass
-
- def switchToPreviousKeyboard(self):
- pass
-
- def hideWindow(self):
- self._is_input_view_visible = False
- self._is_candidates_view_visible = False
-
- def showWindow(self, show_flags: int):
- pass
-
- def requestHideSelf(self, flags: int):
- pass
-
- def requestShowSelf(self, flags: int):
- pass
-
- def isFullscreen(self) -> bool:
- return self._is_fullscreen
-
- def setFullscreen(self, fullscreen: bool):
- self._is_fullscreen = fullscreen
-
- def toString(self) -> str:
- return f"AbstractInputMethodService(fullscreen={self._is_fullscreen})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputMethodService
-# ═══════════════════════════════════════════════════════════════
-
-class InputMethodService(AbstractInputMethodService):
- """InputMethodService — 输入法服务"""
-
- BACK_DISPOSITION_DEFAULT = 0
- BACK_DISPOSITION_WILL_DISMISS = 1
- BACK_DISPOSITION_WILL_NOT_DISMISS = 2
-
- SHOW_INPUT_METHOD_PICKER = 1
- SHOW_EXPLICIT = 2
- SHOW_FORCED = 4
-
- HIDE_EXPLICIT = 1
- HIDE_NOT_ALWAYS = 2
- HIDE_IMPLICIT_ONLY = 4
- HIDE_BY_COMMAND = 8
-
- KEYGUARD_DISABLE_NONE = 0
- KEYGUARD_DISABLE_FEATURES_NONE = 0
- KEYGUARD_DISABLE_FEATURES_ALL = 0x7FFFFFFF
-
- def __init__(self):
- super().__init__()
- self._back_disposition: int = InputMethodService.BACK_DISPOSITION_DEFAULT
- self._is_input_view_shown: bool = False
- self._is_candidates_view_shown: bool = False
- self._extract_view: Any = None
- self._input_connection: Any = None
- self._current_input_editor_info: Any = None
- self._settings_observer: Any = None
-
- def onInitializeInterface(self):
- pass
-
- def onBindInput(self):
- pass
-
- def onUnbindInput(self):
- pass
-
- def onStartInput(self, attribute: Any, restarting: bool):
- super().onStartInput(attribute, attribute, restarting)
-
- def onFinishInput(self):
- super().onFinishInput()
-
- def onDisplayCompletions(self, completions: List[Any]):
- pass
-
- def onUpdateSelection(self, old_sel_start: int, old_sel_end: int,
- new_sel_start: int, new_sel_end: int,
- candidates_start: int, candidates_end: int):
- pass
-
- def onUpdateExtractedText(self, token: int, extracted_text: Any):
- pass
-
- def onExtractedTextClicked(self):
- pass
-
- def onExtractingInputChanged(self, editor_info: Any):
- pass
-
- def onConfigureWindow(self, win: Any, is_fullscreen: bool, is_obscured: bool):
- pass
-
- def onEvaluateFullscreenMode(self) -> bool:
- return self._is_fullscreen
-
- def onEvaluateInputViewShown(self) -> bool:
- return True
-
- def onComputeInsets(self, out_insets: Any):
- pass
-
- def onKeyDown(self, key_code: int, event: Any) -> bool:
- return False
-
- def onKeyUp(self, key_code: int, event: Any) -> bool:
- return False
-
- def onKeyLongPress(self, key_code: int, event: Any) -> bool:
- return False
-
- def onKeyMultiple(self, key_code: int, count: int, event: Any) -> bool:
- return False
-
- def onTrackballEvent(self, event: Any) -> bool:
- return False
-
- def onGenericMotionEvent(self, event: Any) -> bool:
- return False
-
- def onWindowShown(self):
- pass
-
- def onWindowHidden(self):
- pass
-
- def setBackDisposition(self, disposition: int):
- self._back_disposition = disposition
-
- def getBackDisposition(self) -> int:
- return self._back_disposition
-
- def switchInputMethod(self, id: str):
- pass
-
- def changeInputMethodSubtype(self, subtype: Any):
- pass
-
- def getCurrentInputBinding(self) -> Any:
- return None
-
- def getCurrentInputConnection(self) -> Any:
- return self._input_connection
-
- def getCurrentInputEditorInfo(self) -> Any:
- return self._current_input_editor_info
-
- def getCurrentInputStarted(self) -> bool:
- return self._input_view_started
-
- def getLayoutInflater(self) -> Any:
- return None
-
- def getWindow(self) -> Any:
- return None
-
- def isInputViewShown(self) -> bool:
- return self._is_input_view_shown
-
- def setInputView(self, view: Any):
- self._is_input_view_shown = view is not None
-
- def showStatusIcon(self, icon_id: int):
- pass
-
- def hideStatusIcon(self):
- pass
-
- def sendDefaultEditorAction(self, from_enter_key: bool):
- pass
-
- def sendDownUpKeyEvents(self, key_event_code: int):
- pass
-
- def sendKeyChar(self, char: str):
- pass
-
- def updateFullscreenMode(self):
- pass
-
- def updateInputViewShown(self):
- pass
-
- def exposeCompletions(self, completions: List[Any]):
- self.onDisplayCompletions(completions)
-
- def toString(self) -> str:
- return f"InputMethodService(backDisposition={self._back_disposition})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputMethodServiceKeyboardHelper
-# ═══════════════════════════════════════════════════════════════
-
-class InputMethodServiceKeyboardHelper(Stub):
- """InputMethodServiceKeyboardHelper — 输入法键盘辅助类"""
-
- @staticmethod
- def createDefaultQWERTYKeyboard(context: Any) -> Keyboard:
- kb = Keyboard(context, 0, Keyboard.KEYBOARD_TYPE_ALPHA)
- row1_chars = "qwertyuiop"
- row2_chars = "asdfghjkl"
- row3_chars = "zxcvbnm"
- for i, c in enumerate(row1_chars):
- k = Key(ord(c.upper()), c, Key.KEY_TYPE_NORMAL)
- k.setWidth(50)
- k.setHeight(60)
- k.setX(i * 55)
- kb.addKey(k)
- shift_key = Key(KEYCODE_SHIFT_LEFT, "Shift", Key.KEY_TYPE_SHIFT)
- shift_key.setWidth(70)
- shift_key.setHeight(60)
- kb.addKey(shift_key)
- space_key = Key(KEYCODE_SPACE, " ", Key.KEY_TYPE_SPACE)
- space_key.setWidth(200)
- space_key.setHeight(60)
- kb.addKey(space_key)
- del_key = Key(KEYCODE_DEL, "Del", Key.KEY_TYPE_DELETE)
- del_key.setWidth(70)
- del_key.setHeight(60)
- kb.addKey(del_key)
- enter_key = Key(KEYCODE_ENTER, "Enter", Key.KEY_TYPE_DONE)
- enter_key.setWidth(80)
- enter_key.setHeight(60)
- kb.addKey(enter_key)
- return kb
-
- @staticmethod
- def createNumericKeyboard(context: Any) -> Keyboard:
- kb = Keyboard(context, 0, Keyboard.KEYBOARD_TYPE_NUMERIC)
- for i in range(10):
- k = Key(KEYCODE_0 + i, str(i), Key.KEY_TYPE_NORMAL)
- k.setWidth(60)
- k.setHeight(60)
- kb.addKey(k)
- return kb
-
- @staticmethod
- def createPhoneKeyboard(context: Any) -> Keyboard:
- kb = Keyboard(context, 0, Keyboard.KEYBOARD_TYPE_PHONE)
- layout = [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"], ["*", "0", "#"]]
- for row_idx, row in enumerate(layout):
- for col_idx, c in enumerate(row):
- k = Key(KEYCODE_0 + int(c) if c.isdigit() else (
- KEYCODE_STAR if c == "*" else KEYCODE_POUND), c, Key.KEY_TYPE_NORMAL)
- k.setWidth(80)
- k.setHeight(60)
- k.setX(col_idx * 85)
- k.setY(row_idx * 65)
- kb.addKey(k)
- return kb
-
- @staticmethod
- def createSymbolKeyboard(context: Any) -> Keyboard:
- kb = Keyboard(context, 0, Keyboard.KEYBOARD_TYPE_SYMBOLS)
- symbols = "~!@#$%^&*()_+-=[]{}|;':\",./<>?"
- for i, c in enumerate(symbols):
- k = Key(KEYCODE_UNKNOWN, c, Key.KEY_TYPE_NORMAL)
- k.setWidth(45)
- k.setHeight(55)
- kb.addKey(k)
- return kb
-
- @staticmethod
- def createKeyboardView(context: Any, keyboard: Keyboard) -> KeyboardView:
- return KeyboardView(context, keyboard)
\ No newline at end of file
diff --git a/android_pyapi/android/location.py b/android_pyapi/android/location.py
deleted file mode 100644
index fa791f7..0000000
--- a/android_pyapi/android/location.py
+++ /dev/null
@@ -1,1266 +0,0 @@
-"""
-Android Location 组件 — Location, LocationManager, Geocoder 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-import math
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-from datetime import datetime
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-try:
- from .._linux_impl import IS_LINUX, LinuxLocation
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Location
-# ═══════════════════════════════════════════════════════════════
-
-class Location(Stub):
- """Location — 地理位置信息"""
-
- FORMAT_DEGREES = 0
- FORMAT_MINUTES = 1
- FORMAT_SECONDS = 2
-
- def __init__(self, provider: str = ""):
- super().__init__()
- self._provider = provider
- self._latitude: float = 0.0
- self._longitude: float = 0.0
- self._accuracy: float = 0.0
- self._time: int = 0
- self._elapsed_realtime_nanos: int = 0
- self._altitude: float = 0.0
- self._speed: float = 0.0
- self._bearing: float = 0.0
- self._extras: Optional[Dict[str, Any]] = None
-
- def setLatitude(self, latitude: float):
- self._latitude = latitude
-
- def getLatitude(self) -> float:
- return self._latitude
-
- def setLongitude(self, longitude: float):
- self._longitude = longitude
-
- def getLongitude(self) -> float:
- return self._longitude
-
- def setAccuracy(self, accuracy: float):
- self._accuracy = accuracy
-
- def getAccuracy(self) -> float:
- return self._accuracy
-
- def setTime(self, time: int):
- self._time = time
-
- def getTime(self) -> int:
- return self._time
-
- def setElapsedRealtimeNanos(self, nanos: int):
- self._elapsed_realtime_nanos = nanos
-
- def getElapsedRealtimeNanos(self) -> int:
- return self._elapsed_realtime_nanos
-
- def setAltitude(self, altitude: float):
- self._altitude = altitude
-
- def getAltitude(self) -> float:
- return self._altitude
-
- def setSpeed(self, speed: float):
- self._speed = speed
-
- def getSpeed(self) -> float:
- return self._speed
-
- def setBearing(self, bearing: float):
- self._bearing = bearing
-
- def getBearing(self) -> float:
- return self._bearing
-
- def setProvider(self, provider: str):
- self._provider = provider
-
- def getProvider(self) -> str:
- return self._provider
-
- def distanceTo(self, dest: "Location") -> float:
- R = 6371000
- lat1 = math.radians(self._latitude)
- lat2 = math.radians(dest._latitude)
- dlat = math.radians(dest._latitude - self._latitude)
- dlon = math.radians(dest._longitude - self._longitude)
- a = (math.sin(dlat / 2) ** 2 +
- math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2)
- c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
- return R * c
-
- def bearingTo(self, dest: "Location") -> float:
- lat1 = math.radians(self._latitude)
- lat2 = math.radians(dest._latitude)
- dlon = math.radians(dest._longitude - self._longitude)
- y = math.sin(dlon) * math.cos(lat2)
- x = (math.cos(lat1) * math.sin(lat2) -
- math.sin(lat1) * math.cos(lat2) * math.cos(dlon))
- return (math.degrees(math.atan2(y, x)) + 360) % 360
-
- @staticmethod
- def convert(coordinate: Union[str, float], output_type: int = FORMAT_DEGREES) -> Union[str, float]:
- if isinstance(coordinate, str):
- return Location._parse_coordinate(coordinate)
- return Location._format_coordinate(coordinate, output_type)
-
- @staticmethod
- def _parse_coordinate(coord_str: str) -> float:
- coord_str = coord_str.strip()
- try:
- return float(coord_str)
- except ValueError:
- pass
- parts = coord_str.replace(",", ".").split()
- if len(parts) >= 3:
- try:
- d = float(parts[0])
- m = float(parts[1])
- s = float(parts[2].rstrip("NSEW"))
- result = d + m / 60.0 + s / 3600.0
- if coord_str.rstrip()[-1:] in ("S", "W"):
- result = -result
- return result
- except (ValueError, IndexError):
- return 0.0
- return 0.0
-
- @staticmethod
- def _format_coordinate(coord: float, output_type: int) -> str:
- if output_type == Location.FORMAT_DEGREES:
- return f"{coord:.6f}"
- elif output_type == Location.FORMAT_MINUTES:
- deg = int(coord)
- minutes = (coord - deg) * 60
- return f"{deg}:{minutes:.3f}"
- else:
- deg = int(coord)
- minutes = (coord - deg) * 60
- int_min = int(minutes)
- secs = (minutes - int_min) * 60
- return f"{deg}:{int_min}:{secs:.2f}"
-
- def getExtras(self) -> Optional[Dict[str, Any]]:
- return self._extras
-
- def setExtras(self, extras: Dict[str, Any]):
- self._extras = extras
-
- def toString(self) -> str:
- return (f"Location[provider={self._provider}, "
- f"{self._latitude:.6f},{self._longitude:.6f}, "
- f"acc={self._accuracy:.1f}]")
-
- def __repr__(self):
- return self.toString()
-
-
-# ═══════════════════════════════════════════════════════════════
-# Criteria
-# ═══════════════════════════════════════════════════════════════
-
-class Criteria(Stub):
- """Criteria — 位置提供者筛选条件"""
-
- ACCURACY_FINE = 1
- ACCURACY_COARSE = 2
- POWER_LOW = 1
- POWER_MEDIUM = 2
- POWER_HIGH = 3
- NO_REQUIREMENT = 0
-
- def __init__(self):
- super().__init__()
- self._accuracy = self.NO_REQUIREMENT
- self._power_requirement = self.NO_REQUIREMENT
- self._altitude_required = False
- self._bearing_required = False
- self._speed_required = False
- self._cost_allowed = False
-
- def setAccuracy(self, accuracy: int):
- self._accuracy = accuracy
-
- def getAccuracy(self) -> int:
- return self._accuracy
-
- def setPowerRequirement(self, power: int):
- self._power_requirement = power
-
- def getPowerRequirement(self) -> int:
- return self._power_requirement
-
- def setAltitudeRequired(self, required: bool):
- self._altitude_required = required
-
- def isAltitudeRequired(self) -> bool:
- return self._altitude_required
-
- def setBearingRequired(self, required: bool):
- self._bearing_required = required
-
- def isBearingRequired(self) -> bool:
- return self._bearing_required
-
- def setSpeedRequired(self, required: bool):
- self._speed_required = required
-
- def isSpeedRequired(self) -> bool:
- return self._speed_required
-
- def setCostAllowed(self, allowed: bool):
- self._cost_allowed = allowed
-
- def isCostAllowed(self) -> bool:
- return self._cost_allowed
-
- def toString(self) -> str:
- return f"Criteria(acc={self._accuracy}, power={self._power_requirement})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocationProvider
-# ═══════════════════════════════════════════════════════════════
-
-class LocationProvider(Stub):
- """LocationProvider — 位置提供者"""
-
- AVAILABLE = 2
- TEMPORARILY_UNAVAILABLE = 1
- OUT_OF_SERVICE = 0
-
- def __init__(self, name: str = ""):
- super().__init__()
- self._name = name
- self._accuracy = Criteria.NO_REQUIREMENT
- self._power_requirement = Criteria.NO_REQUIREMENT
- self._has_monetary_cost = False
- self._requires_cell = False
- self._requires_network = False
- self._requires_satellite = False
- self._supports_altitude = False
- self._supports_bearing = False
- self._supports_speed = False
-
- def getName(self) -> str:
- return self._name
-
- def getAccuracy(self) -> int:
- return self._accuracy
-
- def getPowerRequirement(self) -> int:
- return self._power_requirement
-
- def hasMonetaryCost(self) -> bool:
- return self._has_monetary_cost
-
- def requiresCell(self) -> bool:
- return self._requires_cell
-
- def requiresNetwork(self) -> bool:
- return self._requires_network
-
- def requiresSatellite(self) -> bool:
- return self._requires_satellite
-
- def supportsAltitude(self) -> bool:
- return self._supports_altitude
-
- def supportsBearing(self) -> bool:
- return self._supports_bearing
-
- def supportsSpeed(self) -> bool:
- return self._supports_speed
-
- def getRequirements(self) -> int:
- req = 0
- if self._requires_cell:
- req |= 1
- if self._requires_network:
- req |= 2
- if self._requires_satellite:
- req |= 4
- return req
-
- def toString(self) -> str:
- return f"LocationProvider(name={self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocationListener
-# ═══════════════════════════════════════════════════════════════
-
-class LocationListener(Stub):
- """LocationListener — 位置变化监听器"""
-
- def onLocationChanged(self, location: Location):
- pass
-
- def onStatusChanged(self, provider: str, status: int, extras: Any):
- pass
-
- def onProviderEnabled(self, provider: str):
- pass
-
- def onProviderDisabled(self, provider: str):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# GpsSatellite
-# ═══════════════════════════════════════════════════════════════
-
-class GpsSatellite(Stub):
- """GpsSatellite — GPS 卫星信息"""
-
- def __init__(self):
- super().__init__()
- self._prn: int = 0
- self._snr: float = 0.0
- self._elevation: float = 0.0
- self._azimuth: float = 0.0
- self._has_almanac: bool = False
- self._has_ephemeris: bool = False
- self._used_in_fix: bool = False
-
- def getPrn(self) -> int:
- return self._prn
-
- def getSnr(self) -> float:
- return self._snr
-
- def getElevation(self) -> float:
- return self._elevation
-
- def getAzimuth(self) -> float:
- return self._azimuth
-
- def hasAlmanac(self) -> bool:
- return self._has_almanac
-
- def hasEphemeris(self) -> bool:
- return self._has_ephemeris
-
- def usedInFix(self) -> bool:
- return self._used_in_fix
-
- def toString(self) -> str:
- return f"GpsSatellite(prn={self._prn}, snr={self._snr})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GpsStatus
-# ═══════════════════════════════════════════════════════════════
-
-class GpsStatus(Stub):
- """GpsStatus — GPS 状态"""
-
- GPS_EVENT_STARTED = 1
- GPS_EVENT_STOPPED = 2
- GPS_EVENT_FIRST_FIX = 3
- GPS_EVENT_SATELLITE_STATUS = 4
-
- def __init__(self):
- super().__init__()
- self._satellites: List[GpsSatellite] = []
- self._max_satellites: int = 32
- self._time_to_first_fix: int = 0
-
- def getSatellites(self) -> List[GpsSatellite]:
- return list(self._satellites)
-
- def getMaxSatellites(self) -> int:
- return self._max_satellites
-
- def getTimeToFirstFix(self) -> int:
- return self._time_to_first_fix
-
- def setTimeToFirstFix(self, ttf: int):
- self._time_to_first_fix = ttf
-
-
-class GpsStatusListener(Stub):
- """GpsStatusListener — GPS 状态监听器"""
-
- def onGpsStatusChanged(self, event: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# GnssClock / GnssMeasurement / GnssMeasurementsEvent / GnssNavigationMessage
-# ═══════════════════════════════════════════════════════════════
-
-class GnssClock(Stub):
- """GnssClock — GNSS 时钟"""
-
- def __init__(self):
- super().__init__()
- self._time_nanos: int = 0
- self._time_uncertainty_nanos: float = 0.0
- self._leap_second: int = 0
- self._full_bias_nanos: int = 0
- self._bias_nanos: float = 0.0
- self._bias_uncertainty_nanos: float = 0.0
- self._drift_nanos_per_sec: float = 0.0
- self._drift_uncertainty_nanos_per_sec: float = 0.0
- self._hardware_clock_discontinuity_count: int = 0
- self._has_leap_second: bool = False
- self._has_full_bias_nanos: bool = False
- self._has_bias_nanos: bool = False
- self._has_bias_uncertainty_nanos: bool = False
- self._has_drift_nanos_per_sec: bool = False
- self._has_drift_uncertainty_nanos_per_sec: bool = False
-
- def getTimeNanos(self) -> int:
- return self._time_nanos
-
- def getTimeUncertaintyNanos(self) -> float:
- return self._time_uncertainty_nanos
-
- def getLeapSecond(self) -> int:
- return self._leap_second
-
- def getFullBiasNanos(self) -> int:
- return self._full_bias_nanos
-
- def getBiasNanos(self) -> float:
- return self._bias_nanos
-
- def getBiasUncertaintyNanos(self) -> float:
- return self._bias_uncertainty_nanos
-
- def getDriftNanosPerSec(self) -> float:
- return self._drift_nanos_per_sec
-
- def getDriftUncertaintyNanosPerSec(self) -> float:
- return self._drift_uncertainty_nanos_per_sec
-
- def getHardwareClockDiscontinuityCount(self) -> int:
- return self._hardware_clock_discontinuity_count
-
-
-class GnssMeasurement(Stub):
- """GnssMeasurement — GNSS 测量值"""
-
- STATE_UNKNOWN = 0
- STATE_CODE_LOCK = 1
- STATE_BIT_SYNC = 2
- STATE_SUBFRAME_SYNC = 3
- STATE_TOW_DECODED = 4
- STATE_MSEC_AMBIGUOUS = 5
-
- def __init__(self):
- super().__init__()
- self._svid: int = 0
- self._constellation_type: int = 0
- self._time_offset_nanos: float = 0.0
- self._state: int = 0
- self._received_gps_tow_nanos: int = 0
- self._received_gps_tow_uncertainty_nanos: int = 0
- self._carrier_frequency_hz: float = 0.0
- self._carrier_phase: float = 0.0
- self._carrier_phase_uncertainty: float = 0.0
- self._multipath_indicator: int = 0
- self._snr_in_db: float = 0.0
- self._constellation_type_val: int = 0
-
- def getSvid(self) -> int:
- return self._svid
-
- def getConstellationType(self) -> int:
- return self._constellation_type
-
- def getTimeOffsetNanos(self) -> float:
- return self._time_offset_nanos
-
- def getState(self) -> int:
- return self._state
-
- def getReceivedGpsTowNanos(self) -> int:
- return self._received_gps_tow_nanos
-
- def getReceivedGpsTowUncertaintyNanos(self) -> int:
- return self._received_gps_tow_uncertainty_nanos
-
- def getCarrierFrequencyHz(self) -> float:
- return self._carrier_frequency_hz
-
- def getCarrierPhase(self) -> float:
- return self._carrier_phase
-
- def getCarrierPhaseUncertainty(self) -> float:
- return self._carrier_phase_uncertainty
-
- def getMultipathIndicator(self) -> int:
- return self._multipath_indicator
-
- def getSnrInDb(self) -> float:
- return self._snr_in_db
-
-
-class GnssMeasurementsEvent(Stub):
- """GnssMeasurementsEvent — GNSS 测量事件"""
-
- def __init__(self, clock: Optional[GnssClock] = None,
- measurements: Optional[List[GnssMeasurement]] = None):
- super().__init__()
- self._clock = clock or GnssClock()
- self._measurements = measurements or []
-
- def getClock(self) -> GnssClock:
- return self._clock
-
- def getMeasurements(self) -> List[GnssMeasurement]:
- return list(self._measurements)
-
-
-class GnssNavigationMessage(Stub):
- """GnssNavigationMessage — GNSS 导航消息"""
-
- STATUS_PARITY_PASSED = 1
- STATUS_PARITY_REBUILT = 2
- TYPE_GPS_L1CA = 256
- TYPE_GPS_L2CA = 512
- TYPE_GPS_L5 = 768
- TYPE_GLO_L1CA = 1024
- TYPE_GLO_L2CA = 1280
- TYPE_BDS_D1 = 1792
- TYPE_BDS_D2 = 2048
- TYPE_GAL_I = 2560
- TYPE_GAL_F = 2816
- TYPE_QZS_L1CA = 3072
- TYPE_QZS_L5 = 3328
-
- def __init__(self):
- super().__init__()
- self._type: int = 0
- self._svid: int = 0
- self._message_id: int = 0
- self._submessage_id: int = 0
- self._data: bytes = b""
- self._status: int = 0
-
- def getType(self) -> int:
- return self._type
-
- def getSvid(self) -> int:
- return self._svid
-
- def getMessageId(self) -> int:
- return self._message_id
-
- def getSubmessageId(self) -> int:
- return self._submessage_id
-
- def getData(self) -> bytes:
- return self._data
-
- def getStatus(self) -> int:
- return self._status
-
-
-# ═══════════════════════════════════════════════════════════════
-# GnssStatus
-# ═══════════════════════════════════════════════════════════════
-
-class GnssStatus(Stub):
- """GnssStatus — GNSS 卫星状态"""
-
- GNSS_CONSTELLATION_GPS = 1
- GNSS_CONSTELLATION_SBAS = 2
- GNSS_CONSTELLATION_GLONASS = 3
- CONSTELLATION_QZSS = 4
- CONSTELLATION_BEIDOU = 5
- CONSTELLATION_GALILEO = 6
- CONSTELLATION_IRNSS = 7
-
- def __init__(self):
- super().__init__()
- self._satellites: List[Dict[str, Any]] = []
-
- def getSatelliteCount(self) -> int:
- return len(self._satellites)
-
- def getSvid(self, index: int) -> int:
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("svid", 0)
- return 0
-
- def getConstellationType(self, index: int) -> int:
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("constellation", 0)
- return 0
-
- def getCarrierFrequencyHz(self, index: int) -> float:
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("carrier_freq", 0.0)
- return 0.0
-
- def getBasebandCn0DbHz(self, index: int) -> float:
- """返回指定卫星的基带载噪比(dB-Hz)。"""
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("baseband_cn0", 0.0)
- return 0.0
-
- def getCn0DbHz(self, index: int) -> float:
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("cn0", 0.0)
- return 0.0
-
- def getAzimuthDegrees(self, index: int) -> float:
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("azimuth", 0.0)
- return 0.0
-
- def getElevationDegrees(self, index: int) -> float:
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("elevation", 0.0)
- return 0.0
-
- def hasAlmanac(self, index: int) -> bool:
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("has_almanac", False)
- return False
-
- def hasEphemeris(self, index: int) -> bool:
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("has_ephemeris", False)
- return False
-
- def usedInFix(self, index: int) -> bool:
- if 0 <= index < len(self._satellites):
- return self._satellites[index].get("used_in_fix", False)
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocationRequest
-# ═══════════════════════════════════════════════════════════════
-
-class LocationRequest(Stub):
- """LocationRequest — 位置请求"""
-
- QUALITY_HIGH_ACCURACY = 100
- QUALITY_BALANCED_POWER_ACCURACY = 102
- QUALITY_LOW_POWER = 104
- QUALITY_PASSIVE = 105
-
- PRIORITY_HIGH_ACCURACY = 100
- PRIORITY_BALANCED_POWER_ACCURACY = 102
- PRIORITY_LOW_POWER = 104
- PRIORITY_NO_POWER = 105
-
- def __init__(self):
- super().__init__()
- self._quality: int = self.QUALITY_BALANCED_POWER_ACCURACY
- self._interval: int = 60000
- self._fastest_interval: int = 30000
- self._smallest_displacement: float = 0.0
- self._max_wait_time: int = 0
- self._duration_millis: int = 0
- self._max_updates: int = 0 # 0 means unlimited
- self._priority: int = self.PRIORITY_BALANCED_POWER_ACCURACY
-
- def setQuality(self, quality: int):
- self._quality = quality
-
- def getQuality(self) -> int:
- return self._quality
-
- def setInterval(self, interval: int):
- self._interval = interval
-
- def getInterval(self) -> int:
- return self._interval
-
- def setFastestInterval(self, interval: int):
- self._fastest_interval = interval
-
- def getFastestInterval(self) -> int:
- return self._fastest_interval
-
- def setSmallestDisplacement(self, displacement: float):
- self._smallest_displacement = displacement
-
- def getSmallestDisplacement(self) -> float:
- return self._smallest_displacement
-
- def setMaxWaitTime(self, time: int):
- self._max_wait_time = time
-
- def getMaxWaitTime(self) -> int:
- return self._max_wait_time
-
- def setDurationMillis(self, duration: int):
- self._duration_millis = duration
-
- def getDurationMillis(self) -> int:
- return self._duration_millis
-
- def setMaxUpdates(self, updates: int):
- self._max_updates = updates
-
- def getMaxUpdates(self) -> int:
- return self._max_updates
-
- def setPriority(self, priority: int):
- self._priority = priority
-
- def getPriority(self) -> int:
- return self._priority
-
- def toString(self) -> str:
- return f"LocationRequest(interval={self._interval}, priority={self._priority})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocationProviderProperties
-# ═══════════════════════════════════════════════════════════════
-
-class LocationProviderProperties(Stub):
- """LocationProviderProperties — 提供者属性"""
-
- def __init__(self, requires_network: bool = False,
- requires_satellite: bool = False,
- requires_cell: bool = False,
- has_monetary_cost: bool = False,
- supports_altitude: bool = False,
- supports_speed: bool = False,
- supports_bearing: bool = False,
- power_requirement: int = Criteria.NO_REQUIREMENT,
- accuracy: int = Criteria.NO_REQUIREMENT):
- super().__init__()
- self.requiresNetwork = requires_network
- self.requiresSatellite = requires_satellite
- self.requiresCell = requires_cell
- self.hasMonetaryCost = has_monetary_cost
- self.supportsAltitude = supports_altitude
- self.supportsSpeed = supports_speed
- self.supportsBearing = supports_bearing
- self.powerRequirement = power_requirement
- self.accuracy = accuracy
-
-
-# ═══════════════════════════════════════════════════════════════
-# SettingInjectorService
-# ═══════════════════════════════════════════════════════════════
-
-class SettingInjectorService(Stub):
- """SettingInjectorService — 设置注入服务"""
-
- ACTION_INJECTED_SETTING = "android.location.InjectedSetting"
-
- def __init__(self, name: str = ""):
- super().__init__()
- self._name = name
-
- def onGetSummary(self) -> str:
- return self._name
-
- def onGetEnabled(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"SettingInjectorService(name={self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Address
-# ═══════════════════════════════════════════════════════════════
-
-class Address(Stub):
- """Address — 地理地址"""
-
- def __init__(self, locale: Any = None):
- super().__init__()
- self._address_lines: List[str] = []
- self._feature_name: str = ""
- self._latitude: float = 0.0
- self._longitude: float = 0.0
- self._has_lat_lon: bool = False
- self._admin_area: str = ""
- self._sub_admin_area: str = ""
- self._locality: str = ""
- self._sub_locality: str = ""
- self._premises: str = ""
- self._thoroughfare: str = ""
- self._sub_thoroughfare: str = ""
- self._postal_code: str = ""
- self._country_name: str = ""
- self._country_code: str = ""
- self._phone: str = ""
- self._url: str = ""
- self._extras: Optional[Dict[str, Any]] = None
-
- def getAddressLine(self, index: int) -> Optional[str]:
- if 0 <= index < len(self._address_lines):
- return self._address_lines[index]
- return None
-
- def getMaxAddressLineIndex(self) -> int:
- return max(0, len(self._address_lines) - 1)
-
- def getAdminArea(self) -> Optional[str]:
- return self._admin_area or None
-
- def getSubAdminArea(self) -> Optional[str]:
- return self._sub_admin_area or None
-
- def getLocality(self) -> Optional[str]:
- return self._locality or None
-
- def getSubLocality(self) -> Optional[str]:
- return self._sub_locality or None
-
- def getPremises(self) -> Optional[str]:
- return self._premises or None
-
- def getThoroughfare(self) -> Optional[str]:
- return self._thoroughfare or None
-
- def getSubThoroughfare(self) -> Optional[str]:
- return self._sub_thoroughfare or None
-
- def getPostalCode(self) -> Optional[str]:
- return self._postal_code or None
-
- def getCountryName(self) -> Optional[str]:
- return self._country_name or None
-
- def getCountryCode(self) -> Optional[str]:
- return self._country_code or None
-
- def getFeatureName(self) -> Optional[str]:
- return self._feature_name or None
-
- def getLatitude(self) -> float:
- return self._latitude
-
- def getLongitude(self) -> float:
- return self._longitude
-
- def getPhone(self) -> Optional[str]:
- return self._phone or None
-
- def getUrl(self) -> Optional[str]:
- return self._url or None
-
- def setAddressLine(self, index: int, line: str):
- while len(self._address_lines) <= index:
- self._address_lines.append("")
- self._address_lines[index] = line
-
- def setFeatureName(self, name: str):
- self._feature_name = name
-
- def setAdminArea(self, area: str):
- self._admin_area = area
-
- def setSubAdminArea(self, area: str):
- self._sub_admin_area = area
-
- def setLocality(self, locality: str):
- self._locality = locality
-
- def setSubLocality(self, sub_locality: str):
- self._sub_locality = sub_locality
-
- def setPremises(self, premises: str):
- self._premises = premises
-
- def setThoroughfare(self, thoroughfare: str):
- self._thoroughfare = thoroughfare
-
- def setSubThoroughfare(self, sub_thoroughfare: str):
- self._sub_thoroughfare = sub_thoroughfare
-
- def setPostalCode(self, postal_code: str):
- self._postal_code = postal_code
-
- def setCountryName(self, country_name: str):
- self._country_name = country_name
-
- def setCountryCode(self, country_code: str):
- self._country_code = country_code
-
- def setPhone(self, phone: str):
- self._phone = phone
-
- def setUrl(self, url: str):
- self._url = url
-
- def setLatitude(self, latitude: float):
- self._latitude = latitude
- self._has_lat_lon = True
-
- def setLongitude(self, longitude: float):
- self._longitude = longitude
- self._has_lat_lon = True
-
- def hasLatitude(self) -> bool:
- return self._has_lat_lon
-
- def hasLongitude(self) -> bool:
- return self._has_lat_lon
-
- def toString(self) -> str:
- return f"Address(locality={self._locality}, country={self._country_name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Geocoder
-# ═══════════════════════════════════════════════════════════════
-
-class Geocoder(Stub):
- """Geocoder — 地理编码/逆地理编码"""
-
- # Nominatim (OpenStreetMap) 免费 API
- _NOMINATIM_URL = "https://nominatim.openstreetmap.org"
- _USER_AGENT = "Android-pyApi/1.0"
-
- def __init__(self, context: Any = None, locale: Any = None):
- super().__init__()
- self._context = context
- self._locale = locale
-
- def _get_locale_str(self) -> str:
- if self._locale is None:
- return "en"
- if hasattr(self._locale, "getLanguage"):
- lang = self._locale.getLanguage()
- country = self._locale.getCountry()
- return f"{lang}-{country}" if country else lang
- return str(self._locale)
-
- @staticmethod
- def _http_get_json(url: str) -> Optional[Any]:
- """使用 urllib 发送 GET 请求并解析 JSON。"""
- try:
- import urllib.request
- import json
- req = urllib.request.Request(url, headers={
- "User-Agent": Geocoder._USER_AGENT,
- "Accept-Language": "en",
- })
- with urllib.request.urlopen(req, timeout=10) as resp:
- return json.loads(resp.read().decode("utf-8"))
- except Exception:
- return None
-
- def getFromLocation(self, latitude: float, longitude: float,
- max_results: int = 1) -> List[Address]:
- """逆地理编码:根据经纬度获取地址。优先使用 Nominatim API。"""
- results: List[Address] = []
- # 尝试在线逆地理编码
- try:
- url = (f"{self._NOMINATIM_URL}/reverse?"
- f"lat={latitude}&lon={longitude}&format=jsonv2"
- f"&addressdetails=1&limit={max_results}")
- data = self._http_get_json(url)
- if data and isinstance(data, dict) and "address" in data:
- addr = self._parse_nominatim_reverse(data)
- results.append(addr)
- except Exception:
- pass
- # 回退到默认地址
- if not results:
- addr = Address()
- addr.setLatitude(latitude)
- addr.setLongitude(longitude)
- addr.setFeatureName("Unknown Location")
- addr.setLocality("Unknown")
- addr.setCountryName("Unknown")
- results.append(addr)
- return results[:max_results] if max_results > 0 else []
-
- def _parse_nominatim_reverse(self, data: dict) -> Address:
- """解析 Nominatim 逆地理编码响应。"""
- addr = Address()
- address = data.get("address", {})
- lat = data.get("lat")
- lon = data.get("lon")
- if lat is not None:
- addr.setLatitude(float(lat))
- if lon is not None:
- addr.setLongitude(float(lon))
- addr.setFeatureName(address.get("road") or address.get("building")
- or data.get("name") or "Unknown")
- addr.setLocality(address.get("city") or address.get("town")
- or address.get("village") or address.get("county") or "Unknown")
- addr.setAdminArea(address.get("state") or "")
- addr.setSubAdminArea(address.get("state_district") or "")
- addr.setCountryName(address.get("country") or "Unknown")
- addr.setCountryCode(address.get("country_code", "").upper())
- addr.setPostalCode(address.get("postcode") or "")
- addr.setAddressLine(0, data.get("display_name", ""))
- return addr
-
- def getFromLocationName(self, location_name: str, max_results: int = 1,
- lower_left_lat: Optional[float] = None,
- lower_left_lon: Optional[float] = None,
- upper_right_lat: Optional[float] = None,
- upper_right_lon: Optional[float] = None) -> List[Address]:
- """地理编码:根据地名获取经纬度。优先使用 Nominatim API。"""
- results: List[Address] = []
- # 尝试在线地理编码
- try:
- import urllib.parse
- params = {
- "q": location_name,
- "format": "jsonv2",
- "addressdetails": "1",
- "limit": str(max_results),
- }
- # 添加边界框
- if all(v is not None for v in (lower_left_lat, lower_left_lon,
- upper_right_lat, upper_right_lon)):
- params["viewbox"] = f"{lower_left_lon},{upper_right_lat},{upper_right_lon},{lower_left_lat}"
- params["bounded"] = "1"
- query = urllib.parse.urlencode(params)
- url = f"{self._NOMINATIM_URL}/search?{query}"
- data = self._http_get_json(url)
- if data and isinstance(data, list):
- for item in data[:max_results]:
- addr = self._parse_nominatim_search(item)
- results.append(addr)
- except Exception:
- pass
- # 回退到默认地址
- if not results:
- addr = Address()
- addr.setFeatureName(location_name)
- addr.setLocality(location_name)
- results.append(addr)
- return results[:max_results] if max_results > 0 else []
-
- def _parse_nominatim_search(self, item: dict) -> Address:
- """解析 Nominatim 搜索响应。"""
- addr = Address()
- lat = item.get("lat")
- lon = item.get("lon")
- if lat is not None:
- addr.setLatitude(float(lat))
- if lon is not None:
- addr.setLongitude(float(lon))
- address = item.get("address", {})
- addr.setFeatureName(item.get("name") or address.get("road") or "Unknown")
- addr.setLocality(address.get("city") or address.get("town")
- or address.get("village") or address.get("county") or "Unknown")
- addr.setAdminArea(address.get("state") or "")
- addr.setCountryName(address.get("country") or "Unknown")
- addr.setCountryCode(address.get("country_code", "").upper())
- addr.setPostalCode(address.get("postcode") or "")
- addr.setAddressLine(0, item.get("display_name", ""))
- return addr
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocationManager
-# ═══════════════════════════════════════════════════════════════
-
-class LocationManager(Stub):
- """LocationManager — 位置管理器"""
-
- GPS_PROVIDER = "gps"
- NETWORK_PROVIDER = "network"
- PASSIVE_PROVIDER = "passive"
- FUSED_PROVIDER = "fused"
-
- KEY_PROXIMITY_ENTERING = "entering"
- KEY_PROXIMITY_DO_ENTER = "doEnter"
- KEY_FLUSH_COMPLETE = "flushComplete"
- KEY_LOCATION_CHANGED = "locationChanged"
- KEY_PROXIMITY_ENTERING_DO_ENTER = "doEnter"
-
- PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED"
- MODE_CHANGED_ACTION = "android.location.MODE_CHANGED"
-
- def __init__(self):
- super().__init__()
- self._listeners: Dict[str, List[LocationListener]] = {}
- self._providers = {
- self.GPS_PROVIDER: LocationProvider(self.GPS_PROVIDER),
- self.NETWORK_PROVIDER: LocationProvider(self.NETWORK_PROVIDER),
- self.PASSIVE_PROVIDER: LocationProvider(self.PASSIVE_PROVIDER),
- self.FUSED_PROVIDER: LocationProvider(self.FUSED_PROVIDER),
- }
- self._last_known_locations: Dict[str, Location] = {}
- self._enabled_providers = {self.GPS_PROVIDER, self.NETWORK_PROVIDER,
- self.PASSIVE_PROVIDER, self.FUSED_PROVIDER}
- self._test_providers: Dict[str, LocationProvider] = {}
- self._test_locations: Dict[str, Location] = {}
- self._proximity_alerts: List[Dict[str, Any]] = []
-
- def getLastKnownLocation(self, provider: str) -> Optional[Location]:
- if _USE_LINUX:
- data = LinuxLocation.get_location()
- loc = Location(provider or "network")
- loc.setLatitude(data.get("latitude", 0.0))
- loc.setLongitude(data.get("longitude", 0.0))
- loc.setAccuracy(data.get("accuracy", 0))
- loc.setTime(int(datetime.now().timestamp() * 1000))
- loc.setProvider(provider or "network")
- return loc
- if provider in self._last_known_locations:
- return self._last_known_locations[provider]
- loc = Location(provider)
- loc.setLatitude(37.7749)
- loc.setLongitude(-122.4194)
- loc.setTime(int(datetime.now().timestamp() * 1000))
- loc.setAccuracy(20.0)
- self._last_known_locations[provider] = loc
- return loc
-
- def requestLocationUpdates(self, provider_or_request: Any, min_time: Any = None,
- min_distance: float = 0.0, listener_or_callback: Any = None,
- looper: Any = None) -> None:
- if isinstance(provider_or_request, str):
- provider = provider_or_request
- else:
- provider = self.GPS_PROVIDER
- if _USE_LINUX and listener_or_callback is not None:
- data = LinuxLocation.get_location()
- loc = Location(provider or "network")
- loc.setLatitude(data.get("latitude", 0.0))
- loc.setLongitude(data.get("longitude", 0.0))
- loc.setAccuracy(data.get("accuracy", 0))
- loc.setTime(int(datetime.now().timestamp() * 1000))
- loc.setProvider(provider or "network")
- try:
- listener_or_callback.onLocationChanged(loc)
- except Exception:
- pass
- if listener_or_callback is not None:
- if provider not in self._listeners:
- self._listeners[provider] = []
- if isinstance(listener_or_callback, LocationListener):
- self._listeners[provider].append(listener_or_callback)
-
- def removeUpdates(self, listener: Any):
- for provider in list(self._listeners.keys()):
- self._listeners[provider] = [
- l for l in self._listeners[provider] if l is not listener
- ]
- if not self._listeners[provider]:
- del self._listeners[provider]
-
- def isProviderEnabled(self, provider: str) -> bool:
- if _USE_LINUX:
- return provider == "network"
- return provider in self._enabled_providers
-
- def getProviders(self, criteria: Optional[Criteria] = None, enabled_only: bool = False) -> List[str]:
- if _USE_LINUX:
- return ["network"]
- providers = list(self._providers.keys())
- if enabled_only:
- providers = [p for p in providers if p in self._enabled_providers]
- return providers
-
- def getBestProvider(self, criteria: Criteria, enabled_only: bool = False) -> Optional[str]:
- if criteria.getAccuracy() == Criteria.ACCURACY_FINE:
- return self.GPS_PROVIDER
- return self.NETWORK_PROVIDER
-
- def getAllProviders(self) -> List[str]:
- return list(self._providers.keys())
-
- def getProvider(self, name: str) -> Optional[LocationProvider]:
- return self._providers.get(name)
-
- def addProximityAlert(self, latitude: float, longitude: float,
- radius: float, expiration: int, intent: Any):
- """添加接近警报。记录警报信息,在位置更新时检查是否进入/离开区域。"""
- import time as _time
- alert = {
- "latitude": latitude,
- "longitude": longitude,
- "radius": radius,
- "expiration": expiration,
- "intent": intent,
- "created_at": _time.time(),
- "last_state": None, # None=未触发, True=在区域内, False=在区域外
- }
- self._proximity_alerts.append(alert)
-
- def sendExtraCommand(self, provider: str, command: str, extras: Any) -> bool:
- """向位置提供者发送额外命令。桌面端无实际效果,返回成功。"""
- return True
-
- def clearTestProviderLocation(self, provider: str):
- """清除测试提供者的位置数据。"""
- self._test_locations.pop(provider, None)
-
- def setTestProviderLocation(self, provider: str, location: Location):
- """设置测试提供者的位置。"""
- self._test_locations[provider] = location
- # 通知该提供者的监听器
- if provider in self._listeners:
- for listener in self._listeners[provider]:
- try:
- listener.onLocationChanged(location)
- except Exception:
- pass
-
- def removeTestProvider(self, provider: str):
- """移除测试提供者。"""
- self._test_providers.pop(provider, None)
- self._test_locations.pop(provider, None)
-
- def addTestProvider(self, name: str, requires_network: bool, requires_satellite: bool,
- requires_cell: bool, has_monetary_cost: bool, supports_altitude: bool,
- supports_speed: bool, supports_bearing: bool, power_requirement: int,
- accuracy: int):
- self._providers[name] = LocationProvider(name)
-
- def toString(self) -> str:
- return f"LocationManager(providers={list(self._providers.keys())})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Location",
- "LocationManager",
- "LocationListener",
- "LocationProvider",
- "Criteria",
- "Geocoder",
- "Address",
- "GpsStatus",
- "GpsSatellite",
- "GpsStatusListener",
- "LocationRequest",
- "LocationProviderProperties",
- "SettingInjectorService",
- "GnssStatus",
- "GnssClock",
- "GnssMeasurement",
- "GnssMeasurementsEvent",
- "GnssNavigationMessage",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/location_ext.py b/android_pyapi/android/location_ext.py
deleted file mode 100644
index 978755c..0000000
--- a/android_pyapi/android/location_ext.py
+++ /dev/null
@@ -1,464 +0,0 @@
-"""
-Android location 扩展组件 — LocationProvider, GpsStatus, LocationRequest, Criteria 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# GpsSatellite
-# ═══════════════════════════════════════════════════════════════
-
-class GpsSatellite(Stub):
- """GpsSatellite — GPS 卫星"""
-
- def __init__(self, prn: int = 0, snr: float = 0.0,
- elevation: float = 0.0, azimuth: float = 0.0,
- has_almanac: bool = False, has_ephemeris: bool = False,
- used_in_fix: bool = False):
- super().__init__()
- self._prn = prn
- self._snr = snr
- self._elevation = elevation
- self._azimuth = azimuth
- self._has_almanac = has_almanac
- self._has_ephemeris = has_ephemeris
- self._used_in_fix = used_in_fix
-
- def getPrn(self) -> int:
- return self._prn
-
- def getSnr(self) -> float:
- return self._snr
-
- def getElevation(self) -> float:
- return self._elevation
-
- def getAzimuth(self) -> float:
- return self._azimuth
-
- def hasAlmanac(self) -> bool:
- return self._has_almanac
-
- def hasEphemeris(self) -> bool:
- return self._has_ephemeris
-
- def usedInFix(self) -> bool:
- return self._used_in_fix
-
- def toString(self) -> str:
- return f"GpsSatellite{{prn={self._prn}, snr={self._snr}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GpsStatus
-# ═══════════════════════════════════════════════════════════════
-
-class GpsStatus(Stub):
- """GpsStatus — GPS 状态"""
-
- SATELITE_TYPE_GPS = 1
- SATELITE_TYPE_GLONASS = 2
- SATELITE_TYPE_BEIDOU = 3
- SATELITE_TYPE_GALILEO = 4
- SATELITE_TYPE_IRNSS = 5
- SATELITE_TYPE_QZSS = 6
-
- def __init__(self):
- super().__init__()
- self._satellites: List[GpsSatellite] = [
- GpsSatellite(prn=1, snr=30.0, elevation=45.0, azimuth=120.0,
- has_almanac=True, has_ephemeris=True, used_in_fix=True),
- GpsSatellite(prn=3, snr=28.0, elevation=30.0, azimuth=200.0,
- has_almanac=True, has_ephemeris=True, used_in_fix=True),
- GpsSatellite(prn=7, snr=25.0, elevation=60.0, azimuth=80.0,
- has_almanac=True, has_ephemeris=False, used_in_fix=False),
- GpsSatellite(prn=11, snr=22.0, elevation=15.0, azimuth=300.0,
- has_almanac=True, has_ephemeris=True, used_in_fix=True),
- GpsSatellite(prn=17, snr=18.0, elevation=5.0, azimuth=180.0,
- has_almanac=False, has_ephemeris=False, used_in_fix=False),
- ]
- self._max_satellites: int = 32
- self._time_to_first_fix: int = 30 # seconds
-
- def getSatellites(self) -> List[GpsSatellite]:
- return list(self._satellites)
-
- def getMaxSatellites(self) -> int:
- return self._max_satellites
-
- def getTimeToFirstFix(self) -> int:
- return self._time_to_first_fix
-
- def setStatus(self, sv_status: Any, time_to_first_fix: int):
- self._time_to_first_fix = time_to_first_fix
-
- def toString(self) -> str:
- return f"GpsStatus{{satellites={len(self._satellites)}, tttf={self._time_to_first_fix}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocationRequest
-# ═══════════════════════════════════════════════════════════════
-
-class LocationRequest(Stub):
- """LocationRequest — 位置请求"""
-
- QUALITY_HIGH_ACCURACY = 100
- QUALITY_BALANCED_POWER_ACCURACY = 102
- QUALITY_LOW_POWER = 104
- QUALITY_PASSIVE_ALLOWED = 105
-
- def __init__(self):
- super().__init__()
- self._quality: int = self.QUALITY_BALANCED_POWER_ACCURACY
- self._interval: int = 60000 # ms
- self._fastest_interval: int = 30000 # ms
- self._expiration_duration: int = -1
- self._expiration_time: int = -1
- self._num_updates: int = -1 # unlimited
- self._smallest_displacement: float = 0.0
- self._max_wait_time: int = 0
- self._priority: int = self.QUALITY_BALANCED_POWER_ACCURACY
-
- @staticmethod
- def create() -> "LocationRequest":
- return LocationRequest()
-
- # ── Quality ──
-
- def getQuality(self) -> int:
- return self._quality
-
- def setQuality(self, quality: int):
- self._quality = quality
-
- # ── Priority ──
-
- def getPriority(self) -> int:
- return self._priority
-
- def setPriority(self, priority: int):
- self._priority = priority
-
- # ── Interval ──
-
- def setInterval(self, intervalMillis: int) -> "LocationRequest":
- self._interval = intervalMillis
- return self
-
- def getInterval(self) -> int:
- return self._interval
-
- def setFastestInterval(self, intervalMillis: int) -> "LocationRequest":
- self._fastest_interval = intervalMillis
- return self
-
- def getFastestInterval(self) -> int:
- return self._fastest_interval
-
- # ── Max wait ──
-
- def setMaxWaitTime(self, maxWaitMillis: int) -> "LocationRequest":
- self._max_wait_time = maxWaitMillis
- return self
-
- def getMaxWaitTime(self) -> int:
- return self._max_wait_time
-
- # ── Expiration ──
-
- def setExpirationDuration(self, durationMillis: int) -> "LocationRequest":
- self._expiration_duration = durationMillis
- return self
-
- def getExpirationDuration(self) -> int:
- return self._expiration_duration
-
- def setExpirationTime(self, timeMillis: int) -> "LocationRequest":
- self._expiration_time = timeMillis
- return self
-
- def getExpirationTime(self) -> int:
- return self._expiration_time
-
- # ── Num updates ──
-
- def setNumUpdates(self, numUpdates: int) -> "LocationRequest":
- self._num_updates = numUpdates
- return self
-
- def getNumUpdates(self) -> int:
- return self._num_updates
-
- # ── Displacement ──
-
- def setSmallestDisplacement(self, smallestDisplacementMeters: float) -> "LocationRequest":
- self._smallest_displacement = smallestDisplacementMeters
- return self
-
- def getSmallestDisplacement(self) -> float:
- return self._smallest_displacement
-
- def toString(self) -> str:
- return f"LocationRequest{{quality={self._quality}, interval={self._interval}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocationProviderProperties
-# ═══════════════════════════════════════════════════════════════
-
-class LocationProviderProperties(Stub):
- """LocationProviderProperties — 位置提供者属性"""
-
- def __init__(self, requires_network: bool = False, requires_satellite: bool = True,
- requires_cell: bool = False, has_monetary_cost: bool = False,
- supports_altitude: bool = True, supports_speed: bool = True,
- supports_bearing: bool = True, power_requirement: int = 2,
- accuracy: int = 1):
- super().__init__()
- self._requires_network = requires_network
- self._requires_satellite = requires_satellite
- self._requires_cell = requires_cell
- self._has_monetary_cost = has_monetary_cost
- self._supports_altitude = supports_altitude
- self._supports_speed = supports_speed
- self._supports_bearing = supports_bearing
- self._power_requirement = power_requirement
- self._accuracy = accuracy
-
- def isRequiresNetwork(self) -> bool:
- return self._requires_network
-
- def isRequiresSatellite(self) -> bool:
- return self._requires_satellite
-
- def isRequiresCell(self) -> bool:
- return self._requires_cell
-
- def isHasMonetaryCost(self) -> bool:
- return self._has_monetary_cost
-
- def isSupportsAltitude(self) -> bool:
- return self._supports_altitude
-
- def isSupportsSpeed(self) -> bool:
- return self._supports_speed
-
- def isSupportsBearing(self) -> bool:
- return self._supports_bearing
-
- def getPowerRequirement(self) -> int:
- return self._power_requirement
-
- def getAccuracy(self) -> int:
- return self._accuracy
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocationProvider
-# ═══════════════════════════════════════════════════════════════
-
-class LocationProvider(Stub):
- """LocationProvider — 位置提供者"""
-
- AVAILABLE = 2
- TEMPORARILY_UNAVAILABLE = 1
- OUT_OF_SERVICE = 0
-
- def __init__(self, name: str = "gps"):
- super().__init__()
- self._name = name
- self._properties = LocationProviderProperties()
- self._connected: bool = True
-
- def getName(self) -> str:
- return self._name
-
- def meetsProviderCriteria(self, criteria: Any) -> bool:
- return True
-
- def requiresNetwork(self) -> bool:
- return self._properties.isRequiresNetwork()
-
- def requiresSatellite(self) -> bool:
- return self._properties.isRequiresSatellite()
-
- def requiresCell(self) -> bool:
- return self._properties.isRequiresCell()
-
- def hasMonetaryCost(self) -> bool:
- return self._properties.isHasMonetaryCost()
-
- def supportsAltitude(self) -> bool:
- return self._properties.isSupportsAltitude()
-
- def supportsSpeed(self) -> bool:
- return self._properties.isSupportsSpeed()
-
- def supportsBearing(self) -> bool:
- return self._properties.isSupportsBearing()
-
- def getPowerRequirement(self) -> int:
- return self._properties.getPowerRequirement()
-
- def getAccuracy(self) -> int:
- return self._properties.getAccuracy()
-
- def getGpsStatus(self) -> Optional[GpsStatus]:
- return GpsStatus()
-
- def isEnabled(self) -> bool:
- return True
-
- def sendExtraCommand(self, command: str, extras: Dict[str, Any]) -> bool:
- return True
-
- def setListener(self, listener: Any):
- pass
-
- def clearListener(self):
- pass
-
- def getConnected(self) -> bool:
- return self._connected
-
- def toString(self) -> str:
- return f"LocationProvider{{name={self._name}, connected={self._connected}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Criteria
-# ═══════════════════════════════════════════════════════════════
-
-class Criteria(Stub):
- """Criteria — 位置提供者选择标准"""
-
- NO_REQUIREMENT = 0
- ACCURACY_FINE = 1
- ACCURACY_COARSE = 2
- POWER_LOW = 1
- POWER_MEDIUM = 2
- POWER_HIGH = 3
-
- def __init__(self):
- super().__init__()
- self._accuracy: int = self.NO_REQUIREMENT
- self._power_requirement: int = self.NO_REQUIREMENT
- self._altitude_required: bool = False
- self._bearing_required: bool = False
- self._speed_required: bool = False
- self._cost_allowed: bool = True
- self._horizontal_accuracy: int = self.NO_REQUIREMENT
- self._vertical_accuracy: int = self.NO_REQUIREMENT
- self._bearing_accuracy: int = self.NO_REQUIREMENT
- self._speed_accuracy: int = self.NO_REQUIREMENT
-
- def setAccuracy(self, accuracy: int):
- self._accuracy = accuracy
-
- def getAccuracy(self) -> int:
- return self._accuracy
-
- def setPowerRequirement(self, power: int):
- self._power_requirement = power
-
- def getPowerRequirement(self) -> int:
- return self._power_requirement
-
- def setAltitudeRequired(self, altitudeRequired: bool):
- self._altitude_required = altitudeRequired
-
- def isAltitudeRequired(self) -> bool:
- return self._altitude_required
-
- def setBearingRequired(self, bearingRequired: bool):
- self._bearing_required = bearingRequired
-
- def isBearingRequired(self) -> bool:
- return self._bearing_required
-
- def setSpeedRequired(self, speedRequired: bool):
- self._speed_required = speedRequired
-
- def isSpeedRequired(self) -> bool:
- return self._speed_required
-
- def setCostAllowed(self, costAllowed: bool):
- self._cost_allowed = costAllowed
-
- def isCostAllowed(self) -> bool:
- return self._cost_allowed
-
- def setHorizontalAccuracy(self, accuracy: int):
- self._horizontal_accuracy = accuracy
-
- def getHorizontalAccuracy(self) -> int:
- return self._horizontal_accuracy
-
- def setVerticalAccuracy(self, accuracy: int):
- self._vertical_accuracy = accuracy
-
- def getVerticalAccuracy(self) -> int:
- return self._vertical_accuracy
-
- def setBearingAccuracy(self, accuracy: int):
- self._bearing_accuracy = accuracy
-
- def getBearingAccuracy(self) -> int:
- return self._bearing_accuracy
-
- def setSpeedAccuracy(self, accuracy: int):
- self._speed_accuracy = accuracy
-
- def getSpeedAccuracy(self) -> int:
- return self._speed_accuracy
-
- def toString(self) -> str:
- return f"Criteria{{accuracy={self._accuracy}, power={self._power_requirement}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SettingInjectorService
-# ═══════════════════════════════════════════════════════════════
-
-class SettingInjectorService(Stub):
- """SettingInjectorService — 设置注入服务"""
-
- def __init__(self):
- super().__init__()
-
- def onGetStatus(self) -> int:
- return 1
-
- def onBind(self, intent: Any) -> Any:
- return None
-
- def toString(self) -> str:
- return f"SettingInjectorService@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "LocationProvider",
- "LocationProviderProperties",
- "GpsStatus",
- "GpsSatellite",
- "LocationRequest",
- "Criteria",
- "SettingInjectorService",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/location_geofence.py b/android_pyapi/android/location_geofence.py
deleted file mode 100644
index 76eec9f..0000000
--- a/android_pyapi/android/location_geofence.py
+++ /dev/null
@@ -1,537 +0,0 @@
-"""
-Android Location Geofence 组件 — Geofence, GeofencingEvent, GeofenceRequest 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import time
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# Geofence 常量
-# ═══════════════════════════════════════════════════════════════
-
-GEOFENCE_TRANSITION_ENTER = 1
-GEOFENCE_TRANSITION_EXIT = 2
-GEOFENCE_TRANSITION_DWELL = 4
-
-GEOFENCE_ENTER = GEOFENCE_TRANSITION_ENTER
-GEOFENCE_EXIT = GEOFENCE_TRANSITION_EXIT
-GEOFENCE_DWELL = GEOFENCE_TRANSITION_DWELL
-
-GEOFENCE_RADIUS_INACCURACY = 1
-GEOFENCE_TRANSITION_UNKNOWN = -1
-
-MONITORING_TYPE_PASSIVE = 0
-MONITORING_TYPE_ACTIVE = 1
-MONITORING_TYPE_PASSIVE_INTERVAL = 2
-MONITORING_TYPE_LOCATION = 3
-MONITORING_TYPE_FUSED_LOCATION = 4
-
-MONITORING_TYPE_GEOFENCE = MONITORING_TYPE_ACTIVE
-
-GEOFENCE_REMOVE_BY_LIST = 1
-GEOFENCE_REMOVE_BY_SIGNATURE = 2
-GEOFENCE_REMOVE_ALL = 3
-
-MONITORING_TYPE_GEOFENCE_ENTER = 1
-MONITORING_TYPE_GEOFENCE_EXIT = 2
-MONITORING_TYPE_GEOFENCE_DWELL = 3
-
-GEOFENCE_AVAILABILITY_UNKNOWN = 0
-GEOFENCE_AVAILABILITY_AVAILABLE = 1
-GEOFENCE_AVAILABILITY_UNAVAILABLE = 2
-
-GEOFENCE_ENTER_INIT = 0
-GEOFENCE_ENTER_FINAL = 1
-GEOFENCE_EXIT_INIT = 2
-GEOFENCE_EXIT_FINAL = 3
-
-
-# ═══════════════════════════════════════════════════════════════
-# Geofence
-# ═══════════════════════════════════════════════════════════════
-
-class Geofence(Stub):
- """Geofence — 地理围栏"""
-
- def __init__(self, request_id: str = "", latitude: float = 0.0,
- longitude: float = 0.0, radius: float = 100.0,
- expiration_duration: int = -1, transition_types: int = 0):
- super().__init__()
- self._request_id = request_id
- self._latitude = latitude
- self._longitude = longitude
- self._radius = max(0.0, radius)
- self._expiration = expiration_duration
- self._transitions = transition_types
- self._monitoring_type = MONITORING_TYPE_PASSIVE
- self._is_monitoring = False
-
- def getRequestId(self) -> str:
- return self._request_id
-
- def getLatitude(self) -> float:
- return self._latitude
-
- def getLongitude(self) -> float:
- return self._longitude
-
- def getRadius(self) -> float:
- return self._radius
-
- def getExpiration(self) -> int:
- return self._expiration
-
- def getTransitions(self) -> int:
- return self._transitions
-
- def setMonitoringType(self, monitor_type: int) -> None:
- self._monitoring_type = monitor_type
-
- def getMonitoringType(self) -> int:
- return self._monitoring_type
-
- def isExpired(self) -> bool:
- if self._expiration < 0:
- return False
- return int(time.time() * 1000) > self._expiration
-
- def isMonitoring(self) -> bool:
- return self._is_monitoring
-
- def setMonitoring(self, monitoring: bool) -> None:
- self._is_monitoring = monitoring
-
- def containsLocation(self, latitude: float, longitude: float) -> bool:
- """检查指定位置是否在此地理围栏内"""
- dx = latitude - self._latitude
- dy = longitude - self._longitude
- distance = math.sqrt(dx * dx + dy * dy) * 111319.9
- return distance <= self._radius
-
- def toString(self) -> str:
- return (f"Geofence(id={self._request_id}, "
- f"lat={self._latitude:.4f}, lng={self._longitude:.4f}, "
- f"radius={self._radius:.1f}m)")
-
-
-class GeofenceBuilder(Stub):
- """GeofenceBuilder — 地理围栏构建器"""
-
- def __init__(self):
- super().__init__()
- self._request_id: str = ""
- self._latitude: float = 0.0
- self._longitude: float = 0.0
- self._radius: float = 100.0
- self._expiration_duration: int = -1
- self._transition_types: int = 0
- self._monitoring_type: int = MONITORING_TYPE_PASSIVE
- self._loitering_delay: int = 0
- self._notification_responsiveness: int = 0
- self._last_transition: int = GEOFENCE_TRANSITION_UNKNOWN
-
- def setRequestId(self, request_id: str) -> "GeofenceBuilder":
- self._request_id = request_id
- return self
-
- def setLatitude(self, latitude: float) -> "GeofenceBuilder":
- self._latitude = latitude
- return self
-
- def setLongitude(self, longitude: float) -> "GeofenceBuilder":
- self._longitude = longitude
- return self
-
- def setRadius(self, radius: float) -> "GeofenceBuilder":
- self._radius = max(0.0, radius)
- return self
-
- def setExpirationDuration(self, duration_ms: int) -> "GeofenceBuilder":
- self._expiration_duration = duration_ms
- return self
-
- def setTransitionTypes(self, types: int) -> "GeofenceBuilder":
- self._transition_types = types
- return self
-
- def setMonitoringType(self, monitor_type: int) -> "GeofenceBuilder":
- self._monitoring_type = monitor_type
- return self
-
- def setLoiteringDelay(self, delay_ms: int) -> "GeofenceBuilder":
- self._loitering_delay = delay_ms
- return self
-
- def setNotificationResponsiveness(self, ms: int) -> "GeofenceBuilder":
- self._notification_responsiveness = ms
- return self
-
- def build(self) -> Geofence:
- geofence = Geofence(
- self._request_id, self._latitude, self._longitude,
- self._radius, self._expiration_duration, self._transition_types
- )
- geofence.setMonitoringType(self._monitoring_type)
- return geofence
-
- def toString(self) -> str:
- return (f"GeofenceBuilder(id={self._request_id}, "
- f"lat={self._latitude:.4f}, lng={self._longitude:.4f})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# GeofencingEvent
-# ═══════════════════════════════════════════════════════════════
-
-class GeofencingEvent(Stub):
- """GeofencingEvent — 地理围栏事件"""
-
- def __init__(self):
- super().__init__()
- self._triggering_geofences: List[Geofence] = []
- self._triggering_locations: List[Tuple[float, float]] = []
- self._transition_type: int = GEOFENCE_TRANSITION_UNKNOWN
- self._error_code: int = 0
- self._initial_trigger: bool = False
- self._event_time: int = 0
-
- def getTriggeringGeofences(self) -> List[Geofence]:
- return list(self._triggering_geofences)
-
- def setTriggeringGeofences(self, geofences: List[Geofence]) -> None:
- self._triggering_geofences = list(geofences)
-
- def getTriggeringLocations(self) -> List[Tuple[float, float]]:
- return list(self._triggering_locations)
-
- def addTriggeringLocation(self, latitude: float, longitude: float) -> None:
- self._triggering_locations.append((latitude, longitude))
-
- def getTransitionType(self) -> int:
- return self._transition_type
-
- def setTransitionType(self, transition: int) -> None:
- self._transition_type = transition
-
- def getErrorCode(self) -> int:
- return self._error_code
-
- def setErrorCode(self, code: int) -> None:
- self._error_code = code
-
- def isInitialTrigger(self) -> bool:
- return self._initial_trigger
-
- def setInitialTrigger(self, initial: bool) -> None:
- self._initial_trigger = initial
-
- def getEventTime(self) -> int:
- return self._event_time
-
- def setEventTime(self, time_ms: int) -> None:
- self._event_time = time_ms
-
- def hasError(self) -> bool:
- return self._error_code != 0
-
- def toString(self) -> str:
- types = {1: "ENTER", 2: "EXIT", 4: "DWELL"}
- return (f"GeofencingEvent(transition={types.get(self._transition_type, 'UNKNOWN')}, "
- f"geofences={len(self._triggering_geofences)}, "
- f"error={self._error_code})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# GeofenceRequest
-# ═══════════════════════════════════════════════════════════════
-
-class GeofenceRequest(Stub):
- """GeofenceRequest — 地理围栏请求"""
-
- INITIAL_TRIGGER_ENTER = 1
- INITIAL_TRIGGER_EXIT = 2
- INITIAL_TRIGGER_DWELL = 4
-
- def __init__(self):
- super().__init__()
- self._geofences: List[Geofence] = []
- self._initial_triggers: int = 0
- self._expiration_duration: int = -1
- self._loitering_delay: int = 0
- self._notification_responsiveness: int = 0
-
- def getGeofences(self) -> List[Geofence]:
- return list(self._geofences)
-
- def addGeofence(self, geofence: Geofence) -> None:
- self._geofences.append(geofence)
-
- def setInitialTriggers(self, triggers: int) -> None:
- self._initial_triggers = triggers
-
- def getInitialTriggers(self) -> int:
- return self._initial_triggers
-
- def setExpirationDuration(self, duration: int) -> None:
- self._expiration_duration = duration
-
- def getExpirationDuration(self) -> int:
- return self._expiration_duration
-
- def setLoiteringDelay(self, delay: int) -> None:
- self._loitering_delay = delay
-
- def getLoiteringDelay(self) -> int:
- return self._loitering_delay
-
- def setNotificationResponsiveness(self, ms: int) -> None:
- self._notification_responsiveness = ms
-
- def getNotificationResponsiveness(self) -> int:
- return self._notification_responsiveness
-
- def toString(self) -> str:
- return (f"GeofenceRequest(geofences={len(self._geofences)}, "
- f"triggers={self._initial_triggers})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# GeofenceHardware
-# ═══════════════════════════════════════════════════════════════
-
-class GeofenceHardware(Stub):
- """GeofenceHardware — 硬件地理围栏"""
-
- GEOFENCE_ENTERED = 0
- GEOFENCE_EXITED = 1
- GEOFENCE_UNCERTAIN = 2
-
- MONITORING_TYPE_GEOFENCE = MONITORING_TYPE_GEOFENCE
-
- def __init__(self):
- super().__init__()
- self._geofences: Dict[int, Geofence] = {}
- self._next_id: int = 1
- self._monitor_callback: Optional["GeofenceHardwareMonitorCallback"] = None
- self._lock = threading.Lock()
-
- def addGeofence(self, fence_id: int, geofence: Geofence) -> bool:
- with self._lock:
- if fence_id < 0:
- fence_id = self._next_id
- self._next_id += 1
- self._geofences[fence_id] = geofence
- return True
-
- def removeGeofence(self, fence_id: int) -> bool:
- with self._lock:
- return self._geofences.pop(fence_id, None) is not None
-
- def pauseGeofence(self, fence_id: int) -> bool:
- return fence_id in self._geofences
-
- def resumeGeofence(self, fence_id: int, monitor_transition: int) -> bool:
- return fence_id in self._geofences
-
- def getMonitoringTypes(self) -> List[int]:
- return [MONITORING_TYPE_GEOFENCE]
-
- def getState(self, monitor_type: int) -> int:
- return GEOFENCE_AVAILABILITY_AVAILABLE
-
- def setMonitorCallback(self, callback: Optional["GeofenceHardwareMonitorCallback"]) -> None:
- self._monitor_callback = callback
-
- def toString(self) -> str:
- return f"GeofenceHardware(geofences={len(self._geofences)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GeofenceHardwareRequest / Float / Circle
-# ═══════════════════════════════════════════════════════════════
-
-class GeofenceHardwareRequest(Stub):
- """GeofenceHardwareRequest — 硬件地理围栏请求"""
-
- GEOFENCE_TYPE_CIRCLE = 0
- GEOFENCE_TYPE_FLOAT = 1
-
- def __init__(self, latitude: float = 0.0, longitude: float = 0.0,
- radius: float = 100.0, geofence_type: int = GEOFENCE_TYPE_CIRCLE):
- super().__init__()
- self._latitude = latitude
- self._longitude = longitude
- self._radius = radius
- self._geofence_type = geofence_type
- self._last_transition: int = GEOFENCE_TRANSITION_UNKNOWN
- self._monitor_transition: int = GEOFENCE_TRANSITION_ENTER
- self._unknown_timer: int = 30000
- self._monitor_notification: int = 5
- self._source_technologies: int = 0
-
- def getLatitude(self) -> float:
- return self._latitude
-
- def getLongitude(self) -> float:
- return self._longitude
-
- def getRadius(self) -> float:
- return self._radius
-
- def getGeofenceType(self) -> int:
- return self._geofence_type
-
- def setLastTransition(self, transition: int) -> None:
- self._last_transition = transition
-
- def getLastTransition(self) -> int:
- return self._last_transition
-
- def setMonitorTransitions(self, transitions: int) -> None:
- self._monitor_transition = transitions
-
- def getMonitorTransitions(self) -> int:
- return self._monitor_transition
-
- def setUnknownTimer(self, timer_ms: int) -> None:
- self._unknown_timer = timer_ms
-
- def getUnknownTimer(self) -> int:
- return self._unknown_timer
-
- def setNotificationResponsiveness(self, ms: int) -> None:
- self._monitor_notification = ms
-
- def getNotificationResponsiveness(self) -> int:
- return self._monitor_notification
-
- def setSourceTechnologies(self, technologies: int) -> None:
- self._source_technologies = technologies
-
- def getSourceTechnologies(self) -> int:
- return self._source_technologies
-
- def toString(self) -> str:
- return (f"GeofenceHardwareRequest(lat={self._latitude:.4f}, "
- f"lng={self._longitude:.4f}, r={self._radius:.1f})")
-
-
-class GeofenceHardwareRequestFloat(GeofenceHardwareRequest):
- """GeofenceHardwareRequestFloat — 浮点型硬件围栏请求"""
-
- def __init__(self, latitude: float = 0.0, longitude: float = 0.0,
- radius: float = 100.0):
- super().__init__(latitude, longitude, radius,
- GeofenceHardwareRequest.GEOFENCE_TYPE_FLOAT)
-
- def toString(self) -> str:
- return (f"GeofenceHardwareRequestFloat(lat={self._latitude:.4f}, "
- f"lng={self._longitude:.4f}, r={self._radius:.1f})")
-
-
-class GeofenceHardwareRequestCircle(GeofenceHardwareRequest):
- """GeofenceHardwareRequestCircle — 圆形硬件围栏请求"""
-
- def __init__(self, latitude: float = 0.0, longitude: float = 0.0,
- radius: float = 100.0):
- super().__init__(latitude, longitude, radius,
- GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE)
-
- def toString(self) -> str:
- return (f"GeofenceHardwareRequestCircle(lat={self._latitude:.4f}, "
- f"lng={self._longitude:.4f}, r={self._radius:.1f})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# GeofenceHardwareMonitorCallback
-# ═══════════════════════════════════════════════════════════════
-
-class GeofenceHardwareMonitorCallback(Stub):
- """GeofenceHardwareMonitorCallback — 硬件围栏监控回调"""
-
- def onMonitoringSystemChange(self, monitor_type: int,
- available: bool,
- location: Optional[Any]) -> None:
- pass
-
- def onGeofenceTransition(self, fence_id: int,
- transition: int,
- location: Any,
- timestamp: int,
- monitoring_type: int) -> None:
- pass
-
- def onGeofenceExpiration(self, fence_id: int,
- monitoring_type: int) -> None:
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# GeofenceManager
-# ═══════════════════════════════════════════════════════════════
-
-class GeofenceManager(Stub):
- """GeofenceManager — 地理围栏管理器"""
-
- def __init__(self):
- super().__init__()
- self._registered_geofences: Dict[str, Geofence] = {}
- self._listeners: Dict[str, Callable] = {}
- self._lock = threading.Lock()
- self._monitoring = False
-
- def addGeofence(self, geofence: Geofence, listener: Callable) -> None:
- with self._lock:
- self._registered_geofences[geofence.getRequestId()] = geofence
- self._listeners[geofence.getRequestId()] = listener
- geofence.setMonitoring(True)
-
- def removeGeofence(self, request_id: str) -> None:
- with self._lock:
- geofence = self._registered_geofences.pop(request_id, None)
- self._listeners.pop(request_id, None)
- if geofence:
- geofence.setMonitoring(False)
-
- def removeAllGeofences(self) -> None:
- with self._lock:
- for geofence in self._registered_geofences.values():
- geofence.setMonitoring(False)
- self._registered_geofences.clear()
- self._listeners.clear()
-
- def getRegisteredGeofences(self) -> List[Geofence]:
- with self._lock:
- return list(self._registered_geofences.values())
-
- def isMonitoring(self) -> bool:
- return self._monitoring
-
- def setMonitoring(self, monitoring: bool) -> None:
- self._monitoring = monitoring
-
- def triggerTransition(self, geofence_id: str, transition: int,
- latitude: float, longitude: float) -> None:
- with self._lock:
- if geofence_id in self._listeners:
- event = GeofencingEvent()
- event.setTransitionType(transition)
- event.addTriggeringLocation(latitude, longitude)
- if geofence_id in self._registered_geofences:
- event.setTriggeringGeofences(
- [self._registered_geofences[geofence_id]]
- )
- self._listeners[geofence_id](event)
-
- def toString(self) -> str:
- return (f"GeofenceManager(geofences={len(self._registered_geofences)}, "
- f"monitoring={self._monitoring})")
\ No newline at end of file
diff --git a/android_pyapi/android/managers.py b/android_pyapi/android/managers.py
deleted file mode 100644
index 624f9a2..0000000
--- a/android_pyapi/android/managers.py
+++ /dev/null
@@ -1,1773 +0,0 @@
-"""
-Android System Manager API — 所有剩余系统 Manager 类集合
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import time
-import json
-import random
-import socket
-import uuid
-import threading
-from datetime import datetime, timedelta
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable, BinaryIO
-
-from .._core import Stub, AndroidOnlyError, _app_data_dir, _sdcard_root
-
-from ..java.lang import RuntimeException
-
-# Linux 真实实现导入
-try:
- from .._linux_impl import IS_LINUX, LinuxNetwork, HAS_IP
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 全局常量
-# ═══════════════════════════════════════════════════════════════
-
-INVALID_ID = -1
-MATCH_ALL = -1
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityManager
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityManager(Stub):
- """AccessibilityManager — 无障碍管理器 (桌面存根)"""
-
- FLAG_CONTENT_CONTROLS = 0x00000001
- FLAG_CONTENT_ICONS = 0x00000002
- FLAG_CONTENT_TEXT = 0x00000004
- FLAG_CONTENT_CONTENT_DESCRIPTION = 0x00000008
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._enabled = False
- self._touch_exploration_enabled = False
- self._high_text_contrast_enabled = False
- self._animator_duration_scale = 1.0
- self._display_magnification_enabled = False
- self._accessibility_volume = 0
- self._speech_rate = 1.0
- self._listeners: List[Any] = []
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def addAccessibilityStateChangeListener(self, listener: Any) -> bool:
- if listener not in self._listeners:
- self._listeners.append(listener)
- return True
-
- def removeAccessibilityStateChangeListener(self, listener: Any) -> bool:
- if listener in self._listeners:
- self._listeners.remove(listener)
- return True
-
- def isTouchExplorationEnabled(self) -> bool:
- return self._touch_exploration_enabled
-
- def isHighTextContrastEnabled(self) -> bool:
- return self._high_text_contrast_enabled
-
- def getAccessibilityServiceList(self) -> List[Any]:
- return []
-
- def addTouchExplorationStateChangeListener(self, listener: Any) -> None:
- pass
-
- def removeTouchExplorationStateChangeListener(self, listener: Any) -> None:
- pass
-
- def sendAccessibilityEvent(self, event: Any) -> None:
- pass
-
- def interrupt(self) -> None:
- pass
-
- def getEnabledAccessibilityServiceList(self, feedbackTypeFlags: int) -> List[Any]:
- return []
-
- def getInstalledAccessibilityServiceList(self) -> List[Any]:
- return []
-
- def toString(self) -> str:
- return f"AccessibilityManager(enabled={self._enabled})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccountManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class AccountManager(Stub):
- """AccountManager — 账户管理器 (扩展)"""
-
- KEY_ACCOUNTS = "accounts"
- KEY_ACCOUNT_NAME = "accountName"
- KEY_ACCOUNT_TYPE = "accountType"
- KEY_AUTHTOKEN = "authtoken"
- KEY_AUTH_FAILED_MESSAGE = "authFailedMessage"
- KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey"
- KEY_BOOLEAN_RESULT = "booleanResult"
- KEY_ERROR_CODE = "errorCode"
- KEY_ERROR_MESSAGE = "errorMessage"
- KEY_INTENT = "intent"
- KEY_PASSWORD = "password"
- KEY_USERDATA = "userdata"
- KEY_CUSTOM_TOKEN_EXPIRY = "customTokenExpiry"
- KEY_ACCOUNT_ACCESS_ID = "accountAccessId"
-
- ERROR_CODE_NETWORK_ERROR = 1
- ERROR_CODE_UNSUPPORTED_OPERATION = 2
- ERROR_CODE_INVALID_RESPONSE = 3
- ERROR_CODE_REMOTE_EXCEPTION = 4
- ERROR_CODE_MANAGEMENT_DISABLED = 5
- ERROR_CODE_BAD_ARGUMENTS = 6
- ERROR_CODE_BAD_REQUEST = 7
- ERROR_CODE_DENIED = 8
- ERROR_CODE_CANCELED = 9
- ERROR_CODE_INVALID_CREDENTIALS = 10
- ERROR_CODE_SESSION_EXPIRED = 11
- ERROR_CODE_USER_RESTRICTION = 12
-
- _instance: Optional["AccountManager"] = None
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._accounts: List[Any] = []
- self._auth_tokens: Dict[str, str] = {}
- self._user_data: Dict[str, Dict[str, str]] = {}
- self._password_data: Dict[str, str] = {}
- self._account_visibility: Dict[str, bool] = {}
- self._lock = threading.Lock()
-
- @staticmethod
- def get(context: Any) -> "AccountManager":
- if AccountManager._instance is None:
- AccountManager._instance = AccountManager(context)
- return AccountManager._instance
-
- def getAccounts(self) -> List[Any]:
- with self._lock:
- return list(self._accounts)
-
- def getAccountsByType(self, type_: str) -> List[Any]:
- with self._lock:
- return [a for a in self._accounts if getattr(a, "type", None) == type_]
-
- def addAccountExplicitly(self, account: Any, password: Optional[str], userdata: Optional[Dict]) -> bool:
- with self._lock:
- if account not in self._accounts:
- self._accounts.append(account)
- name = getattr(account, "name", str(account))
- if password is not None:
- self._password_data[name] = password
- if userdata:
- self._user_data[name] = dict(userdata)
- return True
- return False
-
- def removeAccountExplicitly(self, account: Any) -> bool:
- with self._lock:
- if account in self._accounts:
- self._accounts.remove(account)
- name = getattr(account, "name", str(account))
- self._password_data.pop(name, None)
- self._user_data.pop(name, None)
- return True
- return False
-
- def getUserData(self, account: Any, key: str) -> Optional[str]:
- with self._lock:
- name = getattr(account, "name", str(account))
- return self._user_data.get(name, {}).get(key)
-
- def setUserData(self, account: Any, key: str, value: str) -> None:
- with self._lock:
- name = getattr(account, "name", str(account))
- if name not in self._user_data:
- self._user_data[name] = {}
- self._user_data[name][key] = value
-
- def getPassword(self, account: Any) -> Optional[str]:
- with self._lock:
- name = getattr(account, "name", str(account))
- return self._password_data.get(name)
-
- def setPassword(self, account: Any, password: str) -> None:
- with self._lock:
- name = getattr(account, "name", str(account))
- self._password_data[name] = password
-
- def clearPassword(self, account: Any) -> None:
- with self._lock:
- name = getattr(account, "name", str(account))
- self._password_data.pop(name, None)
-
- def getAuthToken(self, account: Any, authTokenType: str) -> Optional[str]:
- with self._lock:
- name = getattr(account, "name", str(account))
- return self._auth_tokens.get(f"{name}:{authTokenType}")
-
- def setAuthToken(self, account: Any, authTokenType: str, authToken: str) -> None:
- with self._lock:
- name = getattr(account, "name", str(account))
- self._auth_tokens[f"{name}:{authTokenType}"] = authToken
-
- def invalidateAuthToken(self, accountType: str, authToken: str) -> None:
- with self._lock:
- to_remove = [k for k, v in self._auth_tokens.items() if v == authToken]
- for k in to_remove:
- del self._auth_tokens[k]
-
- def hasFeatures(self, account: Any, features: List[str], callback: Any, handler: Any = None) -> None:
- pass
-
- def getAccountVisibility(self, account: Any, packageName: str) -> int:
- return 1
-
- def toString(self) -> str:
- return f"AccountManager(accounts={len(self._accounts)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AlarmManager
-# ═══════════════════════════════════════════════════════════════
-
-class AlarmManager(Stub):
- """AlarmManager — 闹钟管理器"""
-
- RTC_WAKEUP = 0
- RTC = 1
- ELAPSED_REALTIME_WAKEUP = 2
- ELAPSED_REALTIME = 3
- INTERVAL_FIFTEEN_MINUTES = 900000
- INTERVAL_HALF_HOUR = 1800000
- INTERVAL_HOUR = 3600000
- INTERVAL_DAY = 86400000
- FLAG_ALLOW_WHILE_IDLE_UNSCREEN_ON = 0x00000008
- FLAG_ALLOW_WHILE_IDLE = 0x00000004
- FLAG_STANDALONE = 0x00000002
- FLAG_WAKE_FROM_IDLE = 0x00000001
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._alarms: List[Dict[str, Any]] = []
- self._lock = threading.Lock()
- self._next_id = 1
- self._worker: Optional[threading.Thread] = None
- self._running = True
-
- def set(self, type_: int, triggerAtMillis: int, operation: Any) -> None:
- with self._lock:
- self._alarms.append({
- "id": self._next_id,
- "type": type_,
- "trigger": triggerAtMillis,
- "operation": operation,
- "interval": 0,
- "repeat": False,
- "window": 0,
- "allow_while_idle": False,
- })
- self._next_id += 1
-
- def setRepeating(self, type_: int, triggerAtMillis: int, intervalMillis: int, operation: Any) -> None:
- with self._lock:
- self._alarms.append({
- "id": self._next_id,
- "type": type_,
- "trigger": triggerAtMillis,
- "operation": operation,
- "interval": intervalMillis,
- "repeat": True,
- "window": 0,
- "allow_while_idle": False,
- })
- self._next_id += 1
-
- def setWindow(self, type_: int, windowStartMillis: int, windowLengthMillis: int, operation: Any) -> None:
- with self._lock:
- self._alarms.append({
- "id": self._next_id,
- "type": type_,
- "trigger": windowStartMillis,
- "operation": operation,
- "interval": 0,
- "repeat": False,
- "window": windowLengthMillis,
- "allow_while_idle": False,
- })
- self._next_id += 1
-
- def setExact(self, type_: int, triggerAtMillis: int, operation: Any) -> None:
- self.set(type_, triggerAtMillis, operation)
-
- def setExactAndAllowWhileIdle(self, type_: int, triggerAtMillis: int, operation: Any) -> None:
- self.set(type_, triggerAtMillis, operation)
-
- def setAlarmClock(self, info: Any, triggerAtMillis: int, operation: Any) -> None:
- pass
-
- def cancel(self, operation: Any) -> None:
- with self._lock:
- self._alarms = [a for a in self._alarms if a.get("operation") != operation]
-
- def getNextAlarmClock(self) -> Optional[Any]:
- return None
-
- def canScheduleExactAlarms(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"AlarmManager(alarms={len(self._alarms)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AppOpsManager
-# ═══════════════════════════════════════════════════════════════
-
-class AppOpsManager(Stub):
- """AppOpsManager — 应用操作管理器"""
-
- MODE_ALLOWED = 0
- MODE_IGNORED = 1
- MODE_ERRORED = 2
- MODE_DEFAULT = 3
- MODE_FOREGROUND = 4
-
- OPSTR_COARSE_LOCATION = "android:coarse_location"
- OPSTR_FINE_LOCATION = "android:fine_location"
- OPSTR_CAMERA = "android:camera"
- OPSTR_RECORD_AUDIO = "android:record_audio"
- OPSTR_READ_CONTACTS = "android:read_contacts"
- OPSTR_WRITE_CONTACTS = "android:write_contacts"
- OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage"
- OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage"
- OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications"
- OPSTR_POST_NOTIFICATIONS = "android:post_notifications"
- OPSTR_VIBRATE = "android:vibrate"
- OPSTR_CALL_PHONE = "android:call_phone"
- OPSTR_READ_SMS = "android:read_sms"
- OPSTR_SEND_SMS = "android:send_sms"
- OPSTR_RECEIVE_SMS = "android:receive_sms"
- OPSTR_SYSTEM_ALERT_WINDOW = "android:system_alert_window"
- OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages"
- OPSTR_BLUETOOTH = "android:bluetooth"
- OPSTR_BLUETOOTH_SCAN = "android:bluetooth_scan"
- OPSTR_BLUETOOTH_ADVERTISE = "android:bluetooth_advertise"
- OPSTR_BLUETOOTH_CONNECT = "android:bluetooth_connect"
- OPSTR_NFC = "android:nfc"
- OPSTR_NFC_PREFERRED_PAYMENT = "android:nfc_preferred_payment"
- OPSTR_PICTURE_IN_PICTURE = "android:picture_in_picture"
- OPSTR_FOREGROUND_SERVICE = "android:foreground_service"
- OPSTR_MANAGE_EXTERNAL_STORAGE = "android:manage_external_storage"
- OPSTR_BODY_SENSORS = "android:body_sensors"
- OPSTR_ACTIVITY_RECOGNITION = "android:activity_recognition"
- OPSTR_USE_BIOMETRIC = "android:use_biometric"
- OPSTR_USE_FINGERPRINT = "android:use_fingerprint"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._op_modes: Dict[str, Dict[str, int]] = {}
- self._lock = threading.Lock()
-
- def checkOp(self, op: str, uid: int, packageName: str) -> int:
- with self._lock:
- if packageName not in self._op_modes:
- return AppOpsManager.MODE_ALLOWED
- return self._op_modes[packageName].get(op, AppOpsManager.MODE_ALLOWED)
-
- def noteOp(self, op: str, uid: int, packageName: str) -> int:
- return self.checkOp(op, uid, packageName)
-
- def startOp(self, op: str, uid: int, packageName: str) -> int:
- return self.checkOp(op, uid, packageName)
-
- def finishOp(self, op: str, uid: int, packageName: str) -> None:
- pass
-
- def setMode(self, code: int, uid: int, packageName: str, mode: int) -> None:
- with self._lock:
- if packageName not in self._op_modes:
- self._op_modes[packageName] = {}
- self._op_modes[packageName][str(code)] = mode
-
- def toString(self) -> str:
- return f"AppOpsManager(packages={len(self._op_modes)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ClipboardManager
-# ═══════════════════════════════════════════════════════════════
-
-class ClipboardManager(Stub):
- """ClipboardManager — 剪贴板管理器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._primary_clip: Optional[Any] = None
- self._listeners: List[Callable] = []
- self._has_clipboard = True
- self._clipboard_history: List[Any] = []
- self._max_history = 10
-
- def setPrimaryClip(self, clip: Any) -> None:
- self._primary_clip = clip
- if clip is not None:
- self._clipboard_history.append(clip)
- if len(self._clipboard_history) > self._max_history:
- self._clipboard_history.pop(0)
- for listener in self._listeners:
- try:
- listener(clip)
- except Exception:
- pass
-
- def clearPrimaryClip(self) -> None:
- if self._primary_clip is not None:
- self._clipboard_history.append(None)
- self._primary_clip = None
-
- def getPrimaryClip(self) -> Optional[Any]:
- return self._primary_clip
-
- def hasPrimaryClip(self) -> bool:
- return self._primary_clip is not None
-
- def hasClipboardText(self) -> bool:
- if self._primary_clip is None:
- return False
- try:
- return hasattr(self._primary_clip, "getText") and self._primary_clip.getText() is not None
- except Exception:
- return False
-
- def getText(self) -> Optional[str]:
- if self._primary_clip is not None:
- try:
- return self._primary_clip.getText()
- except Exception:
- pass
- return None
-
- def addPrimaryClipChangedListener(self, listener: Callable) -> None:
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removePrimaryClipChangedListener(self, listener: Callable) -> None:
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def getClipboardHistory(self) -> List[Any]:
- return list(self._clipboard_history)
-
- def toString(self) -> str:
- return f"ClipboardManager(has_clip={self.hasPrimaryClip()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ConnectivityManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class ConnectivityManager(Stub):
- """ConnectivityManager — 连接管理器 (扩展)"""
-
- TYPE_NONE = -1
- TYPE_MOBILE = 0
- TYPE_WIFI = 1
- TYPE_MOBILE_MMS = 2
- TYPE_MOBILE_SUPL = 3
- TYPE_MOBILE_DUN = 4
- TYPE_MOBILE_HIPRI = 5
- TYPE_WIMAX = 6
- TYPE_BLUETOOTH = 7
- TYPE_DUMMY = 8
- TYPE_ETHERNET = 9
- TYPE_VPN = 17
- TYPE_WIFI_P2P = 13
-
- EXTRA_NETWORK_TYPE = "networkType"
- EXTRA_IS_FAILOVER = "isFailover"
- EXTRA_OTHER_NETWORK_INFO = "otherNetwork"
- EXTRA_NO_CONNECTIVITY = "noConnectivity"
- EXTRA_REASON = "reason"
- EXTRA_EXTRA_INFO = "extraInfo"
- EXTRA_NETWORK_INFO = "networkInfo"
- EXTRA_NETWORK_REQUEST = "networkRequest"
- EXTRA_NETWORK = "network"
-
- CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._active_network_info: Optional[Any] = None
- self._network_preference = ConnectivityManager.TYPE_WIFI
- self._background_data_setting = True
- self._network_callbacks: List[Any] = []
- self._active_network: Optional[Any] = None
- self._all_networks: List[Any] = []
-
- def _get_linux_active_info(self):
- """从 Linux 真实网络信息构造活跃 NetworkInfo"""
- try:
- from .net import NetworkInfo
- interfaces = LinuxNetwork.get_interfaces()
- # 有真实网络接口 (非环回) 且 operstate=up 即视为已连接
- connected = any(
- (iface.get("ifname") or iface.get("name", "")) != "lo"
- and iface.get("operstate", "").lower() == "up"
- for iface in interfaces
- )
- if not connected:
- connected = LinuxNetwork.get_connectivity()
- ip = LinuxNetwork.get_ip_address()
- iface_name = ""
- net_type = ConnectivityManager.TYPE_ETHERNET
- for iface in interfaces:
- name = iface.get("ifname") or iface.get("name", "")
- state = iface.get("operstate", "")
- if name and name != "lo" and state.lower() == "up":
- iface_name = iface_name or name
- if name and name.startswith(("wl", "wlan", "wlp")):
- net_type = ConnectivityManager.TYPE_WIFI
- iface_name = name
- data = {
- "connected": connected,
- "ip": ip,
- "interface": iface_name,
- "type_name": "WIFI" if net_type == ConnectivityManager.TYPE_WIFI else "ETHERNET",
- }
- return NetworkInfo.from_linux_data(data, network_type=net_type)
- except Exception:
- return self._active_network_info
-
- def getActiveNetworkInfo(self) -> Optional[Any]:
- if _USE_LINUX:
- return self._get_linux_active_info()
- return self._active_network_info
-
- def getNetworkInfo(self, networkType: int) -> Optional[Any]:
- if _USE_LINUX:
- info = self._get_linux_active_info()
- if info is not None and info.getType() == networkType:
- return info
- return None
- return None
-
- def getConnectivityStatus(self) -> bool:
- """返回当前网络连通性 (True=已连接)"""
- if _USE_LINUX:
- return LinuxNetwork.get_connectivity()
- return False
-
- def getAllNetworkInfo(self) -> List[Any]:
- return self._all_networks
-
- def isActiveNetworkMetered(self) -> bool:
- return True
-
- def getActiveNetwork(self) -> Optional[Any]:
- return self._active_network
-
- def getAllNetworks(self) -> List[Any]:
- return list(self._all_networks)
-
- def requestNetwork(self, request: Any, callback: Any) -> None:
- pass
-
- def registerNetworkCallback(self, request: Any, callback: Any) -> None:
- if callback not in self._network_callbacks:
- self._network_callbacks.append(callback)
-
- def unregisterNetworkCallback(self, callback: Any) -> None:
- if callback in self._network_callbacks:
- self._network_callbacks.remove(callback)
-
- def getNetworkCapabilities(self, network: Any) -> Optional[Any]:
- return None
-
- def getLinkProperties(self, network: Any) -> Optional[Any]:
- return None
-
- def setNetworkPreference(self, preference: int) -> None:
- self._network_preference = preference
-
- def getBackgroundDataSetting(self) -> bool:
- return self._background_data_setting
-
- def setBackgroundDataSetting(self, allow: bool) -> None:
- self._background_data_setting = allow
-
- def reportBadNetwork(self, network: Any) -> None:
- pass
-
- def toString(self) -> str:
- return f"ConnectivityManager(active={self._active_network_info is not None})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DevicePolicyManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class DevicePolicyManager(Stub):
- """DevicePolicyManager — 设备策略管理器 (扩展)"""
-
- ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN"
- ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED"
- ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED"
- ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD"
- ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION"
- ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE"
- ACTION_SYSTEM_UPDATE_POLICY = "android.app.action.SYSTEM_UPDATE_POLICY"
-
- KEYGUARD_DISABLE_FEATURES_NONE = 0
- KEYGUARD_DISABLE_FEATURES_ALL = 0x7FFFFFFF
- KEYGUARD_DISABLE_SECURE_CAMERA = 2
- KEYGUARD_DISABLE_FINGERPRINT = 32
- KEYGUARD_DISABLE_REMOTE_INPUT = 64
- KEYGUARD_DISABLE_FACE = 128
- KEYGUARD_DISABLE_IRIS = 256
- KEYGUARD_DISABLE_BIOMETRICS = 32 | 128 | 256
- KEYGUARD_DISABLE_SHORTCUTS = 512
- KEYGUARD_DISABLE_WIDGETS_ALL = 1048576
-
- PASSWORD_QUALITY_UNSPECIFIED = 0
- PASSWORD_QUALITY_SOMETHING = 0x10000
- PASSWORD_QUALITY_NUMERIC = 0x20000
- PASSWORD_QUALITY_NUMERIC_COMPLEX = 0x30000
- PASSWORD_QUALITY_ALPHABETIC = 0x40000
- PASSWORD_QUALITY_ALPHANUMERIC = 0x50000
- PASSWORD_QUALITY_COMPLEX = 0x60000
- PASSWORD_QUALITY_MANAGED = 0x80000
- PASSWORD_QUALITY_BIOMETRIC_WEAK = 0x8000
-
- RESET_PASSWORD_REQUIRE_ENTRY = 0x0001
- RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 0x0002
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._admin_receivers: List[Any] = []
- self._password_quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
- self._password_length = 0
- self._maximum_failed_passwords_for_wipe = 0
- self._maximum_time_to_lock = 0
- self._storage_encryption = False
- self._camera_disabled = False
- self._screen_capture_disabled = False
- self._keyguard_disabled_features = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE
- self._lock_task_packages: List[str] = []
-
- def isDeviceOwnerApp(self, packageName: str) -> bool:
- return False
-
- def isProfileOwnerApp(self, packageName: str) -> bool:
- return False
-
- def getDeviceOwner(self) -> Optional[str]:
- return None
-
- def getProfileOwner(self) -> Optional[Any]:
- return None
-
- def setPasswordQuality(self, admin: Any, quality: int) -> None:
- self._password_quality = quality
-
- def getPasswordQuality(self, admin: Any = None) -> int:
- return self._password_quality
-
- def setPasswordMinimumLength(self, admin: Any, length: int) -> None:
- self._password_length = length
-
- def getPasswordMinimumLength(self, admin: Any = None) -> int:
- return self._password_length
-
- def resetPassword(self, password: str, flags: int = 0) -> bool:
- return True
-
- def setMaximumFailedPasswordsForWipe(self, admin: Any, num: int) -> None:
- self._maximum_failed_passwords_for_wipe = num
-
- def getMaximumFailedPasswordsForWipe(self, admin: Any = None) -> int:
- return self._maximum_failed_passwords_for_wipe
-
- def setMaximumTimeToLock(self, admin: Any, timeMs: int) -> None:
- self._maximum_time_to_lock = timeMs
-
- def getMaximumTimeToLock(self, admin: Any = None) -> int:
- return self._maximum_time_to_lock
-
- def lockNow(self) -> None:
- pass
-
- def wipeData(self, flags: int = 0) -> None:
- raise RuntimeError("wipeData() would wipe device data")
-
- def setStorageEncryption(self, admin: Any, encrypt: bool) -> int:
- self._storage_encryption = encrypt
- return 1
-
- def getStorageEncryption(self, admin: Any = None) -> bool:
- return self._storage_encryption
-
- def setCameraDisabled(self, admin: Any, disabled: bool) -> None:
- self._camera_disabled = disabled
-
- def getCameraDisabled(self, admin: Any = None) -> bool:
- return self._camera_disabled
-
- def setScreenCaptureDisabled(self, admin: Any, disabled: bool) -> None:
- self._screen_capture_disabled = disabled
-
- def getScreenCaptureDisabled(self, admin: Any = None) -> bool:
- return self._screen_capture_disabled
-
- def setKeyguardDisabledFeatures(self, admin: Any, features: int) -> None:
- self._keyguard_disabled_features = features
-
- def getKeyguardDisabledFeatures(self, admin: Any = None) -> int:
- return self._keyguard_disabled_features
-
- def setLockTaskPackages(self, admin: Any, packages: List[str]) -> None:
- self._lock_task_packages = list(packages)
-
- def getLockTaskPackages(self, admin: Any = None) -> List[str]:
- return list(self._lock_task_packages)
-
- def isLockTaskPermitted(self, pkg: str) -> bool:
- return pkg in self._lock_task_packages
-
- def toString(self) -> str:
- return f"DevicePolicyManager(password_quality=0x{self._password_quality:x})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DisplayManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class DisplayManager(Stub):
- """DisplayManager — 显示管理器 (扩展)"""
-
- DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION"
- VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 0x00000001
- VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 0x00000002
- VIRTUAL_DISPLAY_FLAG_PRESENTATION = 0x00000004
- VIRTUAL_DISPLAY_FLAG_SECURE = 0x00000008
- VIRTUAL_DISPLAY_FLAG_PUBLIC = 0x00000010
- VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 0x00000020
- VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 0x00000040
- VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_SURFACE = 0x00000080
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._displays: Dict[int, Any] = {}
- self._display_listeners: List[Any] = []
- self._default_display: Optional[Any] = None
- self._virtual_displays: Dict[str, Any] = {}
-
- def getDisplay(self, displayId: int) -> Optional[Any]:
- return self._displays.get(displayId)
-
- def getDisplays(self, category: Optional[str] = None) -> List[Any]:
- if category:
- return [d for d in self._displays.values()]
- return list(self._displays.values())
-
- def getDefaultDisplay(self) -> Optional[Any]:
- return self._default_display
-
- def registerDisplayListener(self, listener: Any, handler: Any = None) -> None:
- if listener not in self._display_listeners:
- self._display_listeners.append(listener)
-
- def unregisterDisplayListener(self, listener: Any) -> None:
- if listener in self._display_listeners:
- self._display_listeners.remove(listener)
-
- def createVirtualDisplay(
- self, name: str, width: int, height: int, densityDpi: int,
- surface: Any, flags: int = 0
- ) -> Optional[Any]:
- return None
-
- def toString(self) -> str:
- return f"DisplayManager(displays={len(self._displays)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DownloadManager
-# ═══════════════════════════════════════════════════════════════
-
-class DownloadManager(Stub):
- """DownloadManager — 下载管理器"""
-
- ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE"
- ACTION_NOTIFICATION_CLICKED = "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"
- ACTION_VIEW_DOWNLOADS = "android.intent.action.VIEW_DOWNLOADS"
- EXTRA_DOWNLOAD_ID = "extraDownloadId"
- EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS = "extraNotificationClickDownloadIds"
- INTENT_EXTRAS_SORT_BY_SIZE = "android.app.DownloadManager.extraSortBySize"
-
- COLUMN_ID = "_id"
- COLUMN_TITLE = "title"
- COLUMN_DESCRIPTION = "description"
- COLUMN_URI = "uri"
- COLUMN_STATUS = "status"
- COLUMN_REASON = "reason"
- COLUMN_TOTAL_SIZE_BYTES = "total_size"
- COLUMN_BYTES_DOWNLOADED_SO_FAR = "bytes_so_far"
- COLUMN_MEDIA_TYPE = "media_type"
- COLUMN_LOCAL_FILENAME = "local_filename"
- COLUMN_LOCAL_URI = "local_uri"
- COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp"
-
- STATUS_PENDING = 1
- STATUS_RUNNING = 2
- STATUS_PAUSED = 3
- STATUS_SUCCESSFUL = 4
- STATUS_FAILED = 5
- STATUS_QUEUED = 6
- STATUS_WAITING = 7
- STATUS_WAITING_FOR_NETWORK = 8
- STATUS_WAITING_FOR_WIFI = 9
-
- ERROR_UNKNOWN = 1000
- ERROR_DEVICE_NOT_FOUND = 1001
- ERROR_CANNOT_RESUME = 1002
- ERROR_FILE_ALREADY_EXISTS = 1003
- ERROR_FILE_ERROR = 1004
- ERROR_HTTP_DATA_ERROR = 1005
- ERROR_INSUFFICIENT_SPACE = 1006
- ERROR_TOO_MANY_REDIRECTS = 1007
- ERROR_UNHANDLED_HTTP_CODE = 1008
- ERROR_HTTP_406 = 1009
-
- PAUSED_QUEUED_FOR_WIFI = 1
- PAUSED_WAITING_TO_RETRY = 2
- PAUSED_WAITING_FOR_NETWORK = 3
- PAUSED_UNKNOWN = 4
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._downloads: Dict[int, Dict[str, Any]] = {}
- self._next_id = 1
- self._lock = threading.Lock()
-
- def enqueue(self, request: Any) -> int:
- with self._lock:
- download_id = self._next_id
- self._next_id += 1
- self._downloads[download_id] = {
- "id": download_id,
- "status": DownloadManager.STATUS_PENDING,
- "reason": 0,
- "title": "",
- "description": "",
- "uri": "",
- "total_size": -1,
- "bytes_so_far": 0,
- "local_filename": "",
- }
- return download_id
-
- def query(self, query: Any) -> Any:
- return None
-
- def remove(self, varargs: List[int]) -> int:
- removed = 0
- with self._lock:
- for download_id in varargs:
- if download_id in self._downloads:
- del self._downloads[download_id]
- removed += 1
- return removed
-
- def getUriForDownloadedFile(self, downloadId: int) -> Optional[str]:
- return None
-
- def getMimeTypeForDownloadedFile(self, downloadId: int) -> Optional[str]:
- return None
-
- def restartDownload(self, downloadId: int) -> bool:
- return False
-
- def toString(self) -> str:
- return f"DownloadManager(downloads={len(self._downloads)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DropBoxManager
-# ═══════════════════════════════════════════════════════════════
-
-class DropBoxManager(Stub):
- """DropBoxManager — 日志收集管理器"""
-
- IS_EMPTY = 0
- IS_TEXT = 1
- IS_GZIPPED = 2
- IS_ENCRYPTED = 4
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._entries: Dict[str, List[Any]] = {}
- self._max_entries = 100
-
- def addText(self, tag: str, data: str) -> None:
- if tag not in self._entries:
- self._entries[tag] = []
- self._entries[tag].append(("text", data, time.time()))
- if len(self._entries[tag]) > self._max_entries:
- self._entries[tag].pop(0)
-
- def addData(self, tag: str, data: bytes, flags: int = 0) -> None:
- if tag not in self._entries:
- self._entries[tag] = []
- self._entries[tag].append(("data", data, time.time(), flags))
- if len(self._entries[tag]) > self._max_entries:
- self._entries[tag].pop(0)
-
- def getNextEntry(self, tag: str, msec: int) -> Optional[Any]:
- return None
-
- def isTagEnabled(self, tag: str) -> bool:
- return True
-
- def dump(self, pw: Any) -> None:
- pass
-
- def toString(self) -> str:
- return f"DropBoxManager(entries={sum(len(v) for v in self._entries.values())})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FocusManager
-# ═══════════════════════════════════════════════════════════════
-
-class FocusManager(Stub):
- """FocusManager — 焦点管理器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._focused_view: Optional[Any] = None
- self._focus_cycle_enabled = True
- self._focus_search_enabled = True
-
- def getFocusedView(self) -> Optional[Any]:
- return self._focused_view
-
- def setFocusedView(self, view: Any) -> None:
- self._focused_view = view
-
- def clearFocus(self) -> None:
- self._focused_view = None
-
- def isFocusCycleEnabled(self) -> bool:
- return self._focus_cycle_enabled
-
- def setFocusCycleEnabled(self, enabled: bool) -> None:
- self._focus_cycle_enabled = enabled
-
- def requestFocus(self, view: Any, direction: int = 0) -> bool:
- self._focused_view = view
- return True
-
- def toString(self) -> str:
- return f"FocusManager(focused={self._focused_view is not None})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LauncherApps
-# ═══════════════════════════════════════════════════════════════
-
-class LauncherApps(Stub):
- """LauncherApps — 启动器应用管理器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._callbacks: List[Any] = []
- self._shortcuts: Dict[str, List[Any]] = {}
-
- def getActivityList(self, packageName: str, user: Any) -> List[Any]:
- return []
-
- def getApplicationList(self, user: Any) -> List[Any]:
- return []
-
- def startAppDetails(self, component: Any, user: Any, sourceBounds: Any, opts: Any) -> None:
- pass
-
- def startMainActivity(self, component: Any, user: Any, sourceBounds: Any, opts: Any) -> None:
- pass
-
- def getShortcutConfigActivityList(self, packageName: str, user: Any) -> List[Any]:
- return []
-
- def hasShortcutHostPermission(self) -> bool:
- return True
-
- def getShortcuts(self, filter_: Any, user: Any) -> List[Any]:
- return []
-
- def pinShortcuts(self, packageName: str, shortcutIds: List[str], user: Any) -> bool:
- return True
-
- def registerCallback(self, callback: Any) -> None:
- if callback not in self._callbacks:
- self._callbacks.append(callback)
-
- def unregisterCallback(self, callback: Any) -> None:
- if callback in self._callbacks:
- self._callbacks.remove(callback)
-
- def toString(self) -> str:
- return f"LauncherApps(callbacks={len(self._callbacks)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaRouter
-# ═══════════════════════════════════════════════════════════════
-
-class MediaRouter(Stub):
- """MediaRouter — 媒体路由管理器"""
-
- ROUTE_TYPE_LIVE_AUDIO = 1
- ROUTE_TYPE_LIVE_VIDEO = 2
- ROUTE_TYPE_REMOTE_DISPLAY = 4
- ROUTE_TYPE_USER = 8
- ROUTE_TYPE_ANY = 0x800000
-
- UNSELECT_REASON_UNKNOWN = 0
- UNSELECT_REASON_ROUTE_CHANGED = 1
- UNSELECT_REASON_DISCONNECTED = 2
- UNSELECT_REASON_STOPPED = 3
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._routes: List[Any] = []
- self._selected_route: Optional[Any] = None
- self._default_route: Optional[Any] = None
- self._callbacks: List[Any] = []
-
- def getDefaultRoute(self) -> Optional[Any]:
- return self._default_route
-
- def getSelectedRoute(self, type_: int) -> Optional[Any]:
- return self._selected_route
-
- def selectRoute(self, type_: int, route: Any) -> None:
- self._selected_route = route
-
- def addCallback(self, types: int, cb: Any) -> None:
- if cb not in self._callbacks:
- self._callbacks.append(cb)
-
- def removeCallback(self, cb: Any) -> None:
- if cb in self._callbacks:
- self._callbacks.remove(cb)
-
- def getRoutes(self) -> List[Any]:
- return list(self._routes)
-
- def isUserRouteAllowed(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"MediaRouter(routes={len(self._routes)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkPolicyManager
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkPolicyManager(Stub):
- """NetworkPolicyManager — 网络策略管理器"""
-
- POLICY_NONE = 0
- POLICY_REJECT_METERED_BACKGROUND = 1
- POLICY_ALLOW_METERED_BACKGROUND = 4
-
- RULE_ALLOW_ALL = 0
- RULE_REJECT_METERED = 1
- RULE_REJECT_ALL = 2
- RULE_TEMPORARY_ALLOW_METERED = 3
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._uid_policies: Dict[int, int] = {}
- self._uid_rules: Dict[int, int] = {}
- self._restrict_background = False
-
- def getUidPolicy(self, uid: int) -> int:
- return self._uid_policies.get(uid, NetworkPolicyManager.POLICY_NONE)
-
- def setUidPolicy(self, uid: int, policy: int) -> None:
- self._uid_policies[uid] = policy
-
- def getUidsWithPolicy(self, policy: int) -> List[int]:
- return [uid for uid, p in self._uid_policies.items() if p == policy]
-
- def isUidNetworkingBlocked(self, uid: int, metered: bool) -> bool:
- return False
-
- def registerListener(self, listener: Any) -> None:
- pass
-
- def unregisterListener(self, listener: Any) -> None:
- pass
-
- def toString(self) -> str:
- return f"NetworkPolicyManager(uids={len(self._uid_policies)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NotificationManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationManagerExt(Stub):
- """NotificationManager (Extension) — 额外通知管理器功能"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
-
- def getSnoozeIntentForChannel(self, channelId: str) -> Optional[Any]:
- return None
-
- def matchesCallFilter(self, address: Any) -> bool:
- return True
-
- def getActiveNotificationsFromBinder(self) -> List[Any]:
- return []
-
- def getHistoricalNotifications(self) -> List[Any]:
- return []
-
- def canNotifyAsPackage(self, pkg: str) -> bool:
- return True
-
- def setNotificationDelegate(self, delegate: str) -> None:
- pass
-
- def getNotificationDelegate(self) -> Optional[str]:
- return None
-
- def updateNotificationChannelGroup(self, group: Any) -> None:
- pass
-
- def toString(self) -> str:
- return "NotificationManager(Extension)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NsdManager (quick reference for net_nsd 模块)
-# ═══════════════════════════════════════════════════════════════
-
-class NsdManagerQuick(Stub):
- """NsdManager (Quick Reference)"""
-
- PROTOCOL_DNS_SD = 0
- FAILURE_ALREADY_ACTIVE = 3
- FAILURE_INTERNAL_ERROR = 0
- FAILURE_MAX_LIMIT = 4
- FAILURE_SERVICE_NOT_FOUND = 1
- FAILURE_SERVICE_NOT_RUNNING = 2
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
-
- def discoverServices(self, serviceType: str, protocolType: int, listener: Any) -> None:
- pass
-
- def stopServiceDiscovery(self, listener: Any) -> None:
- pass
-
- def registerService(self, serviceInfo: Any, protocolType: int, listener: Any) -> None:
- pass
-
- def unregisterService(self, listener: Any) -> None:
- pass
-
- def resolveService(self, serviceInfo: Any, listener: Any) -> None:
- pass
-
- def toString(self) -> str:
- return "NsdManager"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RestrictionManager
-# ═══════════════════════════════════════════════════════════════
-
-class RestrictionManager(Stub):
- """RestrictionManager — 限制管理器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._restrictions: Dict[str, Any] = {}
- self._lock = threading.Lock()
-
- def getApplicationRestrictions(self, packageName: str) -> Any:
- return None
-
- def setApplicationRestrictions(self, packageName: str, restrictions: Any) -> None:
- pass
-
- def hasRestrictionProvider(self) -> bool:
- return False
-
- def getManifestRestrictions(self, packageName: str) -> List[Any]:
- return []
-
- def getRestrictionsProvider(self, packageName: str) -> Optional[Any]:
- return None
-
- def notifyPermissionResponse(self, packageName: str, response: Any) -> None:
- pass
-
- def toString(self) -> str:
- return "RestrictionManager"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SubscriptionManager
-# ═══════════════════════════════════════════════════════════════
-
-class SubscriptionManager(Stub):
- """SubscriptionManager — 订阅管理器"""
-
- DEFAULT_SUBSCRIPTION_ID = -1
- INVALID_SUBSCRIPTION_ID = -2
- ACTIVE_DATA_SUBSCRIPTION_ID = -3
-
- EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX"
- EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._subscriptions: List[Any] = []
-
- def getActiveSubscriptionInfoList(self) -> List[Any]:
- return list(self._subscriptions)
-
- def getActiveSubscriptionInfo(self, subId: int) -> Optional[Any]:
- for sub in self._subscriptions:
- if getattr(sub, "subscriptionId", None) == subId:
- return sub
- return None
-
- def getActiveSubscriptionInfoForSimSlotIndex(self, slotIndex: int) -> Optional[Any]:
- for sub in self._subscriptions:
- if getattr(sub, "simSlotIndex", None) == slotIndex:
- return sub
- return None
-
- def getDefaultSubscriptionId(self) -> int:
- return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID
-
- def setDefaultSubscriptionId(self, subId: int) -> None:
- pass
-
- def addOnSubscriptionsChangedListener(self, listener: Any) -> None:
- pass
-
- def removeOnSubscriptionsChangedListener(self, listener: Any) -> None:
- pass
-
- def getSlotIndex(self, subscriptionId: int) -> int:
- return -1
-
- def toString(self) -> str:
- return f"SubscriptionManager(subscriptions={len(self._subscriptions)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WallpaperManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class WallpaperManagerExt(Stub):
- """WallpaperManager (Extension)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
-
- def getWallpaperIdForWhom(self, which: int) -> int:
- return -1
-
- def getWallpaperUserId(self) -> int:
- return 0
-
- def setWallpaperOffsets(self, windowToken: Any, xOffset: float, yOffset: float) -> None:
- pass
-
- def clearWallpaperOffsets(self, windowToken: Any) -> None:
- pass
-
- def hasResourceWallpaper(self, resid: int) -> bool:
- return False
-
- def toString(self) -> str:
- return "WallpaperManager(Extension)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiP2pManager / WifiP2pDevice / WifiP2pGroup / WifiP2pConfig
-# ═══════════════════════════════════════════════════════════════
-
-class WifiP2pDevice(Stub):
- """WifiP2pDevice — WiFi P2P 设备"""
-
- CONNECTED = 0
- INVITED = 1
- FAILED = 2
- AVAILABLE = 3
- UNAVAILABLE = 4
-
- def __init__(self):
- super().__init__()
- self.deviceName: Optional[str] = None
- self.deviceAddress: Optional[str] = None
- self.primaryDeviceType: Optional[str] = None
- self.secondaryDeviceType: Optional[str] = None
- self.status = WifiP2pDevice.AVAILABLE
- self.wpsConfigMethodsSupported = 0
- self.groupCapabilityFlags = 0
- self.deviceCapabilityFlags = 0
- self.serviceDiscoveryCapable = False
- self.isGroupOwner = False
- self._supports_wfd = False
- self._interface_address: Optional[str] = None
-
- def isGroupOwner(self) -> bool:
- return self.isGroupOwner
-
- def wpsDisplaySupported(self) -> bool:
- return (self.wpsConfigMethodsSupported & 0x1000) != 0
-
- def wpsKeypadSupported(self) -> bool:
- return (self.wpsConfigMethodsSupported & 0x0100) != 0
-
- def wpsPbcSupported(self) -> bool:
- return (self.wpsConfigMethodsSupported & 0x0040) != 0
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, WifiP2pDevice):
- return self.deviceAddress == other.deviceAddress
- return False
-
- def hashCode(self) -> int:
- return hash(self.deviceAddress) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"WifiP2pDevice(name={self.deviceName}, addr={self.deviceAddress}, status={self.status})"
-
-
-class WifiP2pGroup(Stub):
- """WifiP2pGroup — WiFi P2P 组"""
-
- def __init__(self):
- super().__init__()
- self._network_name: Optional[str] = None
- self._owner: Optional[WifiP2pDevice] = None
- self._is_group_owner = False
- self._passphrase: Optional[str] = None
- self._interface: Optional[str] = None
- self._clients: List[WifiP2pDevice] = []
- self._frequency = 0
-
- def getNetworkName(self) -> Optional[str]:
- return self._network_name
-
- def isGroupOwner(self) -> bool:
- return self._is_group_owner
-
- def getOwner(self) -> Optional[WifiP2pDevice]:
- return self._owner
-
- def getPassphrase(self) -> Optional[str]:
- return self._passphrase
-
- def getInterface(self) -> Optional[str]:
- return self._interface
-
- def getClientList(self) -> List[WifiP2pDevice]:
- return list(self._clients)
-
- def getFrequency(self) -> int:
- return self._frequency
-
- def addClient(self, device: WifiP2pDevice) -> None:
- if device not in self._clients:
- self._clients.append(device)
-
- def removeClient(self, device: WifiP2pDevice) -> None:
- if device in self._clients:
- self._clients.remove(device)
-
- def toString(self) -> str:
- return f"WifiP2pGroup(net={self._network_name}, clients={len(self._clients)})"
-
-
-class WifiP2pConfig(Stub):
- """WifiP2pConfig — WiFi P2P 配置"""
-
- class Builder(Stub):
- """WifiP2pConfig.Builder — 构建器"""
-
- def __init__(self):
- super().__init__()
- self._config = WifiP2pConfig()
-
- def setDeviceAddress(self, address: str) -> "WifiP2pConfig.Builder":
- self._config._device_address = address
- return self
-
- def setDeviceName(self, name: str) -> "WifiP2pConfig.Builder":
- self._config._device_name = name
- return self
-
- def setGroupOwnerIntent(self, intent: int) -> "WifiP2pConfig.Builder":
- self._config._group_owner_intent = intent
- return self
-
- def setNetworkName(self, name: str) -> "WifiP2pConfig.Builder":
- self._config._network_name = name
- return self
-
- def setPassphrase(self, passphrase: str) -> "WifiP2pConfig.Builder":
- self._config._passphrase = passphrase
- return self
-
- def enablePersistentMode(self, enabled: bool) -> "WifiP2pConfig.Builder":
- self._config._persistent_mode = enabled
- return self
-
- def build(self) -> "WifiP2pConfig":
- return self._config
-
- def __init__(self):
- super().__init__()
- self._device_address: Optional[str] = None
- self._device_name: Optional[str] = None
- self._group_owner_intent = -1
- self._network_name: Optional[str] = None
- self._passphrase: Optional[str] = None
- self._persistent_mode = False
- self._wps_config = 0
- self._net_id = -1
-
- def getDeviceAddress(self) -> Optional[str]:
- return self._device_address
-
- def getDeviceName(self) -> Optional[str]:
- return self._device_name
-
- def getGroupOwnerIntent(self) -> int:
- return self._group_owner_intent
-
- def isPersistentMode(self) -> bool:
- return self._persistent_mode
-
- def toString(self) -> str:
- return f"WifiP2pConfig(addr={self._device_address}, name={self._device_name})"
-
-
-class WifiP2pManager(Stub):
- """WifiP2pManager — WiFi P2P 管理器"""
-
- WIFI_P2P_STATE_ENABLED = 2
- WIFI_P2P_STATE_DISABLED = 1
- WIFI_P2P_PEERS_CHANGED_ACTION = "android.net.wifi.p2p.PEERS_CHANGED"
- WIFI_P2P_STATE_CHANGED_ACTION = "android.net.wifi.p2p.STATE_CHANGED"
- WIFI_P2P_CONNECTION_CHANGED_ACTION = "android.net.wifi.p2p.CONNECTION_STATE_CHANGE"
- WIFI_P2P_THIS_DEVICE_CHANGED_ACTION = "android.net.wifi.p2p.THIS_DEVICE_CHANGED"
- WIFI_P2P_DISCOVERY_CHANGED_ACTION = "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE"
- WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION = "android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED"
-
- BUSY = 2
- ERROR = 0
- P2P_UNSUPPORTED = 1
- NO_SERVICE_REQUESTS = 3
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._peers: List[WifiP2pDevice] = []
- self._services: List[Any] = []
- self._discovery_running = False
- self._this_device: Optional[WifiP2pDevice] = None
- self._groups: List[WifiP2pGroup] = []
- self._listeners: Dict[str, List[Any]] = {}
-
- def initialize(self, context: Any, looper: Any, listener: Any) -> "WifiP2pManager":
- return self
-
- def discoverPeers(self, channel: Any, listener: Any) -> None:
- self._discovery_running = True
- if listener:
- listener.onSuccess()
-
- def stopPeerDiscovery(self, channel: Any, listener: Any) -> None:
- self._discovery_running = False
- if listener:
- listener.onSuccess()
-
- def requestPeers(self, channel: Any, listener: Any) -> None:
- if listener:
- listener.onPeersAvailable(self._peers)
-
- def connect(self, channel: Any, config: WifiP2pConfig, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def cancelConnect(self, channel: Any, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def createGroup(self, channel: Any, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def removeGroup(self, channel: Any, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def requestGroupInfo(self, channel: Any, listener: Any) -> None:
- if listener and self._groups:
- listener.onGroupInfoAvailable(self._groups[0] if self._groups else None)
-
- def requestConnectionInfo(self, channel: Any, listener: Any) -> None:
- if listener:
- listener.onConnectionInfoAvailable(None)
-
- def setDeviceName(self, channel: Any, deviceName: str, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def setWpsPbc(self, channel: Any, iface: str, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def setWpsPin(self, channel: Any, iface: str, pin: str, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def getAvailableServiceInfo(self, device: WifiP2pDevice) -> Optional[Any]:
- return None
-
- def addServiceRequest(self, channel: Any, req: Any, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def removeServiceRequest(self, channel: Any, req: Any, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def setServiceResponseListener(self, channel: Any, listener: Any) -> None:
- pass
-
- def clearServiceResponses(self, channel: Any, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def clearLocalServices(self, channel: Any, listener: Any) -> None:
- if listener:
- listener.onSuccess()
-
- def requestServiceInfo(self, channel: Any, device: WifiP2pDevice, listener: Any) -> None:
- if listener:
- listener.onServiceInfoAvailable(None)
-
- def getWifiP2pDeviceList(self) -> List[WifiP2pDevice]:
- return list(self._peers)
-
- def isDiscoveryRunning(self) -> bool:
- return self._discovery_running
-
- def toString(self) -> str:
- return f"WifiP2pManager(peers={len(self._peers)}, discovery={self._discovery_running})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowManager
-# ═══════════════════════════════════════════════════════════════
-
-class WindowManager(Stub):
- """WindowManager — 窗口管理器"""
-
- # LayoutParams 类型
- TYPE_BASE_APPLICATION = 1
- TYPE_APPLICATION = 2
- TYPE_APPLICATION_STARTING = 3
- TYPE_APPLICATION_PANEL = 1000
- TYPE_APPLICATION_MEDIA = 1001
- TYPE_APPLICATION_SUB_PANEL = 1002
- TYPE_APPLICATION_ATTACHED_DIALOG = 1003
- TYPE_APPLICATION_OVERLAY = 1004
- TYPE_STATUS_BAR = 2000
- TYPE_SYSTEM_ALERT = 2003
- TYPE_SYSTEM_OVERLAY = 2006
- TYPE_TOAST = 2005
- TYPE_PHONE = 2002
- TYPE_PRIORITY_PHONE = 2007
- TYPE_SYSTEM_DIALOG = 2008
- TYPE_KEYGUARD = 2004
- TYPE_INPUT_METHOD = 2011
- TYPE_INPUT_METHOD_DIALOG = 2012
- TYPE_WALLPAPER = 2013
- TYPE_NAVIGATION_BAR = 2019
- TYPE_DREAM = 2024
- TYPE_ACCESSIBILITY_OVERLAY = 2032
- TYPE_VOLUME_OVERLAY = 2033
- TYPE_SECURE_SYSTEM_OVERLAY = 2034
-
- # LayoutParams 标志
- FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001
- FLAG_DIM_BEHIND = 0x00000002
- FLAG_BLUR_BEHIND = 0x00000004
- FLAG_NOT_FOCUSABLE = 0x00000008
- FLAG_NOT_TOUCHABLE = 0x00000010
- FLAG_NOT_TOUCH_MODAL = 0x00000020
- FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040
- FLAG_KEEP_SCREEN_ON = 0x00000080
- FLAG_LAYOUT_IN_SCREEN = 0x00000100
- FLAG_LAYOUT_NO_LIMITS = 0x00000200
- FLAG_FULLSCREEN = 0x00000400
- FLAG_FORCE_NOT_FULLSCREEN = 0x00000800
- FLAG_DITHER = 0x00001000
- FLAG_SECURE = 0x00002000
- FLAG_SCALED = 0x00004000
- FLAG_IGNORE_CHEEK_PRESSES = 0x00008000
- FLAG_LAYOUT_INSET_DECOR = 0x00010000
- FLAG_ALT_FOCUSABLE_IM = 0x00020000
- FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000
- FLAG_SHOW_WHEN_LOCKED = 0x00080000
- FLAG_SHOW_WALLPAPER = 0x00100000
- FLAG_TURN_SCREEN_ON = 0x00200000
- FLAG_DISMISS_KEYGUARD = 0x00400000
- FLAG_SPLIT_TOUCH = 0x00800000
- FLAG_HARDWARE_ACCELERATED = 0x01000000
- FLAG_LOCAL_FOCUS_MODE = 0x10000000
- FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x20000000
- FLAG_TRANSLUCENT_STATUS = 0x04000000
- FLAG_TRANSLUCENT_NAVIGATION = 0x08000000
-
- # 软输入模式
- SOFT_INPUT_STATE_UNSPECIFIED = 0
- SOFT_INPUT_STATE_UNCHANGED = 1
- SOFT_INPUT_STATE_HIDDEN = 2
- SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3
- SOFT_INPUT_STATE_VISIBLE = 4
- SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5
- SOFT_INPUT_ADJUST_RESIZE = 0x10
- SOFT_INPUT_ADJUST_PAN = 0x20
- SOFT_INPUT_ADJUST_NOTHING = 0x30
- SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00
- SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100
-
- INVALID_DISPLAY = -1
- DOCKED_INVALID = -1
- DOCKED_LEFT = 1
- DOCKED_TOP = 2
- DOCKED_RIGHT = 3
- DOCKED_BOTTOM = 4
-
- class LayoutParams(Stub):
- """WindowManager.LayoutParams — 窗口布局参数"""
-
- MATCH_PARENT = -1
- WRAP_CONTENT = -2
-
- def __init__(self, w: int = -1, h: int = -1, type_: int = 2, flags: int = 0):
- super().__init__()
- self.width = w
- self.height = h
- self.type = type_
- self.flags = flags
- self.x = 0
- self.y = 0
- self.horizontalWeight = 0.0
- self.verticalWeight = 0.0
- self.horizontalMargin = 0.0
- self.verticalMargin = 0.0
- self.gravity = 0
- self.softInputMode = WindowManager.SOFT_INPUT_STATE_UNSPECIFIED
- self.windowAnimations = -1
- self.alpha = 1.0
- self.dimAmount = 0.0
- self.screenOrientation = -1
- self.screenBrightness = -1.0
- self.buttonBrightness = -1.0
- self.token: Optional[Any] = None
- self.packageName: Optional[str] = None
- self.format = -1
- self.systemUiVisibility = 0
- self.subtreeSystemUiVisibility = 0
- self.preferredRefreshRate: float = 0.0
- self.colorMode = 0
-
- def toString(self) -> str:
- return f"LayoutParams({self.width}x{self.height}, type={self.type}, flags=0x{self.flags:x})"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._default_display: Optional[Any] = None
- self._current_window_focus: Optional[Any] = None
- self._window_views: List[Any] = []
-
- def getDefaultDisplay(self) -> Optional[Any]:
- return self._default_display
-
- def getCurrentWindowFocus(self) -> Optional[Any]:
- return self._current_window_focus
-
- def addView(self, view: Any, params: "WindowManager.LayoutParams") -> None:
- self._window_views.append((view, params))
-
- def updateViewLayout(self, view: Any, params: "WindowManager.LayoutParams") -> None:
- for i, (v, p) in enumerate(self._window_views):
- if v is view:
- self._window_views[i] = (view, params)
- break
-
- def removeView(self, view: Any) -> None:
- self._window_views = [(v, p) for v, p in self._window_views if v is not view]
-
- def removeViewImmediate(self, view: Any) -> None:
- self.removeView(view)
-
- def getWindowViews(self) -> List[Any]:
- return [v for v, _ in self._window_views]
-
- def toString(self) -> str:
- return f"WindowManager(views={len(self._window_views)})"
-
-
-WindowManager_LayoutParams = WindowManager.LayoutParams
\ No newline at end of file
diff --git a/android_pyapi/android/media.py b/android_pyapi/android/media.py
deleted file mode 100644
index 5aca399..0000000
--- a/android_pyapi/android/media.py
+++ /dev/null
@@ -1,2525 +0,0 @@
-"""
-Android Media 组件 — MediaPlayer, MediaRecorder, SoundPool, AudioManager 等
-方法签名完全对齐 Android SDK
-"""
-
-import io
-import json
-import math
-import os
-import subprocess
-import time
-import struct
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError, android_context, HAS_PIL, HAS_PYMUPDF, resolve_android_path
-from .graphics import PointF
-
-# Linux 真实实现导入
-try:
- from .._linux_impl import IS_LINUX, LinuxAudio, HAS_AMIXER
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# ffprobe / ffmpeg 辅助函数
-# ═══════════════════════════════════════════════════════════════
-
-def _ffprobe_metadata(path: str) -> Optional[Dict[str, Any]]:
- """用 ffprobe 获取媒体文件元数据,返回解析后的 JSON 字典。
- 失败时返回 None。"""
- try:
- result = subprocess.run(
- ["ffprobe", "-v", "quiet", "-print_format", "json",
- "-show_format", "-show_streams", path],
- capture_output=True, text=True, timeout=30,
- )
- if result.returncode != 0:
- return None
- return json.loads(result.stdout)
- except (FileNotFoundError, subprocess.SubprocessError,
- json.JSONDecodeError, OSError):
- return None
-
-
-def _ffprobe_duration_ms(path: str) -> int:
- """用 ffprobe 获取时长(毫秒),失败返回 0。"""
- data = _ffprobe_metadata(path)
- if not data:
- return 0
- try:
- fmt = data.get("format", {})
- duration = fmt.get("duration")
- if duration is not None:
- return int(float(duration) * 1000)
- # 回退:从流中找
- for stream in data.get("streams", []):
- d = stream.get("duration")
- if d is not None:
- return int(float(d) * 1000)
- except (ValueError, TypeError):
- pass
- return 0
-
-
-def _ffprobe_video_size(path: str) -> Tuple[int, int]:
- """用 ffprobe 获取视频分辨率 (width, height),失败返回 (0, 0)。"""
- data = _ffprobe_metadata(path)
- if not data:
- return (0, 0)
- try:
- for stream in data.get("streams", []):
- if stream.get("codec_type") == "video":
- w = int(stream.get("width", 0))
- h = int(stream.get("height", 0))
- if w > 0 and h > 0:
- return (w, h)
- except (ValueError, TypeError):
- pass
- return (0, 0)
-
-
-def _ffmpeg_extract_frame(path: str, time_us: int = -1,
- width: int = 0, height: int = 0) -> Optional[Any]:
- """用 ffmpeg 提取指定时间点的视频帧,返回 PIL Image。
- time_us < 0 表示提取第一帧。失败返回 None。"""
- if not HAS_PIL:
- return None
- try:
- from PIL import Image
- cmd = ["ffmpeg", "-v", "quiet"]
- if time_us is not None and time_us >= 0:
- cmd += ["-ss", str(time_us / 1_000_000.0)]
- cmd += ["-i", path, "-frames:v", "1", "-f", "image2pipe",
- "-vcodec", "png", "-"]
- if width > 0 and height > 0:
- # 在解码后缩放
- cmd = ["ffmpeg", "-v", "quiet"]
- if time_us is not None and time_us >= 0:
- cmd += ["-ss", str(time_us / 1_000_000.0)]
- cmd += ["-i", path, "-frames:v", "1", "-vf",
- f"scale={width}:{height}", "-f", "image2pipe",
- "-vcodec", "png", "-"]
- result = subprocess.run(cmd, capture_output=True, timeout=30)
- if result.returncode != 0 or not result.stdout:
- return None
- return Image.open(io.BytesIO(result.stdout))
- except (FileNotFoundError, subprocess.SubprocessError, OSError):
- return None
- except Exception:
- return None
-
-
-def _ffmpeg_extract_cover(path: str) -> Optional[bytes]:
- """用 ffmpeg 提取嵌入的封面图片,返回原始字节。
- 失败返回 None。"""
- try:
- # 尝试提取附加图片流(封面)
- cmd = ["ffmpeg", "-v", "quiet", "-i", path,
- "-map", "0:v", "-frames:v", "1", "-f", "image2pipe",
- "-vcodec", "png", "-"]
- result = subprocess.run(cmd, capture_output=True, timeout=30)
- if result.returncode == 0 and result.stdout:
- return result.stdout
- return None
- except (FileNotFoundError, subprocess.SubprocessError, OSError):
- return None
- except Exception:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioAttributes
-# ═══════════════════════════════════════════════════════════════
-
-class AudioAttributes(Stub):
- """AudioAttributes — 音频属性"""
-
- CONTENT_TYPE_UNKNOWN = 0
- CONTENT_TYPE_SPEECH = 1
- CONTENT_TYPE_MUSIC = 2
- CONTENT_TYPE_MOVIE = 3
- CONTENT_TYPE_SONIFICATION = 4
-
- USAGE_UNKNOWN = 0
- USAGE_MEDIA = 1
- USAGE_VOICE_COMMUNICATION = 2
- USAGE_VOICE_COMMUNICATION_SIGNALLING = 3
- USAGE_ALARM = 4
- USAGE_NOTIFICATION = 5
- USAGE_NOTIFICATION_RINGTONE = 6
- USAGE_GAME = 14
- USAGE_ASSISTANCE_ACCESSIBILITY = 11
- USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12
- USAGE_ASSISTANCE_SONIFICATION = 13
-
- FLAG_AUDIBILITY_ENFORCED = 1
- FLAG_SECURE = 2
- FLAG_SCO = 4
- FLAG_BEACON = 8
- FLAG_BYPASS_INTERRUPTION_POLICY = 16
- FLAG_BYPASS_MUTE = 32
- FLAG_LOW_LATENCY = 64
- FLAG_DEEP_BUFFER = 128
-
- class Builder(Stub):
- """AudioAttributes.Builder — 音频属性构建器"""
-
- def __init__(self):
- super().__init__()
- self._content_type = AudioAttributes.CONTENT_TYPE_UNKNOWN
- self._usage = AudioAttributes.USAGE_UNKNOWN
- self._flags = 0
- self._legacy_stream_type = -1
-
- def setContentType(self, contentType: int) -> "AudioAttributes.Builder":
- self._content_type = contentType
- return self
-
- def setUsage(self, usage: int) -> "AudioAttributes.Builder":
- self._usage = usage
- return self
-
- def setFlags(self, flags: int) -> "AudioAttributes.Builder":
- self._flags = flags
- return self
-
- def setLegacyStreamType(self, streamType: int) -> "AudioAttributes.Builder":
- self._legacy_stream_type = streamType
- return self
-
- def build(self) -> "AudioAttributes":
- attrs = AudioAttributes()
- attrs._content_type = self._content_type
- attrs._usage = self._usage
- attrs._flags = self._flags
- attrs._legacy_stream_type = self._legacy_stream_type
- return attrs
-
- def __init__(self):
- super().__init__()
- self._content_type = AudioAttributes.CONTENT_TYPE_UNKNOWN
- self._usage = AudioAttributes.USAGE_UNKNOWN
- self._flags = 0
- self._legacy_stream_type = -1
-
- def getContentType(self) -> int:
- return self._content_type
-
- def getUsage(self) -> int:
- return self._usage
-
- def getFlags(self) -> int:
- return self._flags
-
- def getLegacyStreamType(self) -> int:
- if self._legacy_stream_type >= 0:
- return self._legacy_stream_type
- usage_map = {
- AudioAttributes.USAGE_MEDIA: 3,
- AudioAttributes.USAGE_ALARM: 4,
- AudioAttributes.USAGE_NOTIFICATION: 5,
- AudioAttributes.USAGE_NOTIFICATION_RINGTONE: 2,
- AudioAttributes.USAGE_VOICE_COMMUNICATION: 0,
- AudioAttributes.USAGE_GAME: 3,
- }
- return usage_map.get(self._usage, 3)
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioFormat
-# ═══════════════════════════════════════════════════════════════
-
-class AudioFormat(Stub):
- """AudioFormat — 音频格式"""
-
- ENCODING_INVALID = 0
- ENCODING_DEFAULT = 1
- ENCODING_PCM_16BIT = 2
- ENCODING_PCM_8BIT = 3
- ENCODING_PCM_FLOAT = 4
- ENCODING_AC3 = 5
- ENCODING_E_AC3 = 6
- ENCODING_DTS = 7
- ENCODING_DTS_HD = 8
- ENCODING_MP3 = 9
- ENCODING_AAC = 10
- ENCODING_AAC_LC = 11
- ENCODING_AAC_HE_V1 = 12
- ENCODING_AAC_HE_V2 = 13
- ENCODING_AAC_ELD = 14
- ENCODING_AAC_XHE = 15
- ENCODING_AMRNB = 16
- ENCODING_AMRWB = 17
- ENCODING_OPUS = 18
-
- CHANNEL_OUT_DEFAULT = 0x000
- CHANNEL_OUT_MONO = 0x004
- CHANNEL_OUT_STEREO = 0x00C
- CHANNEL_OUT_QUAD = 0x01C
- CHANNEL_OUT_SURROUND = 0x03C
- CHANNEL_OUT_5POINT1 = 0x0FC
- CHANNEL_OUT_7POINT1 = 0x3FC
-
- CHANNEL_IN_DEFAULT = 0x000
- CHANNEL_IN_MONO = 0x010
- CHANNEL_IN_STEREO = 0x020
-
- def __init__(self):
- super().__init__()
- self._sample_rate = 44100
- self._encoding = AudioFormat.ENCODING_PCM_16BIT
- self._channel_mask = AudioFormat.CHANNEL_OUT_STEREO
- self._channel_count = 2
-
- def getSampleRate(self) -> int:
- return self._sample_rate
-
- def getEncoding(self) -> int:
- return self._encoding
-
- def getChannelMask(self) -> int:
- return self._channel_mask
-
- def getChannelCount(self) -> int:
- return self._channel_count
-
- @staticmethod
- def toChannelMask(channelCount: int) -> int:
- return AudioFormat.CHANNEL_OUT_MONO if channelCount == 1 else AudioFormat.CHANNEL_OUT_STEREO
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaPlayer
-# ═══════════════════════════════════════════════════════════════
-
-class MediaPlayer(Stub):
- """MediaPlayer — 媒体播放器"""
-
- MEDIA_INFO_UNKNOWN = 1
- MEDIA_INFO_VIDEO_TRACK_LAGGING = 700
- MEDIA_INFO_VIDEO_RENDERING_START = 3
- MEDIA_INFO_BUFFERING_START = 701
- MEDIA_INFO_BUFFERING_END = 702
- MEDIA_INFO_BAD_INTERLEAVING = 800
- MEDIA_INFO_NOT_SEEKABLE = 801
- MEDIA_INFO_METADATA_UPDATE = 802
- MEDIA_INFO_AUDIO_NOT_PLAYING = 804
- MEDIA_INFO_VIDEO_NOT_PLAYING = 805
- MEDIA_INFO_SUBTITLE_TIMED_OUT = 902
- MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901
-
- MEDIA_ERROR_UNKNOWN = 1
- MEDIA_ERROR_SERVER_DIED = 100
- MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200
- MEDIA_ERROR_TIMED_OUT = -110
- MEDIA_ERROR_IO = -1004
- MEDIA_ERROR_MALFORMED = -1007
- MEDIA_ERROR_UNSUPPORTED = -1010
-
- # OnPreparedListener
- class OnPreparedListener(Stub):
- def onPrepared(self, mp: "MediaPlayer"):
- pass
-
- # OnCompletionListener
- class OnCompletionListener(Stub):
- def onCompletion(self, mp: "MediaPlayer"):
- pass
-
- # OnErrorListener
- class OnErrorListener(Stub):
- def onError(self, mp: "MediaPlayer", what: int, extra: int) -> bool:
- return False
-
- # OnInfoListener
- class OnInfoListener(Stub):
- def onInfo(self, mp: "MediaPlayer", what: int, extra: int) -> bool:
- return False
-
- # OnSeekCompleteListener
- class OnSeekCompleteListener(Stub):
- def onSeekComplete(self, mp: "MediaPlayer"):
- pass
-
- # OnVideoSizeChangedListener
- class OnVideoSizeChangedListener(Stub):
- def onVideoSizeChanged(self, mp: "MediaPlayer", width: int, height: int):
- pass
-
- def __init__(self):
- super().__init__()
- self._data_source = None
- self._resolved_path = None
- self._prepared = False
- self._playing = False
- self._looping = False
- self._volume_left = 1.0
- self._volume_right = 1.0
- self._current_position = 0
- self._duration = 0
- self._video_width = 0
- self._video_height = 0
- self._screen_on = False
- self._wake_mode = 0
- self._audio_attributes = None
- self._display = None
- self._surface = None
- self._released = False
- self._start_time = 0.0 # 用于模拟播放进度
-
- # Listeners
- self._on_prepared_listener = None
- self._on_completion_listener = None
- self._on_error_listener = None
- self._on_info_listener = None
- self._on_seek_complete_listener = None
- self._on_video_size_changed_listener = None
-
- def setDataSource(self, path: str = None, uri=None, headers: Dict = None):
- self._data_source = path or str(uri) if uri is not None else path
- if self._data_source:
- self._resolved_path = resolve_android_path(self._data_source)
-
- def _load_media_info(self):
- """用 ffprobe 加载时长和分辨率信息(try/except 保护)。"""
- if not self._resolved_path:
- return
- if not os.path.exists(self._resolved_path):
- return
- try:
- duration = _ffprobe_duration_ms(self._resolved_path)
- if duration > 0:
- self._duration = duration
- except Exception:
- pass
- try:
- w, h = _ffprobe_video_size(self._resolved_path)
- if w > 0 and h > 0:
- self._video_width = w
- self._video_height = h
- if self._on_video_size_changed_listener:
- self._on_video_size_changed_listener.onVideoSizeChanged(
- self, w, h)
- except Exception:
- pass
-
- def prepare(self):
- if self._released:
- return
- if self._resolved_path and not os.path.exists(self._resolved_path):
- if self._on_error_listener:
- self._on_error_listener.onError(
- self, MediaPlayer.MEDIA_ERROR_UNKNOWN, -1004)
- raise IOError(f"数据源文件不存在: {self._resolved_path}")
- self._load_media_info()
- self._prepared = True
-
- def prepareAsync(self):
- if self._released:
- return
- if self._resolved_path and not os.path.exists(self._resolved_path):
- if self._on_error_listener:
- self._on_error_listener.onError(
- self, MediaPlayer.MEDIA_ERROR_UNKNOWN, -1004)
- return
- self._load_media_info()
- self._prepared = True
- if self._on_prepared_listener:
- self._on_prepared_listener.onPrepared(self)
-
- def start(self):
- if self._released:
- return
- self._playing = True
- self._start_time = time.time()
-
- def stop(self):
- self._playing = False
-
- def pause(self):
- if self._playing:
- # 记录已播放的进度
- elapsed = int((time.time() - self._start_time) * 1000)
- self._current_position = min(
- self._current_position + elapsed, self._duration)
- self._playing = False
-
- def reset(self):
- self._playing = False
- self._prepared = False
- self._current_position = 0
- self._duration = 0
- self._video_width = 0
- self._video_height = 0
- self._data_source = None
- self._resolved_path = None
-
- def release(self):
- self._playing = False
- self._prepared = False
- self._released = True
- self._data_source = None
- self._resolved_path = None
- self._on_prepared_listener = None
- self._on_completion_listener = None
- self._on_error_listener = None
- self._on_info_listener = None
- self._on_seek_complete_listener = None
- self._on_video_size_changed_listener = None
-
- def seekTo(self, msec: int):
- self._current_position = max(0, min(msec, self._duration))
- self._start_time = time.time()
- if self._on_seek_complete_listener:
- self._on_seek_complete_listener.onSeekComplete(self)
-
- def getCurrentPosition(self) -> int:
- if self._playing and self._start_time > 0:
- elapsed = int((time.time() - self._start_time) * 1000)
- pos = self._current_position + elapsed
- if self._duration > 0 and pos >= self._duration:
- pos = self._duration
- if self._looping:
- self._current_position = 0
- self._start_time = time.time()
- pos = 0
- else:
- self._playing = False
- if self._on_completion_listener:
- self._on_completion_listener.onCompletion(self)
- return pos
- return self._current_position
-
- def getDuration(self) -> int:
- if self._duration == 0 and self._resolved_path:
- try:
- self._duration = _ffprobe_duration_ms(self._resolved_path)
- except Exception:
- pass
- return self._duration
-
- def isPlaying(self) -> bool:
- return self._playing
-
- def isLooping(self) -> bool:
- return self._looping
-
- def setLooping(self, looping: bool):
- self._looping = looping
-
- def setVolume(self, leftVolume: float, rightVolume: float):
- self._volume_left = leftVolume
- self._volume_right = rightVolume
-
- def getVolume(self) -> Tuple[float, float]:
- return (self._volume_left, self._volume_right)
-
- def setScreenOnWhilePlaying(self, screenOn: bool):
- self._screen_on = screenOn
-
- def setWakeMode(self, context, mode: int):
- self._wake_mode = mode
-
- def setAudioAttributes(self, attributes: AudioAttributes):
- self._audio_attributes = attributes
-
- def setDisplay(self, surface_holder):
- self._display = surface_holder
-
- def getVideoWidth(self) -> int:
- if self._video_width == 0 and self._resolved_path:
- try:
- w, h = _ffprobe_video_size(self._resolved_path)
- if w > 0:
- self._video_width = w
- self._video_height = h
- except Exception:
- pass
- return self._video_width
-
- def getVideoHeight(self) -> int:
- if self._video_height == 0 and self._resolved_path:
- try:
- w, h = _ffprobe_video_size(self._resolved_path)
- if h > 0:
- self._video_width = w
- self._video_height = h
- except Exception:
- pass
- return self._video_height
-
- def setOnPreparedListener(self, listener: "MediaPlayer.OnPreparedListener"):
- self._on_prepared_listener = listener
-
- def setOnCompletionListener(self, listener: "MediaPlayer.OnCompletionListener"):
- self._on_completion_listener = listener
-
- def setOnErrorListener(self, listener: "MediaPlayer.OnErrorListener"):
- self._on_error_listener = listener
-
- def setOnInfoListener(self, listener: "MediaPlayer.OnInfoListener"):
- self._on_info_listener = listener
-
- def setOnSeekCompleteListener(self, listener: "MediaPlayer.OnSeekCompleteListener"):
- self._on_seek_complete_listener = listener
-
- def setOnVideoSizeChangedListener(self, listener: "MediaPlayer.OnVideoSizeChangedListener"):
- self._on_video_size_changed_listener = listener
-
- @staticmethod
- def create(context, resid: int = 0) -> "MediaPlayer":
- mp = MediaPlayer()
- mp._prepared = True
- return mp
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaRecorder
-# ═══════════════════════════════════════════════════════════════
-
-class MediaRecorder(Stub):
- """MediaRecorder — 媒体录制器"""
-
- class AudioSource:
- DEFAULT = 0
- MIC = 1
- VOICE_UPLINK = 2
- VOICE_DOWNLINK = 3
- VOICE_CALL = 4
- CAMCORDER = 5
- VOICE_RECOGNITION = 6
- VOICE_COMMUNICATION = 7
- REMOTE_SUBMIX = 8
- UNPROCESSED = 9
-
- class VideoSource:
- DEFAULT = 0
- CAMERA = 1
- SURFACE = 2
-
- class OutputFormat:
- DEFAULT = 0
- THREE_GPP = 1
- MPEG_4 = 2
- AMR_NB = 3
- AMR_WB = 4
- AAC_ADIF = 5
- AAC_ADTS = 6
- OUTPUT_FORMAT_RTP_AVP = 7
- MPEG_2_TS = 8
- WEBM = 9
- HEIF = 10
- OGG = 11
-
- class AudioEncoder:
- DEFAULT = 0
- AMR_NB = 1
- AMR_WB = 2
- AAC = 3
- HE_AAC = 4
- AAC_ELD = 5
- VORBIS = 6
- OPUS = 7
- LPCM = 8
-
- class VideoEncoder:
- DEFAULT = 0
- H_263 = 1
- H_264 = 2
- MPEG_4_SP = 3
- VP8 = 4
- HEVC = 5
- VP9 = 6
- AV1 = 7
-
- def __init__(self):
- super().__init__()
- self._audio_source = 0
- self._video_source = 0
- self._output_format = 0
- self._audio_encoder = 0
- self._video_encoder = 0
- self._output_file = None
- self._preview_display = None
- self._recording = False
- self._prepared = False
- self._released = False
- self._video_width = 0
- self._video_height = 0
- self._video_frame_rate = 0
- self._video_encoding_bit_rate = 0
- self._audio_encoding_bit_rate = 0
- self._max_duration = 0
- self._max_filesize = 0
-
- def setAudioSource(self, audio_source: int):
- self._audio_source = audio_source
-
- def setVideoSource(self, video_source: int):
- self._video_source = video_source
-
- def setOutputFormat(self, output_format: int):
- self._output_format = output_format
-
- def setAudioEncoder(self, audio_encoder: int):
- self._audio_encoder = audio_encoder
-
- def setVideoEncoder(self, video_encoder: int):
- self._video_encoder = video_encoder
-
- def setOutputFile(self, path: str):
- self._output_file = path
-
- def setVideoSize(self, width: int, height: int):
- self._video_width = width
- self._video_height = height
-
- def setVideoFrameRate(self, rate: int):
- self._video_frame_rate = rate
-
- def setVideoEncodingBitRate(self, bit_rate: int):
- self._video_encoding_bit_rate = bit_rate
-
- def setAudioEncodingBitRate(self, bit_rate: int):
- self._audio_encoding_bit_rate = bit_rate
-
- def setMaxDuration(self, max_duration_ms: int):
- self._max_duration = max_duration_ms
-
- def setMaxFileSize(self, max_filesize_bytes: int):
- self._max_filesize = max_filesize_bytes
-
- def setPreviewDisplay(self, surface_holder):
- self._preview_display = surface_holder
-
- def prepare(self):
- if self._released:
- return
- self._prepared = True
-
- def start(self):
- if self._released or not self._prepared:
- return
- self._recording = True
-
- def stop(self):
- self._recording = False
-
- def reset(self):
- self._recording = False
- self._prepared = False
- self._audio_source = 0
- self._video_source = 0
- self._output_format = 0
- self._audio_encoder = 0
- self._video_encoder = 0
- self._output_file = None
- self._video_width = 0
- self._video_height = 0
- self._video_frame_rate = 0
- self._video_encoding_bit_rate = 0
-
- def release(self):
- self._recording = False
- self._prepared = False
- self._released = True
- self._output_file = None
- self._preview_display = None
-
- def getMaxAmplitude(self) -> int:
- if self._recording:
- import random
- return random.randint(0, 32767)
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# SoundPool
-# ═══════════════════════════════════════════════════════════════
-
-class SoundPool(Stub):
- """SoundPool — 音效池"""
-
- def __init__(self, maxStreams: int = 1, streamType: int = 3, srcQuality: int = 0):
- super().__init__()
- self._max_streams = maxStreams
- self._stream_type = streamType
- self._src_quality = srcQuality
- self._sounds: Dict[int, str] = {}
- self._playing: Dict[int, float] = {}
- self._on_load_complete_listener = None
- self._next_id = 1
-
- def load(self, path: str, priority: int = 1) -> int:
- sound_id = self._next_id
- self._next_id += 1
- self._sounds[sound_id] = path
- if self._on_load_complete_listener:
- self._on_load_complete_listener.onLoadComplete(self, sound_id, 0)
- return sound_id
-
- def load(self, context, resId: int, priority: int) -> int:
- return self.load(str(resId), priority)
-
- def play(self, soundID: int, leftVolume: float, rightVolume: float,
- priority: int, loop: int, rate: float) -> int:
- stream_id = self._next_id
- self._next_id += 1
- self._playing[stream_id] = 0.0
- return stream_id
-
- def pause(self, streamID: int):
- pass
-
- def resume(self, streamID: int):
- pass
-
- def autoPause(self):
- pass
-
- def autoResume(self):
- pass
-
- def release(self):
- self._sounds.clear()
- self._playing.clear()
-
- def setVolume(self, streamID: int, leftVolume: float, rightVolume: float):
- pass
-
- def setRate(self, streamID: int, rate: float):
- pass
-
- def setPriority(self, streamID: int, priority: int):
- pass
-
- def setLoop(self, streamID: int, loop: int):
- pass
-
- def setOnLoadCompleteListener(self, listener):
- self._on_load_complete_listener = listener
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioManager
-# ═══════════════════════════════════════════════════════════════
-
-class AudioManager(Stub):
- """AudioManager — 音频管理器"""
-
- MODE_NORMAL = 0
- MODE_RINGTONE = 1
- MODE_IN_CALL = 2
- MODE_IN_COMMUNICATION = 3
-
- STREAM_VOICE_CALL = 0
- STREAM_SYSTEM = 1
- STREAM_RING = 2
- STREAM_MUSIC = 3
- STREAM_ALARM = 4
- STREAM_NOTIFICATION = 5
- STREAM_BLUETOOTH_SCO = 6
- STREAM_DTMF = 8
- STREAM_TTS = 9
- STREAM_ACCESSIBILITY = 10
-
- ADJUST_RAISE = 1
- ADJUST_LOWER = -1
- ADJUST_SAME = 0
- ADJUST_MUTE = -100
- ADJUST_UNMUTE = 100
- ADJUST_TOGGLE_MUTE = 101
-
- FLAG_PLAY_SOUND = 1
- FLAG_SHOW_UI = 2
- FLAG_REMOVE_SOUND_AND_VIBRATE = 4
- FLAG_ALLOW_RINGER_MODES = 8
- FLAG_VIBRATE = 16
- FLAG_BYPASS_INTERRUPTION_POLICY = 32
- FLAG_BYPASS_MUTE = 64
- FLAG_LOW_LATENCY = 128
-
- RINGER_MODE_NORMAL = 2
- RINGER_MODE_SILENT = 0
- RINGER_MODE_VIBRATE = 1
-
- def __init__(self):
- super().__init__()
- self._mode = AudioManager.MODE_NORMAL
- self._ringer_mode = AudioManager.RINGER_MODE_NORMAL
- self._speakerphone_on = False
- self._bluetooth_sco_on = False
- self._wired_headset_on = False
- self._stream_volumes = {
- AudioManager.STREAM_VOICE_CALL: 4,
- AudioManager.STREAM_SYSTEM: 7,
- AudioManager.STREAM_RING: 5,
- AudioManager.STREAM_MUSIC: 10,
- AudioManager.STREAM_ALARM: 7,
- AudioManager.STREAM_NOTIFICATION: 5,
- }
- self._parameters: Dict[str, str] = {}
-
- def getStreamVolume(self, streamType: int) -> int:
- if _USE_LINUX:
- # STREAM_MUSIC 及其它流类型映射到 Linux 主音量
- return LinuxAudio.get_volume()
- return self._stream_volumes.get(streamType, 0)
-
- def getStreamMaxVolume(self, streamType: int) -> int:
- if _USE_LINUX:
- return 100
- return 15
-
- def setStreamVolume(self, streamType: int, index: int, flags: int = 0):
- if _USE_LINUX:
- # STREAM_MUSIC 及其它流类型映射到 Linux 主音量
- LinuxAudio.set_volume(index)
- return
- if streamType in self._stream_volumes:
- self._stream_volumes[streamType] = max(0, min(15, index))
-
- def isMicrophoneMute(self) -> bool:
- """麦克风是否静音"""
- if _USE_LINUX:
- return LinuxAudio.get_mute()
- return False
-
- def setMicrophoneMute(self, on: bool):
- """设置麦克风静音"""
- if _USE_LINUX:
- LinuxAudio.set_mute(on)
- return
- # 存根: 无操作
-
- def adjustVolume(self, direction: int, flags: int = 0):
- pass
-
- def adjustStreamVolume(self, streamType: int, direction: int, flags: int = 0):
- current = self.getStreamVolume(streamType)
- if direction == AudioManager.ADJUST_RAISE:
- self.setStreamVolume(streamType, current + 1)
- elif direction == AudioManager.ADJUST_LOWER:
- self.setStreamVolume(streamType, current - 1)
-
- def getMode(self) -> int:
- return self._mode
-
- def setMode(self, mode: int):
- self._mode = mode
-
- def setSpeakerphoneOn(self, on: bool):
- self._speakerphone_on = on
-
- def isSpeakerphoneOn(self) -> bool:
- return self._speakerphone_on
-
- def isWiredHeadsetOn(self) -> bool:
- return self._wired_headset_on
-
- def isBluetoothScoOn(self) -> bool:
- return self._bluetooth_sco_on
-
- def setBluetoothScoOn(self, on: bool):
- self._bluetooth_sco_on = on
-
- def setRingerMode(self, ringerMode: int):
- self._ringer_mode = ringerMode
-
- def getRingerMode(self) -> int:
- return self._ringer_mode
-
- def loadSoundEffects(self):
- pass
-
- def unloadSoundEffects(self):
- pass
-
- def getParameters(self, keys: str) -> str:
- return ",".join(f"{k}={v}" for k, v in self._parameters.items() if k in keys)
-
- def setParameters(self, keyValuePairs: str):
- for pair in keyValuePairs.split(";"):
- if "=" in pair:
- k, v = pair.split("=", 1)
- self._parameters[k.strip()] = v.strip()
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioTrack
-# ═══════════════════════════════════════════════════════════════
-
-class AudioTrack(Stub):
- """AudioTrack — 音频轨道"""
-
- STATE_UNINITIALIZED = 0
- STATE_INITIALIZED = 1
- STATE_NO_STATIC_DATA = 2
- MODE_STATIC = 0
- MODE_STREAM = 1
- WRITE_BLOCKING = -1
- WRITE_NON_BLOCKING = 0
- SUCCESS = 0
- ERROR = -1
- ERROR_BAD_VALUE = -2
- ERROR_INVALID_OPERATION = -3
- ERROR_DEAD_OBJECT = -6
- ERROR_WAS_BLOCKED = -8
-
- PERFORMANCE_MODE_NONE = 0
- PERFORMANCE_MODE_LOW_LATENCY = 1
- PERFORMANCE_MODE_POWER_SAVING = 2
-
- def __init__(self, streamType: int, sampleRateInHz: int, channelConfig: int,
- audioFormat: int, bufferSizeInBytes: int, mode: int):
- super().__init__()
- self._state = AudioTrack.STATE_INITIALIZED
- self._playing = False
- self._sample_rate = sampleRateInHz
- self._channel_config = channelConfig
- self._audio_format = audioFormat
- self._buffer_size = bufferSizeInBytes
- self._mode = mode
- self._stream_type = streamType
- self._volume = 1.0
- self._playback_rate = sampleRateInHz
- self._buffer = bytearray(bufferSizeInBytes)
-
- def play(self):
- self._playing = True
-
- def pause(self):
- self._playing = False
-
- def stop(self):
- self._playing = False
-
- def flush(self):
- pass
-
- def release(self):
- self._state = AudioTrack.STATE_UNINITIALIZED
- self._playing = False
-
- def write(self, audioData, offsetInBytes: int = 0, sizeInBytes: int = -1,
- writeMode: int = WRITE_BLOCKING) -> int:
- if sizeInBytes < 0:
- sizeInBytes = len(audioData) - offsetInBytes
- if self._buffer and offsetInBytes + sizeInBytes <= len(self._buffer):
- self._buffer[offsetInBytes:offsetInBytes + sizeInBytes] = audioData[offsetInBytes:offsetInBytes + sizeInBytes]
- return sizeInBytes
-
- def getPlayState(self) -> int:
- return 3 if self._playing else 1
-
- def getState(self) -> int:
- return self._state
-
- def getSampleRate(self) -> int:
- return self._sample_rate
-
- def getPlaybackRate(self) -> int:
- return self._playback_rate
-
- def setPlaybackRate(self, sampleRateInHz: int):
- self._playback_rate = sampleRateInHz
-
- def setVolume(self, volume: float):
- self._volume = max(0.0, min(1.0, volume))
-
- def getVolume(self) -> float:
- return self._volume
-
- def getAudioFormat(self) -> int:
- return self._audio_format
-
- def getChannelConfiguration(self) -> int:
- return self._channel_config
-
- def getChannelCount(self) -> int:
- return 2 if self._channel_config == AudioFormat.CHANNEL_OUT_STEREO else 1
-
- def getNotificationMarkerPosition(self) -> int:
- return 0
-
- def setNotificationMarkerPosition(self, marker: int):
- pass
-
- def getPositionNotificationPeriod(self) -> int:
- return 0
-
- def setPositionNotificationPeriod(self, period: int):
- pass
-
- @staticmethod
- def getMinBufferSize(sampleRateInHz: int, channelConfig: int, audioFormat: int) -> int:
- return sampleRateInHz * 2 * 2 # Conservative estimate
-
- @staticmethod
- def getNativeOutputSampleRate(streamType: int) -> int:
- return 44100
-
- @staticmethod
- def getMaxVolume() -> float:
- return 1.0
-
- @staticmethod
- def getMinVolume() -> float:
- return 0.0
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioRecord
-# ═══════════════════════════════════════════════════════════════
-
-class AudioRecord(Stub):
- """AudioRecord — 音频录制器"""
-
- STATE_UNINITIALIZED = 0
- STATE_INITIALIZED = 1
- SUCCESS = 0
- ERROR = -1
- ERROR_BAD_VALUE = -2
- ERROR_INVALID_OPERATION = -3
- ERROR_DEAD_OBJECT = -6
-
- def __init__(self, audioSource: int, sampleRateInHz: int, channelConfig: int,
- audioFormat: int, bufferSizeInBytes: int):
- super().__init__()
- self._state = AudioRecord.STATE_INITIALIZED
- self._recording = False
- self._audio_source = audioSource
- self._sample_rate = sampleRateInHz
- self._channel_config = channelConfig
- self._audio_format = audioFormat
- self._buffer_size = bufferSizeInBytes
- self._buffer = bytearray(bufferSizeInBytes)
-
- def startRecording(self):
- self._recording = True
-
- def stop(self):
- self._recording = False
-
- def release(self):
- self._state = AudioRecord.STATE_UNINITIALIZED
- self._recording = False
-
- def read(self, audioData, offsetInBytes: int, sizeInBytes: int) -> int:
- return min(sizeInBytes, len(audioData) - offsetInBytes)
-
- def getState(self) -> int:
- return self._state
-
- def getSampleRate(self) -> int:
- return self._sample_rate
-
- def getRecordingState(self) -> int:
- return 3 if self._recording else 1
-
- def getAudioFormat(self) -> int:
- return self._audio_format
-
- def getChannelConfiguration(self) -> int:
- return self._channel_config
-
- def getChannelCount(self) -> int:
- return 2 if self._channel_config == AudioFormat.CHANNEL_IN_STEREO else 1
-
- @staticmethod
- def getMinBufferSize(sampleRateInHz: int, channelConfig: int, audioFormat: int) -> int:
- return sampleRateInHz * 2 * 2
-
- def getAudioSource(self) -> int:
- return self._audio_source
-
-
-# ═══════════════════════════════════════════════════════════════
-# Ringtone
-# ═══════════════════════════════════════════════════════════════
-
-class Ringtone(Stub):
- """Ringtone — 铃声"""
-
- def __init__(self, context=None):
- super().__init__()
- self._title = ""
- self._stream_type = AudioManager.STREAM_RING
- self._playing = False
- self._volume = 1.0
-
- def setStreamType(self, streamType: int):
- self._stream_type = streamType
-
- def getStreamType(self) -> int:
- return self._stream_type
-
- def setTitle(self, title: str):
- self._title = title
-
- def getTitle(self, context=None) -> str:
- return self._title
-
- def play(self):
- self._playing = True
-
- def stop(self):
- self._playing = False
-
- def isPlaying(self) -> bool:
- return self._playing
-
- def setVolume(self, volume: float):
- self._volume = max(0.0, min(1.0, volume))
-
- def getVolume(self) -> float:
- return self._volume
-
- def getAudioAttributes(self) -> AudioAttributes:
- attrs = AudioAttributes()
- if self._stream_type == AudioManager.STREAM_RING:
- attrs._usage = AudioAttributes.USAGE_NOTIFICATION_RINGTONE
- elif self._stream_type == AudioManager.STREAM_ALARM:
- attrs._usage = AudioAttributes.USAGE_ALARM
- else:
- attrs._usage = AudioAttributes.USAGE_NOTIFICATION
- return attrs
-
-
-# ═══════════════════════════════════════════════════════════════
-# RingtoneManager
-# ═══════════════════════════════════════════════════════════════
-
-class RingtoneManager(Stub):
- """RingtoneManager — 铃声管理器"""
-
- TYPE_RINGTONE = 1
- TYPE_NOTIFICATION = 2
- TYPE_ALARM = 4
- TYPE_ALL = 7
-
- ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER"
- EXTRA_RINGTONE_TYPE = "android.intent.extra.ringtone.TYPE"
- EXTRA_RINGTONE_TITLE = "android.intent.extra.ringtone.TITLE"
- EXTRA_RINGTONE_EXISTING_URI = "android.intent.extra.ringtone.EXISTING_URI"
- EXTRA_RINGTONE_DEFAULT_URI = "android.intent.extra.ringtone.DEFAULT_URI"
- EXTRA_RINGTONE_SHOW_DEFAULT = "android.intent.extra.ringtone.SHOW_DEFAULT"
- EXTRA_RINGTONE_INCLUDE_DRM = "android.intent.extra.ringtone.INCLUDE_DRM"
- EXTRA_RINGTONE_PICKED_URI = "android.intent.extra.ringtone.PICKED_URI"
-
- def __init__(self, context):
- super().__init__()
- self._context = context
- self._type = RingtoneManager.TYPE_RINGTONE
- self._cursor = []
- self._cursor_position = -1
-
- def setType(self, type_: int):
- self._type = type_
-
- def getCursor(self):
- return self._cursor
-
- def getRingtoneUri(self, position: int):
- return None
-
- def getRingtonePosition(self, uri) -> int:
- return 0
-
- @staticmethod
- def getRingtone(context, uri) -> Ringtone:
- return Ringtone(context)
-
- @staticmethod
- def getActualDefaultRingtoneUri(context, type_: int):
- return None
-
- @staticmethod
- def setActualDefaultRingtoneUri(context, type_: int, ringtoneUri):
- pass
-
- @staticmethod
- def getDefaultUri(type_: int):
- return None
-
- @staticmethod
- def getValidRingtoneUri(context):
- return None
-
- @staticmethod
- def inferStreamType(type_: int) -> int:
- if type_ == RingtoneManager.TYPE_RINGTONE:
- return AudioManager.STREAM_RING
- elif type_ == RingtoneManager.TYPE_NOTIFICATION:
- return AudioManager.STREAM_NOTIFICATION
- elif type_ == RingtoneManager.TYPE_ALARM:
- return AudioManager.STREAM_ALARM
- return AudioManager.STREAM_RING
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaMetadataRetriever
-# ═══════════════════════════════════════════════════════════════
-
-class MediaMetadataRetriever(Stub):
- """MediaMetadataRetriever — 媒体元数据检索器"""
-
- METADATA_KEY_ALBUM = "album"
- METADATA_KEY_ARTIST = "artist"
- METADATA_KEY_TITLE = "title"
- METADATA_KEY_DURATION = "duration"
- METADATA_KEY_CD_TRACK_NUMBER = "cd_track_number"
- METADATA_KEY_COMPOSER = "composer"
- METADATA_KEY_DATE = "date"
- METADATA_KEY_GENRE = "genre"
- METADATA_KEY_MIMETYPE = "mimetype"
- METADATA_KEY_NUM_TRACKS = "num_tracks"
- METADATA_KEY_WRITER = "writer"
- METADATA_KEY_YEAR = "year"
- METADATA_KEY_VIDEO_WIDTH = "video_width"
- METADATA_KEY_VIDEO_HEIGHT = "video_height"
- METADATA_KEY_HAS_AUDIO = "has_audio"
- METADATA_KEY_HAS_VIDEO = "has_video"
- METADATA_KEY_BITRATE = "bitrate"
- METADATA_KEY_LOCATION = "location"
-
- # 提取帧选项
- OPTION_CLOSEST = 0x01
- OPTION_CLOSEST_SYNC = 0x02
- OPTION_NEXT_SYNC = 0x03
- OPTION_PREVIOUS_SYNC = 0x04
-
- # ffprobe format_name 到 MIME 类型映射
- _MIME_MAP = {
- "mov,mp4,m4a,3gp,3g2,mj2": "video/mp4",
- "matroska,webm": "video/x-matroska",
- "avi": "video/x-msvideo",
- "flv": "video/x-flv",
- "wav": "audio/wav",
- "mp3": "audio/mpeg",
- "aac": "audio/aac",
- "ogg": "audio/ogg",
- "flac": "audio/flac",
- "asf": "video/x-ms-asf",
- "mpeg": "video/mpeg",
- "webm": "video/webm",
- }
-
- def __init__(self):
- super().__init__()
- self._metadata: Dict[str, str] = {}
- self._resolved_path: Optional[str] = None
- self._ffprobe_data: Optional[Dict[str, Any]] = None
-
- def setDataSource(self, path: str, headers: Optional[Dict[str, str]] = None):
- """设置数据源并用 ffprobe 加载元数据。"""
- self._resolved_path = resolve_android_path(path)
- self._metadata = {}
- self._ffprobe_data = None
- if not self._resolved_path or not os.path.exists(self._resolved_path):
- return
- # 用 ffprobe 获取真实元数据(try/except 保护)
- try:
- self._ffprobe_data = _ffprobe_metadata(self._resolved_path)
- except Exception:
- self._ffprobe_data = None
- if self._ffprobe_data:
- self._parse_ffprobe_metadata()
-
- def _parse_ffprobe_metadata(self):
- """将 ffprobe 输出解析为 Android 风格的元数据键值对。"""
- if not self._ffprobe_data:
- return
- data = self._ffprobe_data
- fmt = data.get("format", {})
- tags = fmt.get("tags", {})
- streams = data.get("streams", [])
-
- # 找到视频流和音频流
- video_stream = None
- audio_stream = None
- for s in streams:
- ct = s.get("codec_type", "")
- if ct == "video" and video_stream is None:
- video_stream = s
- elif ct == "audio" and audio_stream is None:
- audio_stream = s
-
- md = self._metadata
-
- # 时长(毫秒)
- duration = fmt.get("duration")
- if duration is None and video_stream:
- duration = video_stream.get("duration")
- if duration is None and audio_stream:
- duration = audio_stream.get("duration")
- if duration is not None:
- try:
- md[MediaMetadataRetriever.METADATA_KEY_DURATION] = str(
- int(float(duration) * 1000))
- except (ValueError, TypeError):
- pass
-
- # 标题
- title = tags.get("title") or tags.get("TITLE")
- if title:
- md[MediaMetadataRetriever.METADATA_KEY_TITLE] = title
-
- # 艺术家
- artist = tags.get("artist") or tags.get("ARTIST")
- if artist:
- md[MediaMetadataRetriever.METADATA_KEY_ARTIST] = artist
-
- # 专辑
- album = tags.get("album") or tags.get("ALBUM")
- if album:
- md[MediaMetadataRetriever.METADATA_KEY_ALBUM] = album
-
- # 作曲家
- composer = tags.get("composer") or tags.get("COMPOSER")
- if composer:
- md[MediaMetadataRetriever.METADATA_KEY_COMPOSER] = composer
-
- # 作者
- writer = tags.get("writer") or tags.get("WRITER")
- if writer:
- md[MediaMetadataRetriever.METADATA_KEY_WRITER] = writer
-
- # 流派
- genre = tags.get("genre") or tags.get("GENRE")
- if genre:
- md[MediaMetadataRetriever.METADATA_KEY_GENRE] = genre
-
- # 日期 / 年份
- date = tags.get("date") or tags.get("DATE") or tags.get("year")
- if date:
- md[MediaMetadataRetriever.METADATA_KEY_DATE] = str(date)
- # 尝试提取年份
- year_str = str(date)[:4]
- if year_str.isdigit():
- md[MediaMetadataRetriever.METADATA_KEY_YEAR] = year_str
-
- # 音轨号
- track = tags.get("track") or tags.get("TRACK")
- if track:
- md[MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER] = str(track)
-
- # 位置
- location = tags.get("location") or tags.get("LOCATION")
- if location:
- md[MediaMetadataRetriever.METADATA_KEY_LOCATION] = str(location)
-
- # MIME 类型
- format_name = fmt.get("format_name", "")
- if format_name:
- mime = MediaMetadataRetriever._MIME_MAP.get(
- format_name, f"video/{format_name.split(',')[0]}")
- md[MediaMetadataRetriever.METADATA_KEY_MIMETYPE] = mime
-
- # 轨道数
- if streams:
- md[MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS] = str(len(streams))
-
- # 比特率
- bit_rate = fmt.get("bit_rate")
- if bit_rate:
- md[MediaMetadataRetriever.METADATA_KEY_BITRATE] = str(bit_rate)
-
- # 视频信息
- if video_stream:
- w = video_stream.get("width", 0)
- h = video_stream.get("height", 0)
- if w:
- md[MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH] = str(w)
- if h:
- md[MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT] = str(h)
- md[MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO] = "yes"
- else:
- md[MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO] = "no"
-
- # 音频信息
- if audio_stream:
- md[MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO] = "yes"
- else:
- md[MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO] = "no"
-
- def extractMetadata(self, keyCode: str) -> Optional[str]:
- return self._metadata.get(keyCode)
-
- def getEmbeddedPicture(self) -> Optional[bytes]:
- """用 ffmpeg 提取嵌入的封面图片,返回原始字节数据。
- 失败返回 None。"""
- if not self._resolved_path or not os.path.exists(self._resolved_path):
- return None
- try:
- return _ffmpeg_extract_cover(self._resolved_path)
- except Exception:
- return None
-
- def getFrameAtTime(self, timeUs: int = -1, option: int = 0) -> Optional["Bitmap"]:
- """用 ffmpeg 提取指定时间点的视频帧,返回 Bitmap(内含 PIL Image)。
- timeUs < 0 表示提取第一帧。失败返回 None。"""
- if not self._resolved_path or not os.path.exists(self._resolved_path):
- return None
- try:
- img = _ffmpeg_extract_frame(self._resolved_path, timeUs)
- if img is not None:
- from .graphics import Bitmap
- w, h = img.size
- bm = Bitmap(w, h, Bitmap.Config.ARGB_8888)
- # 确保 RGBA 模式
- if img.mode != "RGBA":
- img = img.convert("RGBA")
- bm._image = img
- return bm
- except Exception:
- pass
- return None
-
- def getScaledFrameAtTime(self, timeUs: int, option: int,
- width: int, height: int) -> Optional["Bitmap"]:
- """用 ffmpeg 提取并缩放指定时间点的视频帧。"""
- if not self._resolved_path or not os.path.exists(self._resolved_path):
- return None
- try:
- img = _ffmpeg_extract_frame(self._resolved_path, timeUs, width, height)
- if img is not None:
- from .graphics import Bitmap
- bm = Bitmap(width, height, Bitmap.Config.ARGB_8888)
- if img.mode != "RGBA":
- img = img.convert("RGBA")
- bm._image = img
- return bm
- except Exception:
- pass
- return None
-
- def release(self):
- self._metadata.clear()
- self._resolved_path = None
- self._ffprobe_data = None
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaCodec
-# ═══════════════════════════════════════════════════════════════
-
-class MediaCodec(Stub):
- """MediaCodec — 媒体编解码器"""
-
- BUFFER_FLAG_KEY_FRAME = 1
- BUFFER_FLAG_CODEC_CONFIG = 2
- BUFFER_FLAG_END_OF_STREAM = 4
- BUFFER_FLAG_PARTIAL_FRAME = 8
- BUFFER_FLAG_MUXER_DATA = 16
-
- CONFIGURE_FLAG_ENCODE = 1
- CONFIGURE_FLAG_DECODE = 0
-
- CRYPTO_MODE_UNENCRYPTED = 0
- CRYPTO_MODE_AES_CTR = 1
- CRYPTO_MODE_AES_WV = 2
- CRYPTO_MODE_AES_CBC = 3
-
- INFO_TRY_AGAIN_LATER = -1
- INFO_OUTPUT_FORMAT_CHANGED = -2
- INFO_OUTPUT_BUFFERS_CHANGED = -3
-
- MEDIA_CODEC_UNKNOWN = 0
- MEDIA_CODEC_DECODER = 1
- MEDIA_CODEC_ENCODER = 2
-
- PARAMETER_KEY_SUSPEND = "suspend"
- PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate"
- PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync"
- PARAMETER_KEY_DROP_BEFORE = "drop-before"
- PARAMETER_KEY_DROP_AFTER = "drop-after"
- PARAMETER_KEY_OFFSET_TIME = "offset-time"
- PARAMETER_KEY_PRIORITY = "priority"
- PARAMETER_KEY_OPERATING_RATE = "operating-rate"
- PARAMETER_KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period"
- PARAMETER_KEY_LOW_LATENCY = "low-latency"
-
- def __init__(self, name: str):
- super().__init__()
- self._name = name
- self._configured = False
- self._started = False
- self._format = MediaFormat()
-
- @staticmethod
- def createDecoderByType(mimeType: str) -> "MediaCodec":
- return MediaCodec(f"decoder.{mimeType}")
-
- @staticmethod
- def createEncoderByType(mimeType: str) -> "MediaCodec":
- return MediaCodec(f"encoder.{mimeType}")
-
- def configure(self, format: "MediaFormat", surface, crypto, flags: int):
- self._format = format
- self._configured = True
-
- def start(self):
- self._started = True
-
- def stop(self):
- self._started = False
-
- def flush(self):
- pass
-
- def release(self):
- self._started = False
- self._configured = False
-
- def getInputBuffers(self) -> List[Any]:
- return [bytearray(4096)]
-
- def getOutputBuffers(self) -> List[Any]:
- return [bytearray(4096)]
-
- def dequeueInputBuffer(self, timeoutUs: int) -> int:
- return 0
-
- def queueInputBuffer(self, index: int, offset: int, size: int,
- presentationTimeUs: int, flags: int):
- pass
-
- def dequeueOutputBuffer(self, info: "MediaCodec.BufferInfo", timeoutUs: int) -> int:
- return MediaCodec.INFO_TRY_AGAIN_LATER
-
- def releaseOutputBuffer(self, index: int, render: bool):
- pass
-
- def getOutputFormat(self) -> "MediaFormat":
- return self._format
-
- def getInputImage(self, index: int):
- return None
-
- def getOutputImage(self, index: int):
- return None
-
- def getName(self) -> str:
- return self._name
-
- def getCodecInfo(self):
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaCodecBufferInfo (nested class reference)
-# ═══════════════════════════════════════════════════════════════
-
-class MediaCodecBufferInfo(Stub):
- """MediaCodec.BufferInfo — 编解码器缓冲信息"""
-
- def __init__(self):
- super().__init__()
- self.offset = 0
- self.size = 0
- self.presentationTimeUs = 0
- self.flags = 0
-
- def set(self, offset: int, size: int, presentationTimeUs: int, flags: int):
- self.offset = offset
- self.size = size
- self.presentationTimeUs = presentationTimeUs
- self.flags = flags
-
- def duplicate(self) -> "MediaCodecBufferInfo":
- info = MediaCodecBufferInfo()
- info.set(self.offset, self.size, self.presentationTimeUs, self.flags)
- return info
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaFormat
-# ═══════════════════════════════════════════════════════════════
-
-class MediaFormat(Stub):
- """MediaFormat — 媒体格式"""
-
- KEY_MIME = "mime"
- KEY_WIDTH = "width"
- KEY_HEIGHT = "height"
- KEY_FRAME_RATE = "frame-rate"
- KEY_BIT_RATE = "bitrate"
- KEY_COLOR_FORMAT = "color-format"
- KEY_I_FRAME_INTERVAL = "i-frame-interval"
- KEY_CHANNEL_COUNT = "channel-count"
- KEY_SAMPLE_RATE = "sample-rate"
- KEY_DURATION = "durationUs"
- KEY_MAX_INPUT_SIZE = "max-input-size"
- KEY_AAC_PROFILE = "aac-profile"
- KEY_LEVEL = "level"
- KEY_PROFILE = "profile"
- KEY_LANGUAGE = "language"
- KEY_IS_AUTOSELECT = "is-autoselect"
- KEY_IS_DEFAULT = "is-default"
- KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle"
- KEY_PIXEL_ASPECT_RATIO_WIDTH = "pixel-aspect-ratio-width"
- KEY_PIXEL_ASPECT_RATIO_HEIGHT = "pixel-aspect-ratio-height"
- KEY_SLICE_HEIGHT = "slice-height"
- KEY_STRIDE = "stride"
- KEY_TEMPORAL_LAYERING = "temporal-layering"
- KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after"
- KEY_PRIORITY = "priority"
- KEY_OPERATING_RATE = "operating-rate"
- KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period"
- KEY_LATENCY = "latency"
- KEY_MAX_B_FRAMES = "max-bframes"
- KEY_HDR10_PLUS_INFO = "hdr10-plus-info"
-
- MIMETYPE_AUDIO_AAC = "audio/mp4a-latm"
- MIMETYPE_AUDIO_AMR_NB = "audio/3gpp"
- MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb"
- MIMETYPE_AUDIO_FLAC = "audio/flac"
- MIMETYPE_AUDIO_MPEG = "audio/mpeg"
- MIMETYPE_AUDIO_OPUS = "audio/opus"
- MIMETYPE_AUDIO_RAW = "audio/raw"
- MIMETYPE_AUDIO_VORBIS = "audio/vorbis"
- MIMETYPE_VIDEO_AV1 = "video/av01"
- MIMETYPE_VIDEO_AVC = "video/avc"
- MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision"
- MIMETYPE_VIDEO_H263 = "video/3gpp"
- MIMETYPE_VIDEO_HEVC = "video/hevc"
- MIMETYPE_VIDEO_MPEG2 = "video/mpeg2"
- MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es"
- MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8"
- MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9"
- MIMETYPE_VIDEO_RAW = "video/raw"
- MIMETYPE_TEXT_CEA_608 = "text/cea-608"
- MIMETYPE_TEXT_CEA_708 = "text/cea-708"
- MIMETYPE_TEXT_VTT = "text/vtt"
- MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic"
-
- def __init__(self):
- super().__init__()
- self._properties: Dict[str, Any] = {}
-
- def setString(self, key: str, value: str):
- self._properties[key] = value
-
- def setInteger(self, key: str, value: int):
- self._properties[key] = value
-
- def setFloat(self, key: str, value: float):
- self._properties[key] = value
-
- def setByteBuffer(self, key: str, buf):
- self._properties[key] = buf
-
- def setFeatureEnabled(self, feature: str, enabled: bool):
- self._properties[feature] = enabled
-
- def getString(self, key: str) -> Optional[str]:
- v = self._properties.get(key)
- return str(v) if v is not None else None
-
- def getInteger(self, key: str, defaultValue: int = 0) -> int:
- v = self._properties.get(key)
- return int(v) if v is not None else defaultValue
-
- def getFloat(self, key: str, defaultValue: float = 0.0) -> float:
- v = self._properties.get(key)
- return float(v) if v is not None else defaultValue
-
- def getByteBuffer(self, key: str):
- return self._properties.get(key)
-
- def containsKey(self, key: str) -> bool:
- return key in self._properties
-
- def keys(self) -> List[str]:
- return list(self._properties.keys())
-
- @staticmethod
- def createVideoFormat(mime: str, width: int, height: int) -> "MediaFormat":
- fmt = MediaFormat()
- fmt.setString(MediaFormat.KEY_MIME, mime)
- fmt.setInteger(MediaFormat.KEY_WIDTH, width)
- fmt.setInteger(MediaFormat.KEY_HEIGHT, height)
- return fmt
-
- @staticmethod
- def createAudioFormat(mime: str, sampleRate: int, channelCount: int) -> "MediaFormat":
- fmt = MediaFormat()
- fmt.setString(MediaFormat.KEY_MIME, mime)
- fmt.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate)
- fmt.setInteger(MediaFormat.KEY_CHANNEL_COUNT, channelCount)
- return fmt
-
- @staticmethod
- def createSubtitleFormat(mime: str, language: str) -> "MediaFormat":
- fmt = MediaFormat()
- fmt.setString(MediaFormat.KEY_MIME, mime)
- fmt.setString(MediaFormat.KEY_LANGUAGE, language)
- return fmt
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaMuxer
-# ═══════════════════════════════════════════════════════════════
-
-class MediaMuxer(Stub):
- """MediaMuxer — 媒体混合器"""
-
- OUTPUT_FORMAT_MPEG_4 = 0
- OUTPUT_FORMAT_WEBM = 1
- OUTPUT_FORMAT_THREE_GPP = 2
- OUTPUT_FORMAT_HEIF = 3
- OUTPUT_FORMAT_OGG = 4
-
- def __init__(self, path: str, format: int):
- super().__init__()
- self._path = path
- self._format = format
- self._started = False
- self._tracks: Dict[int, MediaFormat] = {}
- self._next_track = 0
-
- def addTrack(self, format: MediaFormat) -> int:
- idx = self._next_track
- self._next_track += 1
- self._tracks[idx] = format
- return idx
-
- def start(self):
- self._started = True
-
- def stop(self):
- self._started = False
-
- def release(self):
- self._started = False
- self._tracks.clear()
-
- def writeSampleData(self, trackIndex: int, byteBuf, bufferInfo: MediaCodecBufferInfo):
- pass
-
- def setOrientationHint(self, degrees: int):
- pass
-
- def setLocation(self, latitude: float, longitude: float):
- pass
-
- def getTrackFormat(self, index: int) -> Optional[MediaFormat]:
- return self._tracks.get(index)
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaExtractor
-# ═══════════════════════════════════════════════════════════════
-
-class MediaExtractor(Stub):
- """MediaExtractor — 媒体提取器"""
-
- SEEK_TO_NEXT_SYNC = 0
- SEEK_TO_PREVIOUS_SYNC = 1
- SEEK_TO_CLOSEST_SYNC = 2
- SEEK_TO_CLOSEST_SYNC = 2
- SAMPLE_FLAG_SYNC = 1
- SAMPLE_FLAG_ENCRYPTED = 2
-
- def __init__(self):
- super().__init__()
- self._tracks: List[MediaFormat] = []
- self._selected_tracks: Set[int] = set()
- self._current_track = 0
-
- def setDataSource(self, path: str):
- pass
-
- def setDataSource(self, context, uri, headers: Dict[str, str] = None):
- pass
-
- def getTrackCount(self) -> int:
- return len(self._tracks)
-
- def getTrackFormat(self, index: int) -> Optional[MediaFormat]:
- if 0 <= index < len(self._tracks):
- return self._tracks[index]
- return None
-
- def selectTrack(self, index: int):
- self._selected_tracks.add(index)
-
- def unselectTrack(self, index: int):
- self._selected_tracks.discard(index)
-
- def readSampleData(self, byteBuf, offset: int) -> int:
- return 0
-
- def getSampleTrackIndex(self) -> int:
- return 0
-
- def getSampleTime(self) -> int:
- return 0
-
- def advance(self) -> bool:
- return False
-
- def release(self):
- self._tracks.clear()
- self._selected_tracks.clear()
-
- def seekTo(self, timeUs: int, mode: int):
- pass
-
- def getSampleFlags(self) -> int:
- return 0
-
- def getCachedDuration(self) -> int:
- return 0
-
- def hasCachedReachedEndOfStream(self) -> bool:
- return False
-
- def getSampleSize(self) -> int:
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# FaceDetector / FaceDetectorFace
-# ═══════════════════════════════════════════════════════════════
-
-class FaceDetectorFace(Stub):
- """FaceDetector.Face — 检测到的人脸"""
-
- CONFIDENCE_THRESHOLD = 0.4
- EULER_X = 0
- EULER_Y = 1
- EULER_Z = 2
-
- def __init__(self):
- super().__init__()
- self._confidence = 0.0
- self._mid_point_x = 0.0
- self._mid_point_y = 0.0
- self._eyes_distance = 0.0
- self._pose_euler_x = 0.0
- self._pose_euler_y = 0.0
- self._pose_euler_z = 0.0
-
- def confidence(self) -> float:
- return self._confidence
-
- def getMidPoint(self, point: PointF):
- point.set(self._mid_point_x, self._mid_point_y)
-
- def eyesDistance(self) -> float:
- return self._eyes_distance
-
- def pose(self, euler: int) -> float:
- if euler == FaceDetectorFace.EULER_X:
- return self._pose_euler_x
- elif euler == FaceDetectorFace.EULER_Y:
- return self._pose_euler_y
- elif euler == FaceDetectorFace.EULER_Z:
- return self._pose_euler_z
- return 0.0
-
-
-class FaceDetector(Stub):
- """FaceDetector — 人脸检测器"""
-
- def __init__(self, width: int, height: int, maxFaces: int):
- super().__init__()
- self._width = width
- self._height = height
- self._max_faces = maxFaces
-
- def findFaces(self, bitmap: "Bitmap", faces: List[FaceDetectorFace]) -> int:
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# ThumbnailUtils
-# ═══════════════════════════════════════════════════════════════
-
-class ThumbnailUtils(Stub):
- """ThumbnailUtils — 缩略图工具"""
-
- OPTIONS_RECYCLE_INPUT = 256
-
- @staticmethod
- def createVideoThumbnail(filePath: str, kind: int) -> Optional["Bitmap"]:
- if HAS_PIL:
- from PIL import Image
- from .graphics import Bitmap
- img = Image.new("RGB", (320, 240), (32, 32, 32))
- bm = Bitmap(320, 240, Bitmap.Config.ARGB_8888)
- bm._image = img
- return bm
- return None
-
- @staticmethod
- def createImageThumbnail(filePath: str, kind: int) -> Optional["Bitmap"]:
- resolved = resolve_android_path(filePath)
- if not os.path.exists(resolved):
- return None
- if HAS_PIL:
- from PIL import Image
- from .graphics import Bitmap
- img = Image.open(resolved)
- img.thumbnail((320, 240), Image.LANCZOS)
- bm = Bitmap(img.width, img.height, Bitmap.Config.ARGB_8888)
- if img.mode != "RGBA":
- img = img.convert("RGBA")
- bm._image = img
- return bm
- return None
-
- @staticmethod
- def extractThumbnail(source: "Bitmap", width: int, height: int,
- options: int = 0) -> Optional["Bitmap"]:
- if HAS_PIL and hasattr(source, "_image") and source._image:
- from PIL import Image
- img = source._image.copy()
- img.thumbnail((width, height), Image.LANCZOS)
- bm = Bitmap(img.width, img.height, source._config)
- bm._image = img
- if options & ThumbnailUtils.OPTIONS_RECYCLE_INPUT:
- source.recycle()
- return bm
- return Bitmap.createScaledBitmap(source, width, height)
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaScannerConnection / MediaScannerConnectionClient
-# ═══════════════════════════════════════════════════════════════
-
-class MediaScannerConnectionClient(Stub):
- """MediaScannerConnection.MediaScannerConnectionClient — 扫描客户端接口"""
-
- def onMediaScannerConnected(self):
- pass
-
- def onScanCompleted(self, path: str, uri):
- pass
-
-
-class MediaScannerConnection(Stub):
- """MediaScannerConnection — 媒体扫描连接"""
-
- def __init__(self, context, client: MediaScannerConnectionClient = None):
- super().__init__()
- self._client = client
- self._connected = False
-
- def connect(self):
- self._connected = True
- if self._client:
- self._client.onMediaScannerConnected()
-
- def disconnect(self):
- self._connected = False
-
- def isConnected(self) -> bool:
- return self._connected
-
- def scanFile(self, path: str, mimeType: str):
- if self._client:
- self._client.onScanCompleted(path, None)
-
- @staticmethod
- def scanFile(context, paths: List[str], mimeTypes: List[str],
- callback: MediaScannerConnectionClient):
- for path in paths:
- if callback:
- callback.onScanCompleted(path, None)
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaActionSound
-# ═══════════════════════════════════════════════════════════════
-
-class MediaActionSound(Stub):
- """MediaActionSound — 媒体操作音效"""
-
- SHUTTER_CLICK = 0
- FOCUS_COMPLETE = 1
- START_VIDEO_RECORDING = 2
- STOP_VIDEO_RECORDING = 3
-
- def __init__(self):
- super().__init__()
-
- def play(self, soundName: int):
- pass
-
- def load(self, soundName: int):
- pass
-
- def release(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ToneGenerator
-# ═══════════════════════════════════════════════════════════════
-
-class ToneGenerator(Stub):
- """ToneGenerator — 音调发生器"""
-
- TONE_DTMF_0 = 0
- TONE_DTMF_1 = 1
- TONE_DTMF_2 = 2
- TONE_DTMF_3 = 3
- TONE_DTMF_4 = 4
- TONE_DTMF_5 = 5
- TONE_DTMF_6 = 6
- TONE_DTMF_7 = 7
- TONE_DTMF_8 = 8
- TONE_DTMF_9 = 9
- TONE_DTMF_S = 10
- TONE_DTMF_P = 11
- TONE_DTMF_A = 12
- TONE_DTMF_B = 13
- TONE_DTMF_C = 14
- TONE_DTMF_D = 15
- TONE_SUP_CALL_WAITING = 16
- TONE_SUP_RINGTONE = 17
- TONE_PROP_BEEP = 24
- TONE_PROP_ACK = 25
- TONE_PROP_NACK = 26
- TONE_PROP_PROMPT = 27
- TONE_PROP_BEEP2 = 28
- TONE_SUP_INTERCEPT = 29
- TONE_SUP_INTERCEPT_ABBREV = 30
- TONE_SUP_CONGESTION = 31
- TONE_SUP_CONGESTION_ABBREV = 32
- TONE_SUP_CONFIRM = 33
- TONE_SUP_RADIO_ACK = 34
- TONE_SUP_RADIO_NOTAVAIL = 35
- TONE_SUP_ERROR = 36
- TONE_SUP_CALL_WAITING = 37
- TONE_SUP_RINGTONE = 38
- TONE_PROP_BEEP = 39
- TONE_PROP_ACK = 40
- TONE_PROP_NACK = 41
- TONE_PROP_PROMPT = 42
- TONE_PROP_BEEP2 = 43
- TONE_SUP_INTERCEPT = 44
- TONE_PROP_END_EMERGENCY = 45
- TONE_CDMA_PRESSHOLDKEY_LITE = 46
- TONE_CDMA_ALERT_SIGNAL_RELEASE = 47
- TONE_CDMA_NETWORK_USA_RINGBACK = 48
- TONE_CDMA_INTERCEPT = 49
- TONE_CDMA_ABBR_INTERCEPT = 50
- TONE_CDMA_REORDER = 51
- TONE_CDMA_ABBR_REORDER = 52
- TONE_CDMA_NETWORK_BUSY = 53
- TONE_CDMA_CONFIRM = 54
- TONE_CDMA_ANSWER = 55
- TONE_CDMA_NETWORK_CALLWAITING = 56
- TONE_CDMA_PRESSHOLDKEY_LITE = 57
- TONE_CDMA_ONE_MIN_BEEP = 58
- TONE_CDMA_SIGNAL_OFF = 59
- TONE_CDMA_SIGNAL_ON = 60
- TONE_CDMA_HIGH_LITE = 61
- TONE_CDMA_MED_LITE = 62
- TONE_CDMA_LOW_LITE = 63
- TONE_CDMA_LOW_PBX_LITE = 64
- TONE_CDMA_HIGH_PBX_LITE = 65
- TONE_CDMA_MED_PBX_LITE = 66
- TONE_CDMA_PBX_OFF = 67
- TONE_CDMA_PBX_ON = 68
- TONE_CDMA_ALERT_CALL_GUARD = 69
- TONE_CDMA_SOFT_ERROR_LITE = 70
- TONE_CDMA_ABBR_ALERT = 71
- TONE_CDMA_NETWORK_BUSY_ONE_SHOT = 72
- TONE_CDMA_NETWORK_BUSY = 73
- TONE_CDMA_NETWORK_BUSY_ONE_SHOT = 74
- TONE_CDMA_ABBR_ALERT = 75
- TONE_CDMA_SOFT_ERROR_LITE = 76
- TONE_CDMA_ALERT_CALL_GUARD = 77
- TONE_CDMA_LOW_PBX_LITE = 78
- TONE_CDMA_MED_PBX_LITE = 79
- TONE_CDMA_HIGH_PBX_LITE = 80
- TONE_CDMA_PBX_OFF = 81
- TONE_CDMA_PBX_ON = 82
- TONE_CDMA_PRESSHOLDKEY_LITE = 83
- TONE_CDMA_ONE_MIN_BEEP = 84
- TONE_CDMA_SIGNAL_OFF = 85
- TONE_CDMA_SIGNAL_ON = 86
- TONE_CDMA_HIGH_LITE = 87
- TONE_CDMA_MED_LITE = 88
- TONE_CDMA_LOW_LITE = 89
- TONE_CDMA_ALERT_AUTO_REDIAL = 90
- TONE_CDMA_ALERT_CALL_GUARD = 91
- TONE_PROP_BEEP = 92
- TONE_PROP_ACK = 93
- TONE_PROP_NACK = 94
- TONE_PROP_PROMPT = 95
- TONE_PROP_BEEP2 = 96
- TONE_SUP_INTERCEPT = 97
- TONE_SUP_INTERCEPT_ABBREV = 98
- TONE_SUP_CONGESTION = 99
- TONE_SUP_CONGESTION_ABBREV = 100
- TONE_SUP_CONFIRM = 101
- TONE_SUP_RADIO_ACK = 102
- TONE_SUP_RADIO_NOTAVAIL = 103
- TONE_SUP_ERROR = 104
- TONE_SUP_CALL_WAITING = 105
- TONE_SUP_RINGTONE = 106
-
- MIN_VOLUME = 0
- MAX_VOLUME = 100
-
- def __init__(self, streamType: int, volume: int):
- super().__init__()
- self._stream_type = streamType
- self._volume = max(0, min(100, volume))
-
- def startTone(self, toneType: int, durationMs: int = -1):
- pass
-
- def stopTone(self):
- pass
-
- def release(self):
- pass
-
- def getAudioSessionId(self) -> int:
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# ExifInterface
-# ═══════════════════════════════════════════════════════════════
-
-class ExifInterface(Stub):
- """ExifInterface — EXIF 接口"""
-
- TAG_APERTURE = "FNumber"
- TAG_DATETIME = "DateTime"
- TAG_EXPOSURE_TIME = "ExposureTime"
- TAG_FLASH = "Flash"
- TAG_FOCAL_LENGTH = "FocalLength"
- TAG_GPS_ALTITUDE = "GPSAltitude"
- TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef"
- TAG_GPS_DATESTAMP = "GPSDateStamp"
- TAG_GPS_LATITUDE = "GPSLatitude"
- TAG_GPS_LATITUDE_REF = "GPSLatitudeRef"
- TAG_GPS_LONGITUDE = "GPSLongitude"
- TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef"
- TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod"
- TAG_GPS_TIMESTAMP = "GPSTimeStamp"
- TAG_IMAGE_LENGTH = "ImageLength"
- TAG_IMAGE_WIDTH = "ImageWidth"
- TAG_ISO = "ISOSpeedRatings"
- TAG_MAKE = "Make"
- TAG_MODEL = "Model"
- TAG_ORIENTATION = "Orientation"
- TAG_WHITE_BALANCE = "WhiteBalance"
-
- ORIENTATION_NORMAL = 1
- ORIENTATION_ROTATE_90 = 6
- ORIENTATION_ROTATE_180 = 3
- ORIENTATION_ROTATE_270 = 8
- ORIENTATION_FLIP_HORIZONTAL = 2
- ORIENTATION_FLIP_VERTICAL = 4
- ORIENTATION_TRANSPOSE = 5
- ORIENTATION_TRANSVERSE = 7
- ORIENTATION_UNDEFINED = 0
-
- WHITEBALANCE_AUTO = 0
- WHITEBALANCE_MANUAL = 1
-
- FLAG_NO_FLASH = 0
- FLAG_FIRED = 1
- FLAG_STROBE_RETURN_LIGHT_DETECTED = 2
- FLAG_STROBE_RETURN_LIGHT_NOT_DETECTED = 4
- FLAG_COMPULSORY_FIRE = 8
- FLAG_COMPULSORY_SUPPRESSION = 16
- FLAG_AUTO_MODE = 24
- FLAG_AUTO_MODE_RED_EYE = 25
- FLAG_NO_STROBE_FUNCTION = 32
- FLAG_RED_EYE_SUPPORT = 64
-
- def __init__(self, filename: str):
- super().__init__()
- self._filename = resolve_android_path(filename)
- self._attributes: Dict[str, str] = {}
- self._pil_image = None
- self._load_exif()
-
- def _load_exif(self):
- """尝试从文件中读取 EXIF 数据"""
- if not self._filename or not os.path.exists(self._filename):
- return
- if HAS_PIL:
- from PIL import Image
- from PIL import ExifTags
- try:
- img = Image.open(self._filename)
- self._pil_image = img
- exif_data = img._getexif()
- if exif_data:
- for tag_id, value in exif_data.items():
- tag_name = ExifTags.TAGS.get(tag_id, str(tag_id))
- self._attributes[str(tag_name)] = str(value)
- except Exception:
- self._attributes[self.TAG_MAKE] = "Unknown"
- self._attributes[self.TAG_MODEL] = "Android Device"
- self._attributes[self.TAG_ORIENTATION] = str(self.ORIENTATION_NORMAL)
- self._attributes[self.TAG_IMAGE_WIDTH] = "1920"
- self._attributes[self.TAG_IMAGE_LENGTH] = "1080"
- else:
- self._attributes[self.TAG_MAKE] = "Unknown"
- self._attributes[self.TAG_MODEL] = "Android Device"
- self._attributes[self.TAG_ORIENTATION] = str(self.ORIENTATION_NORMAL)
-
- def getAttribute(self, tag: str) -> Optional[str]:
- return self._attributes.get(tag)
-
- def getAttributeInt(self, tag: str, defaultValue: int) -> int:
- v = self._attributes.get(tag)
- if v is not None:
- try:
- return int(v)
- except (ValueError, TypeError):
- return defaultValue
- return defaultValue
-
- def getAttributeDouble(self, tag: str, defaultValue: float) -> float:
- v = self._attributes.get(tag)
- if v is not None:
- try:
- # Handle rational strings like "1/100"
- if "/" in str(v):
- num, den = str(v).split("/")
- return float(num) / float(den)
- return float(v)
- except (ValueError, TypeError, ZeroDivisionError):
- return defaultValue
- return defaultValue
-
- def setAttribute(self, tag: str, value: str):
- self._attributes[tag] = value
-
- def saveAttributes(self):
- if not self._filename or not HAS_PIL:
- return
- from PIL import Image
- try:
- img = Image.open(self._filename)
- exif_bytes = img.info.get("exif", b"")
- img.save(self._filename, exif=exif_bytes)
- except Exception:
- pass
-
- def hasThumbnail(self) -> bool:
- return False
-
- def getThumbnail(self) -> Optional[bytes]:
- return None
-
- def getThumbnailRange(self) -> Optional[Tuple[int, int]]:
- return None
-
- def getAttributeRange(self, tag: str) -> Optional[Tuple[int, int]]:
- return None
-
- def setIsUri(self, isUri: bool):
- pass
-
- def flipHorizontally(self):
- if hasattr(self, '_pil_image') and self._pil_image:
- from PIL import Image
- self._pil_image = self._pil_image.transpose(Image.FLIP_LEFT_RIGHT)
- self._save_from_pil()
-
- def flipVertically(self):
- if hasattr(self, '_pil_image') and self._pil_image:
- from PIL import Image
- self._pil_image = self._pil_image.transpose(Image.FLIP_TOP_BOTTOM)
- self._save_from_pil()
-
- def rotate(self, degrees):
- if hasattr(self, '_pil_image') and self._pil_image:
- from PIL import Image
- self._pil_image = self._pil_image.rotate(degrees, expand=True)
- self._save_from_pil()
- # 更新方向属性
- self.setAttribute("Orientation", "1") # Normal after rotation
-
- def _save_from_pil(self):
- """从 PIL 图像保存回文件"""
- if hasattr(self, '_pil_image') and self._pil_image and hasattr(self, '_filename'):
- self._pil_image.save(self._filename)
-
-
-# ═══════════════════════════════════════════════════════════════
-# CamcorderProfile
-# ═══════════════════════════════════════════════════════════════
-
-class CamcorderProfile(Stub):
- """CamcorderProfile — 摄像机配置"""
-
- QUALITY_LOW = 0
- QUALITY_HIGH = 1
- QUALITY_QCIF = 2
- QUALITY_CIF = 3
- QUALITY_480P = 4
- QUALITY_720P = 5
- QUALITY_1080P = 6
- QUALITY_QVGA = 7
- QUALITY_2160P = 8
- QUALITY_VGA = 9
- QUALITY_4KDCI = 10
- QUALITY_QHD = 11
- QUALITY_2K = 12
-
- def __init__(self):
- super().__init__()
- self.quality = CamcorderProfile.QUALITY_HIGH
- self.fileFormat = MediaRecorder.OutputFormat.MPEG_4
- self.duration = 30
- self.videoCodec = MediaRecorder.VideoEncoder.H_264
- self.videoBitRate = 20000000
- self.videoFrameRate = 30
- self.videoFrameWidth = 1920
- self.videoFrameHeight = 1080
- self.audioCodec = MediaRecorder.AudioEncoder.AAC
- self.audioBitRate = 192000
- self.audioSampleRate = 44100
- self.audioChannels = 2
-
- @staticmethod
- def get(cameraId: int, quality: int) -> Optional["CamcorderProfile"]:
- if quality in (CamcorderProfile.QUALITY_LOW, CamcorderProfile.QUALITY_HIGH):
- profile = CamcorderProfile()
- profile.quality = quality
- if quality == CamcorderProfile.QUALITY_LOW:
- profile.videoFrameWidth = 640
- profile.videoFrameHeight = 480
- profile.videoBitRate = 500000
- profile.audioBitRate = 96000
- return profile
- return None
-
- @staticmethod
- def hasProfile(cameraId: int, quality: int) -> bool:
- return True
-
- @staticmethod
- def getAll(cameraId: int) -> List[int]:
- return [
- CamcorderProfile.QUALITY_LOW,
- CamcorderProfile.QUALITY_HIGH,
- CamcorderProfile.QUALITY_480P,
- CamcorderProfile.QUALITY_720P,
- CamcorderProfile.QUALITY_1080P,
- ]
-
-
-# ═══════════════════════════════════════════════════════════════
-# EncoderProfiles
-# ═══════════════════════════════════════════════════════════════
-
-class EncoderProfiles(Stub):
- """EncoderProfiles — 编码器配置 (API 31+)"""
-
- class VideoProfile(Stub):
- def __init__(self):
- super().__init__()
- self.codec = ""
- self.bitrate = 0
- self.width = 0
- self.height = 0
- self.frameRate = 0
- self.profile = 0
- self.bitDepth = 8
- self.chromaSubsampling = 420
- self.hdrFormat = 0
-
- class AudioProfile(Stub):
- def __init__(self):
- super().__init__()
- self.codec = ""
- self.bitrate = 0
- self.sampleRate = 0
- self.channels = 0
- self.profile = 0
-
- def __init__(self):
- super().__init__()
- self._default_duration = 30
- self._recommended_file_format = MediaRecorder.OutputFormat.MPEG_4
- self._video_profiles: List[EncoderProfiles.VideoProfile] = []
- self._audio_profiles: List[EncoderProfiles.AudioProfile] = []
-
- def getDefaultDuration(self) -> int:
- return self._default_duration
-
- def getRecommendedFileFormat(self) -> int:
- return self._recommended_file_format
-
- def getVideoProfiles(self) -> List["VideoProfile"]:
- return list(self._video_profiles)
-
- def getAudioProfiles(self) -> List["AudioProfile"]:
- return list(self._audio_profiles)
-
- @staticmethod
- def get(cameraId: int, quality: int) -> Optional["EncoderProfiles"]:
- profiles = EncoderProfiles()
-
- vp = EncoderProfiles.VideoProfile()
- vp.codec = MediaFormat.MIMETYPE_VIDEO_AVC
- vp.bitrate = 20000000
- vp.width = 1920
- vp.height = 1080
- vp.frameRate = 30
- vp.profile = 8 # High Profile
- profiles._video_profiles.append(vp)
-
- ap = EncoderProfiles.AudioProfile()
- ap.codec = MediaFormat.MIMETYPE_AUDIO_AAC
- ap.bitrate = 192000
- ap.sampleRate = 44100
- ap.channels = 2
- ap.profile = 2 # AAC LC
- profiles._audio_profiles.append(ap)
-
- return profiles
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "MediaPlayer",
- "MediaRecorder",
- "SoundPool",
- "AudioManager",
- "AudioTrack",
- "AudioRecord",
- "Ringtone",
- "RingtoneManager",
- "MediaMetadataRetriever",
- "MediaCodec",
- "MediaCodecBufferInfo",
- "MediaFormat",
- "MediaMuxer",
- "MediaExtractor",
- "FaceDetector",
- "FaceDetectorFace",
- "ThumbnailUtils",
- "MediaScannerConnection",
- "MediaScannerConnectionClient",
- "AudioAttributes",
- "AudioFormat",
- "MediaActionSound",
- "ToneGenerator",
- "ExifInterface",
- "CamcorderProfile",
- "EncoderProfiles",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/media_async.py b/android_pyapi/android/media_async.py
deleted file mode 100644
index 6a6028d..0000000
--- a/android_pyapi/android/media_async.py
+++ /dev/null
@@ -1,1621 +0,0 @@
-"""
-Android media 异步组件 — MediaCodec, MediaExtractor, MediaMuxer, MediaPlayer 扩展等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import io
-import math
-import time
-import struct
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-from enum import IntEnum
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaCodec 常量
-# ═══════════════════════════════════════════════════════════════
-
-BUFFER_FLAG_KEY_FRAME = 1
-BUFFER_FLAG_CODEC_CONFIG = 2
-BUFFER_FLAG_END_OF_STREAM = 4
-BUFFER_FLAG_PARTIAL_FRAME = 8
-BUFFER_FLAG_SYNC_FRAME = 1
-
-CRYPTO_MODE_UNENCRYPTED = 0
-CRYPTO_MODE_AES_CTR = 1
-CRYPTO_MODE_AES_WV = 2
-CRYPTO_MODE_AES_CBC = 3
-
-INFO_TRY_AGAIN_LATER = -1
-INFO_OUTPUT_FORMAT_CHANGED = -2
-INFO_OUTPUT_BUFFERS_CHANGED = -3
-
-MEDIA_CODEC_UNKNOWN = 0
-MEDIA_CODEC_DECODER = 1
-MEDIA_CODEC_ENCODER = 2
-
-COLOR_FormatUnsupported = 0x7FFFFFFF
-COLOR_FormatYUV420Planar = 19
-COLOR_FormatYUV420SemiPlanar = 21
-COLOR_FormatYUV420PackedPlanar = 20
-COLOR_FormatYUV420PackedSemiPlanar = 22
-COLOR_FormatYUV422Planar = 16
-COLOR_FormatYUV422SemiPlanar = 41
-COLOR_FormatYUV422PackedPlanar = 17
-COLOR_FormatYUV422PackedSemiPlanar = 18
-COLOR_FormatYUV444Planar = 31
-COLOR_FormatYUV444SemiPlanar = 42
-COLOR_FormatYUV444PackedPlanar = 32
-COLOR_FormatYUV444PackedSemiPlanar = 33
-COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7F000100
-COLOR_FormatSurface = 0x7F000789
-COLOR_FormatYUV420Flexible = 0x7F420888
-COLOR_Format24BitBGR = 5
-COLOR_Format32BitARGB8888 = 9
-COLOR_Format32BitBGRA8888 = 10
-
-BITRATE_MODE_VBR = 0
-BITRATE_MODE_CBR = 1
-BITRATE_MODE_CQ = 2
-
-CODEC_LEVEL_UNSPECIFIED = 0
-CODEC_PROFILE_UNSPECIFIED = 0
-
-AUDIO_CHANNEL_OUT_MONO = 4
-AUDIO_CHANNEL_OUT_STEREO = 12
-AUDIO_CHANNEL_OUT_5POINT1 = 252
-AUDIO_CHANNEL_OUT_7POINT1 = 6396
-
-AUDIO_CHANNEL_IN_MONO = 16
-AUDIO_CHANNEL_IN_STEREO = 12
-
-PCM_ENCODING_PCM_16BIT = 2
-PCM_ENCODING_PCM_8BIT = 3
-PCM_ENCODING_PCM_FLOAT = 4
-
-AUDIO_OUTPUT_FLAG_NONE = 0
-AUDIO_OUTPUT_FLAG_DIRECT = 1
-AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 8
-
-# MediaFormat KEY 常量
-KEY_MIME = "mime"
-KEY_WIDTH = "width"
-KEY_HEIGHT = "height"
-KEY_FRAME_RATE = "frame-rate"
-KEY_BIT_RATE = "bitrate"
-KEY_COLOR_FORMAT = "color-format"
-KEY_I_FRAME_INTERVAL = "i-frame-interval"
-KEY_CHANNEL_COUNT = "channel-count"
-KEY_SAMPLE_RATE = "sample-rate"
-KEY_MAX_INPUT_SIZE = "max-input-size"
-KEY_DURATION = "durationUs"
-KEY_IS_ADTS = "is-adts"
-KEY_CHANNEL_MASK = "channel-mask"
-KEY_ENCODING = "encoding"
-KEY_PCM_ENCODING = "pcm-encoding"
-KEY_PROFILE = "profile"
-KEY_LEVEL = "level"
-KEY_LANGUAGE = "language"
-KEY_PRIORITY = "priority"
-KEY_OPERATING_RATE = "operating-rate"
-KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period"
-KEY_LATENCY = "latency"
-KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder"
-KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder"
-KEY_PREPEND_HEADER_TO_SYNC_FRAMES = "prepend-sps-pps-to-idr-frames"
-KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after"
-KEY_TEMPORAL_LAYERING = "temporal-layering"
-KEY_HDR10_PLUS_INFO = "hdr10-plus-info"
-KEY_PIXEL_ASPECT_RATIO_WIDTH = "pixel-aspect-ratio-width"
-KEY_PIXEL_ASPECT_RATIO_HEIGHT = "pixel-aspect-ratio-height"
-KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-factor"
-KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-attenuation-factor"
-KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression"
-KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level"
-KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level"
-KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel-count"
-KEY_AAC_PROFILE = "aac-profile"
-KEY_AAC_SBR_MODE = "aac-sbr-mode"
-KEY_ENCODER_DELAY_FRAME_COUNT = "encoder-delay"
-KEY_ENCODER_PADDING_FRAME_COUNT = "encoder-padding"
-KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level"
-KEY_MAX_BIT_RATE = "max-bitrate"
-KEY_QUALITY = "quality"
-KEY_SAMPLE_MIME_TYPE = "sample-mime-type"
-KEY_TRACK_ID = "track-id"
-KEY_IS_AUTOSELECT = "is-autoselect"
-KEY_IS_DEFAULT = "is-default"
-KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle"
-KEY_ROTATION = "rotation"
-KEY_CAPTURE_RATE = "capture-rate"
-KEY_FEATURE_ = "feature-"
-KEY_HDR_STATIC_INFO = "hdr-static-info"
-KEY_HDR10_PLUS_INFO = "hdr10-plus-info"
-KEY_COLOR_TRANSFER_REQUEST = "color-transfer-request"
-KEY_OFFSET_TIME = "offset-time"
-KEY_PCM_ENCODING = "pcm-encoding"
-KEY_SAMPLE_RATE = "sample-rate"
-KEY_SUPPORTED_PCM_ENCODINGS = "supported-pcm-encodings"
-KEY_SUPPORTED_PCM_USAGES = "supported-pcm-usages"
-KEY_TRANSFER_TIMEOUT = "transfer-timeout"
-KEY_VIDEO_QP_B_MAX = "video-qp-b-max"
-KEY_VIDEO_QP_B_MIN = "video-qp-b-min"
-KEY_VIDEO_QP_I_MAX = "video-qp-i-max"
-KEY_VIDEO_QP_I_MIN = "video-qp-i-min"
-KEY_VIDEO_QP_P_MAX = "video-qp-p-max"
-KEY_VIDEO_QP_P_MIN = "video-qp-p-min"
-
-# MIME 类型
-MIMETYPE_VIDEO_AV1 = "video/av01"
-MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9"
-MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8"
-MIMETYPE_VIDEO_H265 = "video/hevc"
-MIMETYPE_VIDEO_H264 = "video/avc"
-MIMETYPE_VIDEO_MPEG2 = "video/mpeg2"
-MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es"
-MIMETYPE_VIDEO_VC1 = "video/wvc1"
-MIMETYPE_VIDEO_DIVX = "video/divx"
-MIMETYPE_VIDEO_DIVX3 = "video/divx3"
-MIMETYPE_VIDEO_FLV = "video/flv1"
-MIMETYPE_VIDEO_H263 = "video/3gpp"
-MIMETYPE_VIDEO_RAW = "video/raw"
-MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision"
-MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled"
-MIMETYPE_AUDIO_AAC = "audio/mp4a-latm"
-MIMETYPE_AUDIO_MP3 = "audio/mpeg"
-MIMETYPE_AUDIO_MPEG = "audio/mpeg"
-MIMETYPE_AUDIO_AMR_NB = "audio/3gpp"
-MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb"
-MIMETYPE_AUDIO_FLAC = "audio/flac"
-MIMETYPE_AUDIO_VORBIS = "audio/vorbis"
-MIMETYPE_AUDIO_OPUS = "audio/opus"
-MIMETYPE_AUDIO_RAW = "audio/raw"
-MIMETYPE_AUDIO_ALAC = "audio/alac"
-MIMETYPE_AUDIO_AC3 = "audio/ac3"
-MIMETYPE_AUDIO_EAC3 = "audio/eac3"
-MIMETYPE_AUDIO_WMA = "audio/x-ms-wma"
-MIMETYPE_AUDIO_MSGSM = "audio/gsm"
-MIMETYPE_TEXT_VTT = "text/vtt"
-MIMETYPE_TEXT_CEA_608 = "text/cea-608"
-MIMETYPE_TEXT_CEA_708 = "text/cea-708"
-MIMETYPE_SUBTITLE_SRT = "application/x-subrip"
-MIMETYPE_SUBTITLE_TTML = "application/ttml+xml"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaCodec.BufferInfo
-# ═══════════════════════════════════════════════════════════════
-
-class CodecBufferInfo(Stub):
- """MediaCodec.BufferInfo — 编解码缓冲区信息"""
-
- BUFFER_FLAG_KEY_FRAME = BUFFER_FLAG_KEY_FRAME
- BUFFER_FLAG_CODEC_CONFIG = BUFFER_FLAG_CODEC_CONFIG
- BUFFER_FLAG_END_OF_STREAM = BUFFER_FLAG_END_OF_STREAM
- BUFFER_FLAG_PARTIAL_FRAME = BUFFER_FLAG_PARTIAL_FRAME
- BUFFER_FLAG_SYNC_FRAME = BUFFER_FLAG_SYNC_FRAME
-
- def __init__(self):
- super().__init__()
- self.offset: int = 0
- self.size: int = 0
- self.presentationTimeUs: int = 0
- self.flags: int = 0
-
- def set(self, new_offset: int, new_size: int, new_time_us: int, new_flags: int) -> None:
- self.offset = new_offset
- self.size = new_size
- self.presentationTimeUs = new_time_us
- self.flags = new_flags
-
- def duplicate(self) -> "CodecBufferInfo":
- info = CodecBufferInfo()
- info.offset = self.offset
- info.size = self.size
- info.presentationTimeUs = self.presentationTimeUs
- info.flags = self.flags
- return info
-
- def toString(self) -> str:
- return (f"BufferInfo(offset={self.offset}, size={self.size}, "
- f"timeUs={self.presentationTimeUs}, flags={self.flags})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaCodec.CryptoInfo
-# ═══════════════════════════════════════════════════════════════
-
-class CryptoInfo(Stub):
- """CryptoInfo — 加密信息 (MediaCodec)"""
-
- def __init__(self):
- super().__init__()
- self.numSubSamples = 0
- self.numBytesOfClearData: List[int] = []
- self.numBytesOfEncryptedData: List[int] = []
- self.key: Optional[bytes] = None
- self.iv: Optional[bytes] = None
- self.mode: int = 0
-
- class Pattern(Stub):
- """Pattern — 加密模式"""
-
- def __init__(self, encrypt_blocks: int = 0, skip_blocks: int = 0):
- super().__init__()
- self.encryptBlocks = encrypt_blocks
- self.skipBlocks = skip_blocks
-
- def toString(self) -> str:
- return f"Pattern(encrypt={self.encryptBlocks}, skip={self.skipBlocks})"
-
- def hashCode(self) -> int:
- return hash((self.encryptBlocks, self.skipBlocks)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, CryptoInfo.Pattern):
- return False
- return (self.encryptBlocks == other.encryptBlocks
- and self.skipBlocks == other.skipBlocks)
-
- def setPattern(self, pattern: "CryptoInfo.Pattern"):
- self._pattern = pattern
-
- def getPattern(self) -> Optional["CryptoInfo.Pattern"]:
- return getattr(self, '_pattern', None)
-
- def toString(self) -> str:
- return (f"CryptoInfo(subsamples={self.numSubSamples}, "
- f"mode={self.mode})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaCodec.CodecException
-# ═══════════════════════════════════════════════════════════════
-
-class CodecException(RuntimeException):
- """MediaCodec.CodecException — 编解码器异常"""
-
- ERROR_RECOVERABLE = 1
- ERROR_INSUFFICIENT_RESOURCE = 2
-
- def __init__(self, error_code: int = 0, diagnostic_info: str = "",
- is_recoverable: bool = False, is_transient: bool = False):
- super().__init__(f"CodecException: {diagnostic_info}")
- self._error_code = error_code
- self._diagnostic_info = diagnostic_info
- self._is_recoverable = is_recoverable
- self._is_transient = is_transient
-
- def getErrorCode(self) -> int:
- return self._error_code
-
- def getDiagnosticInfo(self) -> str:
- return self._diagnostic_info
-
- def isRecoverable(self) -> bool:
- return self._is_recoverable
-
- def isTransient(self) -> bool:
- return self._is_transient
-
- def toString(self) -> str:
- return (f"CodecException(errorCode={self._error_code}, "
- f"recoverable={self._is_recoverable}, "
- f"transient={self._is_transient})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaCodec
-# ═══════════════════════════════════════════════════════════════
-
-class MediaCodec(Stub):
- """MediaCodec — 媒体编解码器"""
-
- # 内部类引用
- BufferInfo = CodecBufferInfo
- CryptoInfo = CryptoInfo
- CodecException = CodecException
-
- BUFFER_FLAG_KEY_FRAME = BUFFER_FLAG_KEY_FRAME
- BUFFER_FLAG_CODEC_CONFIG = BUFFER_FLAG_CODEC_CONFIG
- BUFFER_FLAG_END_OF_STREAM = BUFFER_FLAG_END_OF_STREAM
- BUFFER_FLAG_PARTIAL_FRAME = BUFFER_FLAG_PARTIAL_FRAME
- BUFFER_FLAG_SYNC_FRAME = BUFFER_FLAG_SYNC_FRAME
-
- CRYPTO_MODE_UNENCRYPTED = CRYPTO_MODE_UNENCRYPTED
- CRYPTO_MODE_AES_CTR = CRYPTO_MODE_AES_CTR
- CRYPTO_MODE_AES_WV = CRYPTO_MODE_AES_WV
- CRYPTO_MODE_AES_CBC = CRYPTO_MODE_AES_CBC
-
- INFO_TRY_AGAIN_LATER = INFO_TRY_AGAIN_LATER
- INFO_OUTPUT_FORMAT_CHANGED = INFO_OUTPUT_FORMAT_CHANGED
- INFO_OUTPUT_BUFFERS_CHANGED = INFO_OUTPUT_BUFFERS_CHANGED
-
- CONFIGURE_FLAG_ENCODE = 1
-
- def __init__(self, name: str = ""):
- super().__init__()
- self._name = name
- self._configured = False
- self._started = False
- self._format: Optional["MediaFormat"] = None
- self._input_buffers: Dict[int, Optional[bytes]] = {}
- self._output_buffers: Dict[int, Optional[bytes]] = {}
- self._input_buffer_count = 0
- self._output_buffer_count = 0
- self._input_lock = threading.Lock()
- self._output_lock = threading.Lock()
- self._callback: Optional[MediaCodec.Callback] = None
- self._handler: Optional[Any] = None
-
- @staticmethod
- def createByCodecName(name: str) -> "MediaCodec":
- return MediaCodec(name)
-
- @staticmethod
- def createDecoderByType(type_str: str) -> "MediaCodec":
- return MediaCodec(f"decoder.{type_str}")
-
- @staticmethod
- def createEncoderByType(type_str: str) -> "MediaCodec":
- return MediaCodec(f"encoder.{type_str}")
-
- def configure(self, format: "MediaFormat", surface: Any = None,
- crypto: Any = None, flags: int = 0) -> None:
- self._format = format
- self._configured = True
- self._input_buffers.clear()
- self._output_buffers.clear()
-
- def start(self) -> None:
- if not self._configured:
- raise RuntimeException("MediaCodec 未配置")
- self._started = True
- self._input_buffer_count = 8
- self._output_buffer_count = 8
-
- def stop(self) -> None:
- self._started = False
-
- def flush(self) -> None:
- if not self._started:
- return
- with self._input_lock:
- self._input_buffers.clear()
- with self._output_lock:
- self._output_buffers.clear()
-
- def release(self) -> None:
- self.stop()
- self._configured = False
- self._format = None
-
- def getInputBuffers(self) -> List[Optional[bytes]]:
- return [self._input_buffers.get(i) for i in range(self._input_buffer_count)]
-
- def getOutputBuffers(self) -> List[Optional[bytes]]:
- return [self._output_buffers.get(i) for i in range(self._output_buffer_count)]
-
- def getInputBuffer(self, idx: int) -> Optional[bytes]:
- with self._input_lock:
- if idx not in self._input_buffers:
- self._input_buffers[idx] = bytearray(1024 * 1024)
- return self._input_buffers[idx]
-
- def getOutputBuffer(self, idx: int) -> Optional[bytes]:
- with self._output_lock:
- return self._output_buffers.get(idx)
-
- def queueInputBuffer(self, index: int, offset: int, size: int,
- presentation_time_us: int, flags: int) -> None:
- pass
-
- def queueSecureInputBuffer(self, index: int, offset: int,
- info: CryptoInfo,
- presentation_time_us: int,
- flags: int) -> None:
- pass
-
- def dequeueInputBuffer(self, timeout_us: int) -> int:
- return 0
-
- def dequeueOutputBuffer(self, info: CodecBufferInfo, timeout_us: int) -> int:
- return INFO_TRY_AGAIN_LATER
-
- def releaseOutputBuffer(self, index: int, render: bool) -> None:
- pass
-
- def getOutputFormat(self) -> Optional["MediaFormat"]:
- return self._format
-
- def getCodecInfo(self) -> Optional["MediaCodecInfo"]:
- return None
-
- def getName(self) -> str:
- return self._name
-
- def setCallback(self, cb: Optional["MediaCodec.Callback"],
- handler: Any = None) -> None:
- self._callback = cb
- self._handler = handler
-
- def createInputSurface(self) -> Any:
- raise AndroidOnlyError("createInputSurface() 仅在 Android 上可用")
-
- def signalEndOfInputStream(self) -> None:
- pass
-
- def getMetrics(self) -> Dict[str, Any]:
- return {}
-
- def setVideoScalingMode(self, mode: int) -> None:
- pass
-
- def getCodecName(self) -> str:
- return self._name
-
- def isConfigured(self) -> bool:
- return self._configured
-
- def isStarted(self) -> bool:
- return self._started
-
- def toString(self) -> str:
- return f"MediaCodec(name={self._name}, started={self._started})"
-
-
-class MediaCodecCallback(Stub):
- """MediaCodec.Callback — 编解码器回调"""
-
- def onInputBufferAvailable(self, codec: MediaCodec, index: int) -> None:
- pass
-
- def onOutputBufferAvailable(self, codec: MediaCodec, index: int,
- info: CodecBufferInfo) -> None:
- pass
-
- def onError(self, codec: MediaCodec, e: CodecException) -> None:
- pass
-
- def onOutputFormatChanged(self, codec: MediaCodec, format: "MediaFormat") -> None:
- pass
-
-
-MediaCodec.Callback = MediaCodecCallback
-
-
-class MediaCodecInfo(Stub):
- """MediaCodecInfo — 编解码器信息"""
-
- class CodecCapabilities(Stub):
- """MediaCodecInfo.CodecCapabilities — 编解码能力"""
-
- FEATURE_AdaptivePlayback = "adaptive-playback"
- FEATURE_SecurePlayback = "secure-playback"
- FEATURE_TunneledPlayback = "tunneled-playback"
- FEATURE_PartialFrame = "partial-frame"
-
- def __init__(self):
- super().__init__()
- self.colorFormats: List[int] = []
- self.profileLevels: List[Any] = []
- self.profileEntries: List[Any] = []
- self._flags: int = 0
- self._max_instances: int = 0
- self._bitrate_range: Optional[Tuple[int, int]] = None
- self._width_range: Optional[Tuple[int, int]] = None
- self._height_range: Optional[Tuple[int, int]] = None
- self._frame_rate_range: Optional[Tuple[int, int]] = None
-
- def getColorFormats(self) -> List[int]:
- return list(self.colorFormats)
-
- def getProfileLevels(self) -> List[Any]:
- return list(self.profileLevels)
-
- def getSupportedFeatures(self) -> List[str]:
- features = []
- return features
-
- def isFeatureSupported(self, name: str) -> bool:
- return False
-
- def getVideoCapabilities(self) -> Optional[Any]:
- return None
-
- def getAudioCapabilities(self) -> Optional[Any]:
- return None
-
- def toString(self) -> str:
- return (f"CodecCapabilities(formats={len(self.colorFormats)}, "
- f"profiles={len(self.profileLevels)})")
-
- class CodecProfileLevel(Stub):
- """MediaCodecInfo.CodecProfileLevel — 配置等级"""
-
- def __init__(self):
- super().__init__()
- self.profile: int = 0
- self.level: int = 0
-
- def __init__(self, name: str = "", canonical_name: str = ""):
- super().__init__()
- self._name = name
- self._canonical_name = canonical_name or name
- self._is_encoder: bool = False
- self._is_vendor: bool = False
- self._capabilities: Optional[MediaCodecInfo.CodecCapabilities] = None
- self._supported_types: List[str] = []
-
- def getName(self) -> str:
- return self._name
-
- def getCanonicalName(self) -> str:
- return self._canonical_name
-
- def isEncoder(self) -> bool:
- return self._is_encoder
-
- def setEncoder(self, is_enc: bool) -> None:
- self._is_encoder = is_enc
-
- def isVendor(self) -> bool:
- return self._is_vendor
-
- def getSupportedTypes(self) -> List[str]:
- return list(self._supported_types)
-
- def getCapabilitiesForType(self, type_str: str) -> Optional[CodecCapabilities]:
- if type_str in self._supported_types:
- return self._capabilities
- return None
-
- def toString(self) -> str:
- return (f"MediaCodecInfo(name={self._name}, "
- f"encoder={self._is_encoder}, "
- f"types={len(self._supported_types)})")
-
-
-class MediaCodecList(Stub):
- """MediaCodecList — 编解码器列表"""
-
- REGULAR_CODECS = 0
- ALL_CODECS = 1
-
- def __init__(self, kind: int = REGULAR_CODECS):
- super().__init__()
- self._kind = kind
- self._codecs: List[MediaCodecInfo] = []
-
- def getCodecInfos(self) -> List[MediaCodecInfo]:
- return list(self._codecs)
-
- def findDecoderForFormat(self, format: "MediaFormat") -> Optional[str]:
- return None
-
- def findEncoderForFormat(self, format: "MediaFormat") -> Optional[str]:
- return None
-
- @staticmethod
- def getCodecCount() -> int:
- return 0
-
- @staticmethod
- def getCodecInfoAt(index: int) -> Optional[MediaCodecInfo]:
- return None
-
- def toString(self) -> str:
- return f"MediaCodecList(codecs={len(self._codecs)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaExtractor
-# ═══════════════════════════════════════════════════════════════
-
-class MediaExtractor(Stub):
- """MediaExtractor — 媒体提取器"""
-
- SEEK_TO_PREVIOUS_SYNC = 0
- SEEK_TO_NEXT_SYNC = 1
- SEEK_TO_CLOSEST_SYNC = 2
- SAMPLE_FLAG_SYNC = 1
- SAMPLE_FLAG_ENCRYPTED = 2
-
- def __init__(self):
- super().__init__()
- self._data_source: Optional[str] = None
- self._fd: Optional[int] = None
- self._track_count: int = 0
- self._selected_tracks: Set[int] = set()
- self._current_track: int = -1
- self._sample_time: int = 0
- self._sample_flags: int = 0
- self._sample_size: int = 0
- self._sample_track_index: int = -1
- self._cached_info: Dict[int, "MediaFormat"] = {}
- self._released = False
- self._lock = threading.Lock()
-
- def setDataSource(self, path: str) -> None:
- self._data_source = path
- self._fd = None
- self._parse_source()
-
- def setDataSource(self, path: str, headers: Dict[str, str] = None) -> None:
- self._data_source = path
- self._fd = None
- self._headers = headers or {}
- self._parse_source()
-
- def setDataSource(self, fd: int) -> None:
- self._fd = fd
- self._data_source = None
- if fd > 0:
- self._track_count = 1
-
- def _parse_source(self) -> None:
- if self._data_source and os.path.exists(self._data_source):
- self._track_count = 1
-
- def getTrackCount(self) -> int:
- return self._track_count
-
- def getTrackFormat(self, index: int) -> Optional["MediaFormat"]:
- return self._cached_info.get(index)
-
- def selectTrack(self, index: int) -> None:
- with self._lock:
- if 0 <= index < self._track_count:
- self._selected_tracks.add(index)
-
- def unselectTrack(self, index: int) -> None:
- with self._lock:
- self._selected_tracks.discard(index)
-
- def getSampleTrackIndex(self) -> int:
- return self._sample_track_index
-
- def readSampleData(self, byte_buf: Any, offset: int) -> int:
- return -1
-
- def getSampleTime(self) -> int:
- return self._sample_time
-
- def getSampleFlags(self) -> int:
- return self._sample_flags
-
- def getSampleSize(self) -> int:
- return self._sample_size
-
- def advance(self) -> bool:
- return False
-
- def seekTo(self, time_us: int, mode: int = SEEK_TO_CLOSEST_SYNC) -> None:
- self._sample_time = time_us
-
- def release(self) -> None:
- self._released = True
- self._cached_info.clear()
- self._selected_tracks.clear()
-
- def getCachedDuration(self) -> int:
- return -1
-
- def hasCacheReachedEndOfStream(self) -> bool:
- return False
-
- def getSampleCryptoInfo(self, info: CryptoInfo) -> bool:
- return False
-
- def toString(self) -> str:
- return (f"MediaExtractor(source={self._data_source}, "
- f"tracks={self._track_count})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaMuxer
-# ═══════════════════════════════════════════════════════════════
-
-class MediaMuxer(Stub):
- """MediaMuxer — 媒体复用器"""
-
- OUTPUT_FORMAT_MPEG4 = 0
- OUTPUT_FORMAT_WEBM = 1
- OUTPUT_FORMAT_3GPP = 2
- OUTPUT_FORMAT_HEIF = 3
- OUTPUT_FORMAT_OGG = 4
-
- def __init__(self, path: str, format: int = OUTPUT_FORMAT_MPEG4):
- super().__init__()
- self._path = path
- self._format = format
- self._started = False
- self._track_count = 0
- self._tracks: Dict[int, "MediaFormat"] = {}
- self._next_track_index = 0
- self._released = False
-
- def addTrack(self, format: "MediaFormat") -> int:
- idx = self._next_track_index
- self._next_track_index += 1
- self._tracks[idx] = format
- self._track_count = len(self._tracks)
- return idx
-
- def start(self) -> None:
- if self._started:
- return
- self._started = True
-
- def stop(self) -> None:
- self._started = False
-
- def release(self) -> None:
- self._released = True
- self._tracks.clear()
- self._started = False
-
- def writeSampleData(self, track_index: int, byte_buf: Any,
- offset: int, buffer_info: CodecBufferInfo) -> None:
- pass
-
- def setOrientationHint(self, degrees: int) -> None:
- pass
-
- def setLocation(self, latitude: float, longitude: float) -> None:
- pass
-
- def getTrackCount(self) -> int:
- return self._track_count
-
- def getOutputFormat(self) -> int:
- return self._format
-
- def getPath(self) -> str:
- return self._path
-
- def isStarted(self) -> bool:
- return self._started
-
- def toString(self) -> str:
- return (f"MediaMuxer(path={self._path}, format={self._format}, "
- f"tracks={self._track_count})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaFormat
-# ═══════════════════════════════════════════════════════════════
-
-class MediaFormat(Stub):
- """MediaFormat — 媒体格式"""
-
- # MIME 类型
- MIMETYPE_VIDEO_AV1 = MIMETYPE_VIDEO_AV1
- MIMETYPE_VIDEO_VP9 = MIMETYPE_VIDEO_VP9
- MIMETYPE_VIDEO_VP8 = MIMETYPE_VIDEO_VP8
- MIMETYPE_VIDEO_H265 = MIMETYPE_VIDEO_H265
- MIMETYPE_VIDEO_H264 = MIMETYPE_VIDEO_H264
- MIMETYPE_VIDEO_MPEG2 = MIMETYPE_VIDEO_MPEG2
- MIMETYPE_VIDEO_MPEG4 = MIMETYPE_VIDEO_MPEG4
- MIMETYPE_VIDEO_VC1 = MIMETYPE_VIDEO_VC1
- MIMETYPE_VIDEO_DIVX = MIMETYPE_VIDEO_DIVX
- MIMETYPE_VIDEO_DIVX3 = MIMETYPE_VIDEO_DIVX3
- MIMETYPE_VIDEO_FLV = MIMETYPE_VIDEO_FLV
- MIMETYPE_VIDEO_H263 = MIMETYPE_VIDEO_H263
- MIMETYPE_VIDEO_RAW = MIMETYPE_VIDEO_RAW
- MIMETYPE_VIDEO_DOLBY_VISION = MIMETYPE_VIDEO_DOLBY_VISION
- MIMETYPE_VIDEO_SCRAMBLED = MIMETYPE_VIDEO_SCRAMBLED
- MIMETYPE_AUDIO_AAC = MIMETYPE_AUDIO_AAC
- MIMETYPE_AUDIO_MP3 = MIMETYPE_AUDIO_MP3
- MIMETYPE_AUDIO_AMR_NB = MIMETYPE_AUDIO_AMR_NB
- MIMETYPE_AUDIO_AMR_WB = MIMETYPE_AUDIO_AMR_WB
- MIMETYPE_AUDIO_FLAC = MIMETYPE_AUDIO_FLAC
- MIMETYPE_AUDIO_VORBIS = MIMETYPE_AUDIO_VORBIS
- MIMETYPE_AUDIO_OPUS = MIMETYPE_AUDIO_OPUS
- MIMETYPE_AUDIO_RAW = MIMETYPE_AUDIO_RAW
- MIMETYPE_AUDIO_ALAC = MIMETYPE_AUDIO_ALAC
- MIMETYPE_AUDIO_AC3 = MIMETYPE_AUDIO_AC3
- MIMETYPE_AUDIO_EAC3 = MIMETYPE_AUDIO_EAC3
- MIMETYPE_TEXT_VTT = MIMETYPE_TEXT_VTT
- MIMETYPE_TEXT_CEA_608 = MIMETYPE_TEXT_CEA_608
- MIMETYPE_TEXT_CEA_708 = MIMETYPE_TEXT_CEA_708
- MIMETYPE_SUBTITLE_SRT = MIMETYPE_SUBTITLE_SRT
- MIMETYPE_SUBTITLE_TTML = MIMETYPE_SUBTITLE_TTML
-
- # KEY 常量
- KEY_MIME = KEY_MIME
- KEY_WIDTH = KEY_WIDTH
- KEY_HEIGHT = KEY_HEIGHT
- KEY_FRAME_RATE = KEY_FRAME_RATE
- KEY_BIT_RATE = KEY_BIT_RATE
- KEY_COLOR_FORMAT = KEY_COLOR_FORMAT
- KEY_I_FRAME_INTERVAL = KEY_I_FRAME_INTERVAL
- KEY_CHANNEL_COUNT = KEY_CHANNEL_COUNT
- KEY_SAMPLE_RATE = KEY_SAMPLE_RATE
- KEY_MAX_INPUT_SIZE = KEY_MAX_INPUT_SIZE
- KEY_DURATION = KEY_DURATION
- KEY_IS_ADTS = KEY_IS_ADTS
- KEY_CHANNEL_MASK = KEY_CHANNEL_MASK
- KEY_ENCODING = KEY_ENCODING
- KEY_PROFILE = KEY_PROFILE
- KEY_LEVEL = KEY_LEVEL
- KEY_LANGUAGE = KEY_LANGUAGE
- KEY_PRIORITY = KEY_PRIORITY
- KEY_OPERATING_RATE = KEY_OPERATING_RATE
- KEY_INTRA_REFRESH_PERIOD = KEY_INTRA_REFRESH_PERIOD
- KEY_LATENCY = KEY_LATENCY
- KEY_ROTATION = KEY_ROTATION
- KEY_CAPTURE_RATE = KEY_CAPTURE_RATE
- KEY_QUALITY = KEY_QUALITY
- KEY_MAX_BIT_RATE = KEY_MAX_BIT_RATE
- KEY_FLAC_COMPRESSION_LEVEL = KEY_FLAC_COMPRESSION_LEVEL
- KEY_TRACK_ID = KEY_TRACK_ID
- KEY_IS_AUTOSELECT = KEY_IS_AUTOSELECT
- KEY_IS_DEFAULT = KEY_IS_DEFAULT
- KEY_IS_FORCED_SUBTITLE = KEY_IS_FORCED_SUBTITLE
-
- # 色彩格式
- COLOR_FormatUnsupported = COLOR_FormatUnsupported
- COLOR_FormatYUV420Planar = COLOR_FormatYUV420Planar
- COLOR_FormatYUV420SemiPlanar = COLOR_FormatYUV420SemiPlanar
- COLOR_FormatYUV420Flexible = COLOR_FormatYUV420Flexible
- COLOR_FormatSurface = COLOR_FormatSurface
- COLOR_Format32BitARGB8888 = COLOR_Format32BitARGB8888
-
- def __init__(self):
- super().__init__()
- self._properties: Dict[str, Any] = {}
-
- @staticmethod
- def createVideoFormat(mime: str, width: int, height: int) -> "MediaFormat":
- fmt = MediaFormat()
- fmt.setString(KEY_MIME, mime)
- fmt.setInteger(KEY_WIDTH, width)
- fmt.setInteger(KEY_HEIGHT, height)
- return fmt
-
- @staticmethod
- def createAudioFormat(mime: str, sample_rate: int, channel_count: int) -> "MediaFormat":
- fmt = MediaFormat()
- fmt.setString(KEY_MIME, mime)
- fmt.setInteger(KEY_SAMPLE_RATE, sample_rate)
- fmt.setInteger(KEY_CHANNEL_COUNT, channel_count)
- return fmt
-
- @staticmethod
- def createSubtitleFormat(mime: str, language: str) -> "MediaFormat":
- fmt = MediaFormat()
- fmt.setString(KEY_MIME, mime)
- fmt.setString(KEY_LANGUAGE, language)
- return fmt
-
- def containsKey(self, key: str) -> bool:
- return key in self._properties
-
- def getInteger(self, key: str, default_value: int = 0) -> int:
- val = self._properties.get(key, default_value)
- return int(val) if isinstance(val, (int, float)) else default_value
-
- def getFloat(self, key: str, default_value: float = 0.0) -> float:
- val = self._properties.get(key, default_value)
- return float(val) if isinstance(val, (int, float)) else default_value
-
- def getLong(self, key: str, default_value: int = 0) -> int:
- return self.getInteger(key, default_value)
-
- def getString(self, key: str, default_value: Optional[str] = None) -> Optional[str]:
- val = self._properties.get(key, default_value)
- return str(val) if val is not None else None
-
- def getByteBuffer(self, key: str) -> Optional[bytes]:
- val = self._properties.get(key)
- if isinstance(val, (bytes, bytearray)):
- return bytes(val)
- return None
-
- def setInteger(self, key: str, value: int) -> None:
- self._properties[key] = value
-
- def setFloat(self, key: str, value: float) -> None:
- self._properties[key] = value
-
- def setLong(self, key: str, value: int) -> None:
- self._properties[key] = value
-
- def setString(self, key: str, value: str) -> None:
- self._properties[key] = value
-
- def setByteBuffer(self, key: str, buf: bytes) -> None:
- self._properties[key] = buf
-
- def getMap(self) -> Dict[str, Any]:
- return dict(self._properties)
-
- def toString(self) -> str:
- parts = [f"{k}={v}" for k, v in self._properties.items()]
- return f"MediaFormat({', '.join(parts)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaCrypto
-# ═══════════════════════════════════════════════════════════════
-
-class MediaCrypto(Stub):
- """MediaCrypto — 媒体加密"""
-
- def __init__(self, uuid: str = ""):
- super().__init__()
- self._uuid = uuid
- self._init_data: Optional[bytes] = None
-
- def requiresSecureDecoderComponent(self, mime: str) -> bool:
- return False
-
- def setMediaDrmSession(self, session_id: bytes) -> None:
- pass
-
- def getUUID(self) -> str:
- return self._uuid
-
- def toString(self) -> str:
- return f"MediaCrypto(uuid={self._uuid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaDrm
-# ═══════════════════════════════════════════════════════════════
-
-class MediaDrm(Stub):
- """MediaDrm — 数字版权管理"""
-
- KEY_TYPE_STREAMING = 1
- KEY_TYPE_OFFLINE = 2
- KEY_TYPE_RELEASE = 3
-
- EVENT_PROVISION_REQUIRED = 1
- EVENT_KEY_REQUIRED = 2
- EVENT_KEY_EXPIRED = 3
- EVENT_VENDOR_DEFINED = 4
- EVENT_SESSION_RECLAIMED = 5
-
- KEY_EXPIRED = 0
- KEY_STATUS_OK = 1
- KEY_STATUS_PENDING = 2
- KEY_STATUS_USABLE = 3
- KEY_STATUS_USABLE_IN_FUTURE = 4
-
- def __init__(self, uuid: str = ""):
- super().__init__()
- self._uuid = uuid
- self._sessions: Dict[str, bytes] = {}
- self._event_listener: Optional[Callable] = None
- self._expiration_update_listener: Optional[Callable] = None
- self._key_status_listener: Optional[Callable] = None
-
- def openSession(self) -> Optional[bytes]:
- import os
- session_id = os.urandom(16)
- self._sessions[session_id.hex()] = session_id
- return session_id
-
- def closeSession(self, session_id: bytes) -> None:
- key = session_id.hex() if isinstance(session_id, bytes) else session_id
- self._sessions.pop(key, None)
-
- def getKeyRequest(self, session_id: bytes, init_data: bytes,
- mime_type: str, key_type: int,
- optional_parameters: Optional[Dict[str, str]] = None) -> Any:
- return None
-
- def provideKeyResponse(self, session_id: bytes, response: bytes) -> Optional[bytes]:
- return None
-
- def restoreKeys(self, session_id: bytes, key_set_id: bytes) -> None:
- pass
-
- def removeKeys(self, session_id: bytes) -> None:
- pass
-
- def queryKeyStatus(self, session_id: bytes) -> Optional[Dict[str, str]]:
- return {"status": "usable"}
-
- def getProvisionRequest(self) -> Optional[Tuple[bytes, str]]:
- return None
-
- def provideProvisionResponse(self, response: bytes) -> None:
- pass
-
- def getSecureStops(self) -> List[bytes]:
- return []
-
- def getSecureStop(self, ssid: bytes) -> Optional[bytes]:
- return None
-
- def releaseSecureStops(self, ssid: bytes) -> None:
- pass
-
- def releaseAllSecureStops(self) -> None:
- pass
-
- def getPropertyString(self, name: str) -> str:
- return ""
-
- def setPropertyString(self, name: str, value: str) -> None:
- pass
-
- def getPropertyByteArray(self, name: str) -> Optional[bytes]:
- return None
-
- def setPropertyByteArray(self, name: str, value: bytes) -> None:
- pass
-
- def getMetrics(self) -> Dict[str, Any]:
- return {}
-
- def getMaxSessionCount(self) -> int:
- return 128
-
- def getOpenSessionCount(self) -> int:
- return len(self._sessions)
-
- def getTotalSessionCount(self) -> int:
- return len(self._sessions)
-
- def release(self) -> None:
- self._sessions.clear()
-
- @staticmethod
- def isCryptoSchemeSupported(uuid: str) -> bool:
- return False
-
- def toString(self) -> str:
- return f"MediaDrm(uuid={self._uuid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaDescription / MediaMetadata
-# ═══════════════════════════════════════════════════════════════
-
-class MediaDescription(Stub):
- """MediaDescription — 媒体描述"""
-
- BT_FOLDER_TYPE_ALBUMS = 1
- BT_FOLDER_TYPE_ARTISTS = 2
- BT_FOLDER_TYPE_GENRES = 3
- BT_FOLDER_TYPE_PLAYLISTS = 4
- BT_FOLDER_TYPE_YEARS = 5
- EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE"
- EXTRA_DOWNLOAD_STATUS = "android.media.extra.DOWNLOAD_STATUS"
-
- def __init__(self):
- super().__init__()
- self._media_id: str = ""
- self._title: Optional[str] = None
- self._subtitle: Optional[str] = None
- self._description: Optional[str] = None
- self._icon_uri: Optional[str] = None
- self._extras: Dict[str, Any] = {}
- self._media_uri: Optional[str] = None
- self._flags: int = 0
-
- def getMediaId(self) -> Optional[str]:
- return self._media_id
-
- def getTitle(self) -> Optional[str]:
- return self._title
-
- def getSubtitle(self) -> Optional[str]:
- return self._subtitle
-
- def getDescription(self) -> Optional[str]:
- return self._description
-
- def getIconUri(self) -> Optional[str]:
- return self._icon_uri
-
- def getExtras(self) -> Optional[Dict[str, Any]]:
- return dict(self._extras) if self._extras else None
-
- def getMediaUri(self) -> Optional[str]:
- return self._media_uri
-
- def toString(self) -> str:
- return (f"MediaDescription(id={self._media_id}, "
- f"title={self._title})")
-
-
-class MediaMetadata(Stub):
- """MediaMetadata — 媒体元数据"""
-
- METADATA_KEY_ALBUM = "android.media.metadata.ALBUM"
- METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART"
- METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST"
- METADATA_KEY_ART = "android.media.metadata.ART"
- METADATA_KEY_ARTIST = "android.media.metadata.ARTIST"
- METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR"
- METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION"
- METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER"
- METADATA_KEY_DATE = "android.media.metadata.DATE"
- METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER"
- METADATA_KEY_DURATION = "android.media.metadata.DURATION"
- METADATA_KEY_GENRE = "android.media.metadata.GENRE"
- METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS"
- METADATA_KEY_RATING = "android.media.metadata.RATING"
- METADATA_KEY_TITLE = "android.media.metadata.TITLE"
- METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER"
- METADATA_KEY_WRITER = "android.media.metadata.WRITER"
- METADATA_KEY_YEAR = "android.media.metadata.YEAR"
- METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID"
- METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE"
- METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE"
- METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION"
- METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON"
- METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING"
-
- def __init__(self):
- super().__init__()
- self._values: Dict[str, Any] = {}
-
- def containsKey(self, key: str) -> bool:
- return key in self._values
-
- def getString(self, key: str) -> Optional[str]:
- val = self._values.get(key)
- return str(val) if val is not None else None
-
- def getLong(self, key: str) -> int:
- return int(self._values.get(key, 0))
-
- def getFloat(self, key: str) -> float:
- return float(self._values.get(key, 0.0))
-
- def getBitmap(self, key: str) -> Optional[Any]:
- return None
-
- def putString(self, key: str, value: str) -> None:
- self._values[key] = value
-
- def putLong(self, key: str, value: int) -> None:
- self._values[key] = value
-
- def putFloat(self, key: str, value: float) -> None:
- self._values[key] = value
-
- def putBitmap(self, key: str, bitmap: Any) -> None:
- pass
-
- def size(self) -> int:
- return len(self._values)
-
- def keySet(self) -> Set[str]:
- return set(self._values.keys())
-
- def toString(self) -> str:
- return f"MediaMetadata(entries={len(self._values)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaMetadataRetriever
-# ═══════════════════════════════════════════════════════════════
-
-class MediaMetadataRetriever(Stub):
- """MediaMetadataRetriever — 媒体元数据检索器"""
-
- OPTION_PREVIOUS_SYNC = 0
- OPTION_NEXT_SYNC = 1
- OPTION_CLOSEST_SYNC = 2
- OPTION_CLOSEST = 3
-
- METADATA_KEY_ALBUM = 1
- METADATA_KEY_ALBUM_ARTIST = 13
- METADATA_KEY_ARTIST = 2
- METADATA_KEY_AUTHOR = 3
- METADATA_KEY_BITRATE = 20
- METADATA_KEY_CD_TRACK_NUMBER = 0
- METADATA_KEY_COMPILATION = 15
- METADATA_KEY_COMPOSER = 4
- METADATA_KEY_DATE = 5
- METADATA_KEY_DISC_NUMBER = 14
- METADATA_KEY_DURATION = 9
- METADATA_KEY_GENRE = 6
- METADATA_KEY_HAS_AUDIO = 16
- METADATA_KEY_HAS_VIDEO = 17
- METADATA_KEY_IS_DRM = 22
- METADATA_KEY_LOCATION = 23
- METADATA_KEY_MIMETYPE = 12
- METADATA_KEY_NUM_TRACKS = 10
- METADATA_KEY_TITLE = 7
- METADATA_KEY_VIDEO_HEIGHT = 19
- METADATA_KEY_VIDEO_WIDTH = 18
- METADATA_KEY_WRITER = 11
- METADATA_KEY_YEAR = 8
-
- def __init__(self):
- super().__init__()
- self._data_source: Optional[str] = None
- self._extracted: Dict[int, str] = {}
- self._released = False
-
- def setDataSource(self, path: str) -> None:
- self._data_source = path
- self._extract()
-
- def setDataSource(self, path: str, headers: Dict[str, str]) -> None:
- self._data_source = path
- self._headers = headers
- self._extract()
-
- def setDataSource(self, uri: Any, headers: Dict[str, str]) -> None:
- self._data_source = str(uri)
- self._extract()
-
- def setDataSource(self, fd: int) -> None:
- self._data_source = f"fd:{fd}"
- self._extract()
-
- def _extract(self) -> None:
- if self._data_source and os.path.exists(str(self._data_source)):
- self._extracted[METADATA_KEY_HAS_AUDIO] = "yes"
- self._extracted[METADATA_KEY_HAS_VIDEO] = "yes"
-
- def extractMetadata(self, key_code: int) -> Optional[str]:
- return self._extracted.get(key_code)
-
- def getEmbeddedPicture(self) -> Optional[bytes]:
- return None
-
- def getFrameAtTime(self, time_us: int = -1,
- option: int = OPTION_CLOSEST_SYNC) -> Optional[Any]:
- return None
-
- def getScaledFrameAtTime(self, time_us: int,
- option: int,
- width: int, height: int) -> Optional[Any]:
- return None
-
- def getPrimaryImage(self) -> Optional[Any]:
- return None
-
- def release(self) -> None:
- self._released = True
- self._extracted.clear()
-
- def toString(self) -> str:
- return f"MediaMetadataRetriever(source={self._data_source})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaPlayer 扩展
-# ═══════════════════════════════════════════════════════════════
-
-class MediaPlayer(Stub):
- """MediaPlayer — 媒体播放器(扩展)"""
-
- MEDIA_ERROR_UNKNOWN = 1
- MEDIA_ERROR_SERVER_DIED = 100
- MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200
- MEDIA_ERROR_IO = -1004
- MEDIA_ERROR_MALFORMED = -1007
- MEDIA_ERROR_TIMED_OUT = -110
- MEDIA_ERROR_UNSUPPORTED = -1010
-
- MEDIA_INFO_UNKNOWN = 1
- MEDIA_INFO_VIDEO_TRACK_LAGGING = 700
- MEDIA_INFO_VIDEO_RENDERING_START = 3
- MEDIA_INFO_BUFFERING_START = 701
- MEDIA_INFO_BUFFERING_END = 702
- MEDIA_INFO_BAD_INTERLEAVING = 800
- MEDIA_INFO_NOT_SEEKABLE = 801
- MEDIA_INFO_METADATA_UPDATE = 802
- MEDIA_INFO_AUDIO_NOT_PLAYING = 804
- MEDIA_INFO_VIDEO_NOT_PLAYING = 805
- MEDIA_INFO_SUBTITLE_TIMED_OUT = 902
- MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901
-
- SEEK_CLOSEST = 3
- SEEK_CLOSEST_SYNC = 2
- SEEK_NEXT_SYNC = 1
- SEEK_PREVIOUS_SYNC = 0
-
- VIDEO_SCALING_MODE_SCALE_TO_FIT = 1
- VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2
-
- def __init__(self):
- super().__init__()
- self._data_source: Optional[str] = None
- self._isplaying = False
- self._isloop = False
- self._volume: float = 1.0
- self._position: int = 0
- self._duration: int = 0
- self._isplayback = False
- self._isprepared = False
- self._on_completion: Optional[Callable] = None
- self._on_error: Optional[Callable] = None
- self._on_prepared: Optional[Callable] = None
- self._on_info: Optional[Callable] = None
- self._lock = threading.Lock()
- self._surface: Optional[Any] = None
-
- @staticmethod
- def create(context: Any, uri: Any) -> "MediaPlayer":
- mp = MediaPlayer()
- mp.setDataSource(str(uri))
- mp.prepare()
- return mp
-
- def setDataSource(self, path: str) -> None:
- self._data_source = path
-
- def setDataSource(self, path: str, headers: Dict[str, str]) -> None:
- self._data_source = path
-
- def prepare(self) -> None:
- self._isprepared = True
- self._duration = 10000
- if self._on_prepared:
- self._on_prepared(self)
-
- def prepareAsync(self) -> None:
- self._isprepared = True
- if self._on_prepared:
- self._on_prepared(self)
-
- def start(self) -> None:
- self._isplaying = True
- self._isplayback = True
-
- def stop(self) -> None:
- self._isplaying = False
- self._isplayback = False
- self._position = 0
-
- def pause(self) -> None:
- self._isplaying = False
-
- def seekTo(self, msec: int, mode: int = SEEK_CLOSEST) -> None:
- self._position = max(0, msec)
-
- def getCurrentPosition(self) -> int:
- return self._position
-
- def getDuration(self) -> int:
- return self._duration
-
- def isPlaying(self) -> bool:
- return self._isplaying
-
- def isLooping(self) -> bool:
- return self._isloop
-
- def setLooping(self, looping: bool) -> None:
- self._isloop = looping
-
- def setVolume(self, left_volume: float, right_volume: float) -> None:
- self._volume = (left_volume + right_volume) / 2.0
-
- def getVolume(self) -> float:
- return self._volume
-
- def setSurface(self, surface: Any) -> None:
- self._surface = surface
-
- def setDisplay(self, holder: Any) -> None:
- pass
-
- def setScreenOnWhilePlaying(self, screen_on: bool) -> None:
- pass
-
- def setWakeMode(self, context: Any, mode: int) -> None:
- pass
-
- def setAudioStreamType(self, stream_type: int) -> None:
- pass
-
- def reset(self) -> None:
- self.stop()
- self._isprepared = False
-
- def release(self) -> None:
- self.reset()
-
- def getVideoWidth(self) -> int:
- return 0
-
- def getVideoHeight(self) -> int:
- return 0
-
- def setOnCompletionListener(self, listener: Optional[Callable]) -> None:
- self._on_completion = listener
-
- def setOnErrorListener(self, listener: Optional[Callable]) -> None:
- self._on_error = listener
-
- def setOnPreparedListener(self, listener: Optional[Callable]) -> None:
- self._on_prepared = listener
-
- def setOnInfoListener(self, listener: Optional[Callable]) -> None:
- self._on_info = listener
-
- def setOnBufferingUpdateListener(self, listener: Optional[Callable]) -> None:
- pass
-
- def setOnSeekCompleteListener(self, listener: Optional[Callable]) -> None:
- pass
-
- def setOnVideoSizeChangedListener(self, listener: Optional[Callable]) -> None:
- pass
-
- def attachAuxEffect(self, effect_id: int) -> None:
- pass
-
- def toString(self) -> str:
- return (f"MediaPlayer(source={self._data_source}, "
- f"playing={self._isplaying})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaSync / MediaTimeProvider / TimedMetaData / WebVttParser
-# ═══════════════════════════════════════════════════════════════
-
-class MediaSync(Stub):
- """MediaSync — 媒体同步器"""
-
- def __init__(self):
- super().__init__()
- self._surface: Optional[Any] = None
- self._playback_params: Optional[Any] = None
- self._callback: Optional[Callable] = None
- self._timestamp: int = 0
- self._playback_rate: float = 1.0
-
- def setSurface(self, surface: Any) -> None:
- self._surface = surface
-
- def setCallback(self, cb: Optional[Callable], handler: Any = None) -> None:
- self._callback = cb
-
- def getPlaybackParams(self) -> Any:
- return self._playback_params
-
- def setPlaybackParams(self, params: Any) -> None:
- self._playback_params = params
-
- def queueAudioBuffer(self, buffer_info: CodecBufferInfo, data: bytes,
- offset: int, size: int, presentation_time_us: int) -> None:
- pass
-
- def queueVideoBuffer(self, data: bytes, buffer_info: CodecBufferInfo,
- presentation_time_us: int) -> None:
- pass
-
- def render(self, presentation_time_us: int) -> bool:
- return True
-
- def flush(self) -> None:
- pass
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def release(self) -> None:
- pass
-
- def toString(self) -> str:
- return f"MediaSync(rate={self._playback_rate})"
-
-
-class MediaTimeProvider(Stub):
- """MediaTimeProvider — 媒体时间提供器"""
-
- def getTimeUs(self) -> int:
- return int(time.time() * 1000000)
-
-
-class TimedMetaData(Stub):
- """TimedMetaData — 定时元数据"""
-
- def __init__(self, timestamp_us: int = 0, meta_data: bytes = b""):
- super().__init__()
- self._timestamp_us = timestamp_us
- self._meta_data = meta_data
-
- def getTimestamp(self) -> int:
- return self._timestamp_us
-
- def getMetaData(self) -> bytes:
- return self._meta_data
-
- def toString(self) -> str:
- return (f"TimedMetaData(timestamp={self._timestamp_us}, "
- f"size={len(self._meta_data)})")
-
-
-class WebVttParser(Stub):
- """WebVttParser — WebVTT 字幕解析器"""
-
- def __init__(self):
- super().__init__()
- self._cues: List["WebVttCue"] = []
-
- def parse(self, data: str) -> List["WebVttCue"]:
- self._cues.clear()
- lines = data.split("\n")
- current_cue: Optional["WebVttCue"] = None
- for line in lines:
- line = line.strip()
- if line.startswith("WEBVTT"):
- continue
- if line == "":
- if current_cue is not None:
- self._cues.append(current_cue)
- current_cue = None
- continue
- if "-->" in line:
- parts = line.split("-->")
- start = self._parse_time(parts[0].strip())
- end = self._parse_time(parts[1].strip())
- current_cue = WebVttCue(start, end)
- elif current_cue is not None:
- current_cue.add_text(line)
- if current_cue is not None:
- self._cues.append(current_cue)
- return list(self._cues)
-
- def _parse_time(self, time_str: str) -> int:
- """将 HH:MM:SS.mmm 格式转换为微秒"""
- if ":" in time_str:
- parts = time_str.split(":")
- if len(parts) == 3:
- h, m, s = parts
- else:
- h = "0"
- m, s = parts
- sec_parts = s.split(".")
- seconds = int(sec_parts[0])
- millis = int(sec_parts[1]) if len(sec_parts) > 1 else 0
- total_ms = int(h) * 3600000 + int(m) * 60000 + seconds * 1000 + millis
- return total_ms * 1000
- return 0
-
- def getCues(self) -> List["WebVttCue"]:
- return list(self._cues)
-
- def clear(self) -> None:
- self._cues.clear()
-
-
-class WebVttCue(Stub):
- """WebVttCue — WebVTT 字幕提示"""
-
- def __init__(self, start_us: int = 0, end_us: int = 0, text: str = ""):
- super().__init__()
- self._start_us = start_us
- self._end_us = end_us
- self._text = text
-
- def add_text(self, text: str) -> None:
- if self._text:
- self._text += "\n" + text
- else:
- self._text = text
-
- def getStartTime(self) -> int:
- return self._start_us
-
- def getEndTime(self) -> int:
- return self._end_us
-
- def getText(self) -> str:
- return self._text
-
- def toString(self) -> str:
- return (f"WebVttCue(start={self._start_us}, "
- f"end={self._end_us}, text={self._text[:30]})")
\ No newline at end of file
diff --git a/android_pyapi/android/media_audio.py b/android_pyapi/android/media_audio.py
deleted file mode 100644
index 9ea7d89..0000000
--- a/android_pyapi/android/media_audio.py
+++ /dev/null
@@ -1,1538 +0,0 @@
-"""
-Android media 音频扩展组件 — AudioFormat, AudioTrack, AudioRecord, AudioDeviceInfo,
-AudioRouting, AudioManager, AudioMix, AudioProfile, AudioProductStrategy 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "AudioFormat", "AudioAttributes", "AudioTrack", "AudioRecord",
- "AudioDeviceInfo", "AudioDeviceCallback", "AudioRouting",
- "AudioTimestamp", "AudioPresentation", "AudioPlaybackConfiguration",
- "AudioRecordingConfiguration", "AudioManagerAudio", "AudioMixPort",
- "AudioPort", "AudioPatch", "AudioGain", "AudioGainConfig",
- "AudioMix", "AudioProfile", "AudioProductStrategy", "AudioVolumeGroup",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioFormat
-# ═══════════════════════════════════════════════════════════════
-
-class AudioFormat(Stub):
- """AudioFormat — 音频格式"""
-
- ENCODING_INVALID = 0
- ENCODING_DEFAULT = 1
- ENCODING_PCM_16BIT = 2
- ENCODING_PCM_8BIT = 3
- ENCODING_PCM_FLOAT = 4
- ENCODING_AC3 = 5
- ENCODING_E_AC3 = 6
- ENCODING_DTS = 7
- ENCODING_DTS_HD = 8
- ENCODING_MP3 = 9
- ENCODING_AAC_LC = 10
- ENCODING_AAC_HE_V1 = 11
- ENCODING_AAC_HE_V2 = 12
- ENCODING_PCM_24BIT_PACKED = 13
- ENCODING_PCM_32BIT = 14
- ENCODING_PCM_16BIT_BUNDLED = 15
- ENCODING_PCM_24BIT = 16
- ENCODING_DOLBY_TRUEHD = 17
- ENCODING_DOLBY_MAT = 18
- ENCODING_IEC61937 = 19
- ENCODING_OPUS = 20
- ENCODING_AMRNB = 21
- ENCODING_AMRWB = 22
- ENCODING_FLAC = 23
- ENCODING_MP2 = 24
- ENCODING_AC4 = 25
- ENCODING_AC3_PLUS = 26
- ENCODING_E_AC3_JOC = 27
- ENCODING_DOLBY_MAT_21 = 28
- ENCODING_DSD = 29
- ENCODING_PCM_8_24_BIT = 30
- ENCODING_WMA = 31
- ENCODING_WMA_PRO = 32
- ENCODING_ALAC = 33
- ENCODING_APE = 34
- ENCODING_VORBIS = 35
-
- CHANNEL_INVALID = 0
- CHANNEL_OUT_FRONT_LEFT = 0x4
- CHANNEL_OUT_FRONT_RIGHT = 0x8
- CHANNEL_OUT_FRONT_CENTER = 0x10
- CHANNEL_OUT_LOW_FREQUENCY = 0x20
- CHANNEL_OUT_BACK_LEFT = 0x40
- CHANNEL_OUT_BACK_RIGHT = 0x80
- CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100
- CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200
- CHANNEL_OUT_BACK_CENTER = 0x400
- CHANNEL_OUT_SIDE_LEFT = 0x800
- CHANNEL_OUT_SIDE_RIGHT = 0x1000
- CHANNEL_OUT_TOP_CENTER = 0x2000
- CHANNEL_OUT_TOP_FRONT_LEFT = 0x4000
- CHANNEL_OUT_TOP_FRONT_RIGHT = 0x8000
- CHANNEL_OUT_TOP_FRONT_CENTER = 0x10000
- CHANNEL_OUT_TOP_BACK_LEFT = 0x20000
- CHANNEL_OUT_TOP_BACK_RIGHT = 0x40000
- CHANNEL_OUT_TOP_BACK_CENTER = 0x80000
- CHANNEL_OUT_MONO = 0x4
- CHANNEL_OUT_STEREO = 0xC
- CHANNEL_OUT_QUAD = 0xCC
- CHANNEL_OUT_SURROUND = 0x41C
- CHANNEL_OUT_5POINT1 = 0xFC
- CHANNEL_OUT_7POINT1 = 0x4FC
- CHANNEL_OUT_5POINT1_SIDE = 0x8FC
- CHANNEL_OUT_7POINT1_SURROUND = 0x18FC
-
- CHANNEL_IN_LEFT = 0x4
- CHANNEL_IN_RIGHT = 0x8
- CHANNEL_IN_FRONT = 0x10
- CHANNEL_IN_BACK = 0x40
- CHANNEL_IN_LEFT_PROCESSED = 0x20
- CHANNEL_IN_RIGHT_PROCESSED = 0x80
- CHANNEL_IN_FRONT_PROCESSED = 0x100
- CHANNEL_IN_BACK_PROCESSED = 0x200
- CHANNEL_IN_PRESSURE = 0x400
- CHANNEL_IN_X_AXIS = 0x800
- CHANNEL_IN_Y_AXIS = 0x1000
- CHANNEL_IN_Z_AXIS = 0x2000
- CHANNEL_IN_VOICE_UPLINK = 0x4000
- CHANNEL_IN_VOICE_DNLINK = 0x8000
- CHANNEL_IN_MONO = 0x10
- CHANNEL_IN_STEREO = 0xC
- CHANNEL_IN_DEFAULT = 0x1
-
- SAMPLE_RATE_UNSPECIFIED = 0
-
- class Builder(Stub):
- """AudioFormat.Builder — 音频格式构建器"""
-
- def __init__(self):
- super().__init__()
- self._encoding = AudioFormat.ENCODING_DEFAULT
- self._sample_rate = AudioFormat.SAMPLE_RATE_UNSPECIFIED
- self._channel_mask = AudioFormat.CHANNEL_INVALID
- self._channel_index_mask = 0
-
- def setEncoding(self, encoding: int) -> "AudioFormat.Builder":
- self._encoding = encoding
- return self
-
- def setSampleRate(self, sampleRate: int) -> "AudioFormat.Builder":
- self._sample_rate = sampleRate
- return self
-
- def setChannelMask(self, channelMask: int) -> "AudioFormat.Builder":
- self._channel_mask = channelMask
- return self
-
- def setChannelIndexMask(self, channelIndexMask: int) -> "AudioFormat.Builder":
- self._channel_index_mask = channelIndexMask
- return self
-
- def build(self) -> "AudioFormat":
- fmt = AudioFormat()
- fmt._encoding = self._encoding
- fmt._sample_rate = self._sample_rate
- fmt._channel_mask = self._channel_mask
- fmt._channel_index_mask = self._channel_index_mask
- return fmt
-
- def __init__(self):
- super().__init__()
- self._encoding = AudioFormat.ENCODING_DEFAULT
- self._sample_rate = AudioFormat.SAMPLE_RATE_UNSPECIFIED
- self._channel_mask = AudioFormat.CHANNEL_INVALID
- self._channel_index_mask = 0
-
- def getEncoding(self) -> int:
- return self._encoding
-
- def getSampleRate(self) -> int:
- return self._sample_rate
-
- def getChannelMask(self) -> int:
- return self._channel_mask
-
- def getChannelIndexMask(self) -> int:
- return self._channel_index_mask
-
- def getChannelCount(self) -> int:
- mask = self._channel_mask
- if mask == AudioFormat.CHANNEL_INVALID:
- return 0
- return bin(mask).count("1")
-
- def toString(self) -> str:
- return (f"AudioFormat(encoding={self._encoding}, "
- f"sampleRate={self._sample_rate}, channels={self.getChannelCount()})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioFormat):
- return False
- return (self._encoding == other._encoding and
- self._sample_rate == other._sample_rate and
- self._channel_mask == other._channel_mask)
-
- def hashCode(self) -> int:
- return hash((self._encoding, self._sample_rate, self._channel_mask)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioAttributes (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class AudioAttributes(Stub):
- """AudioAttributes — 音频属性 (完整版)"""
-
- CONTENT_TYPE_UNKNOWN = 0
- CONTENT_TYPE_SPEECH = 1
- CONTENT_TYPE_MUSIC = 2
- CONTENT_TYPE_MOVIE = 3
- CONTENT_TYPE_SONIFICATION = 4
-
- USAGE_UNKNOWN = 0
- USAGE_MEDIA = 1
- USAGE_VOICE_COMMUNICATION = 2
- USAGE_VOICE_COMMUNICATION_SIGNALLING = 3
- USAGE_ALARM = 4
- USAGE_NOTIFICATION = 5
- USAGE_NOTIFICATION_RINGTONE = 6
- USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7
- USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8
- USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9
- USAGE_NOTIFICATION_EVENT = 10
- USAGE_ASSISTANCE_ACCESSIBILITY = 11
- USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12
- USAGE_ASSISTANCE_SONIFICATION = 13
- USAGE_GAME = 14
- USAGE_VIRTUAL_SOURCE = 15
- USAGE_ASSISTANT = 16
- USAGE_CALL_ASSISTANT = 17
- USAGE_EMERGENCY = 18
- USAGE_SAFETY = 19
- USAGE_VEHICLE_STATUS = 20
- USAGE_ANNOUNCEMENT = 21
-
- FLAG_AUDIBILITY_ENFORCED = 1
- FLAG_SECURE = 2
- FLAG_SCO = 4
- FLAG_BEACON = 8
- FLAG_BYPASS_INTERRUPTION_POLICY = 16
- FLAG_BYPASS_MUTE = 32
- FLAG_LOW_LATENCY = 64
- FLAG_DEEP_BUFFER = 128
- FLAG_NO_EXPANDABLE = 256
- FLAG_HW_AV_SYNC = 512
- FLAG_BYPASS_INTERRUPTION_POLICY_FLAG = 1024
-
- ALLOW_CAPTURE_BY_ALL = 0
- ALLOW_CAPTURE_BY_SYSTEM = 1
- ALLOW_CAPTURE_BY_NONE = 2
-
- class Builder(Stub):
- """AudioAttributes.Builder — 音频属性构建器"""
-
- def __init__(self):
- super().__init__()
- self._content_type = AudioAttributes.CONTENT_TYPE_UNKNOWN
- self._usage = AudioAttributes.USAGE_UNKNOWN
- self._flags = 0
- self._legacy_stream_type = -1
- self._allowed_capture_policy = AudioAttributes.ALLOW_CAPTURE_BY_ALL
- self._spatial_behavior = 0
-
- def setContentType(self, contentType: int) -> "AudioAttributes.Builder":
- self._content_type = contentType
- return self
-
- def setUsage(self, usage: int) -> "AudioAttributes.Builder":
- self._usage = usage
- return self
-
- def setFlags(self, flags: int) -> "AudioAttributes.Builder":
- self._flags = flags
- return self
-
- def setLegacyStreamType(self, streamType: int) -> "AudioAttributes.Builder":
- self._legacy_stream_type = streamType
- return self
-
- def setAllowedCapturePolicy(self, capturePolicy: int) -> "AudioAttributes.Builder":
- self._allowed_capture_policy = capturePolicy
- return self
-
- def setSpatialBehavior(self, spatialBehavior: int) -> "AudioAttributes.Builder":
- self._spatial_behavior = spatialBehavior
- return self
-
- def build(self) -> "AudioAttributes":
- attrs = AudioAttributes()
- attrs._content_type = self._content_type
- attrs._usage = self._usage
- attrs._flags = self._flags
- attrs._legacy_stream_type = self._legacy_stream_type
- attrs._allowed_capture_policy = self._allowed_capture_policy
- attrs._spatial_behavior = self._spatial_behavior
- return attrs
-
- def __init__(self):
- super().__init__()
- self._content_type = AudioAttributes.CONTENT_TYPE_UNKNOWN
- self._usage = AudioAttributes.USAGE_UNKNOWN
- self._flags = 0
- self._legacy_stream_type = -1
- self._allowed_capture_policy = AudioAttributes.ALLOW_CAPTURE_BY_ALL
- self._spatial_behavior = 0
-
- def getContentType(self) -> int:
- return self._content_type
-
- def getUsage(self) -> int:
- return self._usage
-
- def getFlags(self) -> int:
- return self._flags
-
- def getAllowedCapturePolicy(self) -> int:
- return self._allowed_capture_policy
-
- def getSpatialBehavior(self) -> int:
- return self._spatial_behavior
-
- def getVolumeControlStream(self) -> int:
- if self._usage in (AudioAttributes.USAGE_VOICE_COMMUNICATION,
- AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING):
- return 0
- if self._usage == AudioAttributes.USAGE_ALARM:
- return 4
- if self._usage in (AudioAttributes.USAGE_NOTIFICATION,
- AudioAttributes.USAGE_NOTIFICATION_RINGTONE,
- AudioAttributes.USAGE_NOTIFICATION_EVENT):
- return 5
- if self._usage in (AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
- AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
- AudioAttributes.USAGE_ASSISTANCE_SONIFICATION):
- return 3
- return 3
-
- toString = lambda self: f"AudioAttributes(usage={self._usage}, contentType={self._content_type})"
- equals = lambda self, other: self is other if not isinstance(other, AudioAttributes) else (self._usage == other._usage and self._content_type == other._content_type)
- hashCode = lambda self: hash((self._usage, self._content_type)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioTimestamp
-# ═══════════════════════════════════════════════════════════════
-
-class AudioTimestamp(Stub):
- """AudioTimestamp — 音频时间戳"""
-
- TIMEBASE_MONOTONIC = 0
- TIMEBASE_BOOTTIME = 1
-
- def __init__(self):
- super().__init__()
- self.framePosition: int = 0
- self.nanoTime: int = 0
-
- def toString(self) -> str:
- return f"AudioTimestamp(frame={self.framePosition}, nanoTime={self.nanoTime})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioTimestamp):
- return False
- return self.framePosition == other.framePosition and self.nanoTime == other.nanoTime
-
- def hashCode(self) -> int:
- return hash((self.framePosition, self.nanoTime)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioPresentation
-# ═══════════════════════════════════════════════════════════════
-
-class AudioPresentation(Stub):
- """AudioPresentation — 音频呈现"""
-
- CONTENT_TYPE_UNKNOWN = 0
- CONTENT_TYPE_DIALOG = 1
- CONTENT_TYPE_MUSIC = 2
- CONTENT_TYPE_VOICEOVER = 3
- CONTENT_TYPE_NARRATION = 4
- CONTENT_TYPE_VISUALLY_IMPAIRED = 5
- CONTENT_TYPE_HEARING_IMPAIRED = 6
- CONTENT_TYPE_COMMENTARY = 7
- CONTENT_TYPE_SPOKEN_SUBTITLE = 8
- CONTENT_TYPE_EMERGENCY = 9
- CONTENT_TYPE_MAIN = 10
- CONTENT_TYPE_SUPPLEMENTARY = 11
-
- MASTERED_FOR_STEREO = 0
- MASTERED_FOR_SURROUND = 1
- MASTERED_FOR_3D = 2
- MASTERED_FOR_HEADPHONE = 3
-
- def __init__(self, presentationId: int = 0, programId: int = 0,
- locale: str = "", contentType: int = CONTENT_TYPE_UNKNOWN,
- masteredFor: int = MASTERED_FOR_STEREO,
- labels: Dict[str, str] = None):
- super().__init__()
- self._presentation_id = presentationId
- self._program_id = programId
- self._locale = locale
- self._content_type = contentType
- self._mastered_for = masteredFor
- self._labels = labels or {}
-
- def getPresentationId(self) -> int:
- return self._presentation_id
-
- def getProgramId(self) -> int:
- return self._program_id
-
- def getLocale(self) -> str:
- return self._locale
-
- def getContentType(self) -> int:
- return self._content_type
-
- def getMasteredFor(self) -> int:
- return self._mastered_for
-
- def getLabels(self) -> Dict[str, str]:
- return dict(self._labels)
-
- def toString(self) -> str:
- return f"AudioPresentation(id={self._presentation_id}, locale={self._locale})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioPresentation):
- return False
- return self._presentation_id == other._presentation_id
-
- def hashCode(self) -> int:
- return self._presentation_id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioTrack
-# ═══════════════════════════════════════════════════════════════
-
-class AudioTrack(Stub):
- """AudioTrack — 音频回放轨道"""
-
- MODE_STATIC = 0
- MODE_STREAM = 1
-
- STATE_UNINITIALIZED = 0
- STATE_INITIALIZED = 1
- STATE_NO_STATIC_DATA = 2
-
- WRITE_BLOCKING = 0
- SUCCESS = 0
- ERROR = -1
- ERROR_BAD_VALUE = -2
- ERROR_INVALID_OPERATION = -3
- ERROR_DEAD_OBJECT = -6
- ERROR_WOULD_BLOCK = -7
-
- PERFORMANCE_MODE_NONE = 0
- PERFORMANCE_MODE_LOW_LATENCY = 1
- PERFORMANCE_MODE_POWER_SAVING = 2
-
- class Builder(Stub):
- """AudioTrack.Builder — 回放轨道构建器"""
-
- def __init__(self):
- super().__init__()
- self._audio_format = None
- self._audio_attributes = None
- self._buffer_size = 0
- self._session_id = 0
- self._transfer_mode = AudioTrack.MODE_STREAM
- self._performance_mode = AudioTrack.PERFORMANCE_MODE_NONE
- self._context = None
-
- def setAudioFormat(self, format_: AudioFormat) -> "AudioTrack.Builder":
- self._audio_format = format_
- return self
-
- def setAudioAttributes(self, attributes: AudioAttributes) -> "AudioTrack.Builder":
- self._audio_attributes = attributes
- return self
-
- def setBufferSizeInBytes(self, bufferSize: int) -> "AudioTrack.Builder":
- self._buffer_size = bufferSize
- return self
-
- def setSessionId(self, sessionId: int) -> "AudioTrack.Builder":
- self._session_id = sessionId
- return self
-
- def setTransferMode(self, mode: int) -> "AudioTrack.Builder":
- self._transfer_mode = mode
- return self
-
- def setPerformanceMode(self, mode: int) -> "AudioTrack.Builder":
- self._performance_mode = mode
- return self
-
- def build(self) -> "AudioTrack":
- return AudioTrack(
- format_=self._audio_format,
- attributes=self._audio_attributes,
- bufferSize=self._buffer_size,
- sessionId=self._session_id,
- mode=self._transfer_mode,
- performanceMode=self._performance_mode,
- )
-
- def __init__(self, format_: Any = None, attributes: Any = None,
- bufferSize: int = 0, sessionId: int = 0,
- mode: int = MODE_STREAM, performanceMode: int = PERFORMANCE_MODE_NONE,
- sampleRate: int = 44100, channelConfig: int = AudioFormat.CHANNEL_OUT_STEREO,
- audioFormat: int = AudioFormat.ENCODING_PCM_16BIT):
- super().__init__()
- self._state = AudioTrack.STATE_INITIALIZED
- self._sample_rate = sampleRate
- self._channel_config = channelConfig
- self._audio_format = audioFormat
- self._buffer_size = bufferSize if bufferSize > 0 else 4096
- self._mode = mode
- self._session_id = sessionId
- self._performance_mode = performanceMode
- self._playback_rate = 1.0
- self._volume = 1.0
- self._position = 0
- self._is_playing = False
- self._audio_attributes = attributes
- self._format = format_
- self._timestamp = AudioTimestamp()
-
- def play(self):
- self._is_playing = True
-
- def stop(self):
- self._is_playing = False
-
- def pause(self):
- self._is_playing = False
-
- def flush(self):
- self._position = 0
-
- def release(self):
- self._state = AudioTrack.STATE_UNINITIALIZED
- self._is_playing = False
-
- def write(self, audioData: Any, offsetInBytes: int = 0, sizeInBytes: int = 0) -> int:
- if self._state != AudioTrack.STATE_INITIALIZED:
- return AudioTrack.ERROR_INVALID_OPERATION
- if isinstance(audioData, (bytes, bytearray)):
- written = sizeInBytes if sizeInBytes > 0 else len(audioData)
- self._position += written
- return written
- if hasattr(audioData, 'nbytes'):
- written = sizeInBytes or audioData.nbytes
- self._position += written
- return written
- return AudioTrack.ERROR_BAD_VALUE
-
- def getMinBufferSize(sampleRateInHz: int, channelConfig: int, audioFormat: int) -> int:
- return 4096
-
- def getNativeOutputSampleRate(streamType: int) -> int:
- return 44100
-
- def getSampleRate(self) -> int:
- return self._sample_rate
-
- def getPlaybackRate(self) -> float:
- return self._playback_rate
-
- def setPlaybackRate(self, rate: float):
- self._playback_rate = rate
-
- def getVolume(self) -> float:
- return self._volume
-
- def setVolume(self, volume: float):
- self._volume = max(0.0, min(1.0, volume))
-
- def getAudioFormat(self) -> int:
- return self._audio_format
-
- def getChannelConfiguration(self) -> int:
- return self._channel_config
-
- def getChannelCount(self) -> int:
- return bin(self._channel_config).count("1")
-
- def getState(self) -> int:
- return self._state
-
- def getPlayState(self) -> int:
- return 3 if self._is_playing else 2
-
- def getBufferSizeInFrames(self) -> int:
- return self._buffer_size // 4
-
- def getTimestamp(self, outTimestamp: AudioTimestamp) -> int:
- base_time = time.time_ns()
- outTimestamp.nanoTime = base_time
- outTimestamp.framePosition = self._position
- return AudioTrack.SUCCESS
-
- def getSessionId(self) -> int:
- return self._session_id
-
- def getPerformanceMode(self) -> int:
- return self._performance_mode
-
- def setPreferredDevice(self, deviceInfo: Any) -> bool:
- return True
-
- def getPreferredDevice(self) -> Optional[Any]:
- return None
-
- def toString(self) -> str:
- return (f"AudioTrack(sampleRate={self._sample_rate}, "
- f"playing={self._is_playing}, state={self._state})")
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioRecord
-# ═══════════════════════════════════════════════════════════════
-
-class AudioRecord(Stub):
- """AudioRecord — 音频录制"""
-
- STATE_UNINITIALIZED = 0
- STATE_INITIALIZED = 1
-
- SUCCESS = 0
- ERROR = -1
- ERROR_BAD_VALUE = -2
- ERROR_INVALID_OPERATION = -3
- ERROR_DEAD_OBJECT = -6
-
- READ_BLOCKING = 0
- READ_NON_BLOCKING = 1
-
- class Builder(Stub):
- """AudioRecord.Builder — 录制构建器"""
-
- def __init__(self):
- super().__init__()
- self._audio_format = None
- self._audio_attributes = None
- self._buffer_size = 0
- self._session_id = 0
- self._context = None
-
- def setAudioFormat(self, format_: AudioFormat) -> "AudioRecord.Builder":
- self._audio_format = format_
- return self
-
- def setAudioAttributes(self, attributes: AudioAttributes) -> "AudioRecord.Builder":
- self._audio_attributes = attributes
- return self
-
- def setBufferSizeInBytes(self, bufferSize: int) -> "AudioRecord.Builder":
- self._buffer_size = bufferSize
- return self
-
- def setSessionId(self, sessionId: int) -> "AudioRecord.Builder":
- self._session_id = sessionId
- return self
-
- def build(self) -> "AudioRecord":
- return AudioRecord(
- format_=self._audio_format,
- attributes=self._audio_attributes,
- bufferSize=self._buffer_size,
- sessionId=self._session_id,
- )
-
- def __init__(self, format_: Any = None, attributes: Any = None,
- bufferSize: int = 0, sessionId: int = 0,
- sampleRate: int = 44100, channelConfig: int = AudioFormat.CHANNEL_IN_MONO,
- audioFormat: int = AudioFormat.ENCODING_PCM_16BIT):
- super().__init__()
- self._state = AudioRecord.STATE_INITIALIZED
- self._sample_rate = sampleRate
- self._channel_config = channelConfig
- self._audio_format = audioFormat
- self._buffer_size = bufferSize if bufferSize > 0 else 4096
- self._session_id = sessionId
- self._is_recording = False
- self._position = 0
- self._format = format_
- self._audio_attributes = attributes
-
- def startRecording(self):
- self._is_recording = True
-
- def stop(self):
- self._is_recording = False
-
- def release(self):
- self._state = AudioRecord.STATE_UNINITIALIZED
- self._is_recording = False
-
- def read(self, audioData: Any, offsetInBytes: int = 0, sizeInBytes: int = 0) -> int:
- if not self._is_recording:
- return AudioRecord.ERROR_INVALID_OPERATION
- return sizeInBytes if sizeInBytes > 0 else 0
-
- def getMinBufferSize(sampleRateInHz: int, channelConfig: int, audioFormat: int) -> int:
- return 4096
-
- def getSampleRate(self) -> int:
- return self._sample_rate
-
- def getAudioFormat(self) -> int:
- return self._audio_format
-
- def getChannelConfiguration(self) -> int:
- return self._channel_config
-
- def getChannelCount(self) -> int:
- return bin(self._channel_config).count("1")
-
- def getState(self) -> int:
- return self._state
-
- def getRecordingState(self) -> int:
- return 3 if self._is_recording else 2
-
- def getBufferSizeInFrames(self) -> int:
- return self._buffer_size // 4
-
- def getSessionId(self) -> int:
- return self._session_id
-
- def setPreferredDevice(self, deviceInfo: Any) -> bool:
- return True
-
- def getPreferredDevice(self) -> Optional[Any]:
- return None
-
- def toString(self) -> str:
- return f"AudioRecord(sampleRate={self._sample_rate}, recording={self._is_recording})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioDeviceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class AudioDeviceInfo(Stub):
- """AudioDeviceInfo — 音频设备信息"""
-
- TYPE_UNKNOWN = 0
- TYPE_BUILTIN_EARPIECE = 1
- TYPE_BUILTIN_SPEAKER = 2
- TYPE_WIRED_HEADSET = 3
- TYPE_WIRED_HEADPHONES = 4
- TYPE_LINE_ANALOG = 5
- TYPE_LINE_DIGITAL = 6
- TYPE_BLUETOOTH_SCO = 7
- TYPE_BLUETOOTH_A2DP = 8
- TYPE_HDMI = 9
- TYPE_HDMI_ARC = 10
- TYPE_USB_DEVICE = 11
- TYPE_USB_ACCESSORY = 12
- TYPE_DOCK = 13
- TYPE_FM = 14
- TYPE_BUILTIN_MIC = 15
- TYPE_FM_TUNER = 16
- TYPE_TV_TUNER = 17
- TYPE_TELEPHONY = 18
- TYPE_AUX_LINE = 19
- TYPE_IP = 20
- TYPE_BUS = 21
- TYPE_USB_HEADSET = 22
- TYPE_HEARING_AID = 23
- TYPE_BUILTIN_SPEAKER_SAFE = 24
- TYPE_REMOTE_SUBMIX = 25
- TYPE_BLE_HEADSET = 26
- TYPE_BLE_SPEAKER = 27
- TYPE_BLE_BROADCAST = 28
-
- def __init__(self, id: int = 0, type_: int = TYPE_UNKNOWN,
- productName: str = "", address: str = "",
- isSource: bool = False, isSink: bool = False,
- sampleRates: List[int] = None,
- channelMasks: List[int] = None,
- encodings: List[int] = None):
- super().__init__()
- self._id = id
- self._type = type_
- self._product_name = productName
- self._address = address
- self._is_source = isSource
- self._is_sink = isSink
- self._sample_rates = sampleRates or [44100, 48000]
- self._channel_masks = channelMasks or [AudioFormat.CHANNEL_OUT_STEREO]
- self._encodings = encodings or [AudioFormat.ENCODING_PCM_16BIT]
-
- def getId(self) -> int:
- return self._id
-
- def getType(self) -> int:
- return self._type
-
- def getProductName(self) -> Any:
- return self._product_name
-
- def getAddress(self) -> str:
- return self._address
-
- def isSource(self) -> bool:
- return self._is_source
-
- def isSink(self) -> bool:
- return self._is_sink
-
- def getSampleRates(self) -> List[int]:
- return list(self._sample_rates)
-
- def getChannelMasks(self) -> List[int]:
- return list(self._channel_masks)
-
- def getEncodings(self) -> List[int]:
- return list(self._encodings)
-
- def getChannelCounts(self) -> List[int]:
- return [bin(m).count("1") for m in self._channel_masks]
-
- def toString(self) -> str:
- type_names = {
- 1: "BUILTIN_EARPIECE", 2: "BUILTIN_SPEAKER", 3: "WIRED_HEADSET",
- 4: "WIRED_HEADPHONES", 8: "BTSCO", 9: "HDMI", 11: "USB_DEVICE",
- }
- return (f"AudioDeviceInfo(id={self._id}, "
- f"type={type_names.get(self._type, str(self._type))})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioDeviceInfo):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioDeviceCallback
-# ═══════════════════════════════════════════════════════════════
-
-class AudioDeviceCallback(Stub):
- """AudioDeviceCallback — 音频设备回调"""
-
- def onAudioDevicesAdded(self, addedDevices: List[AudioDeviceInfo]):
- pass
-
- def onAudioDevicesRemoved(self, removedDevices: List[AudioDeviceInfo]):
- pass
-
- def toString(self) -> str:
- return f"AudioDeviceCallback@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioRouting
-# ═══════════════════════════════════════════════════════════════
-
-class AudioRouting(Stub):
- """AudioRouting — 音频路由接口"""
-
- def setPreferredDevice(self, deviceInfo: AudioDeviceInfo) -> bool:
- raise NotImplementedError
-
- def getPreferredDevice(self) -> Optional[AudioDeviceInfo]:
- return None
-
- def getDevices(self, flags: int) -> List[AudioDeviceInfo]:
- return []
-
- def addOnRoutingPrefChangedListener(self, listener: Any, handler: Any = None):
- pass
-
- def removeOnRoutingPrefChangedListener(self, listener: Any):
- pass
-
- def toString(self) -> str:
- return f"AudioRouting@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioPlaybackConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class AudioPlaybackConfiguration(Stub):
- """AudioPlaybackConfiguration — 音频回放配置"""
-
- PLAYER_STATE_UNKNOWN = -1
- PLAYER_STATE_IDLE = 0
- PLAYER_STATE_STARTED = 1
- PLAYER_STATE_PAUSED = 2
- PLAYER_STATE_STOPPED = 3
-
- def __init__(self, id_: int = 0, usage: int = AudioAttributes.USAGE_MEDIA,
- contentType: int = AudioAttributes.CONTENT_TYPE_MUSIC,
- playerState: int = PLAYER_STATE_UNKNOWN):
- super().__init__()
- self._id = id_
- self._usage = usage
- self._content_type = contentType
- self._player_state = playerState
-
- def getId(self) -> int:
- return self._id
-
- def getUsage(self) -> int:
- return self._usage
-
- def getContentType(self) -> int:
- return self._content_type
-
- def getPlayerState(self) -> int:
- return self._player_state
-
- def toString(self) -> str:
- return f"AudioPlaybackConfiguration(id={self._id}, state={self._player_state})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioPlaybackConfiguration):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioRecordingConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class AudioRecordingConfiguration(Stub):
- """AudioRecordingConfiguration — 音频录制配置"""
-
- def __init__(self, id_: int = 0, clientUid: int = 0,
- sessionId: int = 0, source: int = 0,
- audioFormat: Optional[AudioFormat] = None):
- super().__init__()
- self._id = id_
- self._client_uid = clientUid
- self._session_id = sessionId
- self._source = source
- self._audio_format = audioFormat or AudioFormat()
-
- def getId(self) -> int:
- return self._id
-
- def getClientUid(self) -> int:
- return self._client_uid
-
- def getSessionId(self) -> int:
- return self._session_id
-
- def getSource(self) -> int:
- return self._source
-
- def getAudioFormat(self) -> AudioFormat:
- return self._audio_format
-
- def toString(self) -> str:
- return f"AudioRecordingConfiguration(id={self._id}, source={self._source})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioRecordingConfiguration):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioManagerAudio (扩展音频管理器)
-# ═══════════════════════════════════════════════════════════════
-
-class AudioManagerAudio(Stub):
- """AudioManager — 音频管理器 (扩展版)"""
-
- STREAM_VOICE_CALL = 0
- STREAM_SYSTEM = 1
- STREAM_RING = 2
- STREAM_MUSIC = 3
- STREAM_ALARM = 4
- STREAM_NOTIFICATION = 5
- STREAM_BLUETOOTH_SCO = 6
- STREAM_SYSTEM_ENFORCED = 7
- STREAM_DTMF = 8
- STREAM_TTS = 9
- STREAM_ACCESSIBILITY = 10
-
- FLAG_SHOW_UI = 1
- FLAG_ALLOW_RINGER_MODES = 2
- FLAG_PLAY_SOUND = 4
- FLAG_REMOVE_SOUND_AND_VIBRATE = 8
- FLAG_VIBRATE = 16
- FLAG_BYPASS_INTERRUPTION_POLICY = 32
- FLAG_BYPASS_MUTE = 64
- FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 128
- FLAG_FIXED_VOLUME = 256
-
- MODE_INVALID = -2
- MODE_CURRENT = -1
- MODE_NORMAL = 0
- MODE_RINGTONE = 1
- MODE_IN_CALL = 2
- MODE_IN_COMMUNICATION = 3
-
- DEVICE_OUT_EARPIECE = 0x1
- DEVICE_OUT_SPEAKER = 0x2
- DEVICE_OUT_WIRED_HEADSET = 0x4
- DEVICE_OUT_WIRED_HEADPHONE = 0x8
- DEVICE_OUT_BLUETOOTH_SCO = 0x10
- DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20
- DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40
- DEVICE_OUT_BLUETOOTH_A2DP = 0x80
- DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100
- DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200
- DEVICE_OUT_AUX_DIGITAL = 0x400
- DEVICE_OUT_HDMI = 0x800
- DEVICE_OUT_ANLG_DOCK_HEADSET = 0x1000
- DEVICE_OUT_DGTL_DOCK_HEADSET = 0x2000
- DEVICE_OUT_USB_ACCESSORY = 0x4000
- DEVICE_OUT_USB_DEVICE = 0x8000
- DEVICE_OUT_USB_HEADSET = 0x10000
- DEVICE_OUT_LINE = 0x20000
- DEVICE_OUT_HDMI_ARC = 0x40000
- DEVICE_OUT_HDMI_EARC = 0x80000
- DEVICE_OUT_BLE_HEADSET = 0x100000
- DEVICE_OUT_BLE_SPEAKER = 0x200000
- DEVICE_OUT_REMOTE_SUBMIX = 0x800000
-
- DEVICE_IN_BUILTIN_MIC = 0x80000004
- DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000010
- DEVICE_IN_WIRED_HEADSET = 0x80000020
- DEVICE_IN_HDMI = 0x80000040
- DEVICE_IN_LINE = 0x80000080
- DEVICE_IN_USB_ACCESSORY = 0x80000100
- DEVICE_IN_USB_DEVICE = 0x80000200
- DEVICE_IN_BLUETOOTH_A2DP = 0x80000400
- DEVICE_IN_USB_HEADSET = 0x80000800
- DEVICE_IN_BLE_HEADSET = 0x80001000
- DEVICE_IN_REMOTE_SUBMIX = 0x80002000
-
- FORMAT_DEFAULT = 0
- FORMAT_PCM_16_BIT = 1
- FORMAT_PCM_8_BIT = 2
- FORMAT_PCM_FLOAT = 4
- FORMAT_AC3 = 5
- FORMAT_E_AC3 = 6
- FORMAT_DTS = 7
- FORMAT_DTS_HD = 8
-
- def __init__(self):
- super().__init__()
- self._volumes: Dict[int, int] = {
- AudioManagerAudio.STREAM_MUSIC: 10,
- AudioManagerAudio.STREAM_RING: 7,
- AudioManagerAudio.STREAM_ALARM: 10,
- AudioManagerAudio.STREAM_NOTIFICATION: 7,
- AudioManagerAudio.STREAM_SYSTEM: 7,
- AudioManagerAudio.STREAM_VOICE_CALL: 5,
- }
- self._muted: Dict[int, bool] = {}
- self._mode = AudioManagerAudio.MODE_NORMAL
- self._microphone_muted = False
- self._speakerphone_on = False
- self._master_volume = 1.0
- self._master_mute = False
- self._device_callbacks: List[AudioDeviceCallback] = []
- self._devices: List[AudioDeviceInfo] = []
- self._routed_devices: Dict[int, int] = {}
-
- def getStreamVolume(self, streamType: int) -> int:
- return self._volumes.get(streamType, 0)
-
- def setStreamVolume(self, streamType: int, index: int, flags: int = 0):
- self._volumes[streamType] = max(0, min(index, self.getStreamMaxVolume(streamType)))
-
- def getStreamMaxVolume(self, streamType: int) -> int:
- return 15
-
- def getStreamMinVolume(self, streamType: int) -> int:
- return 0
-
- def isStreamMute(self, streamType: int) -> bool:
- return self._muted.get(streamType, False)
-
- def setStreamMute(self, streamType: int, state: bool):
- self._muted[streamType] = state
-
- def adjustVolume(self, direction: int, flags: int = 0):
- pass
-
- def adjustStreamVolume(self, streamType: int, direction: int, flags: int = 0):
- current = self.getStreamVolume(streamType)
- if direction == 1:
- self.setStreamVolume(streamType, current + 1, flags)
- elif direction == -1:
- self.setStreamVolume(streamType, current - 1, flags)
-
- def getMode(self) -> int:
- return self._mode
-
- def setMode(self, mode: int):
- self._mode = mode
-
- def isMicrophoneMute(self) -> bool:
- return self._microphone_muted
-
- def setMicrophoneMute(self, on: bool):
- self._microphone_muted = on
-
- def isSpeakerphoneOn(self) -> bool:
- return self._speakerphone_on
-
- def setSpeakerphoneOn(self, on: bool):
- self._speakerphone_on = on
-
- def getMasterVolume(self) -> float:
- return self._master_volume
-
- def setMasterVolume(self, volume: float):
- self._master_volume = max(0.0, min(1.0, volume))
-
- def isMasterMute(self) -> bool:
- return self._master_mute
-
- def setMasterMute(self, mute: bool):
- self._master_mute = mute
-
- def getDevices(self, flags: int) -> List[AudioDeviceInfo]:
- return list(self._devices)
-
- def setPreferredDeviceForStrategy(self, strategy: int, device: AudioDeviceInfo) -> bool:
- self._routed_devices[strategy] = device.getId() if device else -1
- return True
-
- def registerAudioDeviceCallback(self, callback: AudioDeviceCallback, handler: Any = None):
- self._device_callbacks.append(callback)
-
- def unregisterAudioDeviceCallback(self, callback: AudioDeviceCallback):
- self._device_callbacks = [cb for cb in self._device_callbacks if cb is not callback]
-
- def getAudioPlaybackConfigurations(self) -> List[AudioPlaybackConfiguration]:
- return []
-
- def getAudioRecordingConfigurations(self) -> List[AudioRecordingConfiguration]:
- return []
-
- def generateAudioSessionId() -> int:
- return int(time.time() * 1000) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"AudioManager(mode={self._mode}, masterVol={self._master_volume})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioMixPort / AudioPort / AudioPatch / AudioGain / AudioGainConfig
-# ═══════════════════════════════════════════════════════════════
-
-class AudioPort(Stub):
- """AudioPort — 音频端口"""
-
- ROLE_NONE = 0
- ROLE_SOURCE = 1
- ROLE_SINK = 2
-
- TYPE_NONE = 0
- TYPE_DEVICE = 1
- TYPE_SUBMIX = 2
- TYPE_SESSION = 3
-
- def __init__(self, id_: int = 0, name: str = "",
- role: int = ROLE_NONE, type_: int = TYPE_NONE,
- gains: List["AudioGain"] = None):
- super().__init__()
- self._id = id_
- self._name = name
- self._role = role
- self._type = type_
- self._gains = gains or []
-
- def getId(self) -> int:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getRole(self) -> int:
- return self._role
-
- def type(self) -> int:
- return self._type
-
- def gains(self) -> List["AudioGain"]:
- return list(self._gains)
-
- def toString(self) -> str:
- return f"AudioPort(id={self._id}, name={self._name})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioPort):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-class AudioMixPort(AudioPort):
- """AudioMixPort — 音频混合端口"""
-
- def __init__(self, id_: int = 0, name: str = "",
- role: int = AudioPort.ROLE_NONE,
- gains: List["AudioGain"] = None):
- super().__init__(id_=id_, name=name, role=role,
- type_=AudioPort.TYPE_SUBMIX, gains=gains)
-
- def toString(self) -> str:
- return f"AudioMixPort(id={self._id}, name={self._name})"
-
-
-class AudioGain(Stub):
- """AudioGain — 音频增益"""
-
- MODE_JOINT = 1
- MODE_CHANNELS = 2
- MODE_RAMP = 4
-
- def __init__(self, id_: int = 0, mode: int = MODE_JOINT,
- channelMask: int = 0, minValue: int = 0,
- maxValue: int = 100, defaultValue: int = 50,
- stepValue: int = 1, minRampMs: int = 0, maxRampMs: int = 0):
- super().__init__()
- self._id = id_
- self._mode = mode
- self._channel_mask = channelMask
- self._min_value = minValue
- self._max_value = maxValue
- self._default_value = defaultValue
- self._step_value = stepValue
- self._min_ramp_ms = minRampMs
- self._max_ramp_ms = maxRampMs
-
- def mode(self) -> int:
- return self._mode
-
- def channelMask(self) -> int:
- return self._channel_mask
-
- def minValue(self) -> int:
- return self._min_value
-
- def maxValue(self) -> int:
- return self._max_value
-
- def defaultValue(self) -> int:
- return self._default_value
-
- def stepValue(self) -> int:
- return self._step_value
-
- def toString(self) -> str:
- return f"AudioGain(id={self._id}, range=[{self._min_value}, {self._max_value}])"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioGain):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-class AudioGainConfig(Stub):
- """AudioGainConfig — 音频增益配置"""
-
- def __init__(self, gain: Optional[AudioGain] = None,
- mode: int = AudioGain.MODE_JOINT,
- channelMask: int = 0,
- values: List[int] = None,
- rampDurationMs: int = 0):
- super().__init__()
- self._gain = gain
- self._mode = mode
- self._channel_mask = channelMask
- self._values = values or []
- self._ramp_duration_ms = rampDurationMs
-
- def getGain(self) -> Optional[AudioGain]:
- return self._gain
-
- def getMode(self) -> int:
- return self._mode
-
- def getChannelMask(self) -> int:
- return self._channel_mask
-
- def getValues(self) -> List[int]:
- return list(self._values)
-
- def getRampDurationMs(self) -> int:
- return self._ramp_duration_ms
-
- def toString(self) -> str:
- return f"AudioGainConfig(mode={self._mode}, values={self._values})"
-
-
-class AudioPatch(Stub):
- """AudioPatch — 音频补丁"""
-
- def __init__(self, id_: int = 0, sources: List[AudioPort] = None,
- sinks: List[AudioPort] = None):
- super().__init__()
- self._id = id_
- self._sources = sources or []
- self._sinks = sinks or []
-
- def getId(self) -> int:
- return self._id
-
- def getSources(self) -> List[AudioPort]:
- return list(self._sources)
-
- def getSinks(self) -> List[AudioPort]:
- return list(self._sinks)
-
- def toString(self) -> str:
- return f"AudioPatch(id={self._id}, sources={len(self._sources)}, sinks={len(self._sinks)})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioPatch):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioMix
-# ═══════════════════════════════════════════════════════════════
-
-class AudioMix(Stub):
- """AudioMix — 音频混合"""
-
- ROUTE_FLAG_RENDER = 1
- ROUTE_FLAG_LOOP_BACK = 2
- ROUTE_FLAG_CAPTURE = 4
-
- CALLBACK_FLAG_NOTIFY_ACTIVITY = 1
-
- def __init__(self, routeFlags: int = ROUTE_FLAG_RENDER,
- callbackFlags: int = 0,
- format_: Optional[AudioFormat] = None,
- deviceType: int = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER):
- super().__init__()
- self._route_flags = routeFlags
- self._callback_flags = callbackFlags
- self._format = format_ or AudioFormat()
- self._device_type = deviceType
-
- def getRouteFlags(self) -> int:
- return self._route_flags
-
- def getCallbackFlags(self) -> int:
- return self._callback_flags
-
- def getFormat(self) -> AudioFormat:
- return self._format
-
- def getDeviceType(self) -> int:
- return self._device_type
-
- def toString(self) -> str:
- return f"AudioMix(routeFlags={self._route_flags})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioMix):
- return False
- return self._route_flags == other._route_flags
-
- def hashCode(self) -> int:
- return self._route_flags & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioProfile
-# ═══════════════════════════════════════════════════════════════
-
-class AudioProfile(Stub):
- """AudioProfile — 音频配置文件"""
-
- def __init__(self, format_: int = AudioFormat.ENCODING_DEFAULT,
- sampleRates: List[int] = None,
- channelMasks: List[int] = None,
- channelIndexMasks: List[int] = None):
- super().__init__()
- self._format = format_
- self._sample_rates = sampleRates or [44100, 48000]
- self._channel_masks = channelMasks or [AudioFormat.CHANNEL_OUT_STEREO]
- self._channel_index_masks = channelIndexMasks or []
-
- def getFormat(self) -> int:
- return self._format
-
- def getSampleRates(self) -> List[int]:
- return list(self._sample_rates)
-
- def getChannelMasks(self) -> List[int]:
- return list(self._channel_masks)
-
- def getChannelIndexMasks(self) -> List[int]:
- return list(self._channel_index_masks)
-
- def toString(self) -> str:
- return f"AudioProfile(format={self._format})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioProfile):
- return False
- return self._format == other._format
-
- def hashCode(self) -> int:
- return self._format & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioProductStrategy
-# ═══════════════════════════════════════════════════════════════
-
-class AudioProductStrategy(Stub):
- """AudioProductStrategy — 音频产品策略"""
-
- def __init__(self, id_: int = 0, name: str = "",
- toleratedFormats: List[int] = None,
- volumeGroup: Optional["AudioVolumeGroup"] = None):
- super().__init__()
- self._id = id_
- self._name = name
- self._tolerated_formats = toleratedFormats or []
- self._volume_group = volume_group
-
- def getId(self) -> int:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getToleratedFormats(self) -> List[int]:
- return list(self._tolerated_formats)
-
- def getVolumeGroup(self) -> Optional["AudioVolumeGroup"]:
- return self._volume_group
-
- def setVolumeGroup(self, group: "AudioVolumeGroup"):
- self._volume_group = group
-
- def toString(self) -> str:
- return f"AudioProductStrategy(id={self._id}, name={self._name})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioProductStrategy):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioVolumeGroup
-# ═══════════════════════════════════════════════════════════════
-
-class AudioVolumeGroup(Stub):
- """AudioVolumeGroup — 音频音量组"""
-
- def __init__(self, id_: int = 0, name: str = "",
- volumeIndexMin: int = 0, volumeIndexMax: int = 15):
- super().__init__()
- self._id = id_
- self._name = name
- self._volume_index_min = volumeIndexMin
- self._volume_index_max = volumeIndexMax
-
- def getId(self) -> int:
- return self._id
-
- def getName(self) -> str:
- return self._name
-
- def getMinVolumeIndex(self) -> int:
- return self._volume_index_min
-
- def getMaxVolumeIndex(self) -> int:
- return self._volume_index_max
-
- def toString(self) -> str:
- return f"AudioVolumeGroup(id={self._id}, name={self._name})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AudioVolumeGroup):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/media_audiofx.py b/android_pyapi/android/media_audiofx.py
deleted file mode 100644
index 45901e4..0000000
--- a/android_pyapi/android/media_audiofx.py
+++ /dev/null
@@ -1,547 +0,0 @@
-"""
-Android media.audiofx 组件 — AudioEffect, Equalizer, BassBoost, Virtualizer 等
-方法签名完全对齐 Android SDK
-"""
-
-import math
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioEffect
-# ═══════════════════════════════════════════════════════════════
-
-class AudioEffect(Stub):
- """AudioEffect — 音频效果基类"""
-
- EFFECT_SUCCESS = 0
- EFFECT_ERROR = -1
- EFFECT_ALREADY_EXISTS = -2
- EFFECT_NO_MORE_SESSION = -3
- EFFECT_REQUEST_INIT = -4
- EFFECT_INIT_FAILED = -5
-
- EFFECT_INSERT = 1
- EFFECT_AUXILIARY = 2
- EFFECT_PRE_PROCESSING = 4
- EFFECT_POST_PROCESSING = 8
-
- CONTENT_TYPE_MUSIC = 2
- CONTENT_TYPE_MOVIE = 3
- CONTENT_TYPE_GAME = 4
- CONTENT_TYPE_VOICE = 1
-
- # ═══════════════════════════════════════════════════════════
- # Descriptor
- # ═══════════════════════════════════════════════════════════
-
- class Descriptor(Stub):
- """AudioEffect.Descriptor — 效果描述符"""
-
- def __init__(self, type: str = "", uuid: str = "",
- connectMode: str = "", name: str = "",
- implementor: str = ""):
- super().__init__()
- self.type = type
- self.uuid = uuid
- self.connectMode = connectMode
- self.name = name
- self.implementor = implementor
-
- def toString(self) -> str:
- return f"Descriptor(type={self.type}, uuid={self.uuid}, name={self.name})"
-
- def __init__(self, effectType: str = "", priority: int = 0,
- audioSession: int = 0):
- super().__init__()
- self._enabled = False
- self._effect_type = effectType
- self._priority = priority
- self._audio_session = audioSession
- self._id = hash(self) & 0x7FFFFFFF
- self._control_status_listener: Optional[Callable] = None
- self._enable_status_listener: Optional[Callable] = None
-
- def getEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool) -> int:
- self._enabled = enabled
- return AudioEffect.EFFECT_SUCCESS
-
- def getId(self) -> int:
- return self._id
-
- def getDescriptor(self) -> Descriptor:
- return AudioEffect.Descriptor(
- type=self._effect_type,
- uuid="",
- connectMode="",
- name=self.__class__.__name__,
- implementor="Android-pyApi"
- )
-
- def release(self):
- self._enabled = False
-
- def setControlStatusListener(self, listener: Callable):
- self._control_status_listener = listener
-
- def setEnableStatusListener(self, listener: Callable):
- self._enable_status_listener = listener
-
-
-# ═══════════════════════════════════════════════════════════════
-# Equalizer
-# ═══════════════════════════════════════════════════════════════
-
-class Equalizer(AudioEffect):
- """Equalizer — 均衡器"""
-
- PARAM_CURRENT_PRESET = 0
- PARAM_GET_BAND = 1
- PARAM_STRING_SIZE_MAX = 2
- PARAM_BAND_LEVEL = 3
- PARAM_LEVEL_RANGE = 4
- PARAM_NUM_BANDS = 5
- PARAM_BAND_FREQ_RANGE = 6
- PARAM_CENTER_FREQ = 7
- PARAM_GET_PRESET_NAME = 8
- PARAM_NUM_PRESETS = 9
- PARAM_PROPERTIES = 10
-
- def __init__(self, priority: int = 0, audioSession: int = 0):
- super().__init__("Equalizer", priority, audioSession)
- self._num_bands = 5
- self._band_levels: Dict[int, int] = {}
- self._presets = [
- "Normal", "Classical", "Dance", "Flat", "Folk",
- "Heavy Metal", "Hip Hop", "Jazz", "Pop", "Rock"
- ]
- self._current_preset = 0
- self._band_freq_ranges: Dict[int, Tuple[int, int]] = {
- 0: (60, 200), 1: (200, 600), 2: (600, 2400),
- 3: (2400, 8000), 4: (8000, 16000)
- }
-
- def getNumberOfBands(self) -> int:
- return self._num_bands
-
- def getBand(self, frequency: int) -> int:
- for band, (low, high) in self._band_freq_ranges.items():
- if low <= frequency <= high:
- return band
- return 0
-
- def getBandLevel(self, band: int) -> int:
- return self._band_levels.get(band, 0)
-
- def setBandLevel(self, band: int, level: int):
- self._band_levels[band] = level
-
- def getBandLevelRange(self) -> List[int]:
- return [-1500, 1500]
-
- def getCenterFreq(self, band: int) -> int:
- if band in self._band_freq_ranges:
- low, high = self._band_freq_ranges[band]
- return (low + high) // 2
- return 0
-
- def getNumberOfPresets(self) -> int:
- return len(self._presets)
-
- def getPresetName(self, preset: int) -> str:
- if 0 <= preset < len(self._presets):
- return self._presets[preset]
- return "Unknown"
-
- def usePreset(self, preset: int):
- if 0 <= preset < len(self._presets):
- self._current_preset = preset
-
- def getCurrentPreset(self) -> int:
- return self._current_preset
-
- def getProperties(self) -> Any:
- return None
-
- def setProperties(self, properties: Any):
- pass
-
- def toString(self) -> str:
- return f"Equalizer(preset={self._presets[self._current_preset]}," \
- f" bands={self._num_bands})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BassBoost
-# ═══════════════════════════════════════════════════════════════
-
-class BassBoost(AudioEffect):
- """BassBoost — 低音增强"""
-
- PARAM_STRENGTH = 1
- PARAM_STRENGTH_SUPPORTED = 2
-
- def __init__(self, priority: int = 0, audioSession: int = 0):
- super().__init__("BassBoost", priority, audioSession)
- self._strength: int = 0
-
- def setStrength(self, strength: int):
- self._strength = max(0, min(1000, strength))
-
- def getRoundedStrength(self) -> int:
- return self._strength
-
- def getStrengthSupported(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"BassBoost(strength={self._strength})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Virtualizer
-# ═══════════════════════════════════════════════════════════════
-
-class Virtualizer(AudioEffect):
- """Virtualizer — 虚拟器 (空间音频)"""
-
- PARAM_STRENGTH = 1
- PARAM_STRENGTH_SUPPORTED = 2
- PARAM_VIRTUALIZATION_MODE = 3
- PARAM_FORCE_VIRTUALIZATION_MODE = 4
-
- VIRTUALIZATION_MODE_AUTO = 0
- VIRTUALIZATION_MODE_OFF = 1
- VIRTUALIZATION_MODE_TRANSAURAL = 2
- VIRTUALIZATION_MODE_BINAURAL = 3
-
- def __init__(self, priority: int = 0, audioSession: int = 0):
- super().__init__("Virtualizer", priority, audioSession)
- self._strength: int = 0
- self._virtualization_mode = Virtualizer.VIRTUALIZATION_MODE_AUTO
-
- def setStrength(self, strength: int):
- self._strength = max(0, min(1000, strength))
-
- def getRoundedStrength(self) -> int:
- return self._strength
-
- def canVirtualize(self, channelMask: int, virtualizationMode: int) -> bool:
- return True
-
- def getVirtualizationMode(self) -> int:
- return self._virtualization_mode
-
- def toString(self) -> str:
- return f"Virtualizer(strength={self._strength}, mode={self._virtualization_mode})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PresetReverb
-# ═══════════════════════════════════════════════════════════════
-
-class PresetReverb(AudioEffect):
- """PresetReverb — 预设混响"""
-
- PRESET_NONE = 0
- PRESET_SMALLROOM = 1
- PRESET_MEDIUMROOM = 2
- PRESET_LARGEROOM = 3
- PRESET_MEDIUMHALL = 4
- PRESET_LARGEHALL = 5
- PRESET_PLATE = 6
-
- PARAM_PRESET = 0
-
- def __init__(self, priority: int = 0, audioSession: int = 0):
- super().__init__("PresetReverb", priority, audioSession)
- self._preset = PresetReverb.PRESET_NONE
- self._preset_names = {
- PresetReverb.PRESET_NONE: "None",
- PresetReverb.PRESET_SMALLROOM: "Small Room",
- PresetReverb.PRESET_MEDIUMROOM: "Medium Room",
- PresetReverb.PRESET_LARGEROOM: "Large Room",
- PresetReverb.PRESET_MEDIUMHALL: "Medium Hall",
- PresetReverb.PRESET_LARGEHALL: "Large Hall",
- PresetReverb.PRESET_PLATE: "Plate",
- }
-
- def setPreset(self, preset: int):
- if preset in self._preset_names:
- self._preset = preset
-
- def getPreset(self) -> int:
- return self._preset
-
- def toString(self) -> str:
- return f"PresetReverb(preset={self._preset_names.get(self._preset, 'Unknown')})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EnvironmentalReverb
-# ═══════════════════════════════════════════════════════════════
-
-class EnvironmentalReverb(AudioEffect):
- """EnvironmentalReverb — 环境混响"""
-
- def __init__(self, priority: int = 0, audioSession: int = 0):
- super().__init__("EnvironmentalReverb", priority, audioSession)
- self._decay_time = 1500
- self._decay_hf_ratio = 500
- self._density = 500
- self._diffusion = 500
- self._reverb_level = 0
- self._room_level = 0
- self._room_hf_level = 0
- self._reflections_delay = 20
- self._reflections_level = -500
- self._reverb_delay = 40
-
- def setDecayTime(self, decayTime: int):
- self._decay_time = decayTime
-
- def getDecayTime(self) -> int:
- return self._decay_time
-
- def setDecayHFRatio(self, decayHFRatio: int):
- self._decay_hf_ratio = decayHFRatio
-
- def getDecayHFRatio(self) -> int:
- return self._decay_hf_ratio
-
- def setDensity(self, density: int):
- self._density = density
-
- def getDensity(self) -> int:
- return self._density
-
- def setDiffusion(self, diffusion: int):
- self._diffusion = diffusion
-
- def getDiffusion(self) -> int:
- return self._diffusion
-
- def setReverbLevel(self, reverbLevel: int):
- self._reverb_level = reverbLevel
-
- def getReverbLevel(self) -> int:
- return self._reverb_level
-
- def setRoomLevel(self, roomLevel: int):
- self._room_level = roomLevel
-
- def getRoomLevel(self) -> int:
- return self._room_level
-
- def setRoomHFLevel(self, roomHFLevel: int):
- self._room_hf_level = roomHFLevel
-
- def getRoomHFLevel(self) -> int:
- return self._room_hf_level
-
- def setReflectionsDelay(self, reflectionsDelay: int):
- self._reflections_delay = reflectionsDelay
-
- def getReflectionsDelay(self) -> int:
- return self._reflections_delay
-
- def setReflectionsLevel(self, reflectionsLevel: int):
- self._reflections_level = reflectionsLevel
-
- def getReflectionsLevel(self) -> int:
- return self._reflections_level
-
- def setReverbDelay(self, reverbDelay: int):
- self._reverb_delay = reverbDelay
-
- def getReverbDelay(self) -> int:
- return self._reverb_delay
-
- def toString(self) -> str:
- return f"EnvironmentalReverb(decayTime={self._decay_time}," \
- f" density={self._density})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LoudnessEnhancer
-# ═══════════════════════════════════════════════════════════════
-
-class LoudnessEnhancer(AudioEffect):
- """LoudnessEnhancer — 响度增强器"""
-
- PARAM_TARGET_GAIN_MB = 0
-
- def __init__(self, audioSession: int = 0):
- super().__init__("LoudnessEnhancer", 0, audioSession)
- self._target_gain = 0
-
- def setTargetGain(self, gainMillibels: int):
- self._target_gain = gainMillibels
-
- def getTargetGain(self) -> int:
- return self._target_gain
-
- def toString(self) -> str:
- return f"LoudnessEnhancer(targetGain={self._target_gain} mB)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DynamicsProcessing
-# ═══════════════════════════════════════════════════════════════
-
-class DynamicsProcessing(AudioEffect):
- """DynamicsProcessing — 动态处理"""
-
- class Stage(Stub):
- """DynamicsProcessing.Stage — 处理阶段"""
-
- def __init__(self, enabled: bool = True):
- super().__init__()
- self._enabled = enabled
- self._in_use = True
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- class EQBand(Stage):
- """DynamicsProcessing.EQBand — EQ 频段"""
-
- def __init__(self, enabled: bool = True):
- super().__init__(enabled)
- self._gain = 0.0
- self._center_freq = 1000.0
-
- def setGain(self, gain: float):
- self._gain = gain
-
- def getGain(self) -> float:
- return self._gain
-
- def setCenterFreq(self, freq: float):
- self._center_freq = freq
-
- def getCenterFreq(self) -> float:
- return self._center_freq
-
- class EQ(Stage):
- """DynamicsProcessing.EQ — 均衡器"""
-
- def __init__(self, enabled: bool = True, bandCount: int = 6):
- super().__init__(enabled)
- self._bands = [EQBand() for _ in range(bandCount)]
-
- def getBand(self, band: int) -> "DynamicsProcessing.EQBand":
- if 0 <= band < len(self._bands):
- return self._bands[band]
- raise IndexError(f"Band {band} out of range")
-
- class MBCBand(Stage):
- """DynamicsProcessing.MBCBand — 多频段压缩频段"""
-
- def __init__(self, enabled: bool = True):
- super().__init__(enabled)
- self._gain = 0.0
-
- def setGain(self, gain: float):
- self._gain = gain
-
- def getGain(self) -> float:
- return self._gain
-
- class MBC(Stage):
- """DynamicsProcessing.MBC — 多频段压缩"""
-
- def __init__(self, enabled: bool = True, bandCount: int = 6):
- super().__init__(enabled)
- self._bands = [MBCBand() for _ in range(bandCount)]
-
- def getBand(self, band: int) -> "DynamicsProcessing.MBCBand":
- if 0 <= band < len(self._bands):
- return self._bands[band]
- raise IndexError(f"Band {band} out of range")
-
- class Limiter(Stage):
- """DynamicsProcessing.Limiter — 限制器"""
-
- def __init__(self, enabled: bool = True):
- super().__init__(enabled)
-
- class Channel(Stub):
- """DynamicsProcessing.Channel — 处理通道"""
-
- def __init__(self, stageCount: int = 1):
- super().__init__()
- self._stage_count = stageCount
-
- class Config(Stub):
- """DynamicsProcessing.Config — 处理配置"""
-
- def __init__(self, channelCount: int = 1, preEqCount: int = 1,
- mbcCount: int = 1, postEqCount: int = 1,
- limiterCount: int = 1, prefEqBandCount: int = 6,
- postEqBandCount: int = 6, mbcBandCount: int = 6):
- super().__init__()
- self._channels = [DynamicsProcessing.Channel(0)
- for _ in range(channelCount)]
-
- def __init__(self, audioSession: int = 0):
- super().__init__("DynamicsProcessing", 0, audioSession)
- self._channel_count = 1
- self._post_constraints: List[Any] = []
- self._pre_eqs: List[DynamicsProcessing.EQ] = [DynamicsProcessing.EQ()]
- self._post_eqs: List[DynamicsProcessing.EQ] = [DynamicsProcessing.EQ()]
- self._mbcs: List[DynamicsProcessing.MBC] = [DynamicsProcessing.MBC()]
- self._limiters: List[DynamicsProcessing.Limiter] = [DynamicsProcessing.Limiter()]
- self._mbands: List[Any] = []
- self._channel_stage: List[Any] = []
-
- def getChannelCount(self) -> int:
- return self._channel_count
-
- def getPostConstraints(self) -> List[Any]:
- return self._post_constraints
-
- def getPreEQs(self) -> List[EQ]:
- return self._pre_eqs
-
- def getMbands(self) -> List[Any]:
- return self._mbands
-
- def getPostEQs(self) -> List[EQ]:
- return self._post_eqs
-
- def getLimiters(self) -> List[Limiter]:
- return self._limiters
-
- def getMbc(self) -> List[MBC]:
- return self._mbcs
-
- def getChannelStage(self) -> List[Any]:
- return self._channel_stage
-
- def toString(self) -> str:
- return f"DynamicsProcessing(channels={self._channel_count})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "AudioEffect",
- "Equalizer",
- "BassBoost",
- "Virtualizer",
- "PresetReverb",
- "EnvironmentalReverb",
- "LoudnessEnhancer",
- "DynamicsProcessing",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/media_browse.py b/android_pyapi/android/media_browse.py
deleted file mode 100644
index 686ab66..0000000
--- a/android_pyapi/android/media_browse.py
+++ /dev/null
@@ -1,310 +0,0 @@
-"""
-Android media.browse 组件 — MediaBrowser, MediaItem, MediaDescription 等
-方法签名完全对齐 Android SDK
-"""
-
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaBrowser
-# ═══════════════════════════════════════════════════════════════
-
-class MediaBrowser(Stub):
- """MediaBrowser — 媒体浏览器"""
-
- EXTRA_PAGE = "android.media.browse.extra.PAGE"
- EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE"
-
- # ═══════════════════════════════════════════════════════════
- # ConnectionCallback
- # ═══════════════════════════════════════════════════════════
-
- class ConnectionCallback(Stub):
- """MediaBrowser.ConnectionCallback — 连接回调"""
-
- def onConnected(self):
- pass
-
- def onConnectionSuspended(self):
- pass
-
- def onConnectionFailed(self):
- pass
-
- # ═══════════════════════════════════════════════════════════
- # SubscriptionCallback
- # ═══════════════════════════════════════════════════════════
-
- class SubscriptionCallback(Stub):
- """MediaBrowser.SubscriptionCallback — 订阅回调"""
-
- def onChildrenLoaded(self, parentId: str, children: List["MediaBrowser.MediaItem"]):
- pass
-
- def onError(self, parentId: str):
- pass
-
- def onChildrenLoadedWithOptions(self, parentId: str,
- children: List["MediaBrowser.MediaItem"],
- options: Any):
- pass
-
- # ═══════════════════════════════════════════════════════════
- # ItemCallback
- # ═══════════════════════════════════════════════════════════
-
- class ItemCallback(Stub):
- """MediaBrowser.ItemCallback — 媒体项回调"""
-
- def onItemLoaded(self, item: "MediaBrowser.MediaItem"):
- pass
-
- def onError(self, mediaId: str):
- pass
-
- # ═══════════════════════════════════════════════════════════
- # MediaItem
- # ═══════════════════════════════════════════════════════════
-
- class MediaItem(Stub):
- """MediaBrowser.MediaItem — 媒体项"""
-
- FLAG_BROWSABLE = 1
- FLAG_PLAYABLE = 2
-
- def __init__(self, description: "MediaDescription" = None, flags: int = FLAG_PLAYABLE):
- super().__init__()
- self._description = description or MediaDescription()
- self._flags = flags
-
- def getMediaId(self) -> Optional[str]:
- return self._description.getMediaId()
-
- def getDescription(self) -> "MediaDescription":
- return self._description
-
- def getFlags(self) -> int:
- return self._flags
-
- def isBrowsable(self) -> bool:
- return bool(self._flags & MediaBrowser.MediaItem.FLAG_BROWSABLE)
-
- def isPlayable(self) -> bool:
- return bool(self._flags & MediaBrowser.MediaItem.FLAG_PLAYABLE)
-
- def toString(self) -> str:
- return f"MediaItem(mediaId={self.getMediaId()}, flags={self._flags})"
-
- def __init__(self, context: Any = None, serviceComponent: Any = None,
- connectionCallback: Optional[ConnectionCallback] = None,
- rootHints: Any = None):
- super().__init__()
- self._connected = False
- self._service_component = serviceComponent
- self._root: str = ""
- self._session_token: Any = None
- self._connection_callback = connectionCallback
- self._subscriptions: Dict[str, List[MediaBrowser.SubscriptionCallback]] = {}
- self._media_tree: Dict[str, List[MediaBrowser.MediaItem]] = {}
- self._item_cache: Dict[str, MediaBrowser.MediaItem] = {}
-
- def connect(self):
- self._connected = True
- self._root = "__ROOT__"
- # Build a simple in-memory media tree
- self._media_tree["__ROOT__"] = [
- MediaBrowser.MediaItem(
- MediaDescription.Builder()
- .setMediaId("__RECENT__")
- .setTitle("Recently Played")
- .setSubtitle("Your recently played media")
- .build(),
- flags=MediaBrowser.MediaItem.FLAG_BROWSABLE
- ),
- MediaBrowser.MediaItem(
- MediaDescription.Builder()
- .setMediaId("__ALL__")
- .setTitle("All Music")
- .setSubtitle("All your music library")
- .build(),
- flags=MediaBrowser.MediaItem.FLAG_BROWSABLE
- ),
- ]
- self._media_tree["__RECENT__"] = [
- MediaBrowser.MediaItem(
- MediaDescription.Builder()
- .setMediaId("song_1")
- .setTitle("Sample Song 1")
- .setSubtitle("Artist 1")
- .build(),
- flags=MediaBrowser.MediaItem.FLAG_PLAYABLE
- ),
- ]
- self._item_cache["song_1"] = self._media_tree["__RECENT__"][0]
-
- if self._connection_callback:
- self._connection_callback.onConnected()
-
- def disconnect(self):
- self._connected = False
- self._subscriptions.clear()
- if self._connection_callback:
- self._connection_callback.onConnectionSuspended()
-
- def getConnected(self) -> bool:
- return self._connected
-
- def getServiceComponent(self) -> Any:
- return self._service_component
-
- def getRoot(self) -> str:
- return self._root
-
- def isConnected(self) -> bool:
- return self._connected
-
- def getSessionToken(self) -> Any:
- return self._session_token
-
- def getItem(self, mediaId: str) -> Optional[MediaItem]:
- return self._item_cache.get(mediaId)
-
- def subscribe(self, parentId: str, callback: SubscriptionCallback):
- if parentId not in self._subscriptions:
- self._subscriptions[parentId] = []
- self._subscriptions[parentId].append(callback)
-
- children = self._media_tree.get(parentId, [])
- if children:
- callback.onChildrenLoaded(parentId, children)
- else:
- callback.onError(parentId)
-
- def unsubscribe(self, parentId: str, callback: Optional[SubscriptionCallback] = None):
- if parentId in self._subscriptions:
- if callback:
- self._subscriptions[parentId] = [
- cb for cb in self._subscriptions[parentId]
- if cb is not callback
- ]
- if not self._subscriptions[parentId]:
- del self._subscriptions[parentId]
- else:
- del self._subscriptions[parentId]
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaDescription
-# ═══════════════════════════════════════════════════════════════
-
-class MediaDescription(Stub):
- """MediaDescription — 媒体描述"""
-
- class Builder(Stub):
- """MediaDescription.Builder — 媒体描述构建器"""
-
- def __init__(self):
- super().__init__()
- self._media_id: Optional[str] = None
- self._title: Optional[str] = None
- self._subtitle: Optional[str] = None
- self._description: Optional[str] = None
- self._icon_bitmap: Any = None
- self._icon_uri: Optional[str] = None
- self._extras: Any = None
- self._media_uri: Optional[str] = None
-
- def setMediaId(self, mediaId: str) -> "MediaDescription.Builder":
- self._media_id = mediaId
- return self
-
- def setTitle(self, title: str) -> "MediaDescription.Builder":
- self._title = title
- return self
-
- def setSubtitle(self, subtitle: str) -> "MediaDescription.Builder":
- self._subtitle = subtitle
- return self
-
- def setDescription(self, description: str) -> "MediaDescription.Builder":
- self._description = description
- return self
-
- def setIconBitmap(self, icon: Any) -> "MediaDescription.Builder":
- self._icon_bitmap = icon
- return self
-
- def setIconUri(self, iconUri: str) -> "MediaDescription.Builder":
- self._icon_uri = iconUri
- return self
-
- def setExtras(self, extras: Any) -> "MediaDescription.Builder":
- self._extras = extras
- return self
-
- def setMediaUri(self, mediaUri: str) -> "MediaDescription.Builder":
- self._media_uri = mediaUri
- return self
-
- def build(self) -> "MediaDescription":
- md = MediaDescription()
- md._media_id = self._media_id
- md._title = self._title
- md._subtitle = self._subtitle
- md._description = self._description
- md._icon_bitmap = self._icon_bitmap
- md._icon_uri = self._icon_uri
- md._extras = self._extras
- md._media_uri = self._media_uri
- return md
-
- def __init__(self):
- super().__init__()
- self._media_id: Optional[str] = None
- self._title: Optional[str] = None
- self._subtitle: Optional[str] = None
- self._description: Optional[str] = None
- self._icon_bitmap: Any = None
- self._icon_uri: Optional[str] = None
- self._extras: Any = None
- self._media_uri: Optional[str] = None
-
- def getMediaId(self) -> Optional[str]:
- return self._media_id
-
- def getTitle(self) -> Optional[str]:
- return self._title
-
- def getSubtitle(self) -> Optional[str]:
- return self._subtitle
-
- def getDescription(self) -> Optional[str]:
- return self._description
-
- def getIconBitmap(self) -> Any:
- return self._icon_bitmap
-
- def getIconUri(self) -> Optional[str]:
- return self._icon_uri
-
- def getExtras(self) -> Any:
- return self._extras
-
- def getMediaUri(self) -> Optional[str]:
- return self._media_uri
-
- def toString(self) -> str:
- return f"MediaDescription(id={self._media_id}, title={self._title})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "MediaBrowser",
- "MediaDescription",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/media_capture.py b/android_pyapi/android/media_capture.py
deleted file mode 100644
index 8ac5bd5..0000000
--- a/android_pyapi/android/media_capture.py
+++ /dev/null
@@ -1,748 +0,0 @@
-"""
-Android media.capture 组件 — CaptureSession, CaptureRequest, CaptureResult 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import math
-import time
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# 捕获请求/结果常量
-# ═══════════════════════════════════════════════════════════════
-
-REQUEST_ID = "request-id"
-REQUEST_TYPE = "request-type"
-RESULT_STATUS = "result-status"
-RESULT_TIMESTAMP = "result-timestamp"
-RESULT_FRAME_NUMBER = "result-frame-number"
-ERROR_CAMERA_DEVICE = 1
-ERROR_CAMERA_DISABLED = 2
-ERROR_CAMERA_IN_USE = 3
-ERROR_CAMERA_SERVICE = 4
-ERROR_MAX_CAMERAS_IN_USE = 5
-ERROR_CAMERA_UNAVAILABLE = 1001
-ERROR_CAMERA_ACCESS_DENIED = 1002
-
-CONTROL_AE_MODE_OFF = 0
-CONTROL_AE_MODE_ON = 1
-CONTROL_AE_MODE_ON_AUTO_FLASH = 2
-CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3
-CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4
-CONTROL_AE_MODE_ON_EXTERNAL_FLASH = 5
-CONTROL_AE_LOCK_OFF = 0
-CONTROL_AE_LOCK_ON = 1
-CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0
-CONTROL_AE_PRECAPTURE_TRIGGER_START = 1
-CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2
-CONTROL_AE_STATE_INACTIVE = 0
-CONTROL_AE_STATE_SEARCHING = 1
-CONTROL_AE_STATE_CONVERGED = 2
-CONTROL_AE_STATE_LOCKED = 3
-CONTROL_AE_STATE_FLASH_REQUIRED = 4
-CONTROL_AE_STATE_PRECAPTURE = 5
-CONTROL_AF_MODE_OFF = 0
-CONTROL_AF_MODE_AUTO = 1
-CONTROL_AF_MODE_MACRO = 2
-CONTROL_AF_MODE_CONTINUOUS_VIDEO = 3
-CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4
-CONTROL_AF_MODE_EDOF = 5
-CONTROL_AF_TRIGGER_IDLE = 0
-CONTROL_AF_TRIGGER_START = 1
-CONTROL_AF_TRIGGER_CANCEL = 2
-CONTROL_AF_STATE_INACTIVE = 0
-CONTROL_AF_STATE_PASSIVE_SCAN = 1
-CONTROL_AF_STATE_PASSIVE_FOCUSED = 2
-CONTROL_AF_STATE_ACTIVE_SCAN = 3
-CONTROL_AF_STATE_FOCUSED_LOCKED = 4
-CONTROL_AF_STATE_NOT_FOCUSED_LOCKED = 5
-CONTROL_AF_STATE_PASSIVE_UNFOCUSED = 6
-CONTROL_AWB_MODE_OFF = 0
-CONTROL_AWB_MODE_AUTO = 1
-CONTROL_AWB_MODE_INCANDESCENT = 2
-CONTROL_AWB_MODE_FLUORESCENT = 3
-CONTROL_AWB_MODE_WARM_FLUORESCENT = 4
-CONTROL_AWB_MODE_DAYLIGHT = 5
-CONTROL_AWB_MODE_CLOUDY_DAYLIGHT = 6
-CONTROL_AWB_MODE_TWILIGHT = 7
-CONTROL_AWB_MODE_SHADE = 8
-CONTROL_AWB_LOCK_OFF = 0
-CONTROL_AWB_LOCK_ON = 1
-CONTROL_AWB_STATE_INACTIVE = 0
-CONTROL_AWB_STATE_SEARCHING = 1
-CONTROL_AWB_STATE_CONVERGED = 2
-CONTROL_AWB_STATE_LOCKED = 3
-CONTROL_CAPTURE_INTENT_PREVIEW = 1
-CONTROL_CAPTURE_INTENT_STILL_CAPTURE = 2
-CONTROL_CAPTURE_INTENT_VIDEO_RECORD = 3
-CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4
-CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG = 5
-CONTROL_CAPTURE_INTENT_MANUAL = 6
-CONTROL_CAPTURE_INTENT_MOTION_TRACKING = 7
-CONTROL_EFFECT_MODE_OFF = 0
-CONTROL_EFFECT_MODE_MONO = 1
-CONTROL_EFFECT_MODE_NEGATIVE = 2
-CONTROL_EFFECT_MODE_SOLARIZE = 3
-CONTROL_EFFECT_MODE_SEPIA = 4
-CONTROL_EFFECT_MODE_POSTERIZE = 5
-CONTROL_EFFECT_MODE_WHITEBOARD = 6
-CONTROL_EFFECT_MODE_BLACKBOARD = 7
-CONTROL_EFFECT_MODE_AQUA = 8
-CONTROL_MODE_AUTO = 1
-CONTROL_MODE_OFF = 0
-CONTROL_MODE_USE_SCENE_MODE = 2
-CONTROL_SCENE_MODE_DISABLED = 0
-CONTROL_SCENE_MODE_FACE_PRIORITY = 1
-CONTROL_SCENE_MODE_ACTION = 2
-CONTROL_SCENE_MODE_PORTRAIT = 3
-CONTROL_SCENE_MODE_LANDSCAPE = 4
-CONTROL_SCENE_MODE_NIGHT = 5
-CONTROL_SCENE_MODE_NIGHT_PORTRAIT = 6
-CONTROL_SCENE_MODE_THEATRE = 7
-CONTROL_SCENE_MODE_BEACH = 8
-CONTROL_SCENE_MODE_SNOW = 9
-CONTROL_SCENE_MODE_SUNSET = 10
-CONTROL_SCENE_MODE_STEADYPHOTO = 11
-CONTROL_SCENE_MODE_FIREWORKS = 12
-CONTROL_SCENE_MODE_SPORTS = 13
-CONTROL_SCENE_MODE_PARTY = 14
-CONTROL_SCENE_MODE_CANDLELIGHT = 15
-CONTROL_SCENE_MODE_BARCODE = 16
-CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17
-CONTROL_SCENE_MODE_HDR = 18
-CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0
-CONTROL_VIDEO_STABILIZATION_MODE_ON = 1
-CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW = 2
-
-STATISTICS_FACE_DETECT_MODE_OFF = 0
-STATISTICS_FACE_DETECT_MODE_SIMPLE = 1
-STATISTICS_FACE_DETECT_MODE_FULL = 2
-STATISTICS_HOT_PIXEL_MAP_MODE_OFF = 0
-STATISTICS_HOT_PIXEL_MAP_MODE_ON = 1
-STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0
-STATISTICS_LENS_SHADING_MAP_MODE_ON = 1
-STATISTICS_OIS_DATA_MODE_OFF = 0
-STATISTICS_OIS_DATA_MODE_ON = 1
-STATISTICS_SCENE_FLICKER_NONE = 0
-STATISTICS_SCENE_FLICKER_50HZ = 1
-STATISTICS_SCENE_FLICKER_60HZ = 2
-
-FLASH_MODE_OFF = 0
-FLASH_MODE_SINGLE = 1
-FLASH_MODE_TORCH = 2
-
-LENS_FACING_FRONT = 0
-LENS_FACING_BACK = 1
-LENS_FACING_EXTERNAL = 2
-
-SENSOR_SENSITIVITY = "sensor-sensitivity"
-SENSOR_EXPOSURE_TIME = "sensor-exposure-time"
-SENSOR_FRAME_DURATION = "sensor-frame-duration"
-SENSOR_TIMESTAMP = "sensor-timestamp"
-
-JPEG_QUALITY = "jpeg-quality"
-JPEG_ORIENTATION = "jpeg-orientation"
-JPEG_GPS_LOCATION = "jpeg-gps-location"
-JPEG_THUMBNAIL_QUALITY = "jpeg-thumbnail-quality"
-JPEG_THUMBNAIL_SIZE = "jpeg-thumbnail-size"
-
-NOISE_REDUCTION_MODE_OFF = 0
-NOISE_REDUCTION_MODE_FAST = 1
-NOISE_REDUCTION_MODE_HIGH_QUALITY = 2
-NOISE_REDUCTION_MODE_MINIMAL = 3
-NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG = 4
-
-EDGE_MODE_OFF = 0
-EDGE_MODE_FAST = 1
-EDGE_MODE_HIGH_QUALITY = 2
-EDGE_MODE_ZERO_SHUTTER_LAG = 3
-
-TONEMAP_MODE_CONTRAST_CURVE = 0
-TONEMAP_MODE_FAST = 1
-TONEMAP_MODE_HIGH_QUALITY = 2
-TONEMAP_MODE_GAMMA_VALUE = 3
-TONEMAP_MODE_PRESET_CURVE = 4
-TONEMAP_PRESET_CURVE_SRGB = 0
-TONEMAP_PRESET_CURVE_REC709 = 1
-
-REQUEST_AVAILABLE_CAPABILITIES = "request-available-capabilities"
-REQUEST_AVAILABLE_CHARACTERISTICS_KEYS = "request-available-characteristics-keys"
-REQUEST_AVAILABLE_RESULT_KEYS = "request-available-result-keys"
-REQUEST_AVAILABLE_SESSION_KEYS = "request-available-session-keys"
-REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES = "request-available-dynamic-range-profiles"
-REQUEST_AVAILABLE_RAW_MIN_DENOISE = "request-available-raw-min-denoise"
-REQUEST_AVAILABLE_TEST_PATTERN_MODES = "request-available-test-pattern-modes"
-REQUEST_PARTIAL_RESULT_COUNT = "request-partial-result-count"
-REQUEST_PIPELINE_MAX_DEPTH = "request-pipeline-max-depth"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CaptureRequest
-# ═══════════════════════════════════════════════════════════════
-
-class CaptureRequest(Stub):
- """CaptureRequest — 捕获请求"""
-
- class Builder(Stub):
- """CaptureRequest.Builder — 捕获请求构建器"""
-
- def __init__(self):
- super().__init__()
- self._parameters: Dict[str, Any] = {}
- self._tags: Dict[str, Any] = {}
- self._surfaces: List[Any] = []
- self._repeating = False
-
- def set(self, key: str, value: Any) -> "CaptureRequest.Builder":
- self._parameters[key] = value
- return self
-
- def get(self, key: str) -> Optional[Any]:
- return self._parameters.get(key)
-
- def setTag(self, key: str, value: Any) -> "CaptureRequest.Builder":
- self._tags[key] = value
- return self
-
- def getTag(self, key: str) -> Optional[Any]:
- return self._tags.get(key)
-
- def addTarget(self, surface: Any) -> "CaptureRequest.Builder":
- if surface not in self._surfaces:
- self._surfaces.append(surface)
- return self
-
- def removeTarget(self, surface: Any) -> "CaptureRequest.Builder":
- if surface in self._surfaces:
- self._surfaces.remove(surface)
- return self
-
- def getTargets(self) -> List[Any]:
- return list(self._surfaces)
-
- def isEmpty(self) -> bool:
- return len(self._parameters) == 0
-
- def build(self) -> "CaptureRequest":
- req = CaptureRequest()
- req._parameters = dict(self._parameters)
- req._tags = dict(self._tags)
- req._surfaces = list(self._surfaces)
- req._repeating = self._repeating
- return req
-
- def toString(self) -> str:
- return (f"CaptureRequest.Builder(params={len(self._parameters)}, "
- f"targets={len(self._surfaces)})")
-
- def __init__(self):
- super().__init__()
- self._parameters: Dict[str, Any] = {}
- self._tags: Dict[str, Any] = {}
- self._surfaces: List[Any] = []
- self._repeating = False
- self._frame_number: int = 0
- self._request_id: int = 0
-
- def get(self, key: str) -> Optional[Any]:
- return self._parameters.get(key)
-
- def set(self, key: str, value: Any) -> None:
- self._parameters[key] = value
-
- def getParameters(self) -> Dict[str, Any]:
- return dict(self._parameters)
-
- def getTags(self) -> Dict[str, Any]:
- return dict(self._tags)
-
- def getTargets(self) -> List[Any]:
- return list(self._surfaces)
-
- def isRepeating(self) -> bool:
- return self._repeating
-
- def setRepeating(self, repeating: bool) -> None:
- self._repeating = repeating
-
- def getFrameNumber(self) -> int:
- return self._frame_number
-
- def setFrameNumber(self, frame: int) -> None:
- self._frame_number = frame
-
- def getRequestId(self) -> int:
- return self._request_id
-
- def setRequestId(self, req_id: int) -> None:
- self._request_id = req_id
-
- def toString(self) -> str:
- return (f"CaptureRequest(id={self._request_id}, "
- f"frame={self._frame_number}, "
- f"params={len(self._parameters)})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CaptureResult
-# ═══════════════════════════════════════════════════════════════
-
-class CaptureResult(Stub):
- """CaptureResult — 捕获结果"""
-
- def __init__(self):
- super().__init__()
- self._results: Dict[str, Any] = {}
- self._request: Optional[CaptureRequest] = None
- self._sequence_id: int = 0
- self._frame_number: int = 0
- self._timestamp: int = 0
- self._partial_count: int = 0
- self._metadata: Dict[str, Any] = {}
-
- def get(self, key: str) -> Optional[Any]:
- return self._results.get(key)
-
- def put(self, key: str, value: Any) -> None:
- self._results[key] = value
-
- def getAll(self) -> Dict[str, Any]:
- return dict(self._results)
-
- def getRequest(self) -> Optional[CaptureRequest]:
- return self._request
-
- def setRequest(self, request: CaptureRequest) -> None:
- self._request = request
-
- def getSequenceId(self) -> int:
- return self._sequence_id
-
- def setSequenceId(self, seq_id: int) -> None:
- self._sequence_id = seq_id
-
- def getFrameNumber(self) -> int:
- return self._frame_number
-
- def setFrameNumber(self, frame: int) -> None:
- self._frame_number = frame
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def setTimestamp(self, ts: int) -> None:
- self._timestamp = ts
-
- def getMetadata(self, key: str) -> Any:
- return self._metadata.get(key)
-
- def setMetadata(self, key: str, value: Any) -> None:
- self._metadata[key] = value
-
- def getPartialCount(self) -> int:
- return self._partial_count
-
- def setPartialCount(self, count: int) -> None:
- self._partial_count = count
-
- def toString(self) -> str:
- return (f"CaptureResult(frame={self._frame_number}, "
- f"seq={self._sequence_id}, "
- f"results={len(self._results)})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# TotalCaptureResult
-# ═══════════════════════════════════════════════════════════════
-
-class TotalCaptureResult(CaptureResult):
- """TotalCaptureResult — 完整捕获结果(包含所有部分结果)"""
-
- def __init__(self):
- super().__init__()
- self._partial_results: List[CaptureResult] = []
- self._sensor_timestamp: int = 0
- self._physical_camera_results: Dict[str, CaptureResult] = {}
-
- def getPartialResults(self) -> List[CaptureResult]:
- return list(self._partial_results)
-
- def addPartialResult(self, result: CaptureResult) -> None:
- self._partial_results.append(result)
-
- def getPhysicalCameraResults(self) -> Dict[str, CaptureResult]:
- return dict(self._physical_camera_results)
-
- def setPhysicalCameraResult(self, camera_id: str, result: CaptureResult) -> None:
- self._physical_camera_results[camera_id] = result
-
- def toString(self) -> str:
- return (f"TotalCaptureResult(frame={self.getFrameNumber()}, "
- f"partials={len(self._partial_results)}, "
- f"physical={len(self._physical_camera_results)})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CaptureFailure
-# ═══════════════════════════════════════════════════════════════
-
-class CaptureFailure(Stub):
- """CaptureFailure — 捕获失败信息"""
-
- REASON_ERROR = 0
- REASON_FLUSHED = 1
- REASON_DROPPED = 2
-
- def __init__(self, request: Optional[CaptureRequest] = None,
- reason: int = REASON_ERROR,
- frame_number: int = 0,
- sequence_id: int = 0,
- is_image_capture: bool = False):
- super().__init__()
- self._request = request
- self._reason = reason
- self._frame_number = frame_number
- self._sequence_id = sequence_id
- self._is_image_capture = is_image_capture
- self._physical_camera_id: Optional[str] = None
-
- def getRequest(self) -> Optional[CaptureRequest]:
- return self._request
-
- def getReason(self) -> int:
- return self._reason
-
- def getFrameNumber(self) -> int:
- return self._frame_number
-
- def getSequenceId(self) -> int:
- return self._sequence_id
-
- def isImageCapture(self) -> bool:
- return self._is_image_capture
-
- def getPhysicalCameraId(self) -> Optional[str]:
- return self._physical_camera_id
-
- def setPhysicalCameraId(self, camera_id: str) -> None:
- self._physical_camera_id = camera_id
-
- def toString(self) -> str:
- reasons = {0: "ERROR", 1: "FLUSHED", 2: "DROPPED"}
- return (f"CaptureFailure(reason={reasons.get(self._reason, 'UNKNOWN')}, "
- f"frame={self._frame_number})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CaptureExtension
-# ═══════════════════════════════════════════════════════════════
-
-class CaptureExtension(Stub):
- """CaptureExtension — 捕获扩展"""
-
- EXTENSION_NONE = 0
- EXTENSION_AUTO = 1
- EXTENSION_BEAUTY = 2
- EXTENSION_BOKEH = 3
- EXTENSION_HDR = 4
- EXTENSION_NIGHT = 5
-
- def __init__(self, extension_type: int = EXTENSION_NONE):
- super().__init__()
- self._extension_type = extension_type
- self._parameters: Dict[str, Any] = {}
- self._enabled = False
-
- def getExtensionType(self) -> int:
- return self._extension_type
-
- def setExtensionType(self, ext_type: int) -> None:
- self._extension_type = ext_type
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool) -> None:
- self._enabled = enabled
-
- def setParameter(self, key: str, value: Any) -> None:
- self._parameters[key] = value
-
- def getParameter(self, key: str) -> Optional[Any]:
- return self._parameters.get(key)
-
- def toString(self) -> str:
- types = {0: "NONE", 1: "AUTO", 2: "BEAUTY", 3: "BOKEH", 4: "HDR", 5: "NIGHT"}
- return f"CaptureExtension(type={types.get(self._extension_type, 'UNKNOWN')})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CaptureSession
-# ═══════════════════════════════════════════════════════════════
-
-class CaptureSession(Stub):
- """CaptureSession — 捕获会话"""
-
- SESSION_ID = "session-id"
- SESSION_CONFIGURATION = "session-configuration"
- SESSION_STATE = "session-state"
-
- SESSION_STATE_OPEN = 0
- SESSION_STATE_READY = 1
- SESSION_STATE_ACTIVE = 2
- SESSION_STATE_CLOSED = 3
-
- CAPTURE = "capture"
- CAPTURE_BURST = "capture-burst"
- SET_REPEATING_REQUEST = "set-repeating-request"
- SET_REPEATING_BURST = "set-repeating-burst"
- STOP_REPEATING = "stop-repeating"
- ABORT_CAPTURES = "abort-captures"
-
- # 回调接口
- class CaptureCallback(Stub):
- """CaptureSession.CaptureCallback — 捕获回调"""
-
- def onCaptureStarted(self, session: "CaptureSession", request: CaptureRequest,
- timestamp: int, frame_number: int) -> None:
- pass
-
- def onCaptureProgressed(self, session: "CaptureSession", request: CaptureRequest,
- partial_result: CaptureResult) -> None:
- pass
-
- def onCaptureCompleted(self, session: "CaptureSession", request: CaptureRequest,
- result: TotalCaptureResult) -> None:
- pass
-
- def onCaptureFailed(self, session: "CaptureSession", request: CaptureRequest,
- failure: CaptureFailure) -> None:
- pass
-
- def onCaptureSequenceCompleted(self, session: "CaptureSession",
- sequence_id: int, frame_number: int) -> None:
- pass
-
- def onCaptureSequenceAborted(self, session: "CaptureSession",
- sequence_id: int) -> None:
- pass
-
- def onCaptureBufferLost(self, session: "CaptureSession",
- request: CaptureRequest, target: Any,
- frame_number: int) -> None:
- pass
-
- class StateCallback(Stub):
- """CaptureSession.StateCallback — 会话状态回调"""
-
- def onConfigured(self, session: "CaptureSession") -> None:
- pass
-
- def onConfigureFailed(self, session: "CaptureSession") -> None:
- pass
-
- def onReady(self, session: "CaptureSession") -> None:
- pass
-
- def onActive(self, session: "CaptureSession") -> None:
- pass
-
- def onClosed(self, session: "CaptureSession") -> None:
- pass
-
- def __init__(self):
- super().__init__()
- self._state = self.SESSION_STATE_CLOSED
- self._state_callback: Optional[CaptureSession.StateCallback] = None
- self._capture_callback: Optional[CaptureSession.CaptureCallback] = None
- self._repeating_request: Optional[CaptureRequest] = None
- self._output_config: Optional[Any] = None
- self._input_config: Optional[Any] = None
- self._session_id: int = 0
- self._next_sequence_id: int = 1
- self._lock = threading.Lock()
-
- def open(self, callback: StateCallback, handler: Any = None) -> None:
- self._state_callback = callback
- self._state = self.SESSION_STATE_OPEN
- if callback:
- callback.onConfigured(self)
-
- def capture(self, request: CaptureRequest,
- callback: Optional[CaptureCallback] = None,
- handler: Any = None) -> int:
- with self._lock:
- seq_id = self._next_sequence_id
- self._next_sequence_id += 1
- if callback:
- callback.onCaptureStarted(self, request, int(time.time() * 1e9), 0)
- result = TotalCaptureResult()
- result.setRequest(request)
- result.setSequenceId(seq_id)
- callback.onCaptureCompleted(self, request, result)
- return seq_id
-
- def captureBurst(self, requests: List[CaptureRequest],
- callback: Optional[CaptureCallback] = None,
- handler: Any = None) -> int:
- with self._lock:
- seq_id = self._next_sequence_id
- self._next_sequence_id += 1
- if callback:
- for req in requests:
- callback.onCaptureStarted(self, req, int(time.time() * 1e9), 0)
- result = TotalCaptureResult()
- result.setRequest(req)
- result.setSequenceId(seq_id)
- callback.onCaptureCompleted(self, req, result)
- return seq_id
-
- def setRepeatingRequest(self, request: CaptureRequest,
- callback: Optional[CaptureCallback] = None,
- handler: Any = None) -> int:
- with self._lock:
- self._repeating_request = request
- seq_id = self._next_sequence_id
- self._next_sequence_id += 1
- return seq_id
-
- def setRepeatingBurst(self, requests: List[CaptureRequest],
- callback: Optional[CaptureCallback] = None,
- handler: Any = None) -> int:
- with self._lock:
- seq_id = self._next_sequence_id
- self._next_sequence_id += 1
- return seq_id
-
- def stopRepeating(self) -> None:
- with self._lock:
- self._repeating_request = None
-
- def abortCaptures(self) -> None:
- with self._lock:
- self._repeating_request = None
-
- def close(self) -> None:
- with self._lock:
- self._state = self.SESSION_STATE_CLOSED
- if self._state_callback:
- self._state_callback.onClosed(self)
-
- def getState(self) -> int:
- return self._state
-
- def isClosed(self) -> bool:
- return self._state == self.SESSION_STATE_CLOSED
-
- def getSessionId(self) -> int:
- return self._session_id
-
- def toString(self) -> str:
- states = {0: "OPEN", 1: "READY", 2: "ACTIVE", 3: "CLOSED"}
- return f"CaptureSession(state={states.get(self._state, 'UNKNOWN')})"
-
-
-CaptureSession.CaptureCallback = CaptureSession.CaptureCallback
-CaptureSession.StateCallback = CaptureSession.StateCallback
-
-
-class CaptureSessionConfig(Stub):
- """CaptureSessionConfig — 捕获会话配置"""
-
- def __init__(self):
- super().__init__()
- self._output_surfaces: List[Any] = []
- self._input_surface: Optional[Any] = None
- self._session_params: Dict[str, Any] = {}
- self._session_type: int = 0
-
- def addOutputSurface(self, surface: Any) -> None:
- if surface not in self._output_surfaces:
- self._output_surfaces.append(surface)
-
- def removeOutputSurface(self, surface: Any) -> None:
- if surface in self._output_surfaces:
- self._output_surfaces.remove(surface)
-
- def getOutputSurfaces(self) -> List[Any]:
- return list(self._output_surfaces)
-
- def setInputSurface(self, surface: Any) -> None:
- self._input_surface = surface
-
- def getInputSurface(self) -> Optional[Any]:
- return self._input_surface
-
- def setSessionParameter(self, key: str, value: Any) -> None:
- self._session_params[key] = value
-
- def getSessionParameter(self, key: str) -> Optional[Any]:
- return self._session_params.get(key)
-
- def toString(self) -> str:
- return (f"CaptureSessionConfig(outputs={len(self._output_surfaces)}, "
- f"input={'yes' if self._input_surface else 'no'})")
-
-
-class CaptureSessionOutput(Stub):
- """CaptureSessionOutput — 会话输出配置"""
-
- def __init__(self, surface: Any):
- super().__init__()
- self._surface = surface
- self._physical_camera_id: Optional[str] = None
-
- def getSurface(self) -> Any:
- return self._surface
-
- def setPhysicalCameraId(self, camera_id: str) -> None:
- self._physical_camera_id = camera_id
-
- def getPhysicalCameraId(self) -> Optional[str]:
- return self._physical_camera_id
-
- def toString(self) -> str:
- return (f"CaptureSessionOutput(surface={self._surface}, "
- f"physicalId={self._physical_camera_id})")
-
-
-class CaptureSessionInput(Stub):
- """CaptureSessionInput — 会话输入配置"""
-
- def __init__(self, surface: Any):
- super().__init__()
- self._surface = surface
-
- def getSurface(self) -> Any:
- return self._surface
-
- def toString(self) -> str:
- return f"CaptureSessionInput(surface={self._surface})"
-
-
-class CaptureSessionParams(Stub):
- """CaptureSessionParams — 会话参数配置"""
-
- def __init__(self):
- super().__init__()
- self._params: Dict[str, Any] = {}
-
- def set(self, key: str, value: Any) -> None:
- self._params[key] = value
-
- def get(self, key: str) -> Optional[Any]:
- return self._params.get(key)
-
- def getAll(self) -> Dict[str, Any]:
- return dict(self._params)
-
- def toString(self) -> str:
- return f"CaptureSessionParams(params={len(self._params)})"
\ No newline at end of file
diff --git a/android_pyapi/android/media_effect.py b/android_pyapi/android/media_effect.py
deleted file mode 100644
index 8164ccc..0000000
--- a/android_pyapi/android/media_effect.py
+++ /dev/null
@@ -1,615 +0,0 @@
-"""
-Android media.effect 组件 — Effect, EffectContext, EffectFactory, EffectUpdateListener
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import math
-import threading
-from typing import Any, Callable, Dict, List, Optional, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# Effect 常量
-# ═══════════════════════════════════════════════════════════════
-
-EFFECT_AUTOFIX = "android.media.effect.effects.AutoFixEffect"
-EFFECT_BACKDROPPER = "android.media.effect.effects.BackDropperEffect"
-EFFECT_BITMAPOVERLAY = "android.media.effect.effects.BitmapOverlayEffect"
-EFFECT_BLACKWHITE = "android.media.effect.effects.BlackWhiteEffect"
-EFFECT_BRIGHTNESS = "android.media.effect.effects.BrightnessEffect"
-EFFECT_CONTRAST = "android.media.effect.effects.ContrastEffect"
-EFFECT_CROSSPROCESS = "android.media.effect.effects.CrossProcessEffect"
-EFFECT_DOCUMENTARY = "android.media.effect.effects.DocumentaryEffect"
-EFFECT_DUOTONE = "android.media.effect.effects.DuotoneEffect"
-EFFECT_FILLLIGHT = "android.media.effect.effects.FillLightEffect"
-EFFECT_FISHEYE = "android.media.effect.effects.FisheyeEffect"
-EFFECT_FLIP = "android.media.effect.effects.FlipEffect"
-EFFECT_GRAIN = "android.media.effect.effects.GrainEffect"
-EFFECT_GRAYSCALE = "android.media.effect.effects.GrayscaleEffect"
-EFFECT_LOMO = "android.media.effect.effects.LomoishEffect"
-EFFECT_NEGATIVE = "android.media.effect.effects.NegativeEffect"
-EFFECT_POSTERIZE = "android.media.effect.effects.PosterizeEffect"
-EFFECT_REDEYE = "android.media.effect.effects.RedEyeEffect"
-EFFECT_ROTATE = "android.media.effect.effects.RotateEffect"
-EFFECT_SATURATE = "android.media.effect.effects.SaturateEffect"
-EFFECT_SEPIA = "android.media.effect.effects.SepiaEffect"
-EFFECT_SHARPEN = "android.media.effect.effects.SharpenEffect"
-EFFECT_TEMPERATURE = "android.media.effect.effects.TemperatureEffect"
-EFFECT_TINT = "android.media.effect.effects.TintEffect"
-EFFECT_VIGNETTE = "android.media.effect.effects.VignetteEffect"
-
-
-class EffectUpdateListener:
- """EffectUpdateListener — 效果更新监听器"""
-
- def onEffectUpdated(self, effect: "Effect", info: Any) -> None:
- """当效果状态更新时调用"""
- pass
-
-
-class Effect(Stub):
- """Effect — 图像效果基类"""
-
- def __init__(self, effect_type: str = ""):
- super().__init__()
- self._type = effect_type
- self._parameters: Dict[str, Any] = {}
- self._update_listener: Optional[EffectUpdateListener] = None
- self._listener_lock = threading.Lock()
-
- def apply(self, input_id: int, output_id: int) -> None:
- """应用效果到输入表面,输出到输出表面"""
- raise AndroidOnlyError("Effect.apply() 仅在 Android 设备上可用")
-
- def setParameter(self, param_key: str, value: Any) -> None:
- """设置效果参数"""
- self._parameters[param_key] = value
-
- def getParameter(self, param_key: str) -> Any:
- """获取效果参数值"""
- return self._parameters.get(param_key, None)
-
- def getName(self) -> str:
- """获取效果名称"""
- return self._type
-
- def setUpdateListener(self, listener: Optional[EffectUpdateListener]) -> None:
- """设置更新监听器"""
- with self._listener_lock:
- self._update_listener = listener
-
- def getUpdateListener(self) -> Optional[EffectUpdateListener]:
- """获取当前更新监听器"""
- with self._listener_lock:
- return self._update_listener
-
- def release(self) -> None:
- """释放效果资源"""
- self._parameters.clear()
- self._update_listener = None
-
- def toString(self) -> str:
- return f"Effect(type={self._type})"
-
-
-class EffectContext(Stub):
- """EffectContext — 效果上下文,管理 GL 资源和效果生命周期"""
-
- _instance_counter = 0
- _instances: Dict[int, "EffectContext"] = {}
- _instances_lock = threading.Lock()
-
- def __init__(self):
- super().__init__()
- with EffectContext._instances_lock:
- EffectContext._instance_counter += 1
- self._context_id = EffectContext._instance_counter
- EffectContext._instances[self._context_id] = self
- self._effects: Dict[str, Effect] = {}
- self._effects_lock = threading.Lock()
- self._released = False
-
- @staticmethod
- def createWithCurrentGlContext() -> "EffectContext":
- """使用当前 GL 上下文创建 EffectContext"""
- ctx = EffectContext()
- return ctx
-
- def getFactory(self) -> "EffectFactory":
- """获取与此上下文关联的 EffectFactory"""
- if self._released:
- raise RuntimeException("EffectContext 已被释放")
- return EffectFactory(self)
-
- def createEffect(self, effect_type: str) -> Effect:
- """创建指定类型的效果"""
- if self._released:
- raise RuntimeException("EffectContext 已被释放")
- factory = self.getFactory()
- return factory.createEffect(effect_type)
-
- def getEffect(self, name: str) -> Optional[Effect]:
- """获取已创建的指定名称的效果"""
- with self._effects_lock:
- return self._effects.get(name, None)
-
- def getAllEffects(self) -> List[Effect]:
- """获取所有已创建的效果列表"""
- with self._effects_lock:
- return list(self._effects.values())
-
- def release(self) -> None:
- """释放 EffectContext 及其所有效果"""
- if self._released:
- return
- self._released = True
- with self._effects_lock:
- for effect in self._effects.values():
- effect.release()
- self._effects.clear()
- with EffectContext._instances_lock:
- EffectContext._instances.pop(self._context_id, None)
-
- def isReleased(self) -> bool:
- """检查是否已释放"""
- return self._released
-
- def getContextId(self) -> int:
- return self._context_id
-
- def toString(self) -> str:
- return f"EffectContext(id={self._context_id}, released={self._released})"
-
-
-class EffectFactory(Stub):
- """EffectFactory — 效果工厂,用于创建各种 Effect 实例"""
-
- # 效果类型常量
- EFFECT_AUTOFIX = EFFECT_AUTOFIX
- EFFECT_BACKDROPPER = EFFECT_BACKDROPPER
- EFFECT_BITMAPOVERLAY = EFFECT_BITMAPOVERLAY
- EFFECT_BLACKWHITE = EFFECT_BLACKWHITE
- EFFECT_BRIGHTNESS = EFFECT_BRIGHTNESS
- EFFECT_CONTRAST = EFFECT_CONTRAST
- EFFECT_CROSSPROCESS = EFFECT_CROSSPROCESS
- EFFECT_DOCUMENTARY = EFFECT_DOCUMENTARY
- EFFECT_DUOTONE = EFFECT_DUOTONE
- EFFECT_FILLLIGHT = EFFECT_FILLLIGHT
- EFFECT_FISHEYE = EFFECT_FISHEYE
- EFFECT_FLIP = EFFECT_FLIP
- EFFECT_GRAIN = EFFECT_GRAIN
- EFFECT_GRAYSCALE = EFFECT_GRAYSCALE
- EFFECT_LOMO = EFFECT_LOMO
- EFFECT_NEGATIVE = EFFECT_NEGATIVE
- EFFECT_POSTERIZE = EFFECT_POSTERIZE
- EFFECT_REDEYE = EFFECT_REDEYE
- EFFECT_ROTATE = EFFECT_ROTATE
- EFFECT_SATURATE = EFFECT_SATURATE
- EFFECT_SEPIA = EFFECT_SEPIA
- EFFECT_SHARPEN = EFFECT_SHARPEN
- EFFECT_TEMPERATURE = EFFECT_TEMPERATURE
- EFFECT_TINT = EFFECT_TINT
- EFFECT_VIGNETTE = EFFECT_VIGNETTE
-
- _EFFECT_NAMES: List[str] = [
- EFFECT_AUTOFIX, EFFECT_BACKDROPPER, EFFECT_BITMAPOVERLAY,
- EFFECT_BLACKWHITE, EFFECT_BRIGHTNESS, EFFECT_CONTRAST,
- EFFECT_CROSSPROCESS, EFFECT_DOCUMENTARY, EFFECT_DUOTONE,
- EFFECT_FILLLIGHT, EFFECT_FISHEYE, EFFECT_FLIP, EFFECT_GRAIN,
- EFFECT_GRAYSCALE, EFFECT_LOMO, EFFECT_NEGATIVE, EFFECT_POSTERIZE,
- EFFECT_REDEYE, EFFECT_ROTATE, EFFECT_SATURATE, EFFECT_SEPIA,
- EFFECT_SHARPEN, EFFECT_TEMPERATURE, EFFECT_TINT, EFFECT_VIGNETTE,
- ]
-
- def __init__(self, context: EffectContext):
- super().__init__()
- self._context = context
-
- def createEffect(self, effect_type: str) -> Effect:
- """创建指定类型的效果"""
- if effect_type not in self._EFFECT_NAMES:
- raise IllegalArgumentException(f"不支持的效果类型: {effect_type}")
- effect = Effect(effect_type)
- with self._context._effects_lock:
- self._context._effects[effect_type] = effect
- return effect
-
- def isEffectSupported(self, effect_type: str) -> bool:
- """检查效果类型是否被支持"""
- return effect_type in self._EFFECT_NAMES
-
- def getSupportedEffects(self) -> List[str]:
- """获取所有支持的效果类型列表"""
- return list(self._EFFECT_NAMES)
-
- def toString(self) -> str:
- return f"EffectFactory(context_id={self._context.getContextId()})"
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-class AutoFixEffect(Effect):
- """AutoFixEffect — 自动修复效果,调整对比度/亮度平衡"""
-
- def __init__(self):
- super().__init__(EFFECT_AUTOFIX)
- self._scale = 0.5
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "scale":
- self._scale = max(0.0, min(1.0, float(value)))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "scale":
- return self._scale
- return super().getParameter(param_key)
-
-
-class BackDropperEffect(Effect):
- """BackDropperEffect — 背景替换效果"""
-
- def __init__(self):
- super().__init__(EFFECT_BACKDROPPER)
- self._source_id = 0
- self._background_id = 0
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "source":
- self._source_id = int(value)
- elif param_key == "background":
- self._background_id = int(value)
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "source":
- return self._source_id
- if param_key == "background":
- return self._background_id
- return super().getParameter(param_key)
-
-
-class BitmapOverlayEffect(Effect):
- """BitmapOverlayEffect — 位图覆盖效果"""
-
- def __init__(self):
- super().__init__(EFFECT_BITMAPOVERLAY)
- self._bitmap: Any = None
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "bitmap":
- self._bitmap = value
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "bitmap":
- return self._bitmap
- return super().getParameter(param_key)
-
-
-class BlackWhiteEffect(Effect):
- """BlackWhiteEffect — 黑白效果"""
-
- def __init__(self):
- super().__init__(EFFECT_BLACKWHITE)
- self._black = 0.0
- self._white = 1.0
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "black":
- self._black = max(0.0, min(1.0, float(value)))
- elif param_key == "white":
- self._white = max(0.0, min(1.0, float(value)))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "black":
- return self._black
- if param_key == "white":
- return self._white
- return super().getParameter(param_key)
-
-
-class BrightnessEffect(Effect):
- """BrightnessEffect — 亮度调整效果"""
-
- def __init__(self):
- super().__init__(EFFECT_BRIGHTNESS)
- self._brightness = 0.0
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "brightness":
- self._brightness = max(-1.0, min(1.0, float(value)))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "brightness":
- return self._brightness
- return super().getParameter(param_key)
-
-
-class ContrastEffect(Effect):
- """ContrastEffect — 对比度调整效果"""
-
- def __init__(self):
- super().__init__(EFFECT_CONTRAST)
- self._contrast = 1.0
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "contrast":
- self._contrast = max(0.0, float(value))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "contrast":
- return self._contrast
- return super().getParameter(param_key)
-
-
-class CrossProcessEffect(Effect):
- """CrossProcessEffect — 交叉冲印效果"""
-
- def __init__(self):
- super().__init__(EFFECT_CROSSPROCESS)
-
-
-class DocumentaryEffect(Effect):
- """DocumentaryEffect — 纪录片风格效果"""
-
- def __init__(self):
- super().__init__(EFFECT_DOCUMENTARY)
-
-
-class DuotoneEffect(Effect):
- """DuotoneEffect — 双色调效果"""
-
- def __init__(self):
- super().__init__(EFFECT_DUOTONE)
- self._first_color = 0xFFFF0000
- self._second_color = 0xFF0000FF
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key in ("first_color", "second_color"):
- setattr(self, f"_{param_key}", int(value) & 0xFFFFFFFF)
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "first_color":
- return self._first_color
- if param_key == "second_color":
- return self._second_color
- return super().getParameter(param_key)
-
-
-class FillLightEffect(Effect):
- """FillLightEffect — 填充光效果(人脸照明增强)"""
-
- def __init__(self):
- super().__init__(EFFECT_FILLLIGHT)
- self._strength = 0.0
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "strength":
- self._strength = max(0.0, min(1.0, float(value)))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "strength":
- return self._strength
- return super().getParameter(param_key)
-
-
-class FisheyeEffect(Effect):
- """FisheyeEffect — 鱼眼效果"""
-
- def __init__(self):
- super().__init__(EFFECT_FISHEYE)
- self._scale = 0.5
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "scale":
- self._scale = max(0.0, min(1.0, float(value)))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "scale":
- return self._scale
- return super().getParameter(param_key)
-
-
-class FlipEffect(Effect):
- """FlipEffect — 翻转效果"""
-
- def __init__(self):
- super().__init__(EFFECT_FLIP)
- self._horizontal = True
- self._vertical = False
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "horizontal":
- self._horizontal = bool(value)
- elif param_key == "vertical":
- self._vertical = bool(value)
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "horizontal":
- return self._horizontal
- if param_key == "vertical":
- return self._vertical
- return super().getParameter(param_key)
-
-
-class GrainEffect(Effect):
- """GrainEffect — 颗粒效果"""
-
- def __init__(self):
- super().__init__(EFFECT_GRAIN)
- self._intensity = 0.5
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "intensity":
- self._intensity = max(0.0, min(1.0, float(value)))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "intensity":
- return self._intensity
- return super().getParameter(param_key)
-
-
-class GrayscaleEffect(Effect):
- """GrayscaleEffect — 灰度效果"""
-
- def __init__(self):
- super().__init__(EFFECT_GRAYSCALE)
-
-
-class LomoishEffect(Effect):
- """LomoishEffect — LOMO 风格效果"""
-
- def __init__(self):
- super().__init__(EFFECT_LOMO)
-
-
-class NegativeEffect(Effect):
- """NegativeEffect — 底片效果"""
-
- def __init__(self):
- super().__init__(EFFECT_NEGATIVE)
-
-
-class PosterizeEffect(Effect):
- """PosterizeEffect — 色调分离效果"""
-
- def __init__(self):
- super().__init__(EFFECT_POSTERIZE)
-
-
-class RedEyeEffect(Effect):
- """RedEyeEffect — 红眼消除效果"""
-
- def __init__(self):
- super().__init__(EFFECT_REDEYE)
-
-
-class RotateEffect(Effect):
- """RotateEffect — 旋转效果"""
-
- def __init__(self):
- super().__init__(EFFECT_ROTATE)
- self._angle = 0.0
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "angle":
- self._angle = float(value) % 360.0
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "angle":
- return self._angle
- return super().getParameter(param_key)
-
-
-class SaturateEffect(Effect):
- """SaturateEffect — 饱和度调整效果"""
-
- def __init__(self):
- super().__init__(EFFECT_SATURATE)
- self._scale = 1.0
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "scale":
- self._scale = max(0.0, float(value))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "scale":
- return self._scale
- return super().getParameter(param_key)
-
-
-class SepiaEffect(Effect):
- """SepiaEffect — 棕褐色效果"""
-
- def __init__(self):
- super().__init__(EFFECT_SEPIA)
-
-
-class SharpenEffect(Effect):
- """SharpenEffect — 锐化效果"""
-
- def __init__(self):
- super().__init__(EFFECT_SHARPEN)
- self._scale = 0.5
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "scale":
- self._scale = max(0.0, float(value))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "scale":
- return self._scale
- return super().getParameter(param_key)
-
-
-class TemperatureEffect(Effect):
- """TemperatureEffect — 色温效果"""
-
- def __init__(self):
- super().__init__(EFFECT_TEMPERATURE)
- self._scale = 0.5
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "scale":
- self._scale = max(0.0, min(1.0, float(value)))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "scale":
- return self._scale
- return super().getParameter(param_key)
-
-
-class TintEffect(Effect):
- """TintEffect — 色调效果"""
-
- def __init__(self):
- super().__init__(EFFECT_TINT)
- self._tint_color = 0xFF000000
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "tint":
- self._tint_color = int(value) & 0xFFFFFFFF
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "tint":
- return self._tint_color
- return super().getParameter(param_key)
-
-
-class VignetteEffect(Effect):
- """VignetteEffect — 暗角效果"""
-
- def __init__(self):
- super().__init__(EFFECT_VIGNETTE)
- self._scale = 0.5
-
- def setParameter(self, param_key: str, value: Any) -> None:
- if param_key == "scale":
- self._scale = max(0.0, min(1.0, float(value)))
- super().setParameter(param_key, value)
-
- def getParameter(self, param_key: str) -> Any:
- if param_key == "scale":
- return self._scale
- return super().getParameter(param_key)
\ No newline at end of file
diff --git a/android_pyapi/android/media_face.py b/android_pyapi/android/media_face.py
deleted file mode 100644
index a0c14a6..0000000
--- a/android_pyapi/android/media_face.py
+++ /dev/null
@@ -1,499 +0,0 @@
-"""
-Android media.face 组件 — FaceDetector, Face 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import threading
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-CONFIDENCE_THRESHOLD = 0.4
-EULER_X = 0
-EULER_Y = 1
-EULER_Z = 2
-ID_SCORE = 3
-
-LANDMARK_X = 0
-LANDMARK_Y = 1
-LANDMARK_Z = 2
-LANDMARK_COUNT = 3
-
-MAX_FACES = 64
-MIN_FACE_SIZE_PERCENT = 0.1
-
-POINT_LEFT_EYE = 0
-POINT_RIGHT_EYE = 1
-POINT_NOSE = 2
-POINT_MOUTH = 3
-
-FACE_LANDMARK_LEFT_EYE = 0
-FACE_LANDMARK_RIGHT_EYE = 1
-FACE_LANDMARK_NOSE_BRIDGE = 2
-FACE_LANDMARK_NOSE_BASE = 3
-FACE_LANDMARK_LEFT_EAR = 4
-FACE_LANDMARK_RIGHT_EAR = 5
-FACE_LANDMARK_LEFT_MOUTH = 6
-FACE_LANDMARK_RIGHT_MOUTH = 7
-FACE_LANDMARK_CHIN = 8
-
-
-class FaceLandmark:
- """FaceLandmark — 人脸特征点"""
-
- def __init__(self, x: float = 0.0, y: float = 0.0,
- z: float = 0.0, landmark_type: int = 0):
- self.x = x
- self.y = y
- self.z = z
- self.type = landmark_type
-
- def getX(self) -> float:
- return self.x
-
- def getY(self) -> float:
- return self.y
-
- def getZ(self) -> float:
- return self.z
-
- def getType(self) -> int:
- return self.type
-
- def toString(self) -> str:
- return f"FaceLandmark(type={self.type}, x={self.x:.2f}, y={self.y:.2f}, z={self.z:.2f})"
-
-
-class Face(Stub):
- """Face — 检测到的人脸信息"""
-
- # 置信度常量
- CONFIDENCE_THRESHOLD = CONFIDENCE_THRESHOLD
-
- # 欧拉角常量
- EULER_X = EULER_X
- EULER_Y = EULER_Y
- EULER_Z = EULER_Z
-
- # ID 分数
- ID_SCORE = ID_SCORE
-
- # 特征点常量
- LANDMARK_X = LANDMARK_X
- LANDMARK_Y = LANDMARK_Y
- LANDMARK_Z = LANDMARK_Z
- LANDMARK_COUNT = LANDMARK_COUNT
-
- # 人脸特征点类型
- POINT_LEFT_EYE = POINT_LEFT_EYE
- POINT_RIGHT_EYE = POINT_RIGHT_EYE
- POINT_NOSE = POINT_NOSE
- POINT_MOUTH = POINT_MOUTH
-
- def __init__(self, confidence: float = 0.0,
- midscore: float = 0.0,
- euler_x: float = 0.0, euler_y: float = 0.0, euler_z: float = 0.0):
- super().__init__()
- self._confidence = max(0.0, min(1.0, confidence))
- self._midscore = midscore
- self._euler_x = euler_x
- self._euler_y = euler_y
- self._euler_z = euler_z
- self._landmarks: List[FaceLandmark] = []
- self._left_eye: Optional[Tuple[float, float]] = None
- self._right_eye: Optional[Tuple[float, float]] = None
- self._mouth: Optional[Tuple[float, float]] = None
- self._id_score: float = 0.0
- self._face_id: int = -1
- self._bounds: Optional[Tuple[int, int, int, int]] = None
-
- def confidence(self) -> float:
- """获取检测置信度 (0.0 - 1.0)"""
- return self._confidence
-
- def getConfidence(self) -> float:
- return self._confidence
-
- def getMidscore(self) -> float:
- return self._midscore
-
- def eyesDistance(self) -> float:
- """获取两眼之间的距离"""
- if self._left_eye is None or self._right_eye is None:
- return 0.0
- dx = self._left_eye[0] - self._right_eye[0]
- dy = self._left_eye[1] - self._right_eye[1]
- return math.sqrt(dx * dx + dy * dy)
-
- def pose(self, euler_type: int) -> float:
- """获取人脸姿态欧拉角"""
- if euler_type == EULER_X:
- return self._euler_x
- if euler_type == EULER_Y:
- return self._euler_y
- if euler_type == EULER_Z:
- return self._euler_z
- return 0.0
-
- def getEulerX(self) -> float:
- return self._euler_x
-
- def getEulerY(self) -> float:
- return self._euler_y
-
- def getEulerZ(self) -> float:
- return self._euler_z
-
- def getLeftEye(self) -> Optional[Tuple[float, float]]:
- return self._left_eye
-
- def setLeftEye(self, x: float, y: float) -> None:
- self._left_eye = (x, y)
-
- def getRightEye(self) -> Optional[Tuple[float, float]]:
- return self._right_eye
-
- def setRightEye(self, x: float, y: float) -> None:
- self._right_eye = (x, y)
-
- def getMouth(self) -> Optional[Tuple[float, float]]:
- return self._mouth
-
- def setMouth(self, x: float, y: float) -> None:
- self._mouth = (x, y)
-
- def getIdScore(self) -> float:
- return self._id_score
-
- def setIdScore(self, score: float) -> None:
- self._id_score = score
-
- def getFaceId(self) -> int:
- return self._face_id
-
- def setFaceId(self, face_id: int) -> None:
- self._face_id = face_id
-
- def getBounds(self) -> Optional[Tuple[int, int, int, int]]:
- """获取人脸边界框 (left, top, right, bottom)"""
- return self._bounds
-
- def setBounds(self, left: int, top: int, right: int, bottom: int) -> None:
- self._bounds = (left, top, right, bottom)
-
- def getLandmarks(self) -> List[FaceLandmark]:
- return list(self._landmarks)
-
- def getLandmarkCount(self) -> int:
- return len(self._landmarks)
-
- def addLandmark(self, landmark: FaceLandmark) -> None:
- self._landmarks.append(landmark)
-
- def toString(self) -> str:
- return (f"Face(confidence={self._confidence:.3f}, "
- f"euler=({self._euler_x:.1f},{self._euler_y:.1f},{self._euler_z:.1f}), "
- f"landmarks={len(self._landmarks)})")
-
-
-class FaceDetector(Stub):
- """FaceDetector — 人脸检测器"""
-
- MAX_FACES = MAX_FACES
- MIN_FACE_SIZE_PERCENT = MIN_FACE_SIZE_PERCENT
-
- # 人脸特征点类型
- POINT_LEFT_EYE = POINT_LEFT_EYE
- POINT_RIGHT_EYE = POINT_RIGHT_EYE
- POINT_NOSE = POINT_NOSE
- POINT_MOUTH = POINT_MOUTH
-
- class Face(Face):
- """FaceDetector.Face — 内部人脸类,继承自 Face"""
-
- def __init__(self, confidence: float = 0.0,
- midscore: float = 0.0,
- euler_x: float = 0.0, euler_y: float = 0.0, euler_z: float = 0.0):
- super().__init__(confidence, midscore, euler_x, euler_y, euler_z)
-
- def runDetector(self, detector: "FaceDetector") -> bool:
- """运行检测器以填充此 Face 的数据"""
- return True
-
- @staticmethod
- def getFaceFromArray(faces: List["Face"], index: int) -> Optional["Face"]:
- if 0 <= index < len(faces):
- return faces[index]
- return None
-
- def __init__(self, width: int = 0, height: int = 0, max_faces: int = MAX_FACES):
- super().__init__()
- self._width = width
- self._height = height
- self._max_faces = min(max_faces, MAX_FACES)
- self._detected_faces: List[Face] = []
- self._detection_lock = threading.Lock()
-
- def findFaces(self, bitmap: Any, faces: List[Face]) -> int:
- """在位图中检测人脸并填充 faces 数组
-
- Args:
- bitmap: 位图对象(需要有 getPixels 方法)
- faces: 预分配的 Face 数组
-
- Returns:
- 检测到的人脸数量
- """
- with self._detection_lock:
- self._detected_faces.clear()
- detected_count = self._run_detection(bitmap)
- for i in range(min(detected_count, len(faces))):
- faces[i] = self._detected_faces[i]
- return min(detected_count, len(faces))
-
- def _run_detection(self, bitmap: Any) -> int:
- """内部检测实现
-
- 桌面环境下返回模拟检测结果。
- """
- return 0
-
- def getDetectedFaces(self) -> List[Face]:
- """获取检测到的人脸列表"""
- with self._detection_lock:
- return list(self._detected_faces)
-
- def getFaceCount(self) -> int:
- """获取检测到的人脸数量"""
- with self._detection_lock:
- return len(self._detected_faces)
-
- def setBitmapSize(self, width: int, height: int) -> None:
- """设置位图尺寸"""
- self._width = width
- self._height = height
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getMaxFaces(self) -> int:
- return self._max_faces
-
- @staticmethod
- def isFaceDetectionSupported() -> bool:
- """检查是否支持人脸检测"""
- return True
-
- def toString(self) -> str:
- return (f"FaceDetector(width={self._width}, height={self._height}, "
- f"max_faces={self._max_faces})")
-
-
-class FaceDetectorBuilder(Stub):
- """FaceDetectorBuilder — 人脸检测器构建器"""
-
- def __init__(self):
- super().__init__()
- self._width = 0
- self._height = 0
- self._max_faces = MAX_FACES
- self._min_face_size = MIN_FACE_SIZE_PERCENT
- self._fast_mode = False
-
- def setWidth(self, width: int) -> "FaceDetectorBuilder":
- self._width = width
- return self
-
- def setHeight(self, height: int) -> "FaceDetectorBuilder":
- self._height = height
- return self
-
- def setMaxFaces(self, max_faces: int) -> "FaceDetectorBuilder":
- self._max_faces = min(max_faces, MAX_FACES)
- return self
-
- def setMinFaceSize(self, size_percent: float) -> "FaceDetectorBuilder":
- self._min_face_size = max(0.01, min(1.0, size_percent))
- return self
-
- def setFastMode(self, fast: bool) -> "FaceDetectorBuilder":
- self._fast_mode = fast
- return self
-
- def build(self) -> FaceDetector:
- detector = FaceDetector(self._width, self._height, self._max_faces)
- return detector
-
- def toString(self) -> str:
- return (f"FaceDetectorBuilder(width={self._width}, height={self._height}, "
- f"max_faces={self._max_faces})")
-
-
-class FaceInfo(Stub):
- """FaceInfo — 人脸详细信息"""
-
- def __init__(self, face: Optional[Face] = None):
- super().__init__()
- self._face = face
- self._smile_score: float = 0.0
- self._left_eye_open_score: float = 0.0
- self._right_eye_open_score: float = 0.0
- self._blink_score: float = 0.0
- self._face_landmarks: Dict[int, Tuple[float, float, float]] = {}
-
- def getSmileScore(self) -> float:
- return self._smile_score
-
- def setSmileScore(self, score: float) -> None:
- self._smile_score = max(0.0, min(1.0, score))
-
- def getLeftEyeOpenScore(self) -> float:
- return self._left_eye_open_score
-
- def setLeftEyeOpenScore(self, score: float) -> None:
- self._left_eye_open_score = max(0.0, min(1.0, score))
-
- def getRightEyeOpenScore(self) -> float:
- return self._right_eye_open_score
-
- def setRightEyeOpenScore(self, score: float) -> None:
- self._right_eye_open_score = max(0.0, min(1.0, score))
-
- def getBlinkScore(self) -> float:
- return self._blink_score
-
- def setBlinkScore(self, score: float) -> None:
- self._blink_score = max(0.0, min(1.0, score))
-
- def toString(self) -> str:
- return (f"FaceInfo(smile={self._smile_score:.2f}, "
- f"blink={self._blink_score:.2f})")
-
-
-class FaceTracker(Stub):
- """FaceTracker — 人脸追踪器"""
-
- def __init__(self, max_faces: int = MAX_FACES):
- super().__init__()
- self._max_faces = max_faces
- self._tracked_faces: Dict[int, Face] = {}
- self._next_id = 1
- self._lock = threading.Lock()
-
- def track(self, detected_faces: List[Face]) -> Dict[int, Face]:
- """追踪检测到的人脸,返回 id->Face 映射"""
- with self._lock:
- result: Dict[int, Face] = {}
- for face in detected_faces:
- face_id = self._assign_id(face)
- result[face_id] = face
- return result
-
- def _assign_id(self, face: Face) -> int:
- """为新检测到的人脸分配 ID,或匹配已有 ID"""
- best_id = self._next_id
- for fid, tracked in self._tracked_faces.items():
- if self._match_faces(tracked, face):
- best_id = fid
- break
- if best_id == self._next_id:
- self._next_id += 1
- self._tracked_faces[best_id] = face
- return best_id
-
- def _match_faces(self, tracked: Face, detected: Face) -> bool:
- """判断两帧中的人脸是否为同一人"""
- return False
-
- def reset(self) -> None:
- """重置追踪器"""
- with self._lock:
- self._tracked_faces.clear()
- self._next_id = 1
-
- def getTrackedFaces(self) -> Dict[int, Face]:
- with self._lock:
- return dict(self._tracked_faces)
-
- def toString(self) -> str:
- return f"FaceTracker(tracked={len(self._tracked_faces)})"
-
-
-class FaceDetectorOptions(Stub):
- """FaceDetectorOptions — 人脸检测器选项(MLKit兼容)"""
-
- PERFORMANCE_MODE_FAST = 1
- PERFORMANCE_MODE_ACCURATE = 2
- LANDMARK_MODE_NONE = 0
- LANDMARK_MODE_ALL = 1
- CONTOUR_MODE_NONE = 0
- CONTOUR_MODE_ALL = 1
- CLASSIFICATION_MODE_NONE = 0
- CLASSIFICATION_MODE_ALL = 1
-
- def __init__(self):
- super().__init__()
- self._performance_mode = self.PERFORMANCE_MODE_FAST
- self._landmark_mode = self.LANDMARK_MODE_NONE
- self._contour_mode = self.CONTOUR_MODE_NONE
- self._classification_mode = self.CLASSIFICATION_MODE_NONE
- self._min_face_size = 0.1
- self._enable_tracking = False
-
- def setPerformanceMode(self, mode: int) -> "FaceDetectorOptions":
- self._performance_mode = mode
- return self
-
- def getPerformanceMode(self) -> int:
- return self._performance_mode
-
- def setLandmarkMode(self, mode: int) -> "FaceDetectorOptions":
- self._landmark_mode = mode
- return self
-
- def getLandmarkMode(self) -> int:
- return self._landmark_mode
-
- def setContourMode(self, mode: int) -> "FaceDetectorOptions":
- self._contour_mode = mode
- return self
-
- def getContourMode(self) -> int:
- return self._contour_mode
-
- def setClassificationMode(self, mode: int) -> "FaceDetectorOptions":
- self._classification_mode = mode
- return self
-
- def getClassificationMode(self) -> int:
- return self._classification_mode
-
- def setMinFaceSize(self, size: float) -> "FaceDetectorOptions":
- self._min_face_size = max(0.01, min(1.0, size))
- return self
-
- def getMinFaceSize(self) -> float:
- return self._min_face_size
-
- def enableTracking(self, enable: bool) -> "FaceDetectorOptions":
- self._enable_tracking = enable
- return self
-
- def isTrackingEnabled(self) -> bool:
- return self._enable_tracking
-
- def toString(self) -> str:
- return (f"FaceDetectorOptions(performance={self._performance_mode}, "
- f"landmarks={self._landmark_mode})")
\ No newline at end of file
diff --git a/android_pyapi/android/media_image.py b/android_pyapi/android/media_image.py
deleted file mode 100644
index a39b932..0000000
--- a/android_pyapi/android/media_image.py
+++ /dev/null
@@ -1,649 +0,0 @@
-"""
-Android media.image 组件 — Image, ImageReader, ImageWriter 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import io
-import math
-import time
-import struct
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# Image 格式常量
-# ═══════════════════════════════════════════════════════════════
-
-FORMAT_NV21 = 17
-FORMAT_NV16 = 16
-FORMAT_YUY2 = 20
-FORMAT_JPEG = 256
-FORMAT_RAW_PRIVATE = 36
-FORMAT_RAW_SENSOR = 32
-FORMAT_RAW10 = 37
-FORMAT_RAW12 = 38
-FORMAT_RAW_DEPTH = 4098
-FORMAT_RAW_DEPTH10 = 4099
-FORMAT_YUV_420_888 = 35
-FORMAT_YUV_422_888 = 39
-FORMAT_YUV_444_888 = 40
-FORMAT_FLEX_RGB_888 = 41
-FORMAT_FLEX_RGBA_8888 = 42
-FORMAT_PRIVATE = 34
-FORMAT_UNKNOWN = 0
-FORMAT_RGB_565 = 4
-FORMAT_RGBA_8888 = 1
-FORMAT_RGBX_8888 = 2
-FORMAT_BGRA_8888 = 5
-FORMAT_Y8 = 538982489
-FORMAT_Y16 = 540422489
-FORMAT_DEPTH16 = 1144402265
-FORMAT_DEPTH_POINT_CLOUD = 257
-FORMAT_HEIC = 1212500294
-
-TRANSFORM_NONE = 0
-TRANSFORM_FLIP_H = 1
-TRANSFORM_FLIP_V = 2
-TRANSFORM_ROTATE_90 = 4
-TRANSFORM_ROTATE_180 = 3
-TRANSFORM_ROTATE_270 = 7
-
-SCALER_ROTATE_90 = 1
-SCALER_ROTATE_180 = 2
-SCALER_ROTATE_270 = 3
-
-
-class Image(Stub):
- """Image — 图像数据容器"""
-
- class Plane(Stub):
- """Image.Plane — 图像平面(YUV 各个平面)"""
-
- def __init__(self, buffer: Optional[bytes] = None,
- row_stride: int = 0, pixel_stride: int = 0):
- super().__init__()
- self._buffer = buffer or b""
- self._row_stride = row_stride
- self._pixel_stride = pixel_stride
-
- def getBuffer(self) -> Optional[bytes]:
- return self._buffer
-
- def getRowStride(self) -> int:
- return self._row_stride
-
- def getPixelStride(self) -> int:
- return self._pixel_stride
-
- def setBuffer(self, buf: bytes) -> None:
- self._buffer = buf
-
- def setRowStride(self, stride: int) -> None:
- self._row_stride = stride
-
- def setPixelStride(self, stride: int) -> None:
- self._pixel_stride = stride
-
- def toString(self) -> str:
- return (f"Plane(rowStride={self._row_stride}, "
- f"pixelStride={self._pixel_stride}, "
- f"bufferSize={len(self._buffer) if self._buffer else 0})")
-
- # Image 格式常量
- FORMAT_NV21 = FORMAT_NV21
- FORMAT_NV16 = FORMAT_NV16
- FORMAT_YUY2 = FORMAT_YUY2
- FORMAT_JPEG = FORMAT_JPEG
- FORMAT_RAW_PRIVATE = FORMAT_RAW_PRIVATE
- FORMAT_RAW_SENSOR = FORMAT_RAW_SENSOR
- FORMAT_RAW10 = FORMAT_RAW10
- FORMAT_RAW12 = FORMAT_RAW12
- FORMAT_RAW_DEPTH = FORMAT_RAW_DEPTH
- FORMAT_RAW_DEPTH10 = FORMAT_RAW_DEPTH10
- FORMAT_YUV_420_888 = FORMAT_YUV_420_888
- FORMAT_YUV_422_888 = FORMAT_YUV_422_888
- FORMAT_YUV_444_888 = FORMAT_YUV_444_888
- FORMAT_FLEX_RGB_888 = FORMAT_FLEX_RGB_888
- FORMAT_FLEX_RGBA_8888 = FORMAT_FLEX_RGBA_8888
- FORMAT_PRIVATE = FORMAT_PRIVATE
- FORMAT_UNKNOWN = FORMAT_UNKNOWN
- FORMAT_RGB_565 = FORMAT_RGB_565
- FORMAT_RGBA_8888 = FORMAT_RGBA_8888
- FORMAT_RGBX_8888 = FORMAT_RGBX_8888
- FORMAT_BGRA_8888 = FORMAT_BGRA_8888
- FORMAT_Y8 = FORMAT_Y8
- FORMAT_Y16 = FORMAT_Y16
- FORMAT_DEPTH16 = FORMAT_DEPTH16
- FORMAT_DEPTH_POINT_CLOUD = FORMAT_DEPTH_POINT_CLOUD
- FORMAT_HEIC = FORMAT_HEIC
-
- def __init__(self, width: int = 0, height: int = 0,
- format: int = FORMAT_UNKNOWN, timestamp: int = 0):
- super().__init__()
- self._width = width
- self._height = height
- self._format = format
- self._timestamp = timestamp
- self._planes: List[Image.Plane] = []
- self._crop: Optional[Tuple[int, int, int, int]] = None
- self._fence: Optional[Any] = None
- self._hardware_buffer: Optional[Any] = None
- self._released = False
- self._owner: Optional[Any] = None
- self._source: Optional[Any] = None
- self._lock = threading.Lock()
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getFormat(self) -> int:
- return self._format
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def setTimestamp(self, timestamp: int) -> None:
- self._timestamp = timestamp
-
- def getPlanes(self) -> List[Plane]:
- return self._planes
-
- def getCropRect(self) -> Optional[Tuple[int, int, int, int]]:
- return self._crop
-
- def setCropRect(self, crop: Tuple[int, int, int, int]) -> None:
- self._crop = crop
-
- def getFence(self) -> Optional[Any]:
- return self._fence
-
- def setFence(self, fence: Any) -> None:
- self._fence = fence
-
- def getHardwareBuffer(self) -> Optional[Any]:
- return self._hardware_buffer
-
- def close(self) -> None:
- with self._lock:
- if self._released:
- return
- self._released = True
- self._planes.clear()
- if self._source:
- self._source._notify_image_closed(self)
-
- def isClosed(self) -> bool:
- return self._released
-
- def toString(self) -> str:
- return (f"Image(width={self._width}, height={self._height}, "
- f"format={self._format}, planes={len(self._planes)}, "
- f"timestamp={self._timestamp})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImageReader
-# ═══════════════════════════════════════════════════════════════
-
-class ImageReader(Stub):
- """ImageReader — 图像读取器"""
-
- def __init__(self, width: int, height: int, format: int,
- max_images: int = 1, usage: int = 0):
- super().__init__()
- self._width = width
- self._height = height
- self._format = format
- self._max_images = max_images
- self._usage = usage
- self._images: List[Image] = []
- self._available_images: List[Image] = []
- self._on_image_available: Optional[Callable[[ImageReader], None]] = None
- self._lock = threading.Lock()
- self._released = False
- self._surface: Optional[Any] = None
-
- @staticmethod
- def newInstance(width: int, height: int, format: int,
- max_images: int = 1, usage: int = 0) -> "ImageReader":
- return ImageReader(width, height, format, max_images, usage)
-
- def acquireLatestImage(self) -> Optional[Image]:
- with self._lock:
- if not self._available_images:
- return None
- latest = self._available_images[-1]
- self._available_images.clear()
- return latest
-
- def acquireNextImage(self) -> Optional[Image]:
- with self._lock:
- if not self._available_images:
- return None
- return self._available_images.pop(0)
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getFormat(self) -> int:
- return self._format
-
- def getMaxImages(self) -> int:
- return self._max_images
-
- def getUsage(self) -> int:
- return self._usage
-
- def getSurface(self) -> Optional[Any]:
- return self._surface
-
- def setOnImageAvailableListener(self, listener: Optional[Callable],
- handler: Optional[Any] = None) -> None:
- self._on_image_available = listener
-
- def getOnImageAvailableListener(self) -> Optional[Callable]:
- return self._on_image_available
-
- def close(self) -> None:
- with self._lock:
- if self._released:
- return
- self._released = True
- for img in self._images:
- img.close()
- self._images.clear()
- self._available_images.clear()
-
- def isClosed(self) -> bool:
- return self._released
-
- def _notify_image_closed(self, image: Image) -> None:
- with self._lock:
- if image in self._images:
- self._images.remove(image)
-
- def _add_image(self, image: Image) -> None:
- with self._lock:
- image._source = self
- self._images.append(image)
- self._available_images.append(image)
- if self._on_image_available:
- self._on_image_available(self)
-
- def toString(self) -> str:
- return (f"ImageReader(width={self._width}, height={self._height}, "
- f"format={self._format}, maxImages={self._max_images})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImageWriter
-# ═══════════════════════════════════════════════════════════════
-
-class ImageWriter(Stub):
- """ImageWriter — 图像写入器"""
-
- def __init__(self, surface: Any, max_images: int = 1):
- super().__init__()
- self._surface = surface
- self._max_images = max_images
- self._queued_images: List[Image] = []
- self._on_image_released: Optional[Callable] = None
- self._lock = threading.Lock()
- self._released = False
-
- @staticmethod
- def newInstance(surface: Any, max_images: int = 1) -> "ImageWriter":
- return ImageWriter(surface, max_images)
-
- def getSurface(self) -> Optional[Any]:
- return self._surface
-
- def getMaxImages(self) -> int:
- return self._max_images
-
- def queueInputImage(self, image: Image) -> None:
- with self._lock:
- if self._released:
- raise RuntimeException("ImageWriter 已关闭")
- self._queued_images.append(image)
- if self._on_image_released:
- self._on_image_released(self)
-
- def setOnImageReleasedListener(self, listener: Optional[Callable],
- handler: Optional[Any] = None) -> None:
- self._on_image_released = listener
-
- def getOnImageReleasedListener(self) -> Optional[Callable]:
- return self._on_image_released
-
- def close(self) -> None:
- with self._lock:
- if self._released:
- return
- self._released = True
- self._queued_images.clear()
-
- def isClosed(self) -> bool:
- return self._released
-
- def toString(self) -> str:
- return (f"ImageWriter(maxImages={self._max_images}, "
- f"queued={len(self._queued_images)})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaImage
-# ═══════════════════════════════════════════════════════════════
-
-class MediaImage(Image):
- """MediaImage — 媒体图像(扩展 Image)"""
-
- def __init__(self, width: int = 0, height: int = 0,
- format: int = FORMAT_UNKNOWN, timestamp: int = 0,
- sequence_number: int = 0):
- super().__init__(width, height, format, timestamp)
- self._sequence_number = sequence_number
- self._metadata: Dict[str, Any] = {}
- self._transform: int = TRANSFORM_NONE
-
- def getSequenceNumber(self) -> int:
- return self._sequence_number
-
- def setSequenceNumber(self, seq: int) -> None:
- self._sequence_number = seq
-
- def getTransform(self) -> int:
- return self._transform
-
- def setTransform(self, transform: int) -> None:
- self._transform = transform
-
- def getMetadata(self, key: str) -> Any:
- return self._metadata.get(key)
-
- def setMetadata(self, key: str, value: Any) -> None:
- self._metadata[key] = value
-
- def getAllMetadata(self) -> Dict[str, Any]:
- return dict(self._metadata)
-
- def toString(self) -> str:
- return (f"MediaImage(width={self.getWidth()}, height={self.getHeight()}, "
- f"format={self.getFormat()}, seq={self._sequence_number})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurfaceImage / ImageTransform
-# ═══════════════════════════════════════════════════════════════
-
-class SurfaceImage(Stub):
- """SurfaceImage — 表面图像(用于 SurfaceView/TextureView 捕获)"""
-
- def __init__(self):
- super().__init__()
- self._image: Optional[Image] = None
- self._transform: int = TRANSFORM_NONE
- self._timestamp: int = 0
- self._lock = threading.Lock()
-
- def getImage(self) -> Optional[Image]:
- with self._lock:
- return self._image
-
- def setImage(self, image: Image) -> None:
- with self._lock:
- self._image = image
- self._timestamp = image.getTimestamp()
-
- def getTransform(self) -> int:
- return self._transform
-
- def setTransform(self, transform: int) -> None:
- self._transform = transform
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def release(self) -> None:
- with self._lock:
- if self._image:
- self._image.close()
- self._image = None
-
-
-class ImageTransform(Stub):
- """ImageTransform — 图像变换"""
-
- SCALER_ROTATE_90 = SCALER_ROTATE_90
- SCALER_ROTATE_180 = SCALER_ROTATE_180
- SCALER_ROTATE_270 = SCALER_ROTATE_270
- TRANSFORM_NONE = TRANSFORM_NONE
- TRANSFORM_FLIP_H = TRANSFORM_FLIP_H
- TRANSFORM_FLIP_V = TRANSFORM_FLIP_V
- TRANSFORM_ROTATE_90 = TRANSFORM_ROTATE_90
- TRANSFORM_ROTATE_180 = TRANSFORM_ROTATE_180
- TRANSFORM_ROTATE_270 = TRANSFORM_ROTATE_270
-
- def __init__(self, rotation: int = 0, flip_h: bool = False, flip_v: bool = False):
- super().__init__()
- self._rotation = rotation
- self._flip_h = flip_h
- self._flip_v = flip_v
-
- def getRotation(self) -> int:
- return self._rotation
-
- def setRotation(self, rotation: int) -> None:
- self._rotation = rotation
-
- def isFlippedHorizontally(self) -> bool:
- return self._flip_h
-
- def setFlipHorizontal(self, flip: bool) -> None:
- self._flip_h = flip
-
- def isFlippedVertically(self) -> bool:
- return self._flip_v
-
- def setFlipVertical(self, flip: bool) -> None:
- self._flip_v = flip
-
- @staticmethod
- def fromTransformBits(transform: int) -> "ImageTransform":
- flip_h = bool(transform & TRANSFORM_FLIP_H)
- flip_v = bool(transform & TRANSFORM_FLIP_V)
- rotation = 0
- if transform & TRANSFORM_ROTATE_90:
- rotation = 90
- elif transform & TRANSFORM_ROTATE_180:
- rotation = 180
- elif transform & TRANSFORM_ROTATE_270:
- rotation = 270
- return ImageTransform(rotation, flip_h, flip_v)
-
- def getTransformBits(self) -> int:
- bits = 0
- if self._rotation == 90:
- bits |= TRANSFORM_ROTATE_90
- elif self._rotation == 180:
- bits |= TRANSFORM_ROTATE_180
- elif self._rotation == 270:
- bits |= TRANSFORM_ROTATE_270
- if self._flip_h:
- bits |= TRANSFORM_FLIP_H
- if self._flip_v:
- bits |= TRANSFORM_FLIP_V
- return bits
-
- def toString(self) -> str:
- return (f"ImageTransform(rotation={self._rotation}, "
- f"flipH={self._flip_h}, flipV={self._flip_v})")
-
-
-class ImageConfig(Stub):
- """ImageConfig — 图像配置"""
-
- def __init__(self, width: int = 0, height: int = 0,
- format: int = FORMAT_UNKNOWN, usage: int = 0):
- super().__init__()
- self._width = width
- self._height = height
- self._format = format
- self._usage = usage
-
- def getWidth(self) -> int:
- return self._width
-
- def setWidth(self, width: int) -> None:
- self._width = width
-
- def getHeight(self) -> int:
- return self._height
-
- def setHeight(self, height: int) -> None:
- self._height = height
-
- def getFormat(self) -> int:
- return self._format
-
- def setFormat(self, fmt: int) -> None:
- self._format = fmt
-
- def getUsage(self) -> int:
- return self._usage
-
- def setUsage(self, usage: int) -> None:
- self._usage = usage
-
- def toString(self) -> str:
- return (f"ImageConfig(width={self._width}, height={self._height}, "
- f"format={self._format})")
-
-
-class ImagePool(Stub):
- """ImagePool — 图像池"""
-
- def __init__(self, max_images: int = 4):
- super().__init__()
- self._max_images = max_images
- self._pool: List[Image] = []
- self._lock = threading.Lock()
-
- def acquireImage(self, width: int, height: int, format: int) -> Optional[Image]:
- with self._lock:
- for img in self._pool:
- if (img.getWidth() == width and img.getHeight() == height
- and img.getFormat() == format and not img.isClosed()):
- self._pool.remove(img)
- return img
- if len(self._pool) < self._max_images:
- img = Image(width, height, format)
- return img
- return None
-
- def releaseImage(self, image: Image) -> None:
- with self._lock:
- if len(self._pool) < self._max_images and not image.isClosed():
- self._pool.append(image)
-
- def close(self) -> None:
- with self._lock:
- for img in self._pool:
- img.close()
- self._pool.clear()
-
- def getAvailableCount(self) -> int:
- with self._lock:
- return len(self._pool)
-
- def getMaxImages(self) -> int:
- return self._max_images
-
- def toString(self) -> str:
- return f"ImagePool(max={self._max_images}, available={len(self._pool)})"
-
-
-class ImageUtils(Stub):
- """ImageUtils — 图像工具类"""
-
- @staticmethod
- def getFormatName(format: int) -> str:
- names = {
- FORMAT_NV21: "NV21",
- FORMAT_NV16: "NV16",
- FORMAT_YUY2: "YUY2",
- FORMAT_JPEG: "JPEG",
- FORMAT_RAW_PRIVATE: "RAW_PRIVATE",
- FORMAT_RAW_SENSOR: "RAW_SENSOR",
- FORMAT_RAW10: "RAW10",
- FORMAT_RAW12: "RAW12",
- FORMAT_RAW_DEPTH: "RAW_DEPTH",
- FORMAT_YUV_420_888: "YUV_420_888",
- FORMAT_FLEX_RGB_888: "FLEX_RGB_888",
- FORMAT_FLEX_RGBA_8888: "FLEX_RGBA_8888",
- FORMAT_PRIVATE: "PRIVATE",
- FORMAT_RGB_565: "RGB_565",
- FORMAT_RGBA_8888: "RGBA_8888",
- FORMAT_BGRA_8888: "BGRA_8888",
- FORMAT_DEPTH16: "DEPTH16",
- FORMAT_DEPTH_POINT_CLOUD: "DEPTH_POINT_CLOUD",
- FORMAT_HEIC: "HEIC",
- }
- return names.get(format, f"UNKNOWN({format})")
-
- @staticmethod
- def isYuvFormat(format: int) -> bool:
- return format in (FORMAT_NV21, FORMAT_NV16, FORMAT_YUY2,
- FORMAT_YUV_420_888, FORMAT_YUV_422_888, FORMAT_YUV_444_888)
-
- @staticmethod
- def getPlaneCount(format: int) -> int:
- if format in (FORMAT_NV21, FORMAT_NV16):
- return 2
- if format in (FORMAT_YUV_420_888, FORMAT_YUV_422_888, FORMAT_YUV_444_888):
- return 3
- if format in (FORMAT_RGBA_8888, FORMAT_RGBX_8888, FORMAT_BGRA_8888,
- FORMAT_RGB_565, FORMAT_JPEG):
- return 1
- if format == FORMAT_PRIVATE:
- return 1
- return 1
-
- @staticmethod
- def getSizeInBytes(width: int, height: int, format: int) -> int:
- bpp = {
- FORMAT_RGBA_8888: 4,
- FORMAT_RGBX_8888: 4,
- FORMAT_BGRA_8888: 4,
- FORMAT_RGB_565: 2,
- FORMAT_YUY2: 2,
- }
- if format == FORMAT_JPEG:
- return width * height * 3
- if format == FORMAT_NV21:
- return width * height * 3 // 2
- if format == FORMAT_NV16:
- return width * height * 2
- if format == FORMAT_YUV_420_888:
- return width * height * 3 // 2
- if format in bpp:
- return width * height * bpp[format]
- return width * height * 4
-
- @staticmethod
- def isDepthFormat(format: int) -> bool:
- return format in (FORMAT_DEPTH16, FORMAT_DEPTH_POINT_CLOUD,
- FORMAT_RAW_DEPTH, FORMAT_RAW_DEPTH10)
\ No newline at end of file
diff --git a/android_pyapi/android/media_midi.py b/android_pyapi/android/media_midi.py
deleted file mode 100644
index ad911af..0000000
--- a/android_pyapi/android/media_midi.py
+++ /dev/null
@@ -1,315 +0,0 @@
-"""
-Android media.midi 组件 — MidiManager, MidiDevice, MidiReceiver, MidiSender 等
-方法签名完全对齐 Android SDK
-"""
-
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# MidiManager
-# ═══════════════════════════════════════════════════════════════
-
-class MidiManager(Stub):
- """MidiManager — MIDI 管理器"""
-
- def __init__(self):
- super().__init__()
- self._devices: Dict[int, MidiDevice] = {}
- self._callbacks: Dict[int, Callable] = {}
- self._next_device_id = 1
- self._init_default_devices()
-
- def _init_default_devices(self):
- info = MidiDeviceInfo(
- id=0, inputPortCount=1, outputPortCount=1,
- type=MidiDeviceInfo.TYPE_VIRTUAL,
- properties={MidiDeviceInfo.PROPERTY_NAME: "Virtual MIDI"}
- )
- device = MidiDevice(info)
- self._devices[0] = device
-
- def getDevices(self) -> List["MidiDeviceInfo"]:
- return [d.getInfo() for d in self._devices.values()]
-
- def registerDeviceCallback(self, callback: Callable, handler: Any = None):
- cid = id(callback)
- self._callbacks[cid] = callback
-
- def unregisterDeviceCallback(self, callback: Callable):
- cid = id(callback)
- self._callbacks.pop(cid, None)
-
- def openDevice(self, deviceInfo: "MidiDeviceInfo",
- callback: Callable, handler: Any = None):
- device = self._devices.get(deviceInfo.getId())
- if device:
- callback(device)
-
- def openBluetoothDevice(self, bluetoothDevice: Any) -> Optional["MidiDevice"]:
- return None
-
- def getDefaultDevice(self) -> Optional["MidiDevice"]:
- for d in self._devices.values():
- return d
- return None
-
- def deviceConnected(self, info: "MidiDeviceInfo"):
- pass
-
- def deviceDisconnected(self, info: "MidiDeviceInfo"):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# MidiDevice
-# ═══════════════════════════════════════════════════════════════
-
-class MidiDevice(Stub):
- """MidiDevice — MIDI 设备"""
-
- # ═══════════════════════════════════════════════════════════
- # MidiConnection
- # ═══════════════════════════════════════════════════════════
-
- class MidiConnection(Stub):
- """MidiDevice.MidiConnection — MIDI 连接"""
-
- def __init__(self):
- super().__init__()
-
- def close(self):
- pass
-
- def toString(self) -> str:
- return "MidiConnection"
-
- def __init__(self, info: "MidiDeviceInfo" = None):
- super().__init__()
- self._info = info or MidiDeviceInfo()
- self._input_ports: List[MidiInputPort] = []
- self._output_ports: List[MidiOutputPort] = []
- self._closed = False
-
- def getInfo(self) -> "MidiDeviceInfo":
- return self._info
-
- def openInputPort(self, portNumber: int) -> Optional["MidiInputPort"]:
- if self._closed:
- return None
- port = MidiInputPort(portNumber)
- self._input_ports.append(port)
- return port
-
- def openOutputPort(self, portNumber: int) -> Optional["MidiOutputPort"]:
- if self._closed:
- return None
- port = MidiOutputPort(portNumber)
- self._output_ports.append(port)
- return port
-
- def close(self):
- self._closed = True
-
- def toString(self) -> str:
- return f"MidiDevice(info={self._info})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MidiDeviceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class MidiDeviceInfo(Stub):
- """MidiDeviceInfo — MIDI 设备信息"""
-
- TYPE_USB = 1
- TYPE_BLUETOOTH = 2
- TYPE_VIRTUAL = 3
-
- PROPERTY_ALSA_CARD = "alsa_card"
- PROPERTY_ALSA_DEVICE = "alsa_device"
- PROPERTY_MANUFACTURER = "manufacturer"
- PROPERTY_NAME = "name"
- PROPERTY_PRODUCT = "product"
- PROPERTY_SERIAL_NUMBER = "serial_number"
- PROPERTY_USB_DEVICE = "usb_device"
-
- def __init__(self, id: int = 0, inputPortCount: int = 0,
- outputPortCount: int = 0, type_: int = TYPE_VIRTUAL,
- properties: Optional[Dict[str, str]] = None):
- super().__init__()
- self._id = id
- self._input_port_count = inputPortCount
- self._output_port_count = outputPortCount
- self._type = type_
- self._properties = properties or {}
-
- def getId(self) -> int:
- return self._id
-
- def getProperties(self) -> Dict[str, str]:
- return dict(self._properties)
-
- def getInputPortCount(self) -> int:
- return self._input_port_count
-
- def getOutputPortCount(self) -> int:
- return self._output_port_count
-
- def getType(self) -> int:
- return self._type
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, MidiDeviceInfo):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return hash(self._id) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"MidiDeviceInfo(id={self._id}, type={self._type}," \
- f" name={self._properties.get(MidiDeviceInfo.PROPERTY_NAME, '')})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MidiReceiver
-# ═══════════════════════════════════════════════════════════════
-
-class MidiReceiver(Stub):
- """MidiReceiver — MIDI 接收器"""
-
- def __init__(self, maxMessageSize: int = 1024):
- super().__init__()
- self._max_message_size = maxMessageSize
-
- def send(self, msg: bytes, offset: int, count: int):
- self.onSend(msg, offset, count)
-
- def onSend(self, msg: bytes, offset: int, count: int):
- pass
-
- def flush(self):
- pass
-
- def getMaxMessageSize(self) -> int:
- return self._max_message_size
-
-
-# ═══════════════════════════════════════════════════════════════
-# MidiSender
-# ═══════════════════════════════════════════════════════════════
-
-class MidiSender(Stub):
- """MidiSender — MIDI 发送器"""
-
- def __init__(self):
- super().__init__()
- self._receivers: List[MidiReceiver] = []
-
- def send(self, msg: bytes, offset: int, count: int):
- for r in self._receivers:
- r.send(msg, offset, count)
-
- def onConnect(self, receiver: MidiReceiver):
- pass
-
- def onDisconnect(self, receiver: MidiReceiver):
- pass
-
- def connect(self, receiver: MidiReceiver):
- self._receivers.append(receiver)
- self.onConnect(receiver)
-
- def disconnect(self, receiver: MidiReceiver):
- if receiver in self._receivers:
- self._receivers.remove(receiver)
- self.onDisconnect(receiver)
-
-
-# ═══════════════════════════════════════════════════════════════
-# MidiInputPort
-# ═══════════════════════════════════════════════════════════════
-
-class MidiInputPort(MidiReceiver):
- """MidiInputPort — MIDI 输入端口"""
-
- def __init__(self, portNumber: int = 0):
- super().__init__()
- self._port_number = portNumber
- self._closed = False
-
- def send(self, msg: bytes, offset: int, count: int):
- if not self._closed:
- self.onSend(msg, offset, count)
-
- def onSend(self, msg: bytes, offset: int, count: int):
- pass
-
- def flush(self):
- pass
-
- def close(self):
- self._closed = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# MidiOutputPort
-# ═══════════════════════════════════════════════════════════════
-
-class MidiOutputPort(MidiSender):
- """MidiOutputPort — MIDI 输出端口"""
-
- def __init__(self, portNumber: int = 0):
- super().__init__()
- self._port_number = portNumber
-
- def send(self, msg: bytes, offset: int, count: int):
- super().send(msg, offset, count)
-
- def onSend(self, msg: bytes, offset: int, count: int):
- pass
-
- def getPortNumber(self) -> int:
- return self._port_number
-
-
-# ═══════════════════════════════════════════════════════════════
-# MidiEndpoint (stub)
-# ═══════════════════════════════════════════════════════════════
-
-class MidiEndpoint(Stub):
- """MidiEndpoint — MIDI 端点"""
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# MidiDeviceService
-# ═══════════════════════════════════════════════════════════════
-
-class MidiDeviceService(Stub):
- """MidiDeviceService — MIDI 设备服务"""
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "MidiManager",
- "MidiDevice",
- "MidiDeviceInfo",
- "MidiReceiver",
- "MidiSender",
- "MidiInputPort",
- "MidiOutputPort",
- "MidiEndpoint",
- "MidiDeviceService",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/media_projection.py b/android_pyapi/android/media_projection.py
deleted file mode 100644
index a7b0794..0000000
--- a/android_pyapi/android/media_projection.py
+++ /dev/null
@@ -1,171 +0,0 @@
-"""
-Android media.projection 组件 — MediaProjectionManager, MediaProjection, MediaProjectionInfo 等
-方法签名完全对齐 Android SDK
-"""
-
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaProjectionManager
-# ═══════════════════════════════════════════════════════════════
-
-class MediaProjectionManager(Stub):
- """MediaProjectionManager — 媒体投影管理器"""
-
- def __init__(self):
- super().__init__()
- self._active_projections: Dict[int, "MediaProjection"] = {}
- self._callbacks: Dict[int, Callable] = {}
-
- def createScreenCaptureIntent(self) -> Any:
- return "SCREEN_CAPTURE_INTENT"
-
- def getMediaProjection(self, resultCode: int, data: Any) -> Optional["MediaProjection"]:
- if resultCode == -1: # RESULT_OK
- proj = MediaProjection()
- self._active_projections[id(proj)] = proj
- return proj
- return None
-
- def getActiveProjectionInfo(self) -> Optional["MediaProjectionInfo"]:
- for proj in self._active_projections.values():
- info = proj.getProjectionInfo()
- if info:
- return info
- return None
-
- def getDisplayProjection(self, displayId: int) -> Optional["MediaProjection"]:
- return None
-
- def addCallback(self, callback: Callable, handler: Any = None):
- cid = id(callback)
- self._callbacks[cid] = callback
-
- def removeCallback(self, callback: Callable):
- cid = id(callback)
- self._callbacks.pop(cid, None)
-
- def isMediaProjectionAllowed(self, packageName: str) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaProjection
-# ═══════════════════════════════════════════════════════════════
-
-class MediaProjection(Stub):
- """MediaProjection — 媒体投影"""
-
- # ═══════════════════════════════════════════════════════════
- # Callback
- # ═══════════════════════════════════════════════════════════
-
- class Callback(Stub):
- """MediaProjection.Callback — 投影回调"""
-
- def onStop(self):
- pass
-
- def onCapturedContentResize(self, width: int, height: int):
- pass
-
- def onCapturedContentVisibilityChanged(self, isVisible: bool):
- pass
-
- def __init__(self):
- super().__init__()
- self._stopped = False
- self._callbacks: List[MediaProjection.Callback] = []
- self._projection_info = MediaProjectionInfo(
- packageName="com.android.systemui",
- uid=1000,
- isVirtualDisplay=False
- )
-
- def createVirtualDisplay(self, name: str, width: int, height: int,
- densityDpi: int, flags: int, surface: Any,
- callback: Callable = None, handler: Any = None) -> Any:
- from .hardware_display import VirtualDisplay
- vd = VirtualDisplay(99, name, width, height, densityDpi, surface, flags)
- return vd
-
- def registerCallback(self, callback: Callback):
- self._callbacks.append(callback)
-
- def unregisterCallback(self, callback: Callback):
- if callback in self._callbacks:
- self._callbacks.remove(callback)
-
- def stop(self):
- self._stopped = True
- for cb in self._callbacks:
- cb.onStop()
-
- def getProjectionInfo(self) -> "MediaProjectionInfo":
- return self._projection_info
-
- def getDisplay(self) -> Optional[Any]:
- from .hardware_display import Display
- return Display(displayId=0, name="Projection Display")
-
- def applyTransparentRegionOverlay(self, region: Any):
- pass
-
- def removeTransparentRegionOverlay(self):
- pass
-
- def toString(self) -> str:
- return f"MediaProjection(stopped={self._stopped})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaProjectionInfo
-# ═══════════════════════════════════════════════════════════════
-
-class MediaProjectionInfo(Stub):
- """MediaProjectionInfo — 媒体投影信息"""
-
- def __init__(self, packageName: str = "", uid: int = 0,
- isVirtualDisplay: bool = False):
- super().__init__()
- self._package_name = packageName
- self._uid = uid
- self._is_virtual_display = isVirtualDisplay
-
- def getProjectionType(self) -> int:
- return 0
-
- def getLaunchedFromPackage(self) -> str:
- return self._package_name
-
- def getLaunchedFromUid(self) -> int:
- return self._uid
-
- def isVirtualDisplay(self) -> bool:
- return self._is_virtual_display
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, MediaProjectionInfo):
- return False
- return (self._package_name == other._package_name
- and self._uid == other._uid)
-
- def hashCode(self) -> int:
- return hash((self._package_name, self._uid)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"MediaProjectionInfo(package={self._package_name}, uid={self._uid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "MediaProjectionManager",
- "MediaProjection",
- "MediaProjectionInfo",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/media_remoteblob.py b/android_pyapi/android/media_remoteblob.py
deleted file mode 100644
index ffe4e9d..0000000
--- a/android_pyapi/android/media_remoteblob.py
+++ /dev/null
@@ -1,633 +0,0 @@
-"""
-Android media.remoteblob 包 — RemoteBlobManager, RemoteBlob, RemoteBlobStore,
-RemoteBlobReader, RemoteBlobQuery, RemoteBlobResult
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-from typing import Any, Dict, List, Optional, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-
-__all__ = [
- "RemoteBlobManager",
- "RemoteBlob",
- "RemoteBlobStore",
- "RemoteBlobReader",
- "RemoteBlobQuery",
- "RemoteBlobResult",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-QUERY_TYPE_ALL = 0
-QUERY_TYPE_BY_ID = 1
-QUERY_TYPE_BY_OWNER = 2
-QUERY_TYPE_BY_TAG = 3
-QUERY_TYPE_BY_TIMESTAMP = 4
-QUERY_TYPE_BY_SIZE = 5
-QUERY_TYPE_BY_MIME_TYPE = 6
-
-STATUS_SUCCESS = 0
-STATUS_PENDING = 1
-STATUS_FAILED = 2
-STATUS_CANCELLED = 3
-STATUS_NOT_FOUND = 4
-STATUS_ACCESS_DENIED = 5
-STATUS_INSUFFICIENT_SPACE = 6
-STATUS_TIMEOUT = 7
-STATUS_INVALID_ARGUMENT = 8
-STATUS_EXPIRED = 9
-
-
-# ═══════════════════════════════════════════════════════════════
-# RemoteBlob
-# ═══════════════════════════════════════════════════════════════
-
-class RemoteBlob(Stub):
- """RemoteBlob — 远程 Blob 数据块"""
-
- def __init__(self, id: str = "", owner: str = "",
- tag: str = "", data: bytes = b"",
- mimeType: str = "application/octet-stream",
- size: int = 0, timestamp: int = 0,
- metadata: Dict[str, str] = None,
- expiryTimestamp: int = 0):
- super().__init__()
- self._id = id
- self._owner = owner
- self._tag = tag
- self._data = data
- self._mime_type = mimeType
- self._size = size if size > 0 else len(data)
- self._timestamp = timestamp
- self._metadata = metadata or {}
- self._expiry_timestamp = expiryTimestamp
-
- def getId(self) -> str:
- return self._id
-
- def getOwner(self) -> str:
- return self._owner
-
- def getTag(self) -> str:
- return self._tag
-
- def getData(self) -> bytes:
- return self._data
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def getSize(self) -> int:
- return self._size
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def getMetadata(self) -> Dict[str, str]:
- return dict(self._metadata)
-
- def getExpiryTimestamp(self) -> int:
- return self._expiry_timestamp
-
- def isExpired(self) -> bool:
- import time
- return 0 < self._expiry_timestamp < int(time.time() * 1000)
-
- def setMetadata(self, key: str, value: str):
- self._metadata[key] = value
-
- def getMetadataValue(self, key: str) -> Optional[str]:
- return self._metadata.get(key)
-
- class Builder(Stub):
- """RemoteBlob.Builder — Blob 构建器"""
-
- def __init__(self):
- super().__init__()
- self._id = ""
- self._owner = ""
- self._tag = ""
- self._data = b""
- self._mime_type = "application/octet-stream"
- self._metadata: Dict[str, str] = {}
- self._expiry_timestamp = 0
-
- def setId(self, id: str) -> "RemoteBlob.Builder":
- self._id = id
- return self
-
- def setOwner(self, owner: str) -> "RemoteBlob.Builder":
- self._owner = owner
- return self
-
- def setTag(self, tag: str) -> "RemoteBlob.Builder":
- self._tag = tag
- return self
-
- def setData(self, data: bytes) -> "RemoteBlob.Builder":
- self._data = data
- return self
-
- def setMimeType(self, mimeType: str) -> "RemoteBlob.Builder":
- self._mime_type = mimeType
- return self
-
- def setMetadata(self, metadata: Dict[str, str]) -> "RemoteBlob.Builder":
- self._metadata = metadata
- return self
-
- def setExpiryTimestamp(self, expiryTimestamp: int) -> "RemoteBlob.Builder":
- self._expiry_timestamp = expiryTimestamp
- return self
-
- def build(self) -> "RemoteBlob":
- return RemoteBlob(
- id=self._id, owner=self._owner, tag=self._tag,
- data=self._data, mimeType=self._mime_type,
- metadata=self._metadata,
- expiryTimestamp=self._expiry_timestamp,
- )
-
- def toString(self) -> str:
- return f"RemoteBlob(id={self._id}, size={self._size}, tag={self._tag})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, RemoteBlob):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return hash(self._id) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RemoteBlobQuery
-# ═══════════════════════════════════════════════════════════════
-
-class RemoteBlobQuery(Stub):
- """RemoteBlobQuery — 远程 Blob 查询"""
-
- def __init__(self, queryType: int = QUERY_TYPE_ALL,
- queryValue: str = "",
- ownerFilter: str = "",
- tagFilter: str = "",
- mimeTypeFilter: str = "",
- minSize: int = 0, maxSize: int = 0,
- startTimestamp: int = 0, endTimestamp: int = 0,
- offset: int = 0, limit: int = 100,
- includeExpired: bool = False):
- super().__init__()
- self._query_type = queryType
- self._query_value = queryValue
- self._owner_filter = ownerFilter
- self._tag_filter = tagFilter
- self._mime_type_filter = mimeTypeFilter
- self._min_size = minSize
- self._max_size = maxSize
- self._start_timestamp = startTimestamp
- self._end_timestamp = endTimestamp
- self._offset = offset
- self._limit = limit
- self._include_expired = includeExpired
-
- def getQueryType(self) -> int:
- return self._query_type
-
- def getQueryValue(self) -> str:
- return self._query_value
-
- def getOwnerFilter(self) -> str:
- return self._owner_filter
-
- def getTagFilter(self) -> str:
- return self._tag_filter
-
- def getMimeTypeFilter(self) -> str:
- return self._mime_type_filter
-
- def getMinSize(self) -> int:
- return self._min_size
-
- def getMaxSize(self) -> int:
- return self._max_size
-
- def getStartTimestamp(self) -> int:
- return self._start_timestamp
-
- def getEndTimestamp(self) -> int:
- return self._end_timestamp
-
- def getOffset(self) -> int:
- return self._offset
-
- def getLimit(self) -> int:
- return self._limit
-
- def includeExpired(self) -> bool:
- return self._include_expired
-
- class Builder(Stub):
- """RemoteBlobQuery.Builder — 查询构建器"""
-
- def __init__(self):
- super().__init__()
- self._query_type = QUERY_TYPE_ALL
- self._query_value = ""
- self._owner_filter = ""
- self._tag_filter = ""
- self._mime_type_filter = ""
- self._min_size = 0
- self._max_size = 0
- self._start_timestamp = 0
- self._end_timestamp = 0
- self._offset = 0
- self._limit = 100
- self._include_expired = False
-
- def setQueryType(self, queryType: int) -> "RemoteBlobQuery.Builder":
- self._query_type = queryType
- return self
-
- def setQueryValue(self, queryValue: str) -> "RemoteBlobQuery.Builder":
- self._query_value = queryValue
- return self
-
- def setOwnerFilter(self, owner: str) -> "RemoteBlobQuery.Builder":
- self._owner_filter = owner
- return self
-
- def setTagFilter(self, tag: str) -> "RemoteBlobQuery.Builder":
- self._tag_filter = tag
- return self
-
- def setMimeTypeFilter(self, mimeType: str) -> "RemoteBlobQuery.Builder":
- self._mime_type_filter = mimeType
- return self
-
- def setSizeRange(self, minSize: int, maxSize: int) -> "RemoteBlobQuery.Builder":
- self._min_size = minSize
- self._max_size = maxSize
- return self
-
- def setTimestampRange(self, start: int, end: int) -> "RemoteBlobQuery.Builder":
- self._start_timestamp = start
- self._end_timestamp = end
- return self
-
- def setOffset(self, offset: int) -> "RemoteBlobQuery.Builder":
- self._offset = offset
- return self
-
- def setLimit(self, limit: int) -> "RemoteBlobQuery.Builder":
- self._limit = limit
- return self
-
- def setIncludeExpired(self, include: bool) -> "RemoteBlobQuery.Builder":
- self._include_expired = include
- return self
-
- def build(self) -> "RemoteBlobQuery":
- return RemoteBlobQuery(
- queryType=self._query_type, queryValue=self._query_value,
- ownerFilter=self._owner_filter, tagFilter=self._tag_filter,
- mimeTypeFilter=self._mime_type_filter,
- minSize=self._min_size, maxSize=self._max_size,
- startTimestamp=self._start_timestamp,
- endTimestamp=self._end_timestamp,
- offset=self._offset, limit=self._limit,
- includeExpired=self._include_expired,
- )
-
- def toString(self) -> str:
- return f"RemoteBlobQuery(type={self._query_type}, limit={self._limit})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, RemoteBlobQuery):
- return False
- return (self._query_type == other._query_type and
- self._query_value == other._query_value)
-
- def hashCode(self) -> int:
- return hash((self._query_type, self._query_value)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RemoteBlobResult
-# ═══════════════════════════════════════════════════════════════
-
-class RemoteBlobResult(Stub):
- """RemoteBlobResult — 远程 Blob 查询结果"""
-
- def __init__(self, status: int = STATUS_SUCCESS,
- blobs: List[RemoteBlob] = None,
- totalCount: int = 0, errorMessage: str = ""):
- super().__init__()
- self._status = status
- self._blobs = blobs or []
- self._total_count = totalCount if totalCount > 0 else len(self._blobs)
- self._error_message = errorMessage
-
- def getStatus(self) -> int:
- return self._status
-
- def getBlobs(self) -> List[RemoteBlob]:
- return list(self._blobs)
-
- def getTotalCount(self) -> int:
- return self._total_count
-
- def getErrorMessage(self) -> str:
- return self._error_message
-
- def isSuccess(self) -> bool:
- return self._status == STATUS_SUCCESS
-
- def toString(self) -> str:
- return f"RemoteBlobResult(status={self._status}, count={len(self._blobs)})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, RemoteBlobResult):
- return False
- return self._status == other._status
-
- def hashCode(self) -> int:
- return self._status & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RemoteBlobStore
-# ═══════════════════════════════════════════════════════════════
-
-class RemoteBlobStore(Stub):
- """RemoteBlobStore — 远程 Blob 存储"""
-
- def __init__(self, name: str = "default",
- basePath: str = "",
- maxCapacity: int = 100 * 1024 * 1024):
- super().__init__()
- self._name = name
- self._base_path = basePath
- self._max_capacity = maxCapacity
- self._blobs: Dict[str, RemoteBlob] = {}
- self._current_size = 0
-
- def getName(self) -> str:
- return self._name
-
- def getBasePath(self) -> str:
- return self._base_path
-
- def getMaxCapacity(self) -> int:
- return self._max_capacity
-
- def getCurrentSize(self) -> int:
- return self._current_size
-
- def put(self, blob: RemoteBlob) -> int:
- if blob.getId() in self._blobs:
- old = self._blobs[blob.getId()]
- self._current_size -= old.getSize()
- self._blobs[blob.getId()] = blob
- self._current_size += blob.getSize()
- return STATUS_SUCCESS
-
- def get(self, id: str) -> Optional[RemoteBlob]:
- return self._blobs.get(id)
-
- def remove(self, id: str) -> int:
- blob = self._blobs.pop(id, None)
- if blob:
- self._current_size -= blob.getSize()
- return STATUS_SUCCESS
- return STATUS_NOT_FOUND
-
- def query(self, query: RemoteBlobQuery) -> RemoteBlobResult:
- results = list(self._blobs.values())
- if query.getQueryType() == QUERY_TYPE_BY_ID and query.getQueryValue():
- results = [b for b in results if b.getId() == query.getQueryValue()]
- elif query.getQueryType() == QUERY_TYPE_BY_OWNER and query.getOwnerFilter():
- results = [b for b in results if b.getOwner() == query.getOwnerFilter()]
- elif query.getQueryType() == QUERY_TYPE_BY_TAG and query.getTagFilter():
- results = [b for b in results if b.getTag() == query.getTagFilter()]
- elif query.getQueryType() == QUERY_TYPE_BY_MIME_TYPE and query.getMimeTypeFilter():
- results = [b for b in results if b.getMimeType() == query.getMimeTypeFilter()]
- if not query.includeExpired():
- results = [b for b in results if not b.isExpired()]
- offset = query.getOffset()
- limit = query.getLimit()
- total = len(results)
- results = results[offset:offset + limit]
- return RemoteBlobResult(status=STATUS_SUCCESS, blobs=results, totalCount=total)
-
- def clear(self):
- self._blobs.clear()
- self._current_size = 0
-
- def contains(self, id: str) -> bool:
- return id in self._blobs
-
- def getSize(self) -> int:
- return len(self._blobs)
-
- def getCapacityRemaining(self) -> int:
- return self._max_capacity - self._current_size
-
- def toString(self) -> str:
- return f"RemoteBlobStore(name={self._name}, count={len(self._blobs)})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, RemoteBlobStore):
- return False
- return self._name == other._name
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RemoteBlobReader
-# ═══════════════════════════════════════════════════════════════
-
-class RemoteBlobReader(Stub):
- """RemoteBlobReader — 远程 Blob 读取器"""
-
- def __init__(self, store: Optional[RemoteBlobStore] = None,
- blobId: str = "", bufferSize: int = 8192):
- super().__init__()
- self._store = store
- self._blob_id = blobId
- self._buffer_size = bufferSize
- self._position = 0
- self._open = False
- self._blob: Optional[RemoteBlob] = None
-
- def open(self) -> int:
- if not self._store:
- return STATUS_FAILED
- self._blob = self._store.get(self._blob_id)
- if not self._blob:
- return STATUS_NOT_FOUND
- self._position = 0
- self._open = True
- return STATUS_SUCCESS
-
- def read(self, size: int = -1) -> Optional[bytes]:
- if not self._open or not self._blob:
- return None
- data = self._blob.getData()
- if self._position >= len(data):
- return b""
- if size < 0:
- result = data[self._position:]
- self._position = len(data)
- else:
- result = data[self._position:self._position + size]
- self._position += len(result)
- return result
-
- def readFully(self) -> Optional[bytes]:
- if not self._open or not self._blob:
- return None
- return self._blob.getData()
-
- def seek(self, position: int) -> int:
- if not self._blob:
- return STATUS_FAILED
- if position < 0 or position > len(self._blob.getData()):
- return STATUS_INVALID_ARGUMENT
- self._position = position
- return STATUS_SUCCESS
-
- def getPosition(self) -> int:
- return self._position
-
- def getRemaining(self) -> int:
- if not self._blob:
- return 0
- return max(0, len(self._blob.getData()) - self._position)
-
- def close(self):
- self._open = False
- self._blob = None
- self._position = 0
-
- def isOpen(self) -> bool:
- return self._open
-
- def toString(self) -> str:
- return f"RemoteBlobReader(blob={self._blob_id}, open={self._open})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RemoteBlobManager
-# ═══════════════════════════════════════════════════════════════
-
-class RemoteBlobManager(Stub):
- """RemoteBlobManager — 远程 Blob 管理器"""
-
- def __init__(self):
- super().__init__()
- self._stores: Dict[str, RemoteBlobStore] = {}
- self._default_store = RemoteBlobStore("default")
- self._stores["default"] = self._default_store
- self._listeners: Dict[int, Callable] = {}
-
- def createStore(self, name: str, basePath: str = "",
- maxCapacity: int = 100 * 1024 * 1024) -> RemoteBlobStore:
- if name in self._stores:
- raise IllegalArgumentException(f"Store '{name}' already exists")
- store = RemoteBlobStore(name=name, basePath=basePath, maxCapacity=maxCapacity)
- self._stores[name] = store
- return store
-
- def getStore(self, name: str) -> Optional[RemoteBlobStore]:
- return self._stores.get(name)
-
- def deleteStore(self, name: str) -> int:
- if name not in self._stores:
- return STATUS_NOT_FOUND
- self._stores[name].clear()
- del self._stores[name]
- return STATUS_SUCCESS
-
- def getDefaultStore(self) -> RemoteBlobStore:
- return self._default_store
-
- def listStores(self) -> List[str]:
- return list(self._stores.keys())
-
- def openReader(self, storeName: str, blobId: str) -> Optional[RemoteBlobReader]:
- store = self._stores.get(storeName)
- if not store:
- return None
- reader = RemoteBlobReader(store=store, blobId=blobId)
- status = reader.open()
- return reader if status == STATUS_SUCCESS else None
-
- def put(self, blob: RemoteBlob, storeName: str = "default") -> int:
- store = self._stores.get(storeName)
- if not store:
- return STATUS_NOT_FOUND
- return store.put(blob)
-
- def get(self, blobId: str, storeName: str = "default") -> Optional[RemoteBlob]:
- store = self._stores.get(storeName)
- if not store:
- return None
- return store.get(blobId)
-
- def remove(self, blobId: str, storeName: str = "default") -> int:
- store = self._stores.get(storeName)
- if not store:
- return STATUS_NOT_FOUND
- return store.remove(blobId)
-
- def query(self, query: RemoteBlobQuery, storeName: str = "default") -> RemoteBlobResult:
- store = self._stores.get(storeName)
- if not store:
- return RemoteBlobResult(status=STATUS_NOT_FOUND)
- return store.query(query)
-
- def registerCallback(self, callback: Callable) -> int:
- lid = id(callback)
- self._listeners[lid] = callback
- return STATUS_SUCCESS
-
- def unregisterCallback(self, callback: Callable) -> int:
- lid = id(callback)
- return STATUS_SUCCESS if self._listeners.pop(lid, None) else STATUS_NOT_FOUND
-
- def getStoreNames(self) -> List[str]:
- return self.listStores()
-
- def getTotalSize(self) -> int:
- return sum(s.getCurrentSize() for s in self._stores.values())
-
- def getTotalCount(self) -> int:
- return sum(s.getSize() for s in self._stores.values())
-
- def clearAll(self):
- for store in self._stores.values():
- store.clear()
-
- def toString(self) -> str:
- return (f"RemoteBlobManager(stores={len(self._stores)}, "
- f"totalBlobs={self.getTotalCount()})")
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/media_session.py b/android_pyapi/android/media_session.py
deleted file mode 100644
index b848285..0000000
--- a/android_pyapi/android/media_session.py
+++ /dev/null
@@ -1,854 +0,0 @@
-"""
-Android media.session 组件 — MediaSession, MediaController, PlaybackState, MediaMetadata 等
-方法签名完全对齐 Android SDK
-"""
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Union
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaSession
-# ═══════════════════════════════════════════════════════════════
-
-class MediaSession(Stub):
- """MediaSession — 媒体会话"""
-
- FLAG_HANDLES_MEDIA_BUTTONS = 1
- FLAG_HANDLES_TRANSPORT_CONTROLS = 2
- FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 4
-
- # ═══════════════════════════════════════════════════════════
- # Callback
- # ═══════════════════════════════════════════════════════════
-
- class Callback(Stub):
- """MediaSession.Callback — 会话回调"""
-
- def onPlay(self):
- pass
-
- def onPause(self):
- pass
-
- def onSkipToNext(self):
- pass
-
- def onSkipToPrevious(self):
- pass
-
- def onFastForward(self):
- pass
-
- def onRewind(self):
- pass
-
- def onStop(self):
- pass
-
- def onSeekTo(self, pos: int):
- pass
-
- def onSetRating(self, rating: "Rating"):
- pass
-
- def onSetRepeatMode(self, repeatMode: int):
- pass
-
- def onSetShuffleMode(self, shuffleMode: int):
- pass
-
- def onCommand(self, command: str, extras: Any, cb: Any):
- pass
-
- def onCustomAction(self, action: str, extras: Any):
- pass
-
- def onMediaButtonEvent(self, mediaButtonIntent: Any) -> bool:
- return False
-
- def onPlayFromMediaId(self, mediaId: str, extras: Any):
- pass
-
- def onPlayFromSearch(self, query: str, extras: Any):
- pass
-
- def onPlayFromUri(self, uri: str, extras: Any):
- pass
-
- def onPrepare(self):
- pass
-
- def onPrepareFromMediaId(self, mediaId: str, extras: Any):
- pass
-
- def onPrepareFromSearch(self, query: str, extras: Any):
- pass
-
- def onPrepareFromUri(self, uri: str, extras: Any):
- pass
-
- def __init__(self, context: Any = None, tag: str = "",
- token: "SessionToken" = None):
- super().__init__()
- self._tag = tag
- self._token = token or SessionToken()
- self._active = False
- self._flags = 0
- self._session_activity: Any = None
- self._callback: Optional[MediaSession.Callback] = None
- self._metadata: Optional["MediaMetadata"] = None
- self._playback_state: Optional["PlaybackState"] = None
- self._queue: List["QueueItem"] = []
- self._queue_title: Optional[str] = None
- self._extras: Any = None
- self._rating_type = Rating.RATING_NONE
- self._repeat_mode = PlaybackState.REPEAT_MODE_NONE
- self._shuffle_mode = PlaybackState.SHUFFLE_MODE_NONE
- self._captioning_enabled = False
- self._controllers: List[MediaController] = []
-
- def setSessionActivity(self, sessionActivity: Any):
- self._session_activity = sessionActivity
-
- def sendSessionEvent(self, event: str, extras: Any):
- for ctrl in self._controllers:
- ctrl._callback.onSessionEvent(event, extras)
-
- def release(self):
- self._active = False
- self._controllers.clear()
-
- def getSessionToken(self) -> "SessionToken":
- return self._token
-
- def setFlags(self, flags: int):
- self._flags = flags
-
- def setPlaybackToLocal(self, volumeProvider: Any = None):
- pass
-
- def setPlaybackToRemote(self, volumeProvider: Any):
- pass
-
- def setActive(self, active: bool):
- self._active = active
-
- def isActive(self) -> bool:
- return self._active
-
- def setMediaMetadata(self, metadata: "MediaMetadata"):
- self._metadata = metadata
- for ctrl in self._controllers:
- ctrl._callback.onMetadataChanged(metadata)
-
- def setPlaybackState(self, state: "PlaybackState"):
- self._playback_state = state
- for ctrl in self._controllers:
- ctrl._callback.onPlaybackStateChanged(state)
-
- def setQueue(self, queue: List["QueueItem"]):
- self._queue = queue
- for ctrl in self._controllers:
- ctrl._callback.onQueueChanged(queue)
-
- def setQueueTitle(self, title: str):
- self._queue_title = title
- for ctrl in self._controllers:
- ctrl._callback.onQueueTitleChanged(title)
-
- def setExtras(self, extras: Any):
- self._extras = extras
- for ctrl in self._controllers:
- ctrl._callback.onExtrasChanged(extras)
-
- def setMetadata(self, metadata: "MediaMetadata"):
- self.setMediaMetadata(metadata)
-
- def setRatingType(self, ratingType: int):
- self._rating_type = ratingType
-
- def setRepeatMode(self, repeatMode: int):
- self._repeat_mode = repeatMode
- for ctrl in self._controllers:
- ctrl._callback.onRepeatModeChanged(repeatMode)
-
- def setShuffleMode(self, shuffleMode: int):
- self._shuffle_mode = shuffleMode
- for ctrl in self._controllers:
- ctrl._callback.onShuffleModeChanged(shuffleMode)
-
- def setCaptioningEnabled(self, enabled: bool):
- self._captioning_enabled = enabled
- for ctrl in self._controllers:
- ctrl._callback.onCaptioningEnabledChanged(enabled)
-
- def getController(self) -> "MediaController":
- ctrl = MediaController(self)
- self._controllers.append(ctrl)
- return ctrl
-
- def getCallerPackageName(self) -> str:
- return "com.android.systemui"
-
- def setCallback(self, callback: Callback, handler: Any = None):
- self._callback = callback
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaController
-# ═══════════════════════════════════════════════════════════════
-
-class MediaController(Stub):
- """MediaController — 媒体控制器"""
-
- # ═══════════════════════════════════════════════════════════
- # Callback
- # ═══════════════════════════════════════════════════════════
-
- class Callback(Stub):
- """MediaController.Callback — 控制器回调"""
-
- def onSessionReady(self):
- pass
-
- def onSessionDestroyed(self):
- pass
-
- def onSessionEvent(self, event: str, extras: Any):
- pass
-
- def onPlaybackStateChanged(self, state: "PlaybackState"):
- pass
-
- def onMetadataChanged(self, metadata: "MediaMetadata"):
- pass
-
- def onQueueChanged(self, queue: List["QueueItem"]):
- pass
-
- def onQueueTitleChanged(self, title: str):
- pass
-
- def onExtrasChanged(self, extras: Any):
- pass
-
- def onAudioInfoChanged(self, info: Any):
- pass
-
- def onCaptioningEnabledChanged(self, enabled: bool):
- pass
-
- def onRepeatModeChanged(self, repeatMode: int):
- pass
-
- def onShuffleModeChanged(self, shuffleMode: int):
- pass
-
- # ═══════════════════════════════════════════════════════════
- # TransportControls
- # ═══════════════════════════════════════════════════════════
-
- class TransportControls(Stub):
- """MediaController.TransportControls — 传输控制"""
-
- def __init__(self, session: "MediaSession"):
- super().__init__()
- self._session = session
-
- def play(self):
- if self._session._callback:
- self._session._callback.onPlay()
-
- def pause(self):
- if self._session._callback:
- self._session._callback.onPause()
-
- def stop(self):
- if self._session._callback:
- self._session._callback.onStop()
-
- def fastForward(self):
- if self._session._callback:
- self._session._callback.onFastForward()
-
- def rewind(self):
- if self._session._callback:
- self._session._callback.onRewind()
-
- def skipToNext(self):
- if self._session._callback:
- self._session._callback.onSkipToNext()
-
- def skipToPrevious(self):
- if self._session._callback:
- self._session._callback.onSkipToPrevious()
-
- def seekTo(self, pos: int):
- if self._session._callback:
- self._session._callback.onSeekTo(pos)
-
- def setRating(self, rating: "Rating"):
- if self._session._callback:
- self._session._callback.onSetRating(rating)
-
- def setRepeatMode(self, repeatMode: int):
- if self._session._callback:
- self._session._callback.onSetRepeatMode(repeatMode)
-
- def setShuffleMode(self, shuffleMode: int):
- if self._session._callback:
- self._session._callback.onSetShuffleMode(shuffleMode)
-
- def sendCustomAction(self, action: str, extras: Any):
- if self._session._callback:
- self._session._callback.onCustomAction(action, extras)
-
- def playFromMediaId(self, mediaId: str, extras: Any):
- if self._session._callback:
- self._session._callback.onPlayFromMediaId(mediaId, extras)
-
- def playFromSearch(self, query: str, extras: Any):
- if self._session._callback:
- self._session._callback.onPlayFromSearch(query, extras)
-
- def playFromUri(self, uri: str, extras: Any):
- if self._session._callback:
- self._session._callback.onPlayFromUri(uri, extras)
-
- def prepare(self):
- if self._session._callback:
- self._session._callback.onPrepare()
-
- def prepareFromMediaId(self, mediaId: str, extras: Any):
- if self._session._callback:
- self._session._callback.onPrepareFromMediaId(mediaId, extras)
-
- def prepareFromSearch(self, query: str, extras: Any):
- if self._session._callback:
- self._session._callback.onPrepareFromSearch(query, extras)
-
- def prepareFromUri(self, uri: str, extras: Any):
- if self._session._callback:
- self._session._callback.onPrepareFromUri(uri, extras)
-
- def __init__(self, session: "MediaSession" = None):
- super().__init__()
- self._session = session
- self._callback = MediaController.Callback()
- self._transport_controls = MediaController.TransportControls(session)
-
- def getSessionToken(self) -> "SessionToken":
- return self._session.getSessionToken() if self._session else SessionToken()
-
- def getTransportControls(self) -> TransportControls:
- return self._transport_controls
-
- def getPlaybackState(self) -> Optional["PlaybackState"]:
- return self._session._playback_state if self._session else None
-
- def getMetadata(self) -> Optional["MediaMetadata"]:
- return self._session._metadata if self._session else None
-
- def getQueueTitle(self) -> Optional[str]:
- return self._session._queue_title if self._session else None
-
- def getQueue(self) -> List["QueueItem"]:
- return self._session._queue if self._session else []
-
- def getRepeatMode(self) -> int:
- return self._session._repeat_mode if self._session else PlaybackState.REPEAT_MODE_NONE
-
- def getShuffleMode(self) -> int:
- return self._session._shuffle_mode if self._session else PlaybackState.SHUFFLE_MODE_NONE
-
- def getRatingType(self) -> int:
- return self._session._rating_type if self._session else Rating.RATING_NONE
-
- def getExtras(self) -> Any:
- return self._session._extras if self._session else None
-
- def getFlags(self) -> int:
- return self._session._flags if self._session else 0
-
- def getPackageName(self) -> str:
- return self._session.getCallerPackageName() if self._session else ""
-
- def getSessionActivity(self) -> Any:
- return self._session._session_activity if self._session else None
-
- def registerCallback(self, callback: Callback, handler: Any = None):
- self._callback = callback
-
- def unregisterCallback(self, callback: Callback):
- self._callback = MediaController.Callback()
-
- def sendCommand(self, command: str, extras: Any, cb: Any):
- if self._session and self._session._callback:
- self._session._callback.onCommand(command, extras, cb)
-
- def adjustVolume(self, direction: int, flags: int):
- pass
-
- def setVolumeTo(self, value: int, flags: int):
- pass
-
- def isSessionReady(self) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# PlaybackState
-# ═══════════════════════════════════════════════════════════════
-
-class PlaybackState(Stub):
- """PlaybackState — 播放状态"""
-
- STATE_NONE = 0
- STATE_STOPPED = 1
- STATE_PAUSED = 2
- STATE_PLAYING = 3
- STATE_FAST_FORWARDING = 4
- STATE_REWINDING = 5
- STATE_BUFFERING = 6
- STATE_ERROR = 7
- STATE_CONNECTING = 8
- STATE_SKIPPING_TO_PREVIOUS = 9
- STATE_SKIPPING_TO_NEXT = 10
- STATE_SKIPPING_TO_QUEUE_ITEM = 11
-
- ACTION_PLAY = 1 << 0
- ACTION_PAUSE = 1 << 1
- ACTION_PLAY_PAUSE = 1 << 2
- ACTION_STOP = 1 << 3
- ACTION_SEEK_TO = 1 << 4
- ACTION_FAST_FORWARD = 1 << 5
- ACTION_REWIND = 1 << 6
- ACTION_SKIP_TO_NEXT = 1 << 7
- ACTION_SKIP_TO_PREVIOUS = 1 << 8
- ACTION_SET_RATING = 1 << 9
- ACTION_SET_REPEAT_MODE = 1 << 10
- ACTION_SET_SHUFFLE_MODE = 1 << 11
- ACTION_SET_CAPTIONING_ENABLED = 1 << 12
- ACTION_SKIP_TO_QUEUE_ITEM = 1 << 13
- ACTION_PLAY_FROM_MEDIA_ID = 1 << 14
- ACTION_PLAY_FROM_SEARCH = 1 << 15
- ACTION_PREPARE = 1 << 16
- ACTION_PREPARE_FROM_MEDIA_ID = 1 << 17
- ACTION_PREPARE_FROM_SEARCH = 1 << 18
- ACTION_PREPARE_FROM_URI = 1 << 19
- ACTION_PLAY_FROM_URI = 1 << 20
-
- REPEAT_MODE_NONE = 0
- REPEAT_MODE_ONE = 1
- REPEAT_MODE_ALL = 2
- REPEAT_MODE_GROUP = 3
-
- SHUFFLE_MODE_NONE = 0
- SHUFFLE_MODE_ALL = 1
- SHUFFLE_MODE_GROUP = 2
-
- class Builder(Stub):
- """PlaybackState.Builder — 播放状态构建器"""
-
- def __init__(self):
- super().__init__()
- self._state = PlaybackState.STATE_NONE
- self._position = 0
- self._speed = 1.0
- self._actions = 0
- self._custom_actions: List[Any] = []
- self._active_queue_item_id = -1
- self._error_message: Optional[str] = None
- self._extras: Any = None
- self._buffered_position = 0
-
- def setState(self, state: int, position: int, speed: float) -> "PlaybackState.Builder":
- self._state = state
- self._position = position
- self._speed = speed
- return self
-
- def setActions(self, actions: int) -> "PlaybackState.Builder":
- self._actions = actions
- return self
-
- def setCustomAction(self, action: str, name: str, icon: Any = None) -> "PlaybackState.Builder":
- self._custom_actions.append((action, name, icon))
- return self
-
- def setActiveQueueItemId(self, id: int) -> "PlaybackState.Builder":
- self._active_queue_item_id = id
- return self
-
- def setErrorMessage(self, error: str) -> "PlaybackState.Builder":
- self._error_message = error
- return self
-
- def setExtras(self, extras: Any) -> "PlaybackState.Builder":
- self._extras = extras
- return self
-
- def setBufferedPosition(self, bufferedPosition: int) -> "PlaybackState.Builder":
- self._buffered_position = bufferedPosition
- return self
-
- def setPosition(self, position: int) -> "PlaybackState.Builder":
- self._position = position
- return self
-
- def setSpeed(self, speed: float) -> "PlaybackState.Builder":
- self._speed = speed
- return self
-
- def addCustomAction(self, action: "PlaybackState.CustomAction") -> "PlaybackState.Builder":
- self._custom_actions.append(action)
- return self
-
- def build(self) -> "PlaybackState":
- ps = PlaybackState()
- ps._state = self._state
- ps._position = self._position
- ps._speed = self._speed
- ps._actions = self._actions
- ps._custom_actions = self._custom_actions
- ps._active_queue_item_id = self._active_queue_item_id
- ps._error_message = self._error_message
- ps._extras = self._extras
- ps._buffered_position = self._buffered_position
- return ps
-
- class CustomAction(Stub):
- """PlaybackState.CustomAction — 自定义操作"""
-
- def __init__(self, action: str, name: str, icon: Any = None):
- super().__init__()
- self._action = action
- self._name = name
- self._icon = icon
-
- def getAction(self) -> str:
- return self._action
-
- def getName(self) -> str:
- return self._name
-
- def getIcon(self) -> Any:
- return self._icon
-
- def __init__(self):
- super().__init__()
- self._state = PlaybackState.STATE_NONE
- self._position = 0
- self._speed = 1.0
- self._actions = 0
- self._custom_actions: List[Any] = []
- self._active_queue_item_id = -1
- self._error_message: Optional[str] = None
- self._extras: Any = None
- self._buffered_position = 0
- self._last_position_update_time = int(time.time() * 1000)
-
- def getState(self) -> int:
- return self._state
-
- def getPosition(self) -> int:
- return self._position
-
- def getPlaybackSpeed(self) -> float:
- return self._speed
-
- def getActions(self) -> int:
- return self._actions
-
- def getCustomActions(self) -> List[Any]:
- return self._custom_actions
-
- def getActiveQueueItemId(self) -> int:
- return self._active_queue_item_id
-
- def getErrorMessage(self) -> Optional[str]:
- return self._error_message
-
- def getExtras(self) -> Any:
- return self._extras
-
- def getBufferedPosition(self) -> int:
- return self._buffered_position
-
- def getLastPositionUpdateTime(self) -> int:
- return self._last_position_update_time
-
- def toString(self) -> str:
- state_names = {
- PlaybackState.STATE_NONE: "NONE",
- PlaybackState.STATE_STOPPED: "STOPPED",
- PlaybackState.STATE_PAUSED: "PAUSED",
- PlaybackState.STATE_PLAYING: "PLAYING",
- }
- return f"PlaybackState(state={state_names.get(self._state, str(self._state))}," \
- f" pos={self._position})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaMetadata
-# ═══════════════════════════════════════════════════════════════
-
-class MediaMetadata(Stub):
- """MediaMetadata — 媒体元数据"""
-
- METADATA_KEY_ALBUM = "android.media.metadata.ALBUM"
- METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART"
- METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST"
- METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI"
- METADATA_KEY_ART = "android.media.metadata.ART"
- METADATA_KEY_ARTIST = "android.media.metadata.ARTIST"
- METADATA_KEY_ART_URI = "android.media.metadata.ART_URI"
- METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR"
- METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION"
- METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER"
- METADATA_KEY_DATE = "android.media.metadata.DATE"
- METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER"
- METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION"
- METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON"
- METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI"
- METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE"
- METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE"
- METADATA_KEY_DURATION = "android.media.metadata.DURATION"
- METADATA_KEY_GENRE = "android.media.metadata.GENRE"
- METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID"
- METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS"
- METADATA_KEY_RATING = "android.media.metadata.RATING"
- METADATA_KEY_TITLE = "android.media.metadata.TITLE"
- METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER"
- METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING"
- METADATA_KEY_WRITER = "android.media.metadata.WRITER"
- METADATA_KEY_YEAR = "android.media.metadata.YEAR"
-
- class Builder(Stub):
- """MediaMetadata.Builder — 元数据构建器"""
-
- def __init__(self):
- super().__init__()
- self._data: Dict[str, Any] = {}
-
- def putString(self, key: str, value: str) -> "MediaMetadata.Builder":
- self._data[key] = value
- return self
-
- def putLong(self, key: str, value: int) -> "MediaMetadata.Builder":
- self._data[key] = value
- return self
-
- def putBitmap(self, key: str, value: Any) -> "MediaMetadata.Builder":
- self._data[key] = value
- return self
-
- def putText(self, key: str, value: str) -> "MediaMetadata.Builder":
- self._data[key] = value
- return self
-
- def putRating(self, key: str, value: "Rating") -> "MediaMetadata.Builder":
- self._data[key] = value
- return self
-
- def build(self) -> "MediaMetadata":
- mm = MediaMetadata()
- mm._data = dict(self._data)
- return mm
-
- def __init__(self):
- super().__init__()
- self._data: Dict[str, Any] = {}
-
- def getString(self, key: str) -> Optional[str]:
- v = self._data.get(key)
- return str(v) if v is not None else None
-
- def getLong(self, key: str) -> int:
- v = self._data.get(key, 0)
- try:
- return int(v)
- except (ValueError, TypeError):
- return 0
-
- def getBitmap(self, key: str) -> Any:
- return self._data.get(key)
-
- def getText(self, key: str) -> Optional[str]:
- return self.getString(key)
-
- def getDescription(self) -> "MediaDescription":
- from .media_browse import MediaDescription
- builder = MediaDescription.Builder()
- title = self.getString(MediaMetadata.METADATA_KEY_TITLE)
- if title:
- builder.setTitle(title)
- artist = self.getString(MediaMetadata.METADATA_KEY_ARTIST)
- if artist:
- builder.setSubtitle(artist)
- media_id = self.getString(MediaMetadata.METADATA_KEY_MEDIA_ID)
- if media_id:
- builder.setMediaId(media_id)
- return builder.build()
-
- def getRating(self, key: str) -> Optional["Rating"]:
- v = self._data.get(key)
- return v if isinstance(v, Rating) else None
-
- def getBitmapDescription(self) -> Any:
- return None
-
- def containsKey(self, key: str) -> bool:
- return key in self._data
-
- def keySet(self) -> Set[str]:
- return set(self._data.keys())
-
- def getMediaId(self) -> Optional[str]:
- return self.getString(MediaMetadata.METADATA_KEY_MEDIA_ID)
-
- def toString(self) -> str:
- title = self.getString(MediaMetadata.METADATA_KEY_TITLE)
- return f"MediaMetadata(title={title})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# QueueItem
-# ═══════════════════════════════════════════════════════════════
-
-class QueueItem(Stub):
- """QueueItem — 队列项"""
-
- def __init__(self, description: "MediaDescription" = None, queueId: int = 0):
- super().__init__()
- self._description = description
- self._queue_id = queueId
-
- def getDescription(self) -> "MediaDescription":
- return self._description
-
- def getQueueId(self) -> int:
- return self._queue_id
-
- def toString(self) -> str:
- return f"QueueItem(id={self._queue_id}, desc={self._description})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Rating
-# ═══════════════════════════════════════════════════════════════
-
-class Rating(Stub):
- """Rating — 评分"""
-
- RATING_NONE = 0
- RATING_HEART = 1
- RATING_THUMB_UP_DOWN = 2
- RATING_3_STARS = 3
- RATING_4_STARS = 4
- RATING_5_STARS = 5
- RATING_PERCENTAGE = 6
-
- def __init__(self, ratingStyle: int = RATING_NONE):
- super().__init__()
- self._rating_style = ratingStyle
- self._rated = False
- self._heart = False
- self._thumb_up = False
- self._star_rating = 0.0
- self._percent_rating = 0.0
-
- @staticmethod
- def newHeartRating(hasHeart: bool) -> "Rating":
- r = Rating(Rating.RATING_HEART)
- r._rated = True
- r._heart = hasHeart
- return r
-
- @staticmethod
- def newThumbRating(thumbUp: bool) -> "Rating":
- r = Rating(Rating.RATING_THUMB_UP_DOWN)
- r._rated = True
- r._thumb_up = thumbUp
- return r
-
- @staticmethod
- def newStarRating(starRatingStyle: int, starRating: float) -> "Rating":
- r = Rating(starRatingStyle)
- r._rated = True
- r._star_rating = starRating
- return r
-
- @staticmethod
- def newPercentageRating(percent: float) -> "Rating":
- r = Rating(Rating.RATING_PERCENTAGE)
- r._rated = True
- r._percent_rating = percent
- return r
-
- @staticmethod
- def newUnratedRating(ratingStyle: int) -> "Rating":
- return Rating(ratingStyle)
-
- def isRated(self) -> bool:
- return self._rated
-
- def getRatingStyle(self) -> int:
- return self._rating_style
-
- def hasHeart(self) -> bool:
- return self._heart
-
- def isThumbUp(self) -> bool:
- return self._thumb_up
-
- def getStarRating(self) -> float:
- return self._star_rating
-
- def getPercentRating(self) -> float:
- return self._percent_rating
-
- def toString(self) -> str:
- return f"Rating(style={self._rating_style}, rated={self._rated})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SessionToken
-# ═══════════════════════════════════════════════════════════════
-
-class SessionToken(Stub):
- """SessionToken — 会话令牌"""
-
- TYPE_SESSION = 0
-
- def __init__(self, type_: int = TYPE_SESSION):
- super().__init__()
- self._type = type_
- self._binder = None
-
- def getType(self) -> int:
- return self._type
-
- def getSessionBinder(self) -> Any:
- return self._binder
-
- def toString(self) -> str:
- return f"SessionToken(type={self._type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "MediaSession",
- "MediaController",
- "PlaybackState",
- "MediaMetadata",
- "QueueItem",
- "Rating",
- "SessionToken",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/media_tv.py b/android_pyapi/android/media_tv.py
deleted file mode 100644
index 07b9882..0000000
--- a/android_pyapi/android/media_tv.py
+++ /dev/null
@@ -1,359 +0,0 @@
-"""
-Android media.tv 组件 — TvInputManager, TvInputInfo, TvInputService 等
-方法签名完全对齐 Android SDK
-"""
-
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvInputManager
-# ═══════════════════════════════════════════════════════════════
-
-class TvInputManager(Stub):
- """TvInputManager — 电视输入管理器"""
-
- ACTION_VIEW_RECORDING_SCHEDULES = "android.tv.action.VIEW_RECORDING_SCHEDULES"
- ACTION_WATCH_NEXT = "android.tv.action.WATCH_NEXT"
-
- TIME_SHIFT_STATUS_AVAILABLE = 0
- TIME_SHIFT_STATUS_UNAVAILABLE = 1
- TIME_SHIFT_STATUS_UNKNOWN = 2
- TIME_SHIFT_STATUS_UNSUPPORTED = 3
-
- VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = 8
- VIDEO_UNAVAILABLE_REASON_BUFFERING = 3
- VIDEO_UNAVAILABLE_REASON_CAS = 7
- VIDEO_UNAVAILABLE_REASON_INSUFFICIENT_RESOURCE = 5
- VIDEO_UNAVAILABLE_REASON_NOT_CONNECTED = 6
- VIDEO_UNAVAILABLE_REASON_PREEMPTED = 4
- VIDEO_UNAVAILABLE_REASON_TUNING = 1
- VIDEO_UNAVAILABLE_REASON_UNKNOWN = 0
- VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 2
-
- # ═══════════════════════════════════════════════════════════
- # TvInputCallback
- # ═══════════════════════════════════════════════════════════
-
- class TvInputCallback(Stub):
- """TvInputManager.TvInputCallback — 电视输入回调"""
-
- def onInputAdded(self, inputId: str):
- pass
-
- def onInputRemoved(self, inputId: str):
- pass
-
- def onInputChanged(self, inputId: str):
- pass
-
- def onInputStateChanged(self, inputId: str, state: int):
- pass
-
- def onTvInputInfoUpdated(self, inputInfo: "TvInputInfo"):
- pass
-
- def __init__(self):
- super().__init__()
- self._inputs: Dict[str, TvInputInfo] = {}
- self._callbacks: Dict[int, TvInputManager.TvInputCallback] = {}
-
- def getTvInputList(self) -> List["TvInputInfo"]:
- return list(self._inputs.values())
-
- def getTvInputInfo(self, inputId: str) -> Optional["TvInputInfo"]:
- return self._inputs.get(inputId)
-
- def getCurrentTvInputInfo(self) -> Optional["TvInputInfo"]:
- for inp in self._inputs.values():
- return inp
- return None
-
- def updateTvInputInfo(self, inputInfo: "TvInputInfo"):
- if inputInfo:
- self._inputs[inputInfo.getId()] = inputInfo
-
- def registerCallback(self, callback: TvInputCallback, handler: Any = None):
- lid = id(callback)
- self._callbacks[lid] = callback
-
- def unregisterCallback(self, callback: TvInputCallback):
- lid = id(callback)
- self._callbacks.pop(lid, None)
-
- def createRecordingSession(self, recordingService: str, inputId: str):
- raise AndroidOnlyError("TvInputManager.createRecordingSession() is not available on desktop")
-
- def sendTvInputNotifyIntent(self, intent: Any, inputId: str):
- pass
-
- def isParentalControlsEnabled(self) -> bool:
- return False
-
- def isRatingBlocked(self, rating: str) -> bool:
- return False
-
- def getBlockedRatings(self) -> List[str]:
- return []
-
- def getAvailableTvInputs(self) -> List[str]:
- return list(self._inputs.keys())
-
- def getTvContentRatingSystems(self) -> List[str]:
- return ["US_TV", "US_MOVIE"]
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvInputInfo
-# ═══════════════════════════════════════════════════════════════
-
-class TvInputInfo(Stub):
- """TvInputInfo — 电视输入信息"""
-
- TYPE_COMPONENT = 1005
- TYPE_COMPOSITE = 1004
- TYPE_HDMI = 1007
- TYPE_OTHER = 1001
- TYPE_SCART = 1003
- TYPE_SVIDEO = 1006
- TYPE_TUNER = 0
- TYPE_DISPLAY_LINK = 1008
- TYPE_VGA = 1002
-
- def __init__(self, id: str = "", serviceInfo: Any = None,
- parentId: str = "", type_: int = TYPE_TUNER,
- hdmiDeviceInfo: Any = None,
- isHidden: bool = False, canRecord: bool = False,
- canPauseRecording: bool = False):
- super().__init__()
- self._id = id
- self._service_info = serviceInfo
- self._parent_id = parentId
- self._type = type_
- self._hdmi_device_info = hdmiDeviceInfo
- self._is_hidden = isHidden
- self._can_record = canRecord
- self._can_pause_recording = canPauseRecording
-
- def getId(self) -> str:
- return self._id
-
- def getServiceInfo(self) -> Any:
- return self._service_info
-
- def getParentId(self) -> str:
- return self._parent_id
-
- def getType(self) -> int:
- return self._type
-
- def getHdmiDeviceInfo(self) -> Any:
- return self._hdmi_device_info
-
- def loadIcon(self, context: Any) -> Any:
- return None
-
- def loadLogo(self, context: Any) -> Any:
- return None
-
- def createIntentForSetupScreen(self) -> Any:
- return None
-
- def isHidden(self) -> bool:
- return self._is_hidden
-
- def canRecord(self) -> bool:
- return self._can_record
-
- def canPauseRecording(self) -> bool:
- return self._can_pause_recording
-
- def toString(self) -> str:
- type_names = {
- TvInputInfo.TYPE_TUNER: "TUNER",
- TvInputInfo.TYPE_HDMI: "HDMI",
- TvInputInfo.TYPE_COMPOSITE: "COMPOSITE",
- TvInputInfo.TYPE_COMPONENT: "COMPONENT",
- }
- return f"TvInputInfo(id={self._id}, type={type_names.get(self._type, str(self._type))})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvInputService
-# ═══════════════════════════════════════════════════════════════
-
-class TvInputService(Stub):
- """TvInputService — 电视输入服务"""
-
- RECORDING_ERROR_RECORDING_LOST = 0
- RECORDING_ERROR_TIMEOUT = 1
- RECORDING_ERROR_OTHER = 2
-
- # ═══════════════════════════════════════════════════════════
- # Session
- # ═══════════════════════════════════════════════════════════
-
- class Session(Stub):
- """TvInputService.Session — 电视会话"""
-
- def __init__(self):
- super().__init__()
- self._main = False
- self._stream_volume = 1.0
- self._caption_enabled = False
-
- def onSetSurface(self, surface: Any) -> bool:
- return True
-
- def onSurfaceChanged(self, format: int, width: int, height: int):
- pass
-
- def onSurfaceReleased(self):
- pass
-
- def onAppPrivateCommand(self, action: str, data: Any):
- pass
-
- def onCreateOverlayView(self) -> Any:
- return None
-
- def onRelayoutContent(self):
- pass
-
- def onSetCaptionEnabled(self, enabled: bool):
- self._caption_enabled = enabled
-
- def onSetStreamVolume(self, volume: float):
- self._stream_volume = volume
-
- def onTimeShiftSetCurrentPositionRequest(self, positionMs: int):
- pass
-
- def notifyTimeShiftStatusChanged(self, status: int):
- pass
-
- def scheduleOverlayView(self, view: Any):
- pass
-
- def timeShiftPlay(self, uri: str):
- pass
-
- def timeShiftPause(self):
- pass
-
- def timeShiftResume(self):
- pass
-
- def timeShiftSeekTo(self, positionMs: int):
- pass
-
- def timeShiftSetPlaybackParams(self, params: Any):
- pass
-
- def timeShiftEnablePositionTracking(self, enable: bool):
- pass
-
- def notifyVideoAvailable(self):
- pass
-
- def notifyVideoUnavailable(self, reason: int):
- pass
-
- def notifySessionEvent(self, eventType: str, eventArgs: Any):
- pass
-
- def notifyTracksChanged(self, tracks: List[Any]):
- pass
-
- def notifyTrackSelected(self, type_: str, trackId: str):
- pass
-
- def notifyContentAllowed(self):
- pass
-
- def notifyContentBlocked(self, rating: str):
- pass
-
- def setMain(self, main: bool):
- self._main = main
-
- def setStreamVolume(self, volume: float):
- self._stream_volume = volume
-
- def __init__(self):
- super().__init__()
- self._sessions: List[TvInputService.Session] = []
-
- def onCreateSession(self, inputId: str) -> Session:
- session = TvInputService.Session()
- self._sessions.append(session)
- return session
-
- def onSetupFinished(self, inputId: str):
- pass
-
- def sessionCreated(self, session: Session):
- pass
-
- def notifyHardwareFailed(self, deviceId: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvRecordingClient / TvRecordingService (stubs)
-# ═══════════════════════════════════════════════════════════════
-
-class TvRecordingClient(Stub):
- """TvRecordingClient — 电视录制客户端"""
-
- def __init__(self):
- super().__init__()
-
- def startRecording(self, uri: str):
- pass
-
- def stopRecording(self):
- pass
-
- def pauseRecording(self):
- pass
-
- def resumeRecording(self):
- pass
-
- def release(self):
- pass
-
-
-class TvRecordingService(Stub):
- """TvRecordingService — 电视录制服务"""
-
- def __init__(self):
- super().__init__()
-
- def onStartRecording(self, inputId: str, sessionId: str):
- pass
-
- def onStopRecording(self, sessionId: str):
- pass
-
- def onPauseRecording(self, sessionId: str):
- pass
-
- def onResumeRecording(self, sessionId: str):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "TvInputManager",
- "TvInputInfo",
- "TvInputService",
- "TvRecordingClient",
- "TvRecordingService",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/media_tv_ext.py b/android_pyapi/android/media_tv_ext.py
deleted file mode 100644
index 35bbcaa..0000000
--- a/android_pyapi/android/media_tv_ext.py
+++ /dev/null
@@ -1,1500 +0,0 @@
-"""
-Android media.tv 扩展组件 — TvContentRating, TvTrackInfo, TvView, TvStreamConfig,
-TvContract, PreviewProgram, PreviewChannel 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "TvInputManager",
- "TvContentRating",
- "TvTrackInfo",
- "TvInputInfo",
- "TvInputService",
- "TvRecordingClient",
- "TvView",
- "TvStreamConfig",
- "TvContract",
- "PreviewProgram",
- "PreviewChannel",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvContentRating
-# ═══════════════════════════════════════════════════════════════
-
-class TvContentRating(Stub):
- """TvContentRating — 电视内容分级"""
-
- RATING_TV_G = "US_TV:US_TV_G"
- RATING_TV_PG = "US_TV:US_TV_PG"
- RATING_TV_14 = "US_TV:US_TV_14"
- RATING_TV_MA = "US_TV:US_TV_MA"
- RATING_TV_Y = "US_TV:US_TV_Y"
- RATING_TV_Y7 = "US_TV:US_TV_Y7"
- RATING_TV_Y7_FV = "US_TV:US_TV_Y7_FV"
- RATING_MOVIE_G = "US_MOVIE:US_MOVIE_G"
- RATING_MOVIE_PG = "US_MOVIE:US_MOVIE_PG"
- RATING_MOVIE_PG13 = "US_MOVIE:US_MOVIE_PG13"
- RATING_MOVIE_R = "US_MOVIE:US_MOVIE_R"
- RATING_MOVIE_NC17 = "US_MOVIE:US_MOVIE_NC17"
-
- def __init__(self, ratingString: str = ""):
- super().__init__()
- self._rating_string = ratingString
- parts = ratingString.split(":") if ratingString else []
- self._domain = parts[0] if len(parts) > 0 else ""
- self._rating_system = parts[1] if len(parts) > 1 else ""
- self._rating_value = parts[2] if len(parts) > 2 else ""
- self._sub_ratings: List[str] = parts[3:] if len(parts) > 3 else []
-
- @staticmethod
- def create(ratingSystemDomain: str, ratingSystem: str,
- ratedRating: str, subRatings: List[str] = None) -> "TvContentRating":
- parts = [ratingSystemDomain, ratingSystem, ratedRating]
- if subRatings:
- parts.extend(subRatings)
- return TvContentRating(":".join(parts))
-
- @staticmethod
- def createRatingSystemString(ratingSystemDomain: str, ratingSystem: str) -> str:
- return f"{ratingSystemDomain}:{ratingSystem}"
-
- @staticmethod
- def unflattenFromString(ratingString: str) -> "TvContentRating":
- return TvContentRating(ratingString)
-
- def flattenToString(self) -> str:
- return self._rating_string
-
- def getDomain(self) -> str:
- return self._domain
-
- def getRatingSystem(self) -> str:
- return self._rating_system
-
- def getMainRating(self) -> str:
- return self._rating_value
-
- def getSubRatings(self) -> List[str]:
- return list(self._sub_ratings)
-
- def getRatingSystemDomain(self) -> str:
- return self._domain
-
- def contains(self, other: "TvContentRating") -> bool:
- return self._rating_string == other._rating_string
-
- def toString(self) -> str:
- return self._rating_string
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, TvContentRating):
- return False
- return self._rating_string == other._rating_string
-
- def hashCode(self) -> int:
- return hash(self._rating_string) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvTrackInfo
-# ═══════════════════════════════════════════════════════════════
-
-class TvTrackInfo(Stub):
- """TvTrackInfo — 电视轨道信息"""
-
- TYPE_AUDIO = 0
- TYPE_VIDEO = 1
- TYPE_SUBTITLE = 2
-
- def __init__(self, type_: int = TYPE_VIDEO, trackId: str = "",
- language: str = "", description: str = "",
- audioChannelCount: int = 0, audioSampleRate: int = 0,
- videoWidth: int = 0, videoHeight: int = 0,
- videoFrameRate: float = 0.0, videoPixelAspectRatioWidth: int = 0,
- videoPixelAspectRatioHeight: int = 0,
- videoActiveFormatDescription: int = 0,
- subtitleType: int = 0, subtitleRoleFlags: int = 0,
- encoding: str = ""):
- super().__init__()
- self._type = type_
- self._track_id = trackId
- self._language = language
- self._description = description
- self._audio_channel_count = audioChannelCount
- self._audio_sample_rate = audioSampleRate
- self._video_width = videoWidth
- self._video_height = videoHeight
- self._video_frame_rate = videoFrameRate
- self._video_pixel_aspect_ratio_width = videoPixelAspectRatioWidth
- self._video_pixel_aspect_ratio_height = videoPixelAspectRatioHeight
- self._video_active_format_description = videoActiveFormatDescription
- self._subtitle_type = subtitleType
- self._subtitle_role_flags = subtitleRoleFlags
- self._encoding = encoding
-
- def getType(self) -> int:
- return self._type
-
- def getTrackId(self) -> str:
- return self._track_id
-
- def getLanguage(self) -> str:
- return self._language
-
- def getDescription(self) -> str:
- return self._description
-
- def getAudioChannelCount(self) -> int:
- return self._audio_channel_count if self._type == TvTrackInfo.TYPE_AUDIO else 0
-
- def getAudioSampleRate(self) -> int:
- return self._audio_sample_rate if self._type == TvTrackInfo.TYPE_AUDIO else 0
-
- def getVideoWidth(self) -> int:
- return self._video_width if self._type == TvTrackInfo.TYPE_VIDEO else 0
-
- def getVideoHeight(self) -> int:
- return self._video_height if self._type == TvTrackInfo.TYPE_VIDEO else 0
-
- def getVideoFrameRate(self) -> float:
- return self._video_frame_rate if self._type == TvTrackInfo.TYPE_VIDEO else 0.0
-
- def getVideoPixelAspectRatioWidth(self) -> int:
- return self._video_pixel_aspect_ratio_width
-
- def getVideoPixelAspectRatioHeight(self) -> int:
- return self._video_pixel_aspect_ratio_height
-
- def getVideoActiveFormatDescription(self) -> int:
- return self._video_active_format_description
-
- def getSubtitleType(self) -> int:
- return self._subtitle_type if self._type == TvTrackInfo.TYPE_SUBTITLE else 0
-
- def getSubtitleRoleFlags(self) -> int:
- return self._subtitle_role_flags
-
- def getEncoding(self) -> str:
- return self._encoding
-
- class Builder(Stub):
- """TvTrackInfo.Builder — 轨道信息构建器"""
-
- def __init__(self, type_: int):
- super().__init__()
- self._type = type_
- self._track_id = ""
- self._language = ""
- self._description = ""
- self._audio_channel_count = 0
- self._audio_sample_rate = 0
- self._video_width = 0
- self._video_height = 0
- self._video_frame_rate = 0.0
- self._video_pixel_aspect_ratio_width = 0
- self._video_pixel_aspect_ratio_height = 0
- self._video_active_format_description = 0
- self._subtitle_type = 0
- self._subtitle_role_flags = 0
- self._encoding = ""
-
- def setTrackId(self, trackId: str) -> "TvTrackInfo.Builder":
- self._track_id = trackId
- return self
-
- def setLanguage(self, language: str) -> "TvTrackInfo.Builder":
- self._language = language
- return self
-
- def setDescription(self, description: str) -> "TvTrackInfo.Builder":
- self._description = description
- return self
-
- def setAudioChannelCount(self, audioChannelCount: int) -> "TvTrackInfo.Builder":
- self._audio_channel_count = audioChannelCount
- return self
-
- def setAudioSampleRate(self, audioSampleRate: int) -> "TvTrackInfo.Builder":
- self._audio_sample_rate = audioSampleRate
- return self
-
- def setVideoWidth(self, videoWidth: int) -> "TvTrackInfo.Builder":
- self._video_width = videoWidth
- return self
-
- def setVideoHeight(self, videoHeight: int) -> "TvTrackInfo.Builder":
- self._video_height = videoHeight
- return self
-
- def setVideoFrameRate(self, videoFrameRate: float) -> "TvTrackInfo.Builder":
- self._video_frame_rate = videoFrameRate
- return self
-
- def setVideoPixelAspectRatioWidth(self, aspectRatioWidth: int) -> "TvTrackInfo.Builder":
- self._video_pixel_aspect_ratio_width = aspectRatioWidth
- return self
-
- def setVideoPixelAspectRatioHeight(self, aspectRatioHeight: int) -> "TvTrackInfo.Builder":
- self._video_pixel_aspect_ratio_height = aspectRatioHeight
- return self
-
- def setVideoActiveFormatDescription(self, afd: int) -> "TvTrackInfo.Builder":
- self._video_active_format_description = afd
- return self
-
- def setSubtitleType(self, subtitleType: int) -> "TvTrackInfo.Builder":
- self._subtitle_type = subtitleType
- return self
-
- def setSubtitleRoleFlags(self, subtitleRoleFlags: int) -> "TvTrackInfo.Builder":
- self._subtitle_role_flags = subtitleRoleFlags
- return self
-
- def setEncoding(self, encoding: str) -> "TvTrackInfo.Builder":
- self._encoding = encoding
- return self
-
- def build(self) -> "TvTrackInfo":
- return TvTrackInfo(
- type_=self._type, trackId=self._track_id,
- language=self._language, description=self._description,
- audioChannelCount=self._audio_channel_count,
- audioSampleRate=self._audio_sample_rate,
- videoWidth=self._video_width, videoHeight=self._video_height,
- videoFrameRate=self._video_frame_rate,
- videoPixelAspectRatioWidth=self._video_pixel_aspect_ratio_width,
- videoPixelAspectRatioHeight=self._video_pixel_aspect_ratio_height,
- videoActiveFormatDescription=self._video_active_format_description,
- subtitleType=self._subtitle_type,
- subtitleRoleFlags=self._subtitle_role_flags,
- encoding=self._encoding,
- )
-
- def toString(self) -> str:
- type_names = {0: "AUDIO", 1: "VIDEO", 2: "SUBTITLE"}
- return f"TvTrackInfo(id={self._track_id}, type={type_names.get(self._type, str(self._type))})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, TvTrackInfo):
- return False
- return self._track_id == other._track_id and self._type == other._type
-
- def hashCode(self) -> int:
- return hash((self._track_id, self._type)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvInputInfo (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class TvInputInfo(Stub):
- """TvInputInfo — 电视输入信息 (完整版)"""
-
- TYPE_COMPONENT = 1005
- TYPE_COMPOSITE = 1004
- TYPE_HDMI = 1007
- TYPE_OTHER = 1001
- TYPE_SCART = 1003
- TYPE_SVIDEO = 1006
- TYPE_TUNER = 0
- TYPE_DISPLAY_LINK = 1008
- TYPE_VGA = 1002
-
- def __init__(self, id: str = "", serviceInfo: Any = None,
- parentId: str = "", type_: int = TYPE_TUNER,
- hdmiDeviceInfo: Any = None,
- isHidden: bool = False, canRecord: bool = False,
- canPauseRecording: bool = False,
- passthroughMode: int = 0, tunerCount: int = 0):
- super().__init__()
- self._id = id
- self._service_info = serviceInfo
- self._parent_id = parentId
- self._type = type_
- self._hdmi_device_info = hdmiDeviceInfo
- self._is_hidden = isHidden
- self._can_record = canRecord
- self._can_pause_recording = canPauseRecording
- self._passthrough_mode = passthroughMode
- self._tuner_count = tunerCount
-
- def getId(self) -> str:
- return self._id
-
- def getServiceInfo(self) -> Any:
- return self._service_info
-
- def getParentId(self) -> str:
- return self._parent_id
-
- def getType(self) -> int:
- return self._type
-
- def getHdmiDeviceInfo(self) -> Any:
- return self._hdmi_device_info
-
- def loadIcon(self, context: Any) -> Any:
- return None
-
- def loadLogo(self, context: Any) -> Any:
- return None
-
- def createIntentForSetupScreen(self) -> Any:
- return None
-
- def isHidden(self) -> bool:
- return self._is_hidden
-
- def canRecord(self) -> bool:
- return self._can_record
-
- def canPauseRecording(self) -> bool:
- return self._can_pause_recording
-
- def getPassthroughMode(self) -> int:
- return self._passthrough_mode
-
- def getTunerCount(self) -> int:
- return self._tuner_count
-
- def toString(self) -> str:
- type_names = {
- TvInputInfo.TYPE_TUNER: "TUNER", TvInputInfo.TYPE_HDMI: "HDMI",
- TvInputInfo.TYPE_COMPOSITE: "COMPOSITE", TvInputInfo.TYPE_COMPONENT: "COMPONENT",
- }
- return f"TvInputInfo(id={self._id}, type={type_names.get(self._type, str(self._type))})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, TvInputInfo):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return hash(self._id) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvInputService (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class TvInputService(Stub):
- """TvInputService — 电视输入服务 (完整版)"""
-
- RECORDING_ERROR_RECORDING_LOST = 0
- RECORDING_ERROR_TIMEOUT = 1
- RECORDING_ERROR_OTHER = 2
- RECORDING_ERROR_INSUFFICIENT_SPACE = 3
- RECORDING_ERROR_SERVICE_UNAVAILABLE = 4
-
- class Session(Stub):
- """TvInputService.Session — 电视会话"""
-
- def __init__(self):
- super().__init__()
- self._main = False
- self._stream_volume = 1.0
- self._caption_enabled = False
- self._surface: Any = None
- self._overlay_view: Any = None
- self._recording_enabled = False
-
- def onSetSurface(self, surface: Any) -> bool:
- self._surface = surface
- return True
-
- def onSurfaceChanged(self, format: int, width: int, height: int):
- pass
-
- def onSurfaceReleased(self):
- self._surface = None
-
- def onAppPrivateCommand(self, action: str, data: Any):
- pass
-
- def onCreateOverlayView(self) -> Any:
- return self._overlay_view
-
- def onRelayoutContent(self):
- pass
-
- def onSetCaptionEnabled(self, enabled: bool):
- self._caption_enabled = enabled
-
- def onSetStreamVolume(self, volume: float):
- self._stream_volume = volume
-
- def onTimeShiftSetCurrentPositionRequest(self, positionMs: int):
- pass
-
- def notifyTimeShiftStatusChanged(self, status: int):
- pass
-
- def scheduleOverlayView(self, view: Any):
- self._overlay_view = view
-
- def timeShiftPlay(self, uri: str):
- pass
-
- def timeShiftPause(self):
- pass
-
- def timeShiftResume(self):
- pass
-
- def timeShiftSeekTo(self, positionMs: int):
- pass
-
- def timeShiftSetPlaybackParams(self, params: Any):
- pass
-
- def timeShiftEnablePositionTracking(self, enable: bool):
- pass
-
- def notifyVideoAvailable(self):
- pass
-
- def notifyVideoUnavailable(self, reason: int):
- pass
-
- def notifySessionEvent(self, eventType: str, eventArgs: Any):
- pass
-
- def notifyTracksChanged(self, tracks: List[Any]):
- pass
-
- def notifyTrackSelected(self, type_: str, trackId: str):
- pass
-
- def notifyContentAllowed(self):
- pass
-
- def notifyContentBlocked(self, rating: str):
- pass
-
- def setMain(self, main: bool):
- self._main = main
-
- def setStreamVolume(self, volume: float):
- self._stream_volume = volume
-
- def notifyRecordingStarted(self):
- self._recording_enabled = True
-
- def notifyRecordingStopped(self):
- self._recording_enabled = False
-
- def notifyRecordingPaused(self):
- pass
-
- def notifyRecordingResumed(self):
- pass
-
- def notifyRecordingError(self, errorCode: int):
- pass
-
- def getSurface(self) -> Any:
- return self._surface
-
- def isCaptionEnabled(self) -> bool:
- return self._caption_enabled
-
- def getStreamVolume(self) -> float:
- return self._stream_volume
-
- def toString(self) -> str:
- return f"Session(main={self._main}, volume={self._stream_volume})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- class RecordingSession(Stub):
- """TvInputService.RecordingSession — 录制会话"""
-
- def __init__(self):
- super().__init__()
- self._input_id = ""
- self._recording_enabled = False
- self._tune_uri: Any = None
-
- def onTune(self, uri: Any):
- self._tune_uri = uri
-
- def onStartRecording(self, uri: Any):
- self._recording_enabled = True
-
- def onStopRecording(self):
- self._recording_enabled = False
-
- def onPauseRecording(self):
- pass
-
- def onResumeRecording(self):
- pass
-
- def notifyRecordingStarted(self):
- pass
-
- def notifyRecordingStopped(self):
- pass
-
- def notifyRecordingPaused(self):
- pass
-
- def notifyRecordingResumed(self):
- pass
-
- def notifyRecordingError(self, errorCode: int):
- pass
-
- def notifyTuned(self, uri: Any):
- pass
-
- def getTuneUri(self) -> Optional[Any]:
- return self._tune_uri
-
- def toString(self) -> str:
- return f"RecordingSession(recording={self._recording_enabled})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- class HardwareSession(Stub):
- """TvInputService.HardwareSession — 硬件会话"""
-
- def __init__(self):
- super().__init__()
- self._session = TvInputService.Session()
-
- def onHardwareVideoAvailable(self):
- pass
-
- def onHardwareVideoUnavailable(self, reason: int):
- pass
-
- def toString(self) -> str:
- return f"HardwareSession@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self):
- super().__init__()
- self._sessions: List[TvInputService.Session] = []
- self._recording_sessions: List[TvInputService.RecordingSession] = []
-
- def onCreateSession(self, inputId: str) -> Session:
- session = TvInputService.Session()
- self._sessions.append(session)
- return session
-
- def onCreateRecordingSession(self, inputId: str) -> RecordingSession:
- session = TvInputService.RecordingSession()
- self._recording_sessions.append(session)
- return session
-
- def onSetupFinished(self, inputId: str):
- pass
-
- def sessionCreated(self, session: Session):
- pass
-
- def notifyHardwareFailed(self, deviceId: int):
- pass
-
- def getSessions(self) -> List[Session]:
- return list(self._sessions)
-
- def getRecordingSessions(self) -> List[RecordingSession]:
- return list(self._recording_sessions)
-
- def toString(self) -> str:
- return f"TvInputService(sessions={len(self._sessions)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvRecordingClient (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class TvRecordingClient(Stub):
- """TvRecordingClient — 电视录制客户端"""
-
- def __init__(self, context: Any = None, inputId: str = "",
- callback: Any = None):
- super().__init__()
- self._context = context
- self._input_id = inputId
- self._callback = callback
- self._recording_uri: Optional[str] = None
- self._is_recording = False
- self._is_paused = False
-
- def startRecording(self, uri: str):
- self._recording_uri = uri
- self._is_recording = True
- self._is_paused = False
-
- def stopRecording(self):
- self._is_recording = False
- self._is_paused = False
-
- def pauseRecording(self):
- if self._is_recording:
- self._is_paused = True
-
- def resumeRecording(self):
- if self._is_paused:
- self._is_paused = False
-
- def release(self):
- self._recording_uri = None
- self._is_recording = False
- self._is_paused = False
-
- def isRecording(self) -> bool:
- return self._is_recording
-
- def isPaused(self) -> bool:
- return self._is_paused
-
- def getRecordingUri(self) -> Optional[str]:
- return self._recording_uri
-
- def getInputId(self) -> str:
- return self._input_id
-
- class Callback(Stub):
- """TvRecordingClient.Callback — 录制回调"""
-
- def onRecordingStarted(self):
- pass
-
- def onRecordingStopped(self):
- pass
-
- def onRecordingPaused(self):
- pass
-
- def onRecordingResumed(self):
- pass
-
- def onError(self, errorCode: int):
- pass
-
- def onTuned(self, channelUri: Any):
- pass
-
- def onConnectionFailed(self, inputId: str):
- pass
-
- def onDisconnected(self, inputId: str):
- pass
-
- def toString(self) -> str:
- return f"RecordingCallback@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"TvRecordingClient(input={self._input_id}, recording={self._is_recording})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvView
-# ═══════════════════════════════════════════════════════════════
-
-class TvView(Stub):
- """TvView — 电视视图"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._input_id: Optional[str] = None
- self._callback: Optional[TvView.TvInputCallback] = None
- self._stream_configs: List[TvStreamConfig] = []
- self._is_overlay = False
- self._time_shift_enabled = False
-
- class TvInputCallback(Stub):
- """TvView.TvInputCallback — 输入回调"""
-
- def onConnectionFailed(self, inputId: str):
- pass
-
- def onDisconnected(self, inputId: str):
- pass
-
- def onChannelRetuned(self, channelUri: Any):
- pass
-
- def onTrackSelected(self, type_: int, trackId: str):
- pass
-
- def onTracksChanged(self, tracks: List[Any]):
- pass
-
- def onVideoAvailable(self, reason: int):
- pass
-
- def onVideoUnavailable(self, reason: int):
- pass
-
- def onContentAllowed(self):
- pass
-
- def onContentBlocked(self, rating: str):
- pass
-
- def onTimeShiftStatusChanged(self, status: int):
- pass
-
- def toString(self) -> str:
- return f"TvInputCallback@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def tune(self, inputId: str, channelUri: Any):
- self._input_id = inputId
-
- def reset(self):
- self._input_id = None
-
- def setCallback(self, callback: TvInputCallback):
- self._callback = callback
-
- def setCaptionEnabled(self, enabled: bool):
- pass
-
- def setStreamVolume(self, volume: float):
- pass
-
- def selectTrack(self, type_: int, trackId: str):
- pass
-
- def getSelectedTrack(self, type_: int) -> Optional[str]:
- return None
-
- def getTracks(self, type_: int) -> List[Any]:
- return []
-
- def timeShiftPlay(self, uri: str):
- self._time_shift_enabled = True
-
- def timeShiftPause(self):
- pass
-
- def timeShiftResume(self):
- pass
-
- def timeShiftSeekTo(self, positionMs: int):
- pass
-
- def timeShiftSetPlaybackParams(self, params: Any):
- pass
-
- def timeShiftEnablePositionTracking(self, enable: bool):
- pass
-
- def timeShiftGetCurrentPosition(self) -> int:
- return 0
-
- def timeShiftGetStartPosition(self) -> int:
- return 0
-
- def sendAppPrivateCommand(self, action: str, data: Any):
- pass
-
- def dispatchKeyEvent(self, event: Any) -> bool:
- return False
-
- def dispatchUnhandledInputEvent(self, event: Any) -> bool:
- return False
-
- def streamOverlay(self, isOverlay: bool):
- self._is_overlay = isOverlay
-
- def getInputId(self) -> Optional[str]:
- return self._input_id
-
- def toString(self) -> str:
- return f"TvView(input={self._input_id})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvStreamConfig
-# ═══════════════════════════════════════════════════════════════
-
-class TvStreamConfig(Stub):
- """TvStreamConfig — 电视流配置"""
-
- STREAM_TYPE_INDEPENDENT_VIDEO = 0
- STREAM_TYPE_INDEPENDENT_SOURCE = 1
- STREAM_TYPE_SESSION = 2
-
- def __init__(self, streamId: int = 0, type_: int = STREAM_TYPE_INDEPENDENT_VIDEO,
- maxWidth: int = 1920, maxHeight: int = 1080,
- generation: int = 0):
- super().__init__()
- self._stream_id = streamId
- self._type = type_
- self._max_width = maxWidth
- self._max_height = maxHeight
- self._generation = generation
-
- def getStreamId(self) -> int:
- return self._stream_id
-
- def getType(self) -> int:
- return self._type
-
- def getMaxWidth(self) -> int:
- return self._max_width
-
- def getMaxHeight(self) -> int:
- return self._max_height
-
- def getGeneration(self) -> int:
- return self._generation
-
- class Builder(Stub):
- """TvStreamConfig.Builder — 流配置构建器"""
-
- def __init__(self):
- super().__init__()
- self._stream_id = 0
- self._type = TvStreamConfig.STREAM_TYPE_INDEPENDENT_VIDEO
- self._max_width = 1920
- self._max_height = 1080
- self._generation = 0
-
- def setStreamId(self, streamId: int) -> "TvStreamConfig.Builder":
- self._stream_id = streamId
- return self
-
- def setType(self, type_: int) -> "TvStreamConfig.Builder":
- self._type = type_
- return self
-
- def setMaxWidth(self, maxWidth: int) -> "TvStreamConfig.Builder":
- self._max_width = maxWidth
- return self
-
- def setMaxHeight(self, maxHeight: int) -> "TvStreamConfig.Builder":
- self._max_height = maxHeight
- return self
-
- def setGeneration(self, generation: int) -> "TvStreamConfig.Builder":
- self._generation = generation
- return self
-
- def build(self) -> "TvStreamConfig":
- return TvStreamConfig(
- streamId=self._stream_id, type_=self._type,
- maxWidth=self._max_width, maxHeight=self._max_height,
- generation=self._generation,
- )
-
- def toString(self) -> str:
- return f"TvStreamConfig(id={self._stream_id}, type={self._type})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, TvStreamConfig):
- return False
- return self._stream_id == other._stream_id
-
- def hashCode(self) -> int:
- return self._stream_id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvContract
-# ═══════════════════════════════════════════════════════════════
-
-class TvContract(Stub):
- """TvContract — TV 内容提供者合约"""
-
- AUTHORITY = "android.media.tv"
- CONTENT_URI_BASE = "content://android.media.tv"
-
- # ═══════════════════════════════════════════════════════════
- # Channels
- # ═══════════════════════════════════════════════════════════
-
- class Channels(Stub):
- """TvContract.Channels — 频道表"""
-
- CONTENT_URI = "content://android.media.tv/channel"
- CONTENT_URI_PASSTHROUGH = "content://android.media.tv/passthrough_channel"
-
- _ID = "_id"
- COLUMN_BROWSABLE = "browsable"
- COLUMN_DESCRIPTION = "description"
- COLUMN_DISPLAY_NAME = "display_name"
- COLUMN_DISPLAY_NUMBER = "display_number"
- COLUMN_INPUT_ID = "input_id"
- COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data"
- COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1"
- COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2"
- COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3"
- COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4"
- COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"
- COLUMN_NETWORK_AFFILIATION = "network_affiliation"
- COLUMN_ORIGINAL_NETWORK_ID = "original_network_id"
- COLUMN_SEARCHABLE = "searchable"
- COLUMN_SERVICE_ID = "service_id"
- COLUMN_SERVICE_TYPE = "service_type"
- COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id"
- COLUMN_TYPE = "type"
- COLUMN_VIDEO_FORMAT = "video_format"
- COLUMN_VIDEO_HEIGHT = "video_height"
- COLUMN_VIDEO_WIDTH = "video_width"
- COLUMN_WATCH_NEXT_PROGRAM_COUNT = "watch_next_program_count"
-
- BROWSABLE_NO = 0
- BROWSABLE_YES = 1
-
- TYPE_1SEG = "1SEG"
- TYPE_ATSC_C = "ATSC_C"
- TYPE_ATSC_M = "ATSC_M"
- TYPE_ATSC_T = "ATSC_T"
- TYPE_DTMB = "DTMB"
- TYPE_DVB_C = "DVB_C"
- TYPE_DVB_C2 = "DVB_C2"
- TYPE_DVB_H = "DVB_H"
- TYPE_DVB_S = "DVB_S"
- TYPE_DVB_S2 = "DVB_S2"
- TYPE_DVB_SH = "DVB_SH"
- TYPE_DVB_T = "DVB_T"
- TYPE_DVB_T2 = "DVB_T2"
- TYPE_ISDB_C = "ISDB_C"
- TYPE_ISDB_S = "ISDB_S"
- TYPE_ISDB_T = "ISDB_T"
- TYPE_ISDB_TB = "ISDB_TB"
- TYPE_NTSC = "NTSC"
- TYPE_OTHER = "OTHER"
- TYPE_PAL = "PAL"
- TYPE_PREVIEW = "PREVIEW"
- TYPE_SECAM = "SECAM"
- TYPE_S_DMB = "S_DMB"
- TYPE_T_DMB = "T_DMB"
-
- VIDEO_FORMAT_1080I = "1080i"
- VIDEO_FORMAT_1080P = "1080p"
- VIDEO_FORMAT_2160P = "2160p"
- VIDEO_FORMAT_240P = "240p"
- VIDEO_FORMAT_360P = "360p"
- VIDEO_FORMAT_4320P = "4320p"
- VIDEO_FORMAT_480I = "480i"
- VIDEO_FORMAT_480P = "480p"
- VIDEO_FORMAT_576I = "576i"
- VIDEO_FORMAT_576P = "576p"
- VIDEO_FORMAT_720P = "720p"
-
- SERVICE_TYPE_AUDIO = "AUDIO"
- SERVICE_TYPE_AUDIO_VIDEO = "AUDIO_VIDEO"
- SERVICE_TYPE_OTHER = "OTHER"
-
- # ═══════════════════════════════════════════════════════════
- # Programs
- # ═══════════════════════════════════════════════════════════
-
- class Programs(Stub):
- """TvContract.Programs — 节目表"""
-
- CONTENT_URI = "content://android.media.tv/program"
-
- _ID = "_id"
- COLUMN_AUDIO_LANGUAGE = "audio_language"
- COLUMN_BROADCAST_GENRE = "broadcast_genre"
- COLUMN_CHANNEL_ID = "channel_id"
- COLUMN_CONTENT_RATING = "content_rating"
- COLUMN_DESCRIPTION = "description"
- COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"
- COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number"
- COLUMN_EPISODE_TITLE = "episode_title"
- COLUMN_INTENT_URI = "intent_uri"
- COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data"
- COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1"
- COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2"
- COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3"
- COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4"
- COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"
- COLUMN_LONG_DESCRIPTION = "long_description"
- COLUMN_POSTER_ART_URI = "poster_art_uri"
- COLUMN_REVIEW_RATING_SCORE = "review_rating_score"
- COLUMN_REVIEW_RATING_STYLE = "review_rating_style"
- COLUMN_SEARCHABLE = "searchable"
- COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number"
- COLUMN_SEASON_TITLE = "season_title"
- COLUMN_SHORT_DESCRIPTION = "short_description"
- COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"
- COLUMN_THUMBNAIL_URI = "thumbnail_uri"
- COLUMN_TITLE = "title"
- COLUMN_VERSION_NUMBER = "version_number"
- COLUMN_VIDEO_HEIGHT = "video_height"
- COLUMN_VIDEO_WIDTH = "video_width"
-
- REVIEW_RATING_STYLE_PERCENTAGE = 0
- REVIEW_RATING_STYLE_STARS = 1
- REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 2
-
- # ═══════════════════════════════════════════════════════════
- # RecordedPrograms
- # ═══════════════════════════════════════════════════════════
-
- class RecordedPrograms(Stub):
- """TvContract.RecordedPrograms — 录制节目表"""
-
- CONTENT_URI = "content://android.media.tv/recorded_program"
-
- _ID = "_id"
- COLUMN_AUDIO_LANGUAGE = "audio_language"
- COLUMN_BROADCAST_GENRE = "broadcast_genre"
- COLUMN_CHANNEL_ID = "channel_id"
- COLUMN_CONTENT_RATING = "content_rating"
- COLUMN_DESCRIPTION = "description"
- COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"
- COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number"
- COLUMN_EPISODE_TITLE = "episode_title"
- COLUMN_INPUT_ID = "input_id"
- COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data"
- COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"
- COLUMN_LONG_DESCRIPTION = "long_description"
- COLUMN_POSTER_ART_URI = "poster_art_uri"
- COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis"
- COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes"
- COLUMN_RECORDING_DATA_URI = "recording_data_uri"
- COLUMN_RECORDING_DURATION_MS = "recording_duration_ms"
- COLUMN_REVIEW_RATING_SCORE = "review_rating_score"
- COLUMN_REVIEW_RATING_STYLE = "review_rating_style"
- COLUMN_SEARCHABLE = "searchable"
- COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number"
- COLUMN_SEASON_TITLE = "season_title"
- COLUMN_SHORT_DESCRIPTION = "short_description"
- COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"
- COLUMN_THUMBNAIL_URI = "thumbnail_uri"
- COLUMN_TITLE = "title"
- COLUMN_VERSION_NUMBER = "version_number"
-
- # ═══════════════════════════════════════════════════════════
- # WatchNextPrograms
- # ═══════════════════════════════════════════════════════════
-
- class WatchNextPrograms(Stub):
- """TvContract.WatchNextPrograms — 待看节目表"""
-
- CONTENT_URI = "content://android.media.tv/watch_next_program"
-
- _ID = "_id"
- COLUMN_AUDIO_LANGUAGE = "audio_language"
- COLUMN_BROADCAST_GENRE = "broadcast_genre"
- COLUMN_CHANNEL_ID = "channel_id"
- COLUMN_CONTENT_RATING = "content_rating"
- COLUMN_DESCRIPTION = "description"
- COLUMN_DURATION_MILLIS = "duration_millis"
- COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"
- COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number"
- COLUMN_EPISODE_TITLE = "episode_title"
- COLUMN_INTENT_URI = "intent_uri"
- COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data"
- COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"
- COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis"
- COLUMN_LONG_DESCRIPTION = "long_description"
- COLUMN_POSTER_ART_URI = "poster_art_uri"
- COLUMN_REVIEW_RATING_SCORE = "review_rating_score"
- COLUMN_REVIEW_RATING_STYLE = "review_rating_style"
- COLUMN_SEARCHABLE = "searchable"
- COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number"
- COLUMN_SEASON_TITLE = "season_title"
- COLUMN_SHORT_DESCRIPTION = "short_description"
- COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"
- COLUMN_THUMBNAIL_URI = "thumbnail_uri"
- COLUMN_TITLE = "title"
- COLUMN_VERSION_NUMBER = "version_number"
- COLUMN_WATCH_NEXT_TYPE = "watch_next_type"
-
- WATCH_NEXT_TYPE_CONTINUE = 0
- WATCH_NEXT_TYPE_NEXT = 1
- WATCH_NEXT_TYPE_NEW = 2
- WATCH_NEXT_TYPE_WATCHLIST = 3
-
- # ═══════════════════════════════════════════════════════════
- # PreviewPrograms
- # ═══════════════════════════════════════════════════════════
-
- class PreviewPrograms(Stub):
- """TvContract.PreviewPrograms — 预览节目表"""
-
- CONTENT_URI = "content://android.media.tv/preview_program"
-
- _ID = "_id"
- COLUMN_AUDIO_LANGUAGE = "audio_language"
- COLUMN_BROADCAST_GENRE = "broadcast_genre"
- COLUMN_CHANNEL_ID = "channel_id"
- COLUMN_CONTENT_RATING = "content_rating"
- COLUMN_DESCRIPTION = "description"
- COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"
- COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number"
- COLUMN_EPISODE_TITLE = "episode_title"
- COLUMN_INTENT_URI = "intent_uri"
- COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data"
- COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"
- COLUMN_ITEM_COUNT = "item_count"
- COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis"
- COLUMN_LONG_DESCRIPTION = "long_description"
- COLUMN_POSTER_ART_URI = "poster_art_uri"
- COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri"
- COLUMN_REVIEW_RATING_SCORE = "review_rating_score"
- COLUMN_REVIEW_RATING_STYLE = "review_rating_style"
- COLUMN_SEARCHABLE = "searchable"
- COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number"
- COLUMN_SEASON_TITLE = "season_title"
- COLUMN_SHORT_DESCRIPTION = "short_description"
- COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"
- COLUMN_THUMBNAIL_URI = "thumbnail_uri"
- COLUMN_TITLE = "title"
- COLUMN_TYPE = "type"
- COLUMN_VERSION_NUMBER = "version_number"
- COLUMN_WEIGHT = "weight"
-
- ASPECT_RATIO_16_9 = 0
- ASPECT_RATIO_1_1 = 1
- ASPECT_RATIO_2_3 = 2
- ASPECT_RATIO_3_2 = 3
- ASPECT_RATIO_4_3 = 4
- ASPECT_RATIO_MOVIE = 5
-
- TYPE_CLIP = "CLIP"
- TYPE_EPISODE = "EPISODE"
- TYPE_MOVIE = "MOVIE"
- TYPE_PLAYLIST = "PLAYLIST"
- TYPE_SERIES = "SERIES"
- TYPE_TRAILER = "TRAILER"
- TYPE_EVENT = "EVENT"
-
- def __init__(self):
- super().__init__()
-
- def buildChannelUri(self, channelId: int) -> str:
- return f"{TvContract.Channels.CONTENT_URI}/{channelId}"
-
- def buildProgramUri(self, programId: int) -> str:
- return f"{TvContract.Programs.CONTENT_URI}/{programId}"
-
- def buildRecordedProgramUri(self, recordedProgramId: int) -> str:
- return f"{TvContract.RecordedPrograms.CONTENT_URI}/{recordedProgramId}"
-
- def buildWatchNextProgramUri(self, watchNextProgramId: int) -> str:
- return f"{TvContract.WatchNextPrograms.CONTENT_URI}/{watchNextProgramId}"
-
- def buildPreviewProgramUri(self, previewProgramId: int) -> str:
- return f"{TvContract.PreviewPrograms.CONTENT_URI}/{previewProgramId}"
-
- def buildChannelsUriForInput(self, inputId: str) -> str:
- return f"{TvContract.Channels.CONTENT_URI}?inputId={inputId}"
-
- def buildInputId(serviceComponentName: str) -> str:
- return serviceComponentName
-
- def toString(self) -> str:
- return f"TvContract@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# PreviewProgram
-# ═══════════════════════════════════════════════════════════════
-
-class PreviewProgram(Stub):
- """PreviewProgram — 预览节目"""
-
- def __init__(self, id: int = 0, channelId: int = 0, title: str = "",
- description: str = "", longDescription: str = "",
- posterArtUri: str = "", thumbnailUri: str = "",
- startTimeUtcMillis: int = 0, endTimeUtcMillis: int = 0,
- weight: int = 0, type_: str = "CLIP"):
- super().__init__()
- self._id = id
- self._channel_id = channelId
- self._title = title
- self._description = description
- self._long_description = longDescription
- self._poster_art_uri = posterArtUri
- self._thumbnail_uri = thumbnailUri
- self._start_time_utc_millis = startTimeUtcMillis
- self._end_time_utc_millis = endTimeUtcMillis
- self._weight = weight
- self._type = type_
-
- def getId(self) -> int:
- return self._id
-
- def getChannelId(self) -> int:
- return self._channel_id
-
- def getTitle(self) -> str:
- return self._title
-
- def getDescription(self) -> str:
- return self._description
-
- def getLongDescription(self) -> str:
- return self._long_description
-
- def getPosterArtUri(self) -> str:
- return self._poster_art_uri
-
- def getThumbnailUri(self) -> str:
- return self._thumbnail_uri
-
- def getStartTimeUtcMillis(self) -> int:
- return self._start_time_utc_millis
-
- def getEndTimeUtcMillis(self) -> int:
- return self._end_time_utc_millis
-
- def getWeight(self) -> int:
- return self._weight
-
- def getType(self) -> str:
- return self._type
-
- def toString(self) -> str:
- return f"PreviewProgram(id={self._id}, title={self._title})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, PreviewProgram):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# PreviewChannel
-# ═══════════════════════════════════════════════════════════════
-
-class PreviewChannel(Stub):
- """PreviewChannel — 预览频道"""
-
- def __init__(self, id: int = 0, type_: str = "PREVIEW",
- displayName: str = "", description: str = "",
- displayNumber: str = "", browsable: bool = True):
- super().__init__()
- self._id = id
- self._type = type_
- self._display_name = displayName
- self._description = description
- self._display_number = displayNumber
- self._browsable = browsable
-
- def getId(self) -> int:
- return self._id
-
- def getType(self) -> str:
- return self._type
-
- def getDisplayName(self) -> str:
- return self._display_name
-
- def getDescription(self) -> str:
- return self._description
-
- def getDisplayNumber(self) -> str:
- return self._display_number
-
- def isBrowsable(self) -> bool:
- return self._browsable
-
- def toString(self) -> str:
- return f"PreviewChannel(id={self._id}, name={self._display_name})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, PreviewChannel):
- return False
- return self._id == other._id
-
- def hashCode(self) -> int:
- return self._id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# TvInputManager (扩展完整版)
-# ═══════════════════════════════════════════════════════════════
-
-class TvInputManager(Stub):
- """TvInputManager — 电视输入管理器 (完整版)"""
-
- ACTION_VIEW_RECORDING_SCHEDULES = "android.tv.action.VIEW_RECORDING_SCHEDULES"
- ACTION_WATCH_NEXT = "android.tv.action.WATCH_NEXT"
- ACTION_PREVIEW_PROGRAM_BROWSABLE = "android.tv.action.PREVIEW_PROGRAM_BROWSABLE"
-
- TIME_SHIFT_STATUS_AVAILABLE = 0
- TIME_SHIFT_STATUS_UNAVAILABLE = 1
- TIME_SHIFT_STATUS_UNKNOWN = 2
- TIME_SHIFT_STATUS_UNSUPPORTED = 3
-
- VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = 8
- VIDEO_UNAVAILABLE_REASON_BUFFERING = 3
- VIDEO_UNAVAILABLE_REASON_CAS = 7
- VIDEO_UNAVAILABLE_REASON_INSUFFICIENT_RESOURCE = 5
- VIDEO_UNAVAILABLE_REASON_NOT_CONNECTED = 6
- VIDEO_UNAVAILABLE_REASON_PREEMPTED = 4
- VIDEO_UNAVAILABLE_REASON_TUNING = 1
- VIDEO_UNAVAILABLE_REASON_UNKNOWN = 0
- VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 2
-
- INPUT_STATE_CONNECTED = 0
- INPUT_STATE_CONNECTED_STANDBY = 4
- INPUT_STATE_DISCONNECTED = 2
- INPUT_STATE_UNKNOWN = 1
-
- class TvInputCallback(Stub):
- """TvInputManager.TvInputCallback — 电视输入回调"""
-
- def onInputAdded(self, inputId: str):
- pass
-
- def onInputRemoved(self, inputId: str):
- pass
-
- def onInputChanged(self, inputId: str):
- pass
-
- def onInputStateChanged(self, inputId: str, state: int):
- pass
-
- def onTvInputInfoUpdated(self, inputInfo: "TvInputInfo"):
- pass
-
- def toString(self) -> str:
- return f"TvInputCallback@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self):
- super().__init__()
- self._inputs: Dict[str, TvInputInfo] = {}
- self._callbacks: Dict[int, TvInputManager.TvInputCallback] = {}
- self._input_states: Dict[str, int] = {}
-
- def getTvInputList(self) -> List["TvInputInfo"]:
- return list(self._inputs.values())
-
- def getTvInputInfo(self, inputId: str) -> Optional["TvInputInfo"]:
- return self._inputs.get(inputId)
-
- def getCurrentTvInputInfo(self) -> Optional["TvInputInfo"]:
- for inp in self._inputs.values():
- return inp
- return None
-
- def updateTvInputInfo(self, inputInfo: "TvInputInfo"):
- if inputInfo:
- self._inputs[inputInfo.getId()] = inputInfo
-
- def registerCallback(self, callback: TvInputCallback, handler: Any = None):
- lid = id(callback)
- self._callbacks[lid] = callback
-
- def unregisterCallback(self, callback: TvInputCallback):
- lid = id(callback)
- self._callbacks.pop(lid, None)
-
- def createRecordingSession(self, recordingService: str, inputId: str):
- raise AndroidOnlyError("TvInputManager.createRecordingSession() is not available on desktop")
-
- def sendTvInputNotifyIntent(self, intent: Any, inputId: str):
- pass
-
- def isParentalControlsEnabled(self) -> bool:
- return False
-
- def isRatingBlocked(self, rating: str) -> bool:
- return False
-
- def getBlockedRatings(self) -> List[str]:
- return []
-
- def getAvailableTvInputs(self) -> List[str]:
- return list(self._inputs.keys())
-
- def getTvContentRatingSystems(self) -> List[str]:
- return ["US_TV", "US_MOVIE"]
-
- def getInputState(self, inputId: str) -> int:
- return self._input_states.get(inputId, TvInputManager.INPUT_STATE_UNKNOWN)
-
- def setInputState(self, inputId: str, state: int):
- self._input_states[inputId] = state
-
- def addInput(self, inputInfo: TvInputInfo):
- if inputInfo:
- self._inputs[inputInfo.getId()] = inputInfo
-
- def removeInput(self, inputId: str):
- self._inputs.pop(inputId, None)
-
- def toString(self) -> str:
- return f"TvInputManager(inputs={len(self._inputs)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/mtp.py b/android_pyapi/android/mtp.py
deleted file mode 100644
index c6c038e..0000000
--- a/android_pyapi/android/mtp.py
+++ /dev/null
@@ -1,476 +0,0 @@
-"""
-Android Media Transfer Protocol API — MtpDevice, MtpStorageInfo, MtpObjectInfo, MtpConstants
-方法签名完全对齐 Android SDK
-"""
-
-import os as _os
-import sys
-import time
-from datetime import datetime
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable, BinaryIO
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "MtpDevice",
- "MtpStorageInfo",
- "MtpObjectInfo",
- "MtpConstants",
- "MtpPropertyGroup",
- "MtpDeviceInfo",
- "MtpStorage",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# MtpConstants — 50+ 格式常量
-# ═══════════════════════════════════════════════════════════════
-
-class MtpConstants(Stub):
- """MTP 协议常量"""
-
- # --- 格式常量 ---
- FORMAT_UNDEFINED = 0x3000
- FORMAT_ASSOCIATION = 0x3001
- FORMAT_SCRIPT = 0x3002
- FORMAT_EXECUTABLE = 0x3003
- FORMAT_TEXT = 0x3004
- FORMAT_HTML = 0x3005
- FORMAT_DPOF = 0x3006
- FORMAT_AIFF = 0x3007
- FORMAT_WAV = 0x3008
- FORMAT_MP3 = 0x3009
- FORMAT_AVI = 0x300A
- FORMAT_MPEG = 0x300B
- FORMAT_ASF = 0x300C
- FORMAT_DEF = 0x300D
- FORMAT_EXIF_JPEG = 0x3801
- FORMAT_TIFF_EP = 0x3802
- FORMAT_FLASHPIX = 0x3803
- FORMAT_BMP = 0x3804
- FORMAT_CIFF = 0x3805
- FORMAT_GIF = 0x3807
- FORMAT_JFIF = 0x3808
- FORMAT_PCD = 0x3809
- FORMAT_PICT = 0x380A
- FORMAT_PNG = 0x380B
- FORMAT_TIFF = 0x380D
- FORMAT_TIFF_IT = 0x380E
- FORMAT_JP2 = 0x380F
- FORMAT_JPX = 0x3810
- FORMAT_XML = 0x3811
- FORMAT_FIRMWARE = 0x3802
- FORMAT_WMA = 0xB901
- FORMAT_WMV = 0xB980
- FORMAT_WPL = 0xBA05
- FORMAT_FLAC = 0xB906
- FORMAT_OGG = 0xB902
- FORMAT_AAC = 0xB903
- FORMAT_MP4_CONTAINER = 0xB904
- FORMAT_MP2 = 0xB905
- FORMAT_3GP = 0xB907
- FORMAT_3GP_CONTAINER = 0xB908
- FORMAT_AVC = 0xB909
- FORMAT_HEVC = 0xB90A
- FORMAT_DNG = 0xB90B
- FORMAT_ARW = 0xB90C
- FORMAT_CR2 = 0xB90D
- FORMAT_RAF = 0xB90E
- FORMAT_NEF = 0xB90F
- FORMAT_ORF = 0xB910
- FORMAT_RW2 = 0xB911
- FORMAT_SRW = 0xB912
-
- # --- 保护状态 ---
- PROTECTION_STATUS_NONE = 0
- PROTECTION_STATUS_READ_ONLY = 0x8001
- PROTECTION_STATUS_PROTECTED = 0x8002
-
- # --- 关联类型 ---
- ASSOCIATION_TYPE_UNDEFINED = 0x0000
- ASSOCIATION_TYPE_GENERIC_FOLDER = 0x0001
-
- # --- 属性格式常量 ---
- PROP_FORMAT_UNDEFINED = 0x0000
- PROP_FORMAT_STRING = 0xFFFF
- PROP_FORMAT_UINT8 = 0x0001
- PROP_FORMAT_UINT16 = 0x0002
- PROP_FORMAT_UINT32 = 0x0004
- PROP_FORMAT_UINT64 = 0x0008
- PROP_FORMAT_INT8 = 0x0009
- PROP_FORMAT_INT16 = 0x000A
- PROP_FORMAT_INT32 = 0x000B
- PROP_FORMAT_INT64 = 0x000C
- PROP_FORMAT_BOOL = 0x4001
- PROP_FORMAT_DATE = 0x4002
-
- # --- 操作码 ---
- OPERATION_GET_DEVICE_INFO = 0x1001
- OPERATION_OPEN_SESSION = 0x1002
- OPERATION_CLOSE_SESSION = 0x1003
- OPERATION_GET_STORAGE_IDS = 0x1004
- OPERATION_GET_STORAGE_INFO = 0x1005
- OPERATION_GET_OBJECT_PROP_VALUE = 0x9802
- OPERATION_SET_OBJECT_PROP_VALUE = 0x9803
- OPERATION_GET_OBJECT_INFO = 0x1007
- OPERATION_GET_OBJECT = 0x1009
- OPERATION_GET_THUMB = 0x100A
- OPERATION_DELETE_OBJECT = 0x100B
- OPERATION_SEND_OBJECT_INFO = 0x100C
- OPERATION_SEND_OBJECT = 0x100D
- OPERATION_GET_OBJECT_REFERENCES = 0x1010
- OPERATION_SET_OBJECT_REFERENCES = 0x1011
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# MtpDevice
-# ═══════════════════════════════════════════════════════════════
-
-class MtpDevice(Stub):
- """MtpDevice — MTP 设备 (桌面存根)"""
-
- def __init__(self, device: Any = None):
- super().__init__()
- self._device = device
- self._opened = False
-
- def open(self) -> bool:
- """打开 MTP 设备"""
- raise AndroidOnlyError("MtpDevice.open() 仅在 Android 设备上可用")
-
- def close(self):
- """关闭 MTP 设备"""
- self._opened = False
-
- def getDeviceInfo(self) -> "MtpDeviceInfo":
- """获取设备信息"""
- return MtpDeviceInfo()
-
- def getDeviceName(self) -> str:
- """获取设备名称"""
- return "MTP Device"
-
- def getObjectHandles(
- self, storageId: int, format: int, objectHandle: int
- ) -> List[int]:
- """获取对象句柄列表"""
- return []
-
- def getObjectInfo(self, objectHandle: int) -> Optional["MtpObjectInfo"]:
- """获取对象信息"""
- return None
-
- def getObject(self, objectHandle: int, dataSize: int) -> Optional[bytes]:
- """获取对象数据"""
- return None
-
- def getThumbnail(self, objectHandle: int) -> Optional[bytes]:
- """获取缩略图"""
- return None
-
- def getStorageIds(self) -> List[int]:
- """获取存储 ID 列表"""
- return [0x00010001]
-
- def getStorageInfo(self, storageId: int) -> "MtpStorageInfo":
- """获取存储信息"""
- return MtpStorageInfo()
-
- def importFile(self, objectHandle: int, destPath: str) -> bool:
- """导入文件"""
- raise AndroidOnlyError("MtpDevice.importFile() 仅在 Android 设备上可用")
-
- def deleteObject(self, objectHandle: int) -> bool:
- """删除对象"""
- raise AndroidOnlyError("MtpDevice.deleteObject() 仅在 Android 设备上可用")
-
- def getParent(self, objectHandle: int) -> int:
- """获取父对象句柄"""
- return 0xFFFFFFFF
-
- def getObjectReferences(self, objectHandle: int) -> List[int]:
- """获取对象引用列表"""
- return []
-
- def setObjectReferences(self, objectHandle: int, references: List[int]) -> bool:
- """设置对象引用"""
- raise AndroidOnlyError("MtpDevice.setObjectReferences() 仅在 Android 设备上可用")
-
- def sendObject(self, objectHandle: int, data: bytes) -> bool:
- """发送对象"""
- raise AndroidOnlyError("MtpDevice.sendObject() 仅在 Android 设备上可用")
-
- def sendObjectInfo(
- self, storageId: int, parent: int, info: "MtpObjectInfo"
- ) -> int:
- """发送对象信息"""
- raise AndroidOnlyError("MtpDevice.sendObjectInfo() 仅在 Android 设备上可用")
-
- def toString(self) -> str:
- return f"MtpDevice(name={self.getDeviceName()})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# MtpStorageInfo
-# ═══════════════════════════════════════════════════════════════
-
-class MtpStorageInfo(Stub):
- """MtpStorageInfo — MTP 存储信息"""
-
- def __init__(self):
- super().__init__()
- self._storage_id = 0x00010001
- self._max_capacity = 32 * 1024 * 1024 * 1024 # 32GB
- self._free_space = 16 * 1024 * 1024 * 1024 # 16GB
- self._description = "Internal Storage"
- self._volume_identifier = ""
-
- def getStorageId(self) -> int:
- return self._storage_id
-
- def getMaxCapacity(self) -> int:
- return self._max_capacity
-
- def getFreeSpace(self) -> int:
- return self._free_space
-
- def getDescription(self) -> str:
- return self._description
-
- def getVolumeIdentifier(self) -> str:
- return self._volume_identifier
-
- def toString(self) -> str:
- return (f"MtpStorageInfo(id={self._storage_id}, "
- f"free={self._free_space}B)")
-
- def equals(self, other) -> bool:
- if not isinstance(other, MtpStorageInfo):
- return False
- return self._storage_id == other._storage_id
-
- def hashCode(self) -> int:
- return self._storage_id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# MtpObjectInfo
-# ═══════════════════════════════════════════════════════════════
-
-class MtpObjectInfo(Stub):
- """MtpObjectInfo — MTP 对象信息"""
-
- def __init__(self):
- super().__init__()
- self._object_handle = 0
- self._storage_id = 0
- self._format = MtpConstants.FORMAT_UNDEFINED
- self._protection_status = MtpConstants.PROTECTION_STATUS_NONE
- self._compressed_size = 0
- self._thumb_format = MtpConstants.FORMAT_UNDEFINED
- self._thumb_compressed_size = 0
- self._thumb_pix_width = 0
- self._thumb_pix_height = 0
- self._image_pix_width = 0
- self._image_pix_height = 0
- self._image_pix_depth = 0
- self._parent = 0
- self._association_desc = 0
- self._association_type = 0
- self._sequence_number = 0
- self._name = ""
- self._date_created = 0
- self._date_modified = 0
- self._keywords = ""
-
- def getObjectHandle(self) -> int:
- return self._object_handle
-
- def getStorageId(self) -> int:
- return self._storage_id
-
- def getFormat(self) -> int:
- return self._format
-
- def getProtectionStatus(self) -> int:
- return self._protection_status
-
- def getCompressedSize(self) -> int:
- return self._compressed_size
-
- def getThumbFormat(self) -> int:
- return self._thumb_format
-
- def getThumbCompressedSize(self) -> int:
- return self._thumb_compressed_size
-
- def getThumbPixWidth(self) -> int:
- return self._thumb_pix_width
-
- def getThumbPixHeight(self) -> int:
- return self._thumb_pix_height
-
- def getImagePixWidth(self) -> int:
- return self._image_pix_width
-
- def getImagePixHeight(self) -> int:
- return self._image_pix_height
-
- def getImagePixDepth(self) -> int:
- return self._image_pix_depth
-
- def getParent(self) -> int:
- return self._parent
-
- def getAssociationDesc(self) -> int:
- return self._association_desc
-
- def getAssociationType(self) -> int:
- return self._association_type
-
- def getSequenceNumber(self) -> int:
- return self._sequence_number
-
- def getName(self) -> str:
- return self._name
-
- def getDateCreated(self) -> int:
- return self._date_created
-
- def getDateModified(self) -> int:
- return self._date_modified
-
- def getKeywords(self) -> str:
- return self._keywords
-
- def toString(self) -> str:
- return f"MtpObjectInfo(name={self._name}, handle={self._object_handle})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, MtpObjectInfo):
- return False
- return self._object_handle == other._object_handle
-
- def hashCode(self) -> int:
- return self._object_handle & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# MtpPropertyGroup
-# ═══════════════════════════════════════════════════════════════
-
-class MtpPropertyGroup(Stub):
- """MtpPropertyGroup — MTP 属性组"""
-
- def __init__(self):
- super().__init__()
- self._properties: Dict[int, Any] = {}
-
- def getPropertyValue(self, propertyCode: int) -> Optional[Any]:
- return self._properties.get(propertyCode)
-
- def toString(self) -> str:
- return f"MtpPropertyGroup(properties={len(self._properties)})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# MtpDeviceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class MtpDeviceInfo(Stub):
- """MtpDeviceInfo — MTP 设备信息"""
-
- def __init__(self):
- super().__init__()
- self._manufacturer = "Unknown"
- self._model = "MTP Device"
- self._device_version = "1.0"
- self._serial_number = "00000000"
- self._operations_supported: List[int] = []
- self._events_supported: List[int] = []
- self._device_properties_supported: List[int] = []
-
- def getManufacturer(self) -> str:
- return self._manufacturer
-
- def getModel(self) -> str:
- return self._model
-
- def getDeviceVersion(self) -> str:
- return self._device_version
-
- def getSerialNumber(self) -> str:
- return self._serial_number
-
- def getOperationsSupported(self) -> List[int]:
- return list(self._operations_supported)
-
- def getEventsSupported(self) -> List[int]:
- return list(self._events_supported)
-
- def getDevicePropertySupported(self) -> List[int]:
- return list(self._device_properties_supported)
-
- def toString(self) -> str:
- return f"MtpDeviceInfo(manufacturer={self._manufacturer}, model={self._model})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, MtpDeviceInfo):
- return False
- return self._serial_number == other._serial_number
-
- def hashCode(self) -> int:
- return hash(self._serial_number) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# MtpStorage
-# ═══════════════════════════════════════════════════════════════
-
-class MtpStorage(Stub):
- """MtpStorage — MTP 存储"""
-
- def __init__(self, storageId: int = 0x00010001, path: str = ""):
- super().__init__()
- self._storage_id = storageId
- self._path = path
- self._description = "Storage"
-
- def getStorageId(self) -> int:
- return self._storage_id
-
- def getPath(self) -> str:
- return self._path
-
- def getDescription(self) -> str:
- return self._description
-
- def toString(self) -> str:
- return f"MtpStorage(id={self._storage_id}, path={self._path})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, MtpStorage):
- return False
- return self._storage_id == other._storage_id
-
- def hashCode(self) -> int:
- return self._storage_id & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/net.py b/android_pyapi/android/net.py
deleted file mode 100644
index 2bc46bd..0000000
--- a/android_pyapi/android/net.py
+++ /dev/null
@@ -1,1559 +0,0 @@
-"""
-Android Network 组件 — ConnectivityManager, NetworkInfo, Uri_Builder 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-import socket
-import struct
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-from urllib.parse import urlparse, urlunparse, quote, unquote
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-# Linux 真实实现导入
-try:
- from .._linux_impl import IS_LINUX, LinuxNetwork, HAS_IP
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Uri (re-export from content)
-# ═══════════════════════════════════════════════════════════════
-
-# Uri is defined in android.content; re-export the reference here.
-from .content import Uri
-
-Uri_Builder = Uri.Builder
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocalSocket / LocalSocketAddress
-# ═══════════════════════════════════════════════════════════════
-
-class LocalSocketAddress(Stub):
- """Android LocalSocketAddress"""
-
- class Namespace(Stub):
- ABSTRACT = 0
- RESERVED = 1
- FILESYSTEM = 2
-
- def __init__(self, name: str, namespace: int = Namespace.ABSTRACT):
- super().__init__()
- self._name = name
- self._namespace = namespace
-
- def getName(self) -> str:
- return self._name
-
- def getNamespace(self) -> int:
- return self._namespace
-
-
-class LocalSocket(Stub):
- """Android LocalSocket — 基于 Unix domain socket 实现"""
-
- def __init__(self, sock_type: int = 1): # SOCK_STREAM
- super().__init__()
- self._sock: Optional[socket.socket] = None
- self._sock_type = sock_type
- self._input_stream: Optional[bytes] = b""
- self._output_stream: Optional[bytes] = b""
- self._closed = False
- self._so_timeout: float = 0.0
- self._address: Optional[LocalSocketAddress] = None
-
- def connect(self, address: LocalSocketAddress, timeout: int = 0):
- self._address = address
- ns = address.getNamespace()
- if ns == LocalSocketAddress.Namespace.ABSTRACT:
- sock_path = "\0" + address.getName()
- elif ns == LocalSocketAddress.Namespace.FILESYSTEM:
- sock_path = address.getName()
- else:
- sock_path = os.path.join("/dev/socket", address.getName())
- try:
- self._sock = socket.socket(socket.AF_UNIX, self._sock_type)
- if timeout > 0:
- self._sock.settimeout(timeout / 1000.0)
- self._sock.connect(sock_path)
- except (OSError, socket.error) as e:
- raise AndroidOnlyError(f"LocalSocket.connect failed: {e}")
-
- def bind(self, address: LocalSocketAddress):
- self._address = address
- ns = address.getNamespace()
- if ns == LocalSocketAddress.Namespace.ABSTRACT:
- sock_path = "\0" + address.getName()
- elif ns == LocalSocketAddress.Namespace.FILESYSTEM:
- sock_path = address.getName()
- else:
- sock_path = os.path.join("/dev/socket", address.getName())
- try:
- self._sock = socket.socket(socket.AF_UNIX, self._sock_type)
- self._sock.bind(sock_path)
- except (OSError, socket.error) as e:
- raise AndroidOnlyError(f"LocalSocket.bind failed: {e}")
-
- def getInputStream(self):
- return self._input_stream
-
- def getOutputStream(self):
- return self._output_stream
-
- def close(self):
- self._closed = True
- if self._sock:
- try:
- self._sock.close()
- except Exception:
- pass
- self._sock = None
-
- def setSoTimeout(self, timeout: int):
- self._so_timeout = timeout / 1000.0
- if self._sock:
- self._sock.settimeout(self._so_timeout)
-
- def getSoTimeout(self) -> int:
- return int(self._so_timeout * 1000)
-
- def shutdownInput(self):
- if self._sock:
- try:
- self._sock.shutdown(socket.SHUT_RD)
- except Exception:
- pass
-
- def shutdownOutput(self):
- if self._sock:
- try:
- self._sock.shutdown(socket.SHUT_WR)
- except Exception:
- pass
-
- def isClosed(self) -> bool:
- return self._closed
-
- def isConnected(self) -> bool:
- return self._sock is not None
-
- def getRemoteSocketAddress(self) -> Optional[LocalSocketAddress]:
- return self._address
-
- def toString(self) -> str:
- return f"LocalSocket(address={self._address})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkUtils
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkUtils(Stub):
- """NetworkUtils — 网络工具"""
-
- @staticmethod
- def getNetworkPartOfAddress(addr: str, prefix_len: int) -> str:
- return addr
-
- @staticmethod
- def intToInetAddress(host_address: int) -> str:
- try:
- return socket.inet_ntoa(struct.pack("!I", host_address & 0xFFFFFFFF))
- except Exception:
- return "0.0.0.0"
-
- @staticmethod
- def inetAddressToInt(addr: str) -> int:
- try:
- return struct.unpack("!I", socket.inet_aton(addr))[0]
- except Exception:
- return 0
-
- @staticmethod
- def isIPv6ULA(addr: str) -> bool:
- return addr.startswith("fc") or addr.startswith("fd")
-
- @staticmethod
- def isIPv6GlobalMulticast(addr: str) -> bool:
- return addr.startswith("ff")
-
- @staticmethod
- def prefixLengthToSubnetMask(prefix_len: int) -> int:
- return (0xFFFFFFFF << (32 - prefix_len)) & 0xFFFFFFFF if prefix_len <= 32 else 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# InetAddresses
-# ═══════════════════════════════════════════════════════════════
-
-class InetAddresses(Stub):
- """InetAddresses — 地址解析工具"""
-
- @staticmethod
- def isNumeric(address: str) -> bool:
- try:
- socket.inet_aton(address)
- return True
- except OSError:
- return False
-
- @staticmethod
- def parseNumericAddress(address: str) -> str:
- return address
-
- @staticmethod
- def getAddressFamily(address: str) -> int:
- return 2 # AF_INET
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkSpecifier / MatchAllNetworkSpecifier
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkSpecifier(Stub):
- """NetworkSpecifier — 网络说明符基类"""
-
- def __init__(self):
- super().__init__()
-
- def satisfiedBy(self, other: "NetworkSpecifier") -> bool:
- return self is other
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self.__class__.__name__) & 0x7FFFFFFF
-
-
-class MatchAllNetworkSpecifier(NetworkSpecifier):
- """匹配所有网络的说明符"""
-
- def __init__(self):
- super().__init__()
-
- def satisfiedBy(self, other: NetworkSpecifier) -> bool:
- return True
-
- def toString(self) -> str:
- return "MatchAllNetworkSpecifier"
-
-
-class WifiAwareNetworkSpecifier(NetworkSpecifier):
- """WiFi Aware 网络说明符"""
-
- def __init__(self, role: int, client_id: int, peer_id: int, peer_mac: Optional[str] = None):
- super().__init__()
- self._role = role
- self._client_id = client_id
- self._peer_id = peer_id
- self._peer_mac = peer_mac
-
- def getRole(self) -> int:
- return self._role
-
- def getClientId(self) -> int:
- return self._client_id
-
- def toString(self) -> str:
- return f"WifiAwareNetworkSpecifier(role={self._role}, client={self._client_id})"
-
-
-class EthernetNetworkSpecifier(NetworkSpecifier):
- """以太网网络说明符"""
-
- def __init__(self, data: Optional[str] = None):
- super().__init__()
- self._data = data
-
- def getData(self) -> Optional[str]:
- return self._data
-
- def toString(self) -> str:
- return f"EthernetNetworkSpecifier(data={self._data})"
-
-
-class TelephonyNetworkSpecifier(NetworkSpecifier):
- """电话网络说明符"""
-
- def __init__(self, subscription_id: int = 0):
- super().__init__()
- self._subscription_id = subscription_id
-
- def getSubscriptionId(self) -> int:
- return self._subscription_id
-
- def toString(self) -> str:
- return f"TelephonyNetworkSpecifier(subId={self._subscription_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkState
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkState(Stub):
- """NetworkState — 网络状态"""
-
- def __init__(self, network: Optional["Network"] = None,
- network_info: Optional["NetworkInfo"] = None,
- link_properties: Optional["LinkProperties"] = None,
- network_capabilities: Optional["NetworkCapabilities"] = None,
- subscriber_id: Optional[str] = None):
- super().__init__()
- self.network = network
- self.network_info = network_info
- self.link_properties = link_properties
- self.network_capabilities = network_capabilities
- self.subscriber_id = subscriber_id
-
- def getNetwork(self) -> Optional["Network"]:
- return self.network
-
- def getNetworkInfo(self) -> Optional["NetworkInfo"]:
- return self.network_info
-
- def getLinkProperties(self) -> Optional["LinkProperties"]:
- return self.link_properties
-
- def getNetworkCapabilities(self) -> Optional["NetworkCapabilities"]:
- return self.network_capabilities
-
- def toString(self) -> str:
- return f"NetworkState(network={self.network})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkInfo
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkInfo(Stub):
- """NetworkInfo — 网络连接信息"""
-
- class DetailedState(Stub):
- CONNECTED = "CONNECTED"
- CONNECTING = "CONNECTING"
- DISCONNECTED = "DISCONNECTED"
- SUSPENDED = "SUSPENDED"
- IDLE = "IDLE"
- FAILED = "FAILED"
- BLOCKED = "BLOCKED"
- VERIFYING_POOR_CONNECTION = "VERIFYING_POOR_CONNECTION"
- CAPTIVE_PORTAL_CHECK = "CAPTIVE_PORTAL_CHECK"
- OBTAINING_IPADDR = "OBTAINING_IPADDR"
-
- class State(Stub):
- CONNECTED = "CONNECTED"
- CONNECTING = "CONNECTING"
- DISCONNECTED = "DISCONNECTED"
- SUSPENDED = "SUSPENDED"
- UNKNOWN = "UNKNOWN"
-
- def __init__(self, type_: int = 0, subtype: int = 0,
- state: str = "DISCONNECTED", detailed_state: str = "DISCONNECTED",
- type_name: str = "", subtype_name: str = "",
- extra_info: Optional[str] = None, reason: Optional[str] = None,
- failover: bool = False, roaming: bool = False,
- is_available: bool = True):
- super().__init__()
- self._type = type_
- self._subtype = subtype
- self._state = state
- self._detailed_state = detailed_state
- self._type_name = type_name or self._default_type_name(type_)
- self._subtype_name = subtype_name
- self._extra_info = extra_info
- self._reason = reason
- self._failover = failover
- self._roaming = roaming
- self._is_available = is_available
- self._is_connected = (state == "CONNECTED")
- self._is_connecting = (state == "CONNECTING")
-
- def _default_type_name(self, type_: int) -> str:
- names = {
- 0: "MOBILE", 1: "WIFI", 6: "WIMAX", 7: "BLUETOOTH",
- 9: "ETHERNET", 17: "VPN",
- }
- return names.get(type_, "UNKNOWN")
-
- @classmethod
- def from_linux_data(cls, data: Optional[dict] = None,
- network_type: int = 9) -> "NetworkInfo":
- """从 Linux 真实网络数据构造 NetworkInfo
-
- data 字典可包含: ip, interface, connected, type_name 等
- """
- if data is None:
- data = {}
- connected = bool(data.get("connected", False))
- state = "CONNECTED" if connected else "DISCONNECTED"
- detailed_state = "CONNECTED" if connected else "DISCONNECTED"
- type_name = data.get("type_name") or cls._default_type_name_static(network_type)
- extra_info = data.get("ip") or data.get("interface")
- return cls(
- type_=network_type,
- state=state,
- detailed_state=detailed_state,
- type_name=type_name,
- extra_info=extra_info,
- is_available=True,
- roaming=False,
- )
-
- @staticmethod
- def _default_type_name_static(type_: int) -> str:
- names = {
- 0: "MOBILE", 1: "WIFI", 6: "WIMAX", 7: "BLUETOOTH",
- 9: "ETHERNET", 17: "VPN",
- }
- return names.get(type_, "UNKNOWN")
-
- def getType(self) -> int:
- return self._type
-
- def getSubtype(self) -> int:
- return self._subtype
-
- def isConnected(self) -> bool:
- return self._state == "CONNECTED"
-
- def isConnectedOrConnecting(self) -> bool:
- return self._state in ("CONNECTED", "CONNECTING")
-
- def getState(self) -> str:
- return self._state
-
- def getDetailedState(self) -> str:
- return self._detailed_state
-
- def getTypeName(self) -> str:
- return self._type_name
-
- def getSubtypeName(self) -> str:
- return self._subtype_name
-
- def getExtraInfo(self) -> Optional[str]:
- return self._extra_info
-
- def getReason(self) -> Optional[str]:
- return self._reason
-
- def getFailover(self) -> bool:
- return self._failover
-
- def getRoaming(self) -> bool:
- return self._roaming
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def isFailover(self) -> bool:
- return self._failover
-
- def isRoaming(self) -> bool:
- return self._roaming
-
- def toString(self) -> str:
- return (f"NetworkInfo(type={self._type_name}[{self._type}], "
- f"state={self._state}/{self._detailed_state}, "
- f"roaming={self._roaming}, available={self._is_available})")
-
- def hashCode(self) -> int:
- return self._type
-
- def equals(self, other) -> bool:
- if isinstance(other, NetworkInfo):
- return self._type == other._type and self._state == other._state
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Network
-# ═══════════════════════════════════════════════════════════════
-
-class Network(Stub):
- """Network — 网络句柄"""
-
- def __init__(self, net_id: int = 0):
- super().__init__()
- self._net_id = net_id
-
- def getNetworkHandle(self) -> int:
- return self._net_id
-
- def getNetworkCapabilities(self) -> Optional["NetworkCapabilities"]:
- return None
-
- def getLinkProperties(self) -> Optional["LinkProperties"]:
- return None
-
- def bindSocket(self, socket_obj: Any):
- pass
-
- def bindSocketToNetwork(self, socket_obj: Any) -> bool:
- return True
-
- def equals(self, other) -> bool:
- if isinstance(other, Network):
- return self._net_id == other._net_id
- return False
-
- def hashCode(self) -> int:
- return self._net_id
-
- def toString(self) -> str:
- return f"Network({self._net_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkCapabilities
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkCapabilities(Stub):
- """NetworkCapabilities — 网络能力"""
-
- NET_CAPABILITY_INTERNET = 12
- NET_CAPABILITY_NOT_METERED = 11
- NET_CAPABILITY_NOT_ROAMING = 18
- NET_CAPABILITY_VALIDATED = 16
- NET_CAPABILITY_CAPTIVE_PORTAL = 17
- NET_CAPABILITY_NOT_VPN = 15
- NET_CAPABILITY_MMS = 0
- NET_CAPABILITY_SUPL = 1
- NET_CAPABILITY_DUN = 2
- NET_CAPABILITY_FOTA = 3
- NET_CAPABILITY_IMS = 4
- NET_CAPABILITY_CBS = 5
- NET_CAPABILITY_WIFI_P2P = 6
- NET_CAPABILITY_IA = 7
- NET_CAPABILITY_RCS = 8
- NET_CAPABILITY_XCAP = 9
- NET_CAPABILITY_EIMS = 10
- NET_CAPABILITY_NOT_CONGESTED = 13
- NET_CAPABILITY_NOT_RESTRICTED = 14
- NET_CAPABILITY_TRUSTED = 19
- NET_CAPABILITY_NOT_VCN_MANAGED = 20
- NET_CAPABILITY_PRIORITIZE_LATENCY = 21
- NET_CAPABILITY_PRIORITIZE_BANDWIDTH = 22
-
- TRANSPORT_WIFI = 1
- TRANSPORT_CELLULAR = 0
- TRANSPORT_ETHERNET = 3
- TRANSPORT_BLUETOOTH = 2
- TRANSPORT_VPN = 4
- TRANSPORT_WIFI_AWARE = 5
- TRANSPORT_LOWPAN = 6
- TRANSPORT_TEST = 7
-
- SIGNAL_STRENGTH_UNSPECIFIED = -2147483648
-
- def __init__(self):
- super().__init__()
- self._capabilities: Set[int] = set()
- self._transports: Set[int] = set()
- self._link_upstream_bw = 0
- self._link_downstream_bw = 0
- self._signal_strength = self.SIGNAL_STRENGTH_UNSPECIFIED
- self._network_specifier: Optional[NetworkSpecifier] = None
- self._owner_uid = -1
- self._ssid: Optional[str] = None
- self._administrator_uids: List[int] = []
- self._enterprise_ids: List[int] = []
-
- def hasCapability(self, capability: int) -> bool:
- return capability in self._capabilities
-
- def hasTransport(self, transport: int) -> bool:
- return transport in self._transports
-
- def addCapability(self, capability: int) -> "NetworkCapabilities":
- self._capabilities.add(capability)
- return self
-
- def removeCapability(self, capability: int) -> "NetworkCapabilities":
- self._capabilities.discard(capability)
- return self
-
- def getCapabilities(self) -> List[int]:
- return sorted(self._capabilities)
-
- def getLinkUpstreamBandwidthKbps(self) -> int:
- return self._link_upstream_bw
-
- def getLinkDownstreamBandwidthKbps(self) -> int:
- return self._link_downstream_bw
-
- def setLinkUpstreamBandwidthKbps(self, bw: int):
- self._link_upstream_bw = bw
-
- def setLinkDownstreamBandwidthKbps(self, bw: int):
- self._link_downstream_bw = bw
-
- def addTransportType(self, transport: int) -> "NetworkCapabilities":
- self._transports.add(transport)
- return self
-
- def removeTransportType(self, transport: int) -> "NetworkCapabilities":
- self._transports.discard(transport)
- return self
-
- def getTransportInfo(self) -> Optional[Any]:
- return None
-
- def setNetworkSpecifier(self, specifier: NetworkSpecifier):
- self._network_specifier = specifier
-
- def getNetworkSpecifier(self) -> Optional[NetworkSpecifier]:
- return self._network_specifier
-
- def getSignalStrength(self) -> int:
- return self._signal_strength
-
- def setSignalStrength(self, strength: int):
- self._signal_strength = strength
-
- def getOwnerUid(self) -> int:
- return self._owner_uid
-
- def setOwnerUid(self, uid: int):
- self._owner_uid = uid
-
- def getSsid(self) -> Optional[str]:
- return self._ssid
-
- def setSsid(self, ssid: str):
- self._ssid = ssid
-
- def getAdministratorUids(self) -> List[int]:
- return list(self._administrator_uids)
-
- def setAdministratorUids(self, uids: List[int]):
- self._administrator_uids = list(uids)
-
- def equals(self, other) -> bool:
- if isinstance(other, NetworkCapabilities):
- return (self._capabilities == other._capabilities
- and self._transports == other._transports)
- return False
-
- def hashCode(self) -> int:
- return hash(frozenset(self._capabilities)) ^ hash(frozenset(self._transports))
-
- def toString(self) -> str:
- caps = ",".join(str(c) for c in sorted(self._capabilities))
- trans = ",".join(str(t) for t in sorted(self._transports))
- return f"NetworkCapabilities(caps=[{caps}], transports=[{trans}])"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkRequest
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkRequest(Stub):
- """NetworkRequest — 网络请求"""
-
- class Builder(Stub):
- """Builder 模式"""
-
- def __init__(self):
- super().__init__()
- self._capabilities: Set[int] = set()
- self._transports: Set[int] = set()
- self._network_specifier: Optional[NetworkSpecifier] = None
- self._clear_capabilities: Set[int] = set()
-
- def addCapability(self, capability: int) -> "NetworkRequest.Builder":
- self._capabilities.add(capability)
- return self
-
- def removeCapability(self, capability: int) -> "NetworkRequest.Builder":
- self._capabilities.discard(capability)
- self._clear_capabilities.add(capability)
- return self
-
- def addTransportType(self, transport: int) -> "NetworkRequest.Builder":
- self._transports.add(transport)
- return self
-
- def removeTransportType(self, transport: int) -> "NetworkRequest.Builder":
- self._transports.discard(transport)
- return self
-
- def setNetworkSpecifier(self, specifier: NetworkSpecifier) -> "NetworkRequest.Builder":
- self._network_specifier = specifier
- return self
-
- def build(self) -> "NetworkRequest":
- request = NetworkRequest()
- request._capabilities = set(self._capabilities)
- request._transports = set(self._transports)
- request._network_specifier = self._network_specifier
- request._request_id = id(request)
- return request
-
- def __init__(self):
- super().__init__()
- self._capabilities: Set[int] = set()
- self._transports: Set[int] = set()
- self._network_specifier: Optional[NetworkSpecifier] = None
- self._request_id = 0
-
- def hasCapability(self, capability: int) -> bool:
- return capability in self._capabilities
-
- def hasTransport(self, transport: int) -> bool:
- return transport in self._transports
-
- def getCapabilities(self) -> Set[int]:
- return set(self._capabilities)
-
- def getTransports(self) -> Set[int]:
- return set(self._transports)
-
- def getNetworkSpecifier(self) -> Optional[NetworkSpecifier]:
- return self._network_specifier
-
- def getRequestId(self) -> int:
- return self._request_id
-
- def toString(self) -> str:
- return f"NetworkRequest(id={self._request_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkCallback
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkCallback(Stub):
- """NetworkCallback — 网络回调"""
-
- def __init__(self, flags: int = 0):
- super().__init__()
- self._flags = flags
-
- def onAvailable(self, network: Network):
- pass
-
- def onLost(self, network: Network):
- pass
-
- def onCapabilitiesChanged(self, network: Network, capabilities: NetworkCapabilities):
- pass
-
- def onLinkPropertiesChanged(self, network: Network, link_properties: "LinkProperties"):
- pass
-
- def onNetworkSuspended(self, network: Network):
- pass
-
- def onResumed(self, network: Network):
- pass
-
- def onBlockedStatusChanged(self, network: Network, blocked: bool):
- pass
-
- def onLosing(self, network: Network, max_ms_to_live: int):
- pass
-
- def onPreCheck(self, network: Network) -> bool:
- return True
-
- def onUnavailable(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinkAddress
-# ═══════════════════════════════════════════════════════════════
-
-class LinkAddress(Stub):
- """LinkAddress — 链接地址"""
-
- def __init__(self, address: str = "0.0.0.0",
- prefix_length: int = 24,
- flags: int = 0,
- scope: int = 0):
- super().__init__()
- self._address = address
- self._prefix_length = prefix_length
- self._flags = flags
- self._scope = scope
- self._is_ipv6 = ":" in address
-
- def getAddress(self) -> str:
- return self._address
-
- def getPrefixLength(self) -> int:
- return self._prefix_length
-
- def getFlags(self) -> int:
- return self._flags
-
- def getScope(self) -> int:
- return self._scope
-
- def isIpv6(self) -> bool:
- return self._is_ipv6
-
- def toString(self) -> str:
- return f"{self._address}/{self._prefix_length}"
-
- def equals(self, other) -> bool:
- if isinstance(other, LinkAddress):
- return self._address == other._address
- return False
-
- def hashCode(self) -> int:
- return hash(self._address) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RouteInfo
-# ═══════════════════════════════════════════════════════════════
-
-class RouteInfo(Stub):
- """RouteInfo — 路由信息"""
-
- RTN_UNICAST = 1
- RTN_UNREACHABLE = 2
- RTN_BROADCAST = 3
- RTN_THROW = 4
- RTN_OTHER = 5
-
- def __init__(self, destination: Optional[LinkAddress] = None,
- gateway: str = "",
- interface_name: str = "",
- is_default: bool = False,
- type_: int = RTN_UNICAST):
- super().__init__()
- self._destination = destination
- self._gateway = gateway
- self._interface_name = interface_name
- self._is_default = is_default
- self._type = type_
-
- def getDestination(self) -> Optional[LinkAddress]:
- return self._destination
-
- def getGateway(self) -> str:
- return self._gateway
-
- def getInterface(self) -> str:
- return self._interface_name
-
- def getType(self) -> int:
- return self._type
-
- def isDefaultRoute(self) -> bool:
- return self._is_default
-
- def isIPv4Default(self) -> bool:
- return self._is_default and self._destination is not None and not self._destination.isIpv6()
-
- def isIPv6Default(self) -> bool:
- return self._is_default and self._destination is not None and self._destination.isIpv6()
-
- def toString(self) -> str:
- dest = str(self._destination) if self._destination else "0.0.0.0/0"
- gw = self._gateway or "0.0.0.0"
- return f"RouteInfo({dest} -> {gw} via {self._interface_name})"
-
- def equals(self, other) -> bool:
- if isinstance(other, RouteInfo):
- return (self._gateway == other._gateway
- and self._interface_name == other._interface_name)
- return False
-
- def hashCode(self) -> int:
- return hash(self._gateway) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinkProperties
-# ═══════════════════════════════════════════════════════════════
-
-class LinkProperties(Stub):
- """LinkProperties — 链接属性"""
-
- def __init__(self):
- super().__init__()
- self._link_addresses: List[LinkAddress] = []
- self._routes: List[RouteInfo] = []
- self._dns_servers: List[str] = []
- self._interface_name: str = ""
- self._mtu: int = 1500
- self._http_proxy: Optional[ProxyInfo] = None
- self._private_dns_server_name: str = ""
- self._private_dns_active: bool = False
- self._domains: str = ""
- self._pcscf: List[str] = []
-
- def getLinkAddresses(self) -> List[LinkAddress]:
- return list(self._link_addresses)
-
- def getRoutes(self) -> List[RouteInfo]:
- return list(self._routes)
-
- def getDnsServers(self) -> List[str]:
- return list(self._dns_servers)
-
- def getInterfaceName(self) -> str:
- return self._interface_name
-
- def setInterfaceName(self, name: str):
- self._interface_name = name
-
- def addLinkAddress(self, address: LinkAddress):
- if address not in self._link_addresses:
- self._link_addresses.append(address)
-
- def removeLinkAddress(self, address: LinkAddress):
- self._link_addresses = [a for a in self._link_addresses if a != address]
-
- def addRoute(self, route: RouteInfo):
- if route not in self._routes:
- self._routes.append(route)
-
- def removeRoute(self, route: RouteInfo):
- self._routes = [r for r in self._routes if r != route]
-
- def addDnsServer(self, dns: str):
- if dns not in self._dns_servers:
- self._dns_servers.append(dns)
-
- def removeDnsServer(self, dns: str):
- self._dns_servers = [d for d in self._dns_servers if d != dns]
-
- def getMtu(self) -> int:
- return self._mtu
-
- def setMtu(self, mtu: int):
- self._mtu = mtu
-
- def getHttpProxy(self) -> Optional["ProxyInfo"]:
- return self._http_proxy
-
- def setHttpProxy(self, proxy: "ProxyInfo"):
- self._http_proxy = proxy
-
- def getPrivateDnsServerName(self) -> str:
- return self._private_dns_server_name
-
- def setPrivateDnsServerName(self, name: str):
- self._private_dns_server_name = name
- self._private_dns_active = bool(name)
-
- def isPrivateDnsActive(self) -> bool:
- return self._private_dns_active
-
- def setLinkAddresses(self, addresses: List[LinkAddress]):
- self._link_addresses = list(addresses)
-
- def setDnsServers(self, dns_servers: List[str]):
- self._dns_servers = list(dns_servers)
-
- def getDomains(self) -> str:
- return self._domains
-
- def setDomains(self, domains: str):
- self._domains = domains
-
- def getPcscf(self) -> List[str]:
- return list(self._pcscf)
-
- def addPcscf(self, addr: str):
- if addr not in self._pcscf:
- self._pcscf.append(addr)
-
- def setMtuV4(int_mtu: int):
- pass
-
- def setMtuV6(int_mtu: int):
- pass
-
- def clearLinkAddresses(self):
- self._link_addresses.clear()
-
- def clearRoutes(self):
- self._routes.clear()
-
- def clearDnsServers(self):
- self._dns_servers.clear()
-
- def toString(self) -> str:
- iface = self._interface_name or "none"
- return f"LinkProperties(iface={iface}, mtu={self._mtu}, dns={self._dns_servers})"
-
- def equals(self, other) -> bool:
- if isinstance(other, LinkProperties):
- return (self._interface_name == other._interface_name
- and self._mtu == other._mtu)
- return False
-
- def hashCode(self) -> int:
- return hash(self._interface_name) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# DnsResolver
-# ═══════════════════════════════════════════════════════════════
-
-class DnsResolver(Stub):
- """DnsResolver — DNS 解析器"""
-
- CLASS_IN = 1
- TYPE_A = 1
- TYPE_AAAA = 28
-
- @staticmethod
- def getInstance() -> "DnsResolver":
- return DnsResolver()
-
- def query(self, hostname: str, callback: Any, flags: int = 0):
- try:
- result = socket.getaddrinfo(hostname, None)
- callback.onAnswer(None, 0, result)
- except socket.gaierror:
- callback.onAnswer(None, -1, None)
-
-
-# ═══════════════════════════════════════════════════════════════
-# DhcpInfo
-# ═══════════════════════════════════════════════════════════════
-
-class DhcpInfo(Stub):
- """DhcpInfo — DHCP 信息"""
-
- def __init__(self):
- super().__init__()
- self.ipAddress = 0
- self.gateway = 0
- self.netmask = 0
- self.dns1 = 0
- self.dns2 = 0
- self.serverAddress = 0
- self.leaseDuration = 0
-
- def toString(self) -> str:
- return (f"DhcpInfo(ip={self.ipAddress}, gw={self.gateway}, "
- f"mask={self.netmask}, dns1={self.dns1}, dns2={self.dns2})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# SSLSessionCache
-# ═══════════════════════════════════════════════════════════════
-
-class SSLSessionCache(Stub):
- """SSLSessionCache — SSL 会话缓存"""
-
- def __init__(self, context_or_dir: Any):
- super().__init__()
- self._dir: Optional[str] = None
- if isinstance(context_or_dir, str):
- self._dir = context_or_dir
- else:
- self._dir = os.path.join(_app_data_dir, "ssl_cache")
-
- def getDir(self) -> Optional[str]:
- return self._dir
-
-
-# ═══════════════════════════════════════════════════════════════
-# TrafficStats
-# ═══════════════════════════════════════════════════════════════
-
-class TrafficStats(Stub):
- """TrafficStats — 流量统计"""
-
- UID_TETHERING = "UNSUPPORTED"
- UNSUPPORTED = -1
- TAG_SYSTEM_UPDATE = 0
-
- _cached_stats = None
- _cache_time = 0
-
- @staticmethod
- def _read_net_dev():
- """读取 /proc/net/dev 获取网络流量"""
- try:
- with open("/proc/net/dev", "r") as f:
- lines = f.readlines()[2:] # 跳过前两行表头
- total_rx = 0
- total_tx = 0
- for line in lines:
- parts = line.split()
- ifname = parts[0].rstrip(":")
- if ifname == "lo":
- continue
- rx_bytes = int(parts[1])
- tx_bytes = int(parts[9])
- total_rx += rx_bytes
- total_tx += tx_bytes
- return {"rx_bytes": total_rx, "tx_bytes": total_tx,
- "rx_packets": 0, "tx_packets": 0}
- except Exception:
- return {"rx_bytes": 0, "tx_bytes": 0, "rx_packets": 0, "tx_packets": 0}
-
- @staticmethod
- def getMobileRxBytes():
- return 0 # 桌面无移动数据
-
- @staticmethod
- def getMobileTxBytes():
- return 0
-
- @staticmethod
- def getMobileRxPackets():
- return 0
-
- @staticmethod
- def getMobileTxPackets():
- return 0
-
- @staticmethod
- def getTotalRxBytes():
- return TrafficStats._read_net_dev()["rx_bytes"]
-
- @staticmethod
- def getTotalTxBytes():
- return TrafficStats._read_net_dev()["tx_bytes"]
-
- @staticmethod
- def getTotalRxPackets():
- return TrafficStats._read_net_dev()["rx_packets"]
-
- @staticmethod
- def getTotalTxPackets():
- return TrafficStats._read_net_dev()["tx_packets"]
-
- @staticmethod
- def getUidRxBytes(uid):
- try:
- with open(f"/proc/uid_stat/{uid}/tcp_rcv", "r") as f:
- return int(f.read().strip())
- except Exception:
- return 0
-
- @staticmethod
- def getUidTxBytes(uid):
- try:
- with open(f"/proc/uid_stat/{uid}/tcp_snd", "r") as f:
- return int(f.read().strip())
- except Exception:
- return 0
-
- @staticmethod
- def getUidRxPackets(uid):
- return TrafficStats.getUidRxBytes(uid)
-
- @staticmethod
- def getUidTxPackets(uid):
- return TrafficStats.getUidTxBytes(uid)
-
- @staticmethod
- def getThreadStatsTag():
- return getattr(TrafficStats, '_thread_tag', 0)
-
- @staticmethod
- def setThreadStatsTag(tag):
- TrafficStats._thread_tag = tag
-
- @staticmethod
- def clearThreadStatsTag():
- TrafficStats._thread_tag = 0
-
- @staticmethod
- def getUidTcpTxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidTcpRxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidUdpTxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidUdpRxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def setThreadStatsUid(uid: int):
- pass
-
- @staticmethod
- def clearThreadStatsUid():
- pass
-
- @staticmethod
- def incrementOperationCount(uid: int, tag: int, count: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Proxy / ProxyInfo
-# ═══════════════════════════════════════════════════════════════
-
-class Proxy(Stub):
- """Proxy — 系统代理信息"""
-
- @staticmethod
- def getDefaultHost() -> Optional[str]:
- return None
-
- @staticmethod
- def getDefaultPort() -> int:
- return -1
-
-
-class ProxyInfo(Stub):
- """ProxyInfo — 代理详细信息"""
-
- def __init__(self, host: str = "", port: int = 0,
- pac_file_url: Optional[str] = None,
- username: str = "", password: str = "",
- exclusion_list: Optional[List[str]] = None):
- super().__init__()
- self._host = host
- self._port = port
- self._pac_file_url = pac_file_url
- self._username = username
- self._password = password
- self._exclusion_list = list(exclusion_list) if exclusion_list else []
- self._valid = bool(host) or bool(pac_file_url)
-
- def getHost(self) -> str:
- return self._host
-
- def getPort(self) -> int:
- return self._port
-
- def getPacFileUrl(self) -> Optional[str]:
- return self._pac_file_url
-
- def getUsername(self) -> str:
- return self._username
-
- def getPassword(self) -> str:
- return self._password
-
- def getExclusionList(self) -> List[str]:
- return list(self._exclusion_list)
-
- def isValid(self) -> bool:
- return self._valid
-
- def makeProxy(self, url: str):
- return self
-
- def equals(self, other) -> bool:
- if isinstance(other, ProxyInfo):
- return self._host == other._host and self._port == other._port
- return False
-
- def hashCode(self) -> int:
- return hash(self._host) ^ self._port
-
- def toString(self) -> str:
- pac = f" pac={self._pac_file_url}" if self._pac_file_url else ""
- return f"ProxyInfo(host={self._host}:{self._port}{pac})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ConnectivityManager
-# ═══════════════════════════════════════════════════════════════
-
-class ConnectivityManager(Stub):
- """ConnectivityManager — 连接管理器"""
-
- TYPE_WIFI = 1
- TYPE_MOBILE = 0
- TYPE_BLUETOOTH = 7
- TYPE_ETHERNET = 9
- TYPE_VPN = 17
- TYPE_WIMAX = 6
- TYPE_DUMMY = 8
- TYPE_PROXY = 16
-
- CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"
-
- DEFAULT_NETWORK_PREFERENCE = 1
-
- def __init__(self):
- super().__init__()
- self._networks: Dict[int, "Network"] = {}
- self._callbacks: List[Tuple[NetworkCallback, Optional[NetworkRequest]]] = []
- self._active_network_info = NetworkInfo(
- type_=self.TYPE_WIFI, state="CONNECTED", detailed_state="CONNECTED",
- type_name="WIFI", is_available=True,
- )
- self._net_id_counter = 0
- self._network_caps: Dict[int, NetworkCapabilities] = {}
- self._link_props: Dict[int, LinkProperties] = {}
-
- def _get_linux_active_info(self) -> Optional[NetworkInfo]:
- """从 Linux 真实网络信息构造活跃 NetworkInfo"""
- try:
- interfaces = LinuxNetwork.get_interfaces()
- # 有真实网络接口 (非环回) 且 operstate=up 即视为已连接
- connected = any(
- (iface.get("ifname") or iface.get("name", "")) != "lo"
- and iface.get("operstate", "").lower() == "up"
- for iface in interfaces
- )
- # 若有活跃接口但 get_connectivity 为 False (外网不可达), 仍视为已连接
- if not connected:
- connected = LinuxNetwork.get_connectivity()
- ip = LinuxNetwork.get_ip_address()
- iface_name = ""
- for iface in interfaces:
- name = iface.get("ifname") or iface.get("name", "")
- state = iface.get("operstate", "")
- if name and name != "lo" and state.lower() == "up":
- iface_name = name
- break
- # 判断网络类型 (无线接口 -> WIFI, 否则 ETHERNET)
- net_type = self.TYPE_ETHERNET
- for iface in interfaces:
- name = iface.get("ifname") or iface.get("name", "")
- if name and name.startswith(("wl", "wlan", "wlp")):
- net_type = self.TYPE_WIFI
- iface_name = iface_name or name
- break
- data = {
- "connected": connected,
- "ip": ip,
- "interface": iface_name,
- "type_name": "WIFI" if net_type == self.TYPE_WIFI else "ETHERNET",
- }
- return NetworkInfo.from_linux_data(data, network_type=net_type)
- except Exception:
- return self._active_network_info
-
- def getActiveNetworkInfo(self) -> Optional[NetworkInfo]:
- if _USE_LINUX:
- return self._get_linux_active_info()
- return self._active_network_info
-
- def getNetworkInfo(self, network_type: int) -> Optional[NetworkInfo]:
- if _USE_LINUX:
- info = self._get_linux_active_info()
- if info is not None and info.getType() == network_type:
- return info
- # 请求的类型与活跃网络不同时, 返回断开状态
- return NetworkInfo(
- type_=network_type, state="DISCONNECTED",
- detailed_state="DISCONNECTED", is_available=False,
- )
- network = self._networks.get(network_type)
- if network:
- return NetworkInfo(type_=network_type, state="CONNECTED", is_available=True)
- return self._active_network_info
-
- def getConnectivityStatus(self) -> bool:
- """返回当前网络连通性 (True=已连接)"""
- if _USE_LINUX:
- return LinuxNetwork.get_connectivity()
- return True
-
- def getNetworkInfoForUid(self, network: Network, uid: int) -> Optional[NetworkInfo]:
- return self._active_network_info
-
- def getAllNetworks(self) -> List[Network]:
- if _USE_LINUX:
- networks: List[Network] = []
- try:
- interfaces = LinuxNetwork.get_interfaces()
- idx = 0
- for iface in interfaces:
- name = iface.get("ifname") or iface.get("name", "")
- if not name or name == "lo":
- continue
- idx += 1
- net = Network(idx)
- networks.append(net)
- # 若无真实接口, 回退到内部缓存
- if networks:
- return networks
- except Exception:
- pass
- return list(self._networks.values())
-
- def getActiveNetwork(self) -> Optional[Network]:
- if _USE_LINUX:
- try:
- interfaces = LinuxNetwork.get_interfaces()
- for iface in interfaces:
- name = iface.get("ifname") or iface.get("name", "")
- state = iface.get("operstate", "")
- if name and name != "lo" and state.lower() == "up":
- net = Network(1)
- self._networks[1] = net
- return net
- # 回退: 若有外网连通性, 仍返回一个活跃 Network
- if LinuxNetwork.get_connectivity():
- net = Network(1)
- self._networks[1] = net
- return net
- except Exception:
- pass
- if self._networks:
- nid = next(iter(self._networks))
- return self._networks[nid]
- net = Network(1)
- self._networks[1] = net
- return net
-
- def getActiveNetworkForUid(self, uid: int) -> Optional[Network]:
- return self.getActiveNetwork()
-
- def getNetworkCapabilities(self, network: Network) -> Optional[NetworkCapabilities]:
- caps = self._network_caps.get(network.getNetworkHandle())
- if caps is None:
- caps = NetworkCapabilities()
- caps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- caps.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- caps.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- caps.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- self._network_caps[network.getNetworkHandle()] = caps
- return caps
-
- def getLinkProperties(self, network: Network) -> Optional[LinkProperties]:
- lp = self._link_props.get(network.getNetworkHandle())
- if lp is None:
- lp = LinkProperties()
- self._link_props[network.getNetworkHandle()] = lp
- return lp
-
- def requestNetwork(self, request: NetworkRequest, callback: NetworkCallback, timeout_ms: int = 0,
- handler: Any = None, network_specifier: int = 0) -> None:
- self._callbacks.append((callback, request))
- net = self.getActiveNetwork()
- if net:
- try:
- callback.onAvailable(net)
- except Exception:
- pass
-
- def registerDefaultNetworkCallback(self, callback: NetworkCallback, handler: Any = None) -> None:
- self._callbacks.append((callback, None))
- net = self.getActiveNetwork()
- if net:
- try:
- callback.onAvailable(net)
- except Exception:
- pass
-
- def registerNetworkCallback(self, request: NetworkRequest, callback: NetworkCallback,
- handler: Any = None) -> None:
- self._callbacks.append((callback, request))
- net = self.getActiveNetwork()
- if net:
- try:
- callback.onAvailable(net)
- except Exception:
- pass
-
- def unregisterNetworkCallback(self, callback_or_request: Any):
- if isinstance(callback_or_request, NetworkCallback):
- self._callbacks = [
- (cb, req) for cb, req in self._callbacks
- if cb is not callback_or_request
- ]
- elif isinstance(callback_or_request, NetworkRequest):
- self._callbacks = [
- (cb, req) for cb, req in self._callbacks
- if req is not callback_or_request
- ]
-
- def bindProcessToNetwork(self, network: Optional[Network]) -> bool:
- return True
-
- def getProcessDefaultNetwork(self) -> Optional[Network]:
- return self.getActiveNetwork()
-
- @staticmethod
- def setProcessDefaultNetwork(network: Optional[Network]) -> bool:
- return True
-
- def getAllNetworkInfo(self) -> List[NetworkInfo]:
- return [self._active_network_info]
-
- def getNetworkInfoForProcess(self) -> Optional[NetworkInfo]:
- return self._active_network_info
-
- def isDefaultNetworkActive(self) -> bool:
- return True
-
- def addDefaultNetworkActiveListener(self, listener: Any):
- pass
-
- def removeDefaultNetworkActiveListener(self, listener: Any):
- pass
-
- def reportBadNetwork(self, network: Network):
- pass
-
- def setNetworkPreference(self, preference: int):
- pass
-
- def getNetworkPreference(self) -> int:
- return self.DEFAULT_NETWORK_PREFERENCE
-
- def startCaptivePortalApp(self, network: Network):
- pass
-
- def setProcessDefaultNetworkForUid(self, uid: int) -> bool:
- return True
-
- def registerNetworkAgent(self, agent: Any) -> int:
- return 0
-
- def toString(self) -> str:
- return f"ConnectivityManager(networks={len(self._networks)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Uri",
- "Uri_Builder",
- "ConnectivityManager",
- "NetworkInfo",
- "Network",
- "NetworkCapabilities",
- "NetworkRequest",
- "NetworkCallback",
- "LinkProperties",
- "LinkAddress",
- "RouteInfo",
- "DnsResolver",
- "DhcpInfo",
- "InetAddresses",
- "SSLSessionCache",
- "TrafficStats",
- "Proxy",
- "ProxyInfo",
- "NetworkSpecifier",
- "MatchAllNetworkSpecifier",
- "WifiAwareNetworkSpecifier",
- "EthernetNetworkSpecifier",
- "TelephonyNetworkSpecifier",
- "NetworkState",
- "LocalSocket",
- "LocalSocketAddress",
- "NetworkUtils",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/net_ethernet.py b/android_pyapi/android/net_ethernet.py
deleted file mode 100644
index 1e55431..0000000
--- a/android_pyapi/android/net_ethernet.py
+++ /dev/null
@@ -1,551 +0,0 @@
-"""
-Android net 以太网组件 — EthernetManager, EthernetNetworkSpecifier,
-EthernetConfig, IpConfiguration, StaticIpConfiguration
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-__all__ = [
- "EthernetManager",
- "EthernetNetworkSpecifier",
- "EthernetNetworkUpdate",
- "EthernetConfig",
- "IpConfiguration",
- "StaticIpConfiguration",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-ETH_STATE_DISCONNECTED = 0
-ETH_STATE_CONNECTING = 1
-ETH_STATE_CONNECTED = 2
-ETH_STATE_SUSPENDED = 3
-
-ETH_MODE_DHCP = 0
-ETH_MODE_STATIC = 1
-
-ETH_LINK_MODE_AUTO = 0
-ETH_LINK_MODE_10_HALF = 1
-ETH_LINK_MODE_10_FULL = 2
-ETH_LINK_MODE_100_HALF = 3
-ETH_LINK_MODE_100_FULL = 4
-ETH_LINK_MODE_1000_HALF = 5
-ETH_LINK_MODE_1000_FULL = 6
-ETH_LINK_MODE_2500_FULL = 7
-ETH_LINK_MODE_5000_FULL = 8
-ETH_LINK_MODE_10000_FULL = 9
-
-ETH_ERROR_NONE = 0
-ETH_ERROR_INTERFACE_NOT_FOUND = -1
-ETH_ERROR_CONFIG_FAILED = -2
-ETH_ERROR_LINK_DOWN = -3
-ETH_ERROR_NOT_SUPPORTED = -4
-ETH_ERROR_PERMISSION_DENIED = -5
-
-ETH_CAPABILITY_WOL = 1
-ETH_CAPABILITY_VLAN = 2
-ETH_CAPABILITY_JUMBO_FRAMES = 4
-ETH_CAPABILITY_EEE = 8
-ETH_CAPABILITY_PTP = 16
-
-ETH_DUPLEX_HALF = 0
-ETH_DUPLEX_FULL = 1
-ETH_DUPLEX_AUTO = 2
-
-ETH_AUTH_NONE = 0
-ETH_AUTH_8021X = 1
-ETH_AUTH_MAB = 2
-
-
-# ═══════════════════════════════════════════════════════════════
-# IpConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class IpConfiguration(Stub):
- """IpConfiguration — IP 配置"""
-
- class IpAssignment(Stub):
- """IpConfiguration.IpAssignment — IP 分配方式"""
- DHCP = 0
- STATIC = 1
- UNASSIGNED = 2
-
- class ProxySettings(Stub):
- """IpConfiguration.ProxySettings — 代理设置"""
- NONE = 0
- STATIC = 1
- PAC = 2
- UNASSIGNED = 3
-
- def __init__(self, ipAssignment: int = IpAssignment.DHCP,
- proxySettings: int = ProxySettings.NONE,
- staticConfig: Optional["StaticIpConfiguration"] = None):
- super().__init__()
- self._ip_assignment = ipAssignment
- self._proxy_settings = proxySettings
- self._static_config = staticConfig
-
- def getIpAssignment(self) -> int:
- return self._ip_assignment
-
- def setIpAssignment(self, assignment: int):
- self._ip_assignment = assignment
-
- def getProxySettings(self) -> int:
- return self._proxy_settings
-
- def setProxySettings(self, settings: int):
- self._proxy_settings = settings
-
- def getStaticIpConfiguration(self) -> Optional["StaticIpConfiguration"]:
- return self._static_config
-
- def setStaticIpConfiguration(self, config: "StaticIpConfiguration"):
- self._static_config = config
-
- def toString(self) -> str:
- assignments = {0: "DHCP", 1: "STATIC", 2: "UNASSIGNED"}
- return f"IpConfiguration(assignment={assignments.get(self._ip_assignment, str(self._ip_assignment))})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, IpConfiguration):
- return False
- return self._ip_assignment == other._ip_assignment
-
- def hashCode(self) -> int:
- return self._ip_assignment & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# StaticIpConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class StaticIpConfiguration(Stub):
- """StaticIpConfiguration — 静态 IP 配置"""
-
- def __init__(self, ipAddress: str = "192.168.1.100",
- gateway: str = "192.168.1.1",
- prefixLength: int = 24,
- dnsServers: List[str] = None,
- domains: str = ""):
- super().__init__()
- self._ip_address = ipAddress
- self._gateway = gateway
- self._prefix_length = prefixLength
- self._dns_servers = dnsServers or ["8.8.8.8", "8.8.4.4"]
- self._domains = domains
-
- def getIpAddress(self) -> str:
- return self._ip_address
-
- def setIpAddress(self, ip: str):
- self._ip_address = ip
-
- def getGateway(self) -> str:
- return self._gateway
-
- def setGateway(self, gateway: str):
- self._gateway = gateway
-
- def getPrefixLength(self) -> int:
- return self._prefix_length
-
- def setPrefixLength(self, prefixLength: int):
- self._prefix_length = prefixLength
-
- def getDnsServers(self) -> List[str]:
- return list(self._dns_servers)
-
- def setDnsServers(self, dnsServers: List[str]):
- self._dns_servers = list(dnsServers)
-
- def addDnsServer(self, server: str):
- self._dns_servers.append(server)
-
- def getDomains(self) -> str:
- return self._domains
-
- def setDomains(self, domains: str):
- self._domains = domains
-
- class Builder(Stub):
- """StaticIpConfiguration.Builder — 静态 IP 构建器"""
-
- def __init__(self):
- super().__init__()
- self._ip_address = ""
- self._gateway = ""
- self._prefix_length = 24
- self._dns_servers: List[str] = []
- self._domains = ""
-
- def setIpAddress(self, ip: str) -> "StaticIpConfiguration.Builder":
- self._ip_address = ip
- return self
-
- def setGateway(self, gateway: str) -> "StaticIpConfiguration.Builder":
- self._gateway = gateway
- return self
-
- def setPrefixLength(self, prefixLength: int) -> "StaticIpConfiguration.Builder":
- self._prefix_length = prefixLength
- return self
-
- def setDnsServers(self, dnsServers: List[str]) -> "StaticIpConfiguration.Builder":
- self._dns_servers = list(dnsServers)
- return self
-
- def setDomains(self, domains: str) -> "StaticIpConfiguration.Builder":
- self._domains = domains
- return self
-
- def build(self) -> "StaticIpConfiguration":
- return StaticIpConfiguration(
- ipAddress=self._ip_address, gateway=self._gateway,
- prefixLength=self._prefix_length,
- dnsServers=self._dns_servers, domains=self._domains,
- )
-
- def toString(self) -> str:
- return f"StaticIpConfiguration(ip={self._ip_address}, gateway={self._gateway})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, StaticIpConfiguration):
- return False
- return self._ip_address == other._ip_address
-
- def hashCode(self) -> int:
- return hash(self._ip_address) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# EthernetNetworkSpecifier
-# ═══════════════════════════════════════════════════════════════
-
-class EthernetNetworkSpecifier(Stub):
- """EthernetNetworkSpecifier — 以太网网络指定器"""
-
- def __init__(self, interfaceName: str = ""):
- super().__init__()
- self._interface_name = interfaceName
-
- def getInterfaceName(self) -> str:
- return self._interface_name
-
- def satisfiedBy(self, other: Optional["EthernetNetworkSpecifier"]) -> bool:
- if other is None:
- return False
- return self._interface_name == other._interface_name
-
- def toString(self) -> str:
- return f"EthernetNetworkSpecifier(iface={self._interface_name})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, EthernetNetworkSpecifier):
- return False
- return self._interface_name == other._interface_name
-
- def hashCode(self) -> int:
- return hash(self._interface_name) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# EthernetNetworkUpdate
-# ═══════════════════════════════════════════════════════════════
-
-class EthernetNetworkUpdate(Stub):
- """EthernetNetworkUpdate — 以太网网络更新"""
-
- def __init__(self, interfaceName: str = "",
- state: int = ETH_STATE_DISCONNECTED,
- config: Optional["EthernetConfig"] = None):
- super().__init__()
- self._interface_name = interfaceName
- self._state = state
- self._config = config
-
- def getInterfaceName(self) -> str:
- return self._interface_name
-
- def getState(self) -> int:
- return self._state
-
- def getConfig(self) -> Optional["EthernetConfig"]:
- return self._config
-
- def toString(self) -> str:
- return f"EthernetNetworkUpdate(iface={self._interface_name}, state={self._state})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, EthernetNetworkUpdate):
- return False
- return self._interface_name == other._interface_name
-
- def hashCode(self) -> int:
- return hash(self._interface_name) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# EthernetConfig
-# ═══════════════════════════════════════════════════════════════
-
-class EthernetConfig(Stub):
- """EthernetConfig — 以太网配置"""
-
- def __init__(self, ipConfig: Optional[IpConfiguration] = None,
- linkMode: int = ETH_LINK_MODE_AUTO,
- interfaceName: str = "",
- mtu: int = 1500,
- macAddress: str = ""):
- super().__init__()
- self._ip_config = ipConfig or IpConfiguration()
- self._link_mode = linkMode
- self._interface_name = interfaceName
- self._mtu = mtu
- self._mac_address = macAddress
-
- def getIpConfiguration(self) -> IpConfiguration:
- return self._ip_config
-
- def setIpConfiguration(self, config: IpConfiguration):
- self._ip_config = config
-
- def getLinkMode(self) -> int:
- return self._link_mode
-
- def setLinkMode(self, mode: int):
- self._link_mode = mode
-
- def getInterfaceName(self) -> str:
- return self._interface_name
-
- def setInterfaceName(self, name: str):
- self._interface_name = name
-
- def getMtu(self) -> int:
- return self._mtu
-
- def setMtu(self, mtu: int):
- self._mtu = mtu
-
- def getMacAddress(self) -> str:
- return self._mac_address
-
- def setMacAddress(self, mac: str):
- self._mac_address = mac
-
- class Builder(Stub):
- """EthernetConfig.Builder — 以太网配置构建器"""
-
- def __init__(self):
- super().__init__()
- self._ip_config = IpConfiguration()
- self._link_mode = ETH_LINK_MODE_AUTO
- self._interface_name = ""
- self._mtu = 1500
- self._mac_address = ""
-
- def setIpConfiguration(self, config: IpConfiguration) -> "EthernetConfig.Builder":
- self._ip_config = config
- return self
-
- def setLinkMode(self, mode: int) -> "EthernetConfig.Builder":
- self._link_mode = mode
- return self
-
- def setInterfaceName(self, name: str) -> "EthernetConfig.Builder":
- self._interface_name = name
- return self
-
- def setMtu(self, mtu: int) -> "EthernetConfig.Builder":
- self._mtu = mtu
- return self
-
- def setMacAddress(self, mac: str) -> "EthernetConfig.Builder":
- self._mac_address = mac
- return self
-
- def build(self) -> "EthernetConfig":
- return EthernetConfig(
- ipConfig=self._ip_config, linkMode=self._link_mode,
- interfaceName=self._interface_name, mtu=self._mtu,
- macAddress=self._mac_address,
- )
-
- def toString(self) -> str:
- return f"EthernetConfig(iface={self._interface_name}, linkMode={self._link_mode})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, EthernetConfig):
- return False
- return self._interface_name == other._interface_name
-
- def hashCode(self) -> int:
- return hash(self._interface_name) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# EthernetManager
-# ═══════════════════════════════════════════════════════════════
-
-class EthernetManager(Stub):
- """EthernetManager — 以太网管理器"""
-
- ACTION_ETHERNET_STATE_CHANGED = "android.net.ethernet.ETHERNET_STATE_CHANGED"
- EXTRA_ETHERNET_STATE = "ethernet_state"
- EXTRA_INTERFACE_NAME = "interface_name"
- EXTRA_LINK_MODE = "link_mode"
-
- STATE_DISABLED = 0
- STATE_ENABLED = 1
-
- def __init__(self):
- super().__init__()
- self._enabled = False
- self._interfaces: Dict[str, EthernetConfig] = {}
- self._state = EthernetManager.STATE_DISABLED
- self._listeners: Dict[int, Callable] = {}
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
- self._state = EthernetManager.STATE_ENABLED if enabled else EthernetManager.STATE_DISABLED
-
- def getState(self) -> int:
- return self._state
-
- def getConfiguration(self, interfaceName: str) -> Optional["EthernetConfig"]:
- return self._interfaces.get(interfaceName)
-
- def setConfiguration(self, interfaceName: str, config: "EthernetConfig"):
- self._interfaces[interfaceName] = config
-
- def removeInterface(self, interfaceName: str):
- self._interfaces.pop(interfaceName, None)
-
- def getInterfaceNames(self) -> List[str]:
- return list(self._interfaces.keys())
-
- def addInterface(self, interfaceName: str, config: Optional[EthernetConfig] = None):
- self._interfaces[interfaceName] = config or EthernetConfig(interfaceName=interfaceName)
-
- def setLinkMode(self, interfaceName: str, mode: int):
- config = self._interfaces.get(interfaceName)
- if config:
- config.setLinkMode(mode)
-
- def updateConfiguration(self, update: EthernetNetworkUpdate) -> bool:
- iface = update.getInterfaceName()
- config = update.getConfig()
- if config:
- self._interfaces[iface] = config
- elif iface in self._interfaces:
- pass
- return True
-
- def registerEthernetEventListener(self, listener: Callable):
- lid = id(listener)
- self._listeners[lid] = listener
-
- def unregisterEthernetEventListener(self, listener: Callable):
- lid = id(listener)
- self._listeners.pop(lid, None)
-
- def getAvailableInterfaces(self) -> List[str]:
- import socket
- import netifaces
- interfaces = []
- try:
- import netifaces
- for iface in netifaces.interfaces():
- if iface.startswith(("eth", "en", "em")):
- interfaces.append(iface)
- except ImportError:
- import psutil
- try:
- import psutil
- stats = psutil.net_if_stats()
- for name in stats:
- if name.startswith(("eth", "en", "em")):
- interfaces.append(name)
- except ImportError:
- pass
- return interfaces + list(self._interfaces.keys())
-
- def isInterfaceAvailable(self, interfaceName: str) -> bool:
- return interfaceName in self._interfaces
-
- def toString(self) -> str:
- return f"EthernetManager(enabled={self._enabled}, interfaces={len(self._interfaces)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def getInterfaceCount(self) -> int:
- return len(self._interfaces)
-
- def hasInterface(self, interfaceName: str) -> bool:
- return interfaceName in self._interfaces
-
- def getInterfaceNames(self) -> List[str]:
- return list(self._interfaces.keys())
-
- def getEnabledInterfaces(self) -> List[str]:
- return [name for name, cfg in self._interfaces.items()
- if cfg.getLinkMode() != ETH_STATE_DISCONNECTED]
-
- def getInterfaceConfig(self, interfaceName: str) -> Optional[EthernetConfig]:
- return self._interfaces.get(interfaceName)
-
- def setInterfaceUp(self, interfaceName: str) -> bool:
- config = self._interfaces.get(interfaceName)
- if config:
- config.setLinkMode(ETH_LINK_MODE_AUTO)
- return True
- return False
-
- def setInterfaceDown(self, interfaceName: str) -> bool:
- config = self._interfaces.get(interfaceName)
- if config:
- config.setLinkMode(ETH_STATE_DISCONNECTED)
- return True
- return False
-
- def getLinkMode(self, interfaceName: str) -> int:
- config = self._interfaces.get(interfaceName)
- return config.getLinkMode() if config else ETH_STATE_DISCONNECTED
-
- def getMtu(self, interfaceName: str) -> int:
- config = self._interfaces.get(interfaceName)
- return config.getMtu() if config else 0
-
- def setMtu(self, interfaceName: str, mtu: int) -> bool:
- config = self._interfaces.get(interfaceName)
- if config:
- config.setMtu(mtu)
- return True
- return False
-
- def getMacAddress(self, interfaceName: str) -> str:
- config = self._interfaces.get(interfaceName)
- return config.getMacAddress() if config else ""
-
- def setMacAddress(self, interfaceName: str, mac: str) -> bool:
- config = self._interfaces.get(interfaceName)
- if config:
- config.setMacAddress(mac)
- return True
- return False
\ No newline at end of file
diff --git a/android_pyapi/android/net_ext.py b/android_pyapi/android/net_ext.py
deleted file mode 100644
index 0d3c499..0000000
--- a/android_pyapi/android/net_ext.py
+++ /dev/null
@@ -1,1447 +0,0 @@
-"""
-Android net 网络扩展组件 — Network, NetworkCapabilities, NetworkRequest,
-NetworkAgent, LinkProperties, TrafficStats, ProxyInfo, DhcpInfo,
-ConnectivityDiagnosticsManager, ConnectivityManager 扩展等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import socket
-import struct
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from .net import ConnectivityManager as _BaseConnectivityManager
-from .net import DhcpInfo as _BaseDhcpInfo
-from .net import LinkAddress as _BaseLinkAddress
-from .net import LinkProperties as _BaseLinkProperties
-from .net import Network as _BaseNetwork
-from .net import NetworkCapabilities as _BaseNetworkCapabilities
-from .net import NetworkInfo as _BaseNetworkInfo
-from .net import NetworkRequest as _BaseNetworkRequest
-from .net import NetworkSpecifier as _BaseNetworkSpecifier
-from .net import ProxyInfo as _BaseProxyInfo
-from .net import TrafficStats as _BaseTrafficStats
-from .net import MatchAllNetworkSpecifier as _BaseMatchAllNetworkSpecifier
-
-# Linux 真实实现导入
-try:
- from .._linux_impl import IS_LINUX, LinuxNetwork, HAS_IP
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-__all__ = [
- "Network", "NetworkCapabilities", "NetworkRequest", "NetworkSpecifier",
- "MatchAllNetworkSpecifier", "NetworkAgent", "NetworkInfo",
- "LinkProperties", "LinkAddress", "LinkQualityInfo",
- "TrafficStats", "ProxyInfo", "DhcpInfo", "DhcpInfoInternal",
- "WifiLinkQualityInfo", "EthernetLinkQualityInfo", "MobileLinkQualityInfo",
- "NetworkBadging", "ConnectivityDiagnosticsManager",
- "ConnectivityManager",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# Network
-# ═══════════════════════════════════════════════════════════════
-
-class Network(_BaseNetwork):
- """Network — 网络"""
-
- def __init__(self, netId: int = 0):
- super().__init__()
- self._net_id = netId
- self._capabilities: Optional["NetworkCapabilities"] = None
- self._link_properties: Optional["LinkProperties"] = None
-
- def getNetId(self) -> int:
- return self._net_id
-
- def getNetworkCapabilities(self) -> Optional["NetworkCapabilities"]:
- return self._capabilities
-
- def getLinkProperties(self) -> Optional["LinkProperties"]:
- return self._link_properties
-
- def setCapabilities(self, caps: "NetworkCapabilities"):
- self._capabilities = caps
-
- def setLinkProperties(self, props: "LinkProperties"):
- self._link_properties = props
-
- def bindSocket(self, socketObj: Any):
- """绑定 socket 到该网络"""
- raise AndroidOnlyError("Network.bindSocket() is not available on desktop")
-
- def toString(self) -> str:
- return f"Network(netId={self._net_id})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, Network):
- return False
- return self._net_id == other._net_id
-
- def hashCode(self) -> int:
- return self._net_id & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkCapabilities
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkCapabilities(_BaseNetworkCapabilities):
- """NetworkCapabilities — 网络能力"""
-
- TRANSPORT_CELLULAR = 0
- TRANSPORT_WIFI = 1
- TRANSPORT_BLUETOOTH = 2
- TRANSPORT_ETHERNET = 3
- TRANSPORT_VPN = 4
- TRANSPORT_WIFI_AWARE = 5
- TRANSPORT_LOWPAN = 6
- TRANSPORT_TEST = 7
- TRANSPORT_USB = 8
-
- NET_CAPABILITY_MMS = 0
- NET_CAPABILITY_SUPL = 1
- NET_CAPABILITY_DUN = 2
- NET_CAPABILITY_FOTA = 3
- NET_CAPABILITY_IMS = 4
- NET_CAPABILITY_CBS = 5
- NET_CAPABILITY_WIFI_P2P = 6
- NET_CAPABILITY_IA = 7
- NET_CAPABILITY_RCS = 8
- NET_CAPABILITY_XCAP = 9
- NET_CAPABILITY_EIMS = 10
- NET_CAPABILITY_NOT_METERED = 11
- NET_CAPABILITY_INTERNET = 12
- NET_CAPABILITY_NOT_RESTRICTED = 13
- NET_CAPABILITY_TRUSTED = 14
- NET_CAPABILITY_NOT_VPN = 15
- NET_CAPABILITY_VALIDATED = 16
- NET_CAPABILITY_CAPTIVE_PORTAL = 17
- NET_CAPABILITY_NOT_ROAMING = 18
- NET_CAPABILITY_FOREGROUND = 19
- NET_CAPABILITY_NOT_CONGESTED = 20
- NET_CAPABILITY_NOT_SUSPENDED = 21
- NET_CAPABILITY_OEM_PAID = 22
- NET_CAPABILITY_MCX = 23
- NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24
- NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25
- NET_CAPABILITY_HEAD_UNIT = 26
- NET_CAPABILITY_NOT_CARRIER_PRIVILEGED = 27
- NET_CAPABILITY_BIP = 28
-
- SIGNAL_STRENGTH_UNSPECIFIED = -2147483648
-
- def __init__(self):
- super().__init__()
- self._transport_types: Set[int] = set()
- self._capabilities: Set[int] = set()
- self._link_down_bandwidth_kbps = 0
- self._link_up_bandwidth_kbps = 0
- self._signal_strength = NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED
- self._network_specifier: Optional["NetworkSpecifier"] = None
- self._owner_uid = -1
- self._ssid: Optional[str] = None
-
- def addTransportType(self, transportType: int) -> "NetworkCapabilities":
- self._transport_types.add(transportType)
- return self
-
- def removeTransportType(self, transportType: int) -> "NetworkCapabilities":
- self._transport_types.discard(transportType)
- return self
-
- def hasTransport(self, transportType: int) -> bool:
- return transportType in self._transport_types
-
- def addCapability(self, capability: int) -> "NetworkCapabilities":
- self._capabilities.add(capability)
- return self
-
- def removeCapability(self, capability: int) -> "NetworkCapabilities":
- self._capabilities.discard(capability)
- return self
-
- def hasCapability(self, capability: int) -> bool:
- return capability in self._capabilities
-
- def hasAllCapabilities(self, capabilities: List[int]) -> bool:
- return all(c in self._capabilities for c in capabilities)
-
- def getTransportTypes(self) -> List[int]:
- return sorted(self._transport_types)
-
- def getCapabilities(self) -> List[int]:
- return sorted(self._capabilities)
-
- def setLinkUpstreamBandwidthKbps(self, up: int) -> "NetworkCapabilities":
- self._link_up_bandwidth_kbps = up
- return self
-
- def setLinkDownstreamBandwidthKbps(self, down: int) -> "NetworkCapabilities":
- self._link_down_bandwidth_kbps = down
- return self
-
- def getLinkUpstreamBandwidthKbps(self) -> int:
- return self._link_up_bandwidth_kbps
-
- def getLinkDownstreamBandwidthKbps(self) -> int:
- return self._link_down_bandwidth_kbps
-
- def setSignalStrength(self, signalStrength: int) -> "NetworkCapabilities":
- self._signal_strength = signalStrength
- return self
-
- def getSignalStrength(self) -> int:
- return self._signal_strength
-
- def setNetworkSpecifier(self, specifier: "NetworkSpecifier") -> "NetworkCapabilities":
- self._network_specifier = specifier
- return self
-
- def getNetworkSpecifier(self) -> Optional["NetworkSpecifier"]:
- return self._network_specifier
-
- def setOwnerUid(self, uid: int) -> "NetworkCapabilities":
- self._owner_uid = uid
- return self
-
- def getOwnerUid(self) -> int:
- return self._owner_uid
-
- def setSsid(self, ssid: str) -> "NetworkCapabilities":
- self._ssid = ssid
- return self
-
- def getSsid(self) -> Optional[str]:
- return self._ssid
-
- def describeCapabilities(self) -> str:
- names = {
- 0: "MMS", 1: "SUPL", 2: "DUN", 3: "FOTA", 4: "IMS",
- 5: "CBS", 6: "WIFI_P2P", 7: "IA", 8: "RCS", 9: "XCAP",
- 10: "EIMS", 11: "NOT_METERED", 12: "INTERNET",
- 13: "NOT_RESTRICTED", 14: "TRUSTED", 15: "NOT_VPN",
- 16: "VALIDATED", 17: "CAPTIVE_PORTAL", 18: "NOT_ROAMING",
- 19: "FOREGROUND", 20: "NOT_CONGESTED", 21: "NOT_SUSPENDED",
- }
- return ", ".join(names.get(c, str(c)) for c in sorted(self._capabilities))
-
- def toString(self) -> str:
- transports = {
- 0: "CELLULAR", 1: "WIFI", 2: "BT", 3: "ETHERNET",
- 4: "VPN", 5: "WIFI_AWARE",
- }
- trans_str = ", ".join(transports.get(t, str(t)) for t in sorted(self._transport_types))
- return f"NetworkCapabilities(transports=[{trans_str}], caps=[{self.describeCapabilities()}])"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, NetworkCapabilities):
- return False
- return (self._transport_types == other._transport_types and
- self._capabilities == other._capabilities)
-
- def hashCode(self) -> int:
- return hash((frozenset(self._transport_types), frozenset(self._capabilities))) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkSpecifier / MatchAllNetworkSpecifier
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkSpecifier(_BaseNetworkSpecifier):
- """NetworkSpecifier — 网络指定器"""
-
- def satisfiedBy(self, other: Optional["NetworkSpecifier"]) -> bool:
- return False
-
- def toString(self) -> str:
- return f"NetworkSpecifier@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-class MatchAllNetworkSpecifier(_BaseMatchAllNetworkSpecifier, NetworkSpecifier):
- """MatchAllNetworkSpecifier — 匹配所有网络"""
-
- def satisfiedBy(self, other: Optional["NetworkSpecifier"]) -> bool:
- return True
-
- def toString(self) -> str:
- return "MatchAllNetworkSpecifier"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkRequest
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkRequest(_BaseNetworkRequest):
- """NetworkRequest — 网络请求"""
-
- def __init__(self, capabilities: Optional[NetworkCapabilities] = None,
- networkSpecifier: Optional[NetworkSpecifier] = None,
- legacyType: int = -1, isRequest: bool = True):
- super().__init__()
- self._capabilities = capabilities or NetworkCapabilities()
- self._network_specifier = networkSpecifier
- self._legacy_type = legacyType
- self._is_request = isRequest
-
- def getCapabilities(self) -> NetworkCapabilities:
- return self._capabilities
-
- def getNetworkSpecifier(self) -> Optional[NetworkSpecifier]:
- return self._network_specifier
-
- def getLegacyType(self) -> int:
- return self._legacy_type
-
- def hasCapability(self, capability: int) -> bool:
- return self._capabilities.hasCapability(capability)
-
- def hasTransport(self, transport: int) -> bool:
- return self._capabilities.hasTransport(transport)
-
- class Builder(Stub):
- """NetworkRequest.Builder — 请求构建器"""
-
- def __init__(self):
- super().__init__()
- self._capabilities = NetworkCapabilities()
- self._network_specifier: Optional[NetworkSpecifier] = None
-
- def addTransportType(self, transportType: int) -> "NetworkRequest.Builder":
- self._capabilities.addTransportType(transportType)
- return self
-
- def removeTransportType(self, transportType: int) -> "NetworkRequest.Builder":
- self._capabilities.removeTransportType(transportType)
- return self
-
- def addCapability(self, capability: int) -> "NetworkRequest.Builder":
- self._capabilities.addCapability(capability)
- return self
-
- def removeCapability(self, capability: int) -> "NetworkRequest.Builder":
- self._capabilities.removeCapability(capability)
- return self
-
- def addCapabilities(self, capabilities: List[int]) -> "NetworkRequest.Builder":
- for c in capabilities:
- self._capabilities.addCapability(c)
- return self
-
- def removeCapabilities(self, capabilities: List[int]) -> "NetworkRequest.Builder":
- for c in capabilities:
- self._capabilities.removeCapability(c)
- return self
-
- def setNetworkSpecifier(self, specifier: NetworkSpecifier) -> "NetworkRequest.Builder":
- self._network_specifier = specifier
- return self
-
- def build(self) -> "NetworkRequest":
- caps = self._capabilities
- caps.setNetworkSpecifier(self._network_specifier)
- return NetworkRequest(capabilities=caps, networkSpecifier=self._network_specifier)
-
- def toString(self) -> str:
- return f"NetworkRequest(caps={self._capabilities})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, NetworkRequest):
- return False
- return self._capabilities == other._capabilities
-
- def hashCode(self) -> int:
- return self._capabilities.hashCode()
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkAgent
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkAgent(Stub):
- """NetworkAgent — 网络代理"""
-
- def __init__(self, looper: Any = None, network: Optional[Network] = None,
- capabilities: Optional[NetworkCapabilities] = None,
- linkProperties: Optional["LinkProperties"] = None,
- score: int = 0):
- super().__init__()
- self._network = network or Network()
- self._capabilities = capabilities or NetworkCapabilities()
- self._link_properties = linkProperties or LinkProperties()
- self._score = score
- self._validated = False
- self._connected = False
- self._callback: Optional[Callable] = None
-
- def getNetwork(self) -> Network:
- return self._network
-
- def getCapabilities(self) -> NetworkCapabilities:
- return self._capabilities
-
- def getLinkProperties(self) -> "LinkProperties":
- return self._link_properties
-
- def getScore(self) -> int:
- return self._score
-
- def setScore(self, score: int):
- self._score = score
-
- def connect(self):
- self._connected = True
-
- def disconnect(self):
- self._connected = False
-
- def isConnected(self) -> bool:
- return self._connected
-
- def isValidated(self) -> bool:
- return self._validated
-
- def setValidated(self, validated: bool):
- self._validated = validated
-
- def sendNetworkCapabilities(self, capabilities: NetworkCapabilities):
- self._capabilities = capabilities
-
- def sendLinkProperties(self, linkProperties: "LinkProperties"):
- self._link_properties = linkProperties
-
- def sendNetworkScore(self, score: int):
- self._score = score
-
- def registerCallback(self, callback: Callable):
- self._callback = callback
-
- def unregisterCallback(self, callback: Callable):
- if self._callback is callback:
- self._callback = None
-
- def toString(self) -> str:
- return f"NetworkAgent(net={self._network}, score={self._score}, connected={self._connected})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, NetworkAgent):
- return False
- return self._network == other._network
-
- def hashCode(self) -> int:
- return self._network.hashCode()
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkInfo (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkInfo(_BaseNetworkInfo):
- """NetworkInfo — 网络信息 (完整版)"""
-
- TYPE_NONE = -1
- TYPE_MOBILE = 0
- TYPE_WIFI = 1
- TYPE_WIMAX = 6
- TYPE_ETHERNET = 9
- TYPE_BLUETOOTH = 7
- TYPE_VPN = 17
- TYPE_WIFI_P2P = 13
- TYPE_MOBILE_MMS = 2
- TYPE_MOBILE_SUPL = 3
- TYPE_MOBILE_DUN = 4
- TYPE_MOBILE_HIPRI = 5
- TYPE_MOBILE_FOTA = 10
- TYPE_MOBILE_IMS = 11
- TYPE_MOBILE_CBS = 12
- TYPE_MOBILE_IA = 14
- TYPE_MOBILE_EMERGENCY = 15
- TYPE_PROXY = 16
-
- STATE_CONNECTING = 0
- STATE_CONNECTED = 1
- STATE_SUSPENDED = 2
- STATE_DISCONNECTING = 3
- STATE_DISCONNECTED = 4
- STATE_UNKNOWN = 5
-
- DETAILED_STATE_IDLE = 0
- DETAILED_STATE_SCANNING = 1
- DETAILED_STATE_CONNECTING = 2
- DETAILED_STATE_AUTHENTICATING = 3
- DETAILED_STATE_OBTAINING_IPADDR = 4
- DETAILED_STATE_CONNECTED = 5
- DETAILED_STATE_SUSPENDED = 6
- DETAILED_STATE_DISCONNECTING = 7
- DETAILED_STATE_DISCONNECTED = 8
- DETAILED_STATE_FAILED = 9
- DETAILED_STATE_BLOCKED = 10
- DETAILED_STATE_VERIFYING_POOR_LINK = 11
- DETAILED_STATE_CAPTIVE_PORTAL_CHECK = 12
-
- def __init__(self, type_: int = TYPE_NONE, subtype: int = 0,
- state: int = STATE_DISCONNECTED,
- detailedState: int = DETAILED_STATE_IDLE,
- isAvailable: bool = True,
- isRoaming: bool = False,
- extraInfo: str = "",
- isFailover: bool = False,
- reason: str = ""):
- super().__init__()
- self._type = type_
- self._subtype = subtype
- self._state = state
- self._detailed_state = detailedState
- self._is_available = isAvailable
- self._is_roaming = isRoaming
- self._extra_info = extraInfo
- self._is_failover = isFailover
- self._reason = reason
-
- def getType(self) -> int:
- return self._type
-
- def getSubtype(self) -> int:
- return self._subtype
-
- def getState(self) -> int:
- return self._state
-
- def getDetailedState(self) -> int:
- return self._detailed_state
-
- def isConnected(self) -> bool:
- return self._state == NetworkInfo.STATE_CONNECTED
-
- def isConnectedOrConnecting(self) -> bool:
- return self._state in (NetworkInfo.STATE_CONNECTED, NetworkInfo.STATE_CONNECTING)
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def isRoaming(self) -> bool:
- return self._is_roaming
-
- def isFailover(self) -> bool:
- return self._is_failover
-
- def getExtraInfo(self) -> str:
- return self._extra_info
-
- def getReason(self) -> str:
- return self._reason
-
- def getTypeName(self) -> str:
- names = {
- -1: "NONE", 0: "MOBILE", 1: "WIFI", 6: "WIMAX",
- 9: "ETHERNET", 7: "BLUETOOTH", 17: "VPN",
- 13: "WIFI_P2P", 16: "PROXY",
- }
- return names.get(self._type, f"TYPE_{self._type}")
-
- def setDetailedState(self, detailedState: int, reason: str, extraInfo: str):
- self._detailed_state = detailedState
- self._reason = reason
- self._extra_info = extraInfo
-
- def setState(self, state: int):
- self._state = state
-
- def toString(self) -> str:
- return (f"NetworkInfo(type={self.getTypeName()}, state={self._state}, "
- f"connected={self.isConnected()})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, NetworkInfo):
- return False
- return self._type == other._type and self._state == other._state
-
- def hashCode(self) -> int:
- return hash((self._type, self._state)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinkAddress
-# ═══════════════════════════════════════════════════════════════
-
-class LinkAddress(_BaseLinkAddress):
- """LinkAddress — 链路地址"""
-
- def __init__(self, address: str = "0.0.0.0", prefixLength: int = 24,
- flags: int = 0, scope: int = 0):
- super().__init__()
- self._address = address
- self._prefix_length = prefixLength
- self._flags = flags
- self._scope = scope
-
- def getAddress(self) -> str:
- return self._address
-
- def getPrefixLength(self) -> int:
- return self._prefix_length
-
- def getFlags(self) -> int:
- return self._flags
-
- def getScope(self) -> int:
- return self._scope
-
- def isGlobalPreferred(self) -> bool:
- return self._scope == 0
-
- def toString(self) -> str:
- return f"{self._address}/{self._prefix_length}"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, LinkAddress):
- return False
- return self._address == other._address and self._prefix_length == other._prefix_length
-
- def hashCode(self) -> int:
- return hash((self._address, self._prefix_length)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinkProperties
-# ═══════════════════════════════════════════════════════════════
-
-class LinkProperties(_BaseLinkProperties):
- """LinkProperties — 链路属性"""
-
- def __init__(self):
- super().__init__()
- self._interface_name: str = ""
- self._link_addresses: List[LinkAddress] = []
- self._dns_servers: List[str] = []
- self._domains: str = ""
- self._mtu: int = 1500
- self._http_proxy: Optional["ProxyInfo"] = None
- self._private_dns_server_name: str = ""
- self._routes: List[str] = []
-
- def setInterfaceName(self, name: str):
- self._interface_name = name
-
- def getInterfaceName(self) -> str:
- return self._interface_name
-
- def addLinkAddress(self, address: LinkAddress):
- self._link_addresses.append(address)
-
- def removeLinkAddress(self, address: LinkAddress):
- self._link_addresses = [a for a in self._link_addresses if a != address]
-
- def getLinkAddresses(self) -> List[LinkAddress]:
- return list(self._link_addresses)
-
- def addDnsServer(self, dnsServer: str):
- self._dns_servers.append(dnsServer)
-
- def removeDnsServer(self, dnsServer: str):
- self._dns_servers = [d for d in self._dns_servers if d != dnsServer]
-
- def getDnsServers(self) -> List[str]:
- return list(self._dns_servers)
-
- def setDomains(self, domains: str):
- self._domains = domains
-
- def getDomains(self) -> str:
- return self._domains
-
- def setMtu(self, mtu: int):
- self._mtu = mtu
-
- def getMtu(self) -> int:
- return self._mtu
-
- def setHttpProxy(self, proxy: "ProxyInfo"):
- self._http_proxy = proxy
-
- def getHttpProxy(self) -> Optional["ProxyInfo"]:
- return self._http_proxy
-
- def setPrivateDnsServerName(self, name: str):
- self._private_dns_server_name = name
-
- def getPrivateDnsServerName(self) -> str:
- return self._private_dns_server_name
-
- def addRoute(self, route: str):
- self._routes.append(route)
-
- def removeRoute(self, route: str):
- self._routes = [r for r in self._routes if r != route]
-
- def getRoutes(self) -> List[str]:
- return list(self._routes)
-
- def clear(self):
- self._link_addresses.clear()
- self._dns_servers.clear()
- self._routes.clear()
-
- def toString(self) -> str:
- return (f"LinkProperties(iface={self._interface_name}, "
- f"dns={self._dns_servers}, mtu={self._mtu})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, LinkProperties):
- return False
- return self._interface_name == other._interface_name
-
- def hashCode(self) -> int:
- return hash(self._interface_name) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinkQualityInfo
-# ═══════════════════════════════════════════════════════════════
-
-class LinkQualityInfo(Stub):
- """LinkQualityInfo — 链路质量信息"""
-
- NORMALIZED_MIN = 0
- NORMALIZED_MAX = 100
-
- def __init__(self):
- super().__init__()
- self._normalized_rssi = LinkQualityInfo.NORMALIZED_MIN
- self._normalized_signal_strength = LinkQualityInfo.NORMALIZED_MIN
- self._timestamp = 0
- self._theoretical_tx_rate = 0
- self._theoretical_rx_rate = 0
-
- def getNormalizedRssi(self) -> int:
- return self._normalized_rssi
-
- def setNormalizedRssi(self, rssi: int):
- self._normalized_rssi = max(LinkQualityInfo.NORMALIZED_MIN,
- min(LinkQualityInfo.NORMALIZED_MAX, rssi))
-
- def getNormalizedSignalStrength(self) -> int:
- return self._normalized_signal_strength
-
- def setNormalizedSignalStrength(self, strength: int):
- self._normalized_signal_strength = max(LinkQualityInfo.NORMALIZED_MIN,
- min(LinkQualityInfo.NORMALIZED_MAX, strength))
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def setTimestamp(self, timestamp: int):
- self._timestamp = timestamp
-
- def getTheoreticalTxRate(self) -> int:
- return self._theoretical_tx_rate
-
- def setTheoreticalTxRate(self, rate: int):
- self._theoretical_tx_rate = rate
-
- def getTheoreticalRxRate(self) -> int:
- return self._theoretical_rx_rate
-
- def setTheoreticalRxRate(self, rate: int):
- self._theoretical_rx_rate = rate
-
- def toString(self) -> str:
- return f"LinkQualityInfo(rssi={self._normalized_rssi}, txRate={self._theoretical_tx_rate})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-class WifiLinkQualityInfo(LinkQualityInfo):
- """WifiLinkQualityInfo — WiFi 链路质量"""
-
- def __init__(self):
- super().__init__()
- self._ssid: str = ""
- self._bssid: str = ""
- self._rssi: int = 0
- self._link_speed_mbps: int = 0
- self._frequency: int = 0
-
- def getSsid(self) -> str:
- return self._ssid
-
- def setSsid(self, ssid: str):
- self._ssid = ssid
-
- def getBssid(self) -> str:
- return self._bssid
-
- def setBssid(self, bssid: str):
- self._bssid = bssid
-
- def getRssi(self) -> int:
- return self._rssi
-
- def setRssi(self, rssi: int):
- self._rssi = rssi
-
- def getLinkSpeedMbps(self) -> int:
- return self._link_speed_mbps
-
- def setLinkSpeedMbps(self, speed: int):
- self._link_speed_mbps = speed
-
- def getFrequency(self) -> int:
- return self._frequency
-
- def setFrequency(self, freq: int):
- self._frequency = freq
-
- def toString(self) -> str:
- return f"WifiLinkQualityInfo(ssid={self._ssid}, rssi={self._rssi})"
-
-
-class EthernetLinkQualityInfo(LinkQualityInfo):
- """EthernetLinkQualityInfo — 以太网链路质量"""
-
- def __init__(self):
- super().__init__()
- self._cable_status: int = 0
- self._link_speed: int = 1000
-
- def getCableStatus(self) -> int:
- return self._cable_status
-
- def setCableStatus(self, status: int):
- self._cable_status = status
-
- def getLinkSpeed(self) -> int:
- return self._link_speed
-
- def setLinkSpeed(self, speed: int):
- self._link_speed = speed
-
- def toString(self) -> str:
- return f"EthernetLinkQualityInfo(speed={self._link_speed})"
-
-
-class MobileLinkQualityInfo(LinkQualityInfo):
- """MobileLinkQualityInfo — 移动网络链路质量"""
-
- def __init__(self):
- super().__init__()
- self._network_type: int = 0
- self._signal_dbm: int = 0
- self._sinr: int = 0
- self._rsrp: int = 0
- self._rsrq: int = 0
- self._rssnr: int = 0
-
- def getNetworkType(self) -> int:
- return self._network_type
-
- def setNetworkType(self, type_: int):
- self._network_type = type_
-
- def getSignalDbm(self) -> int:
- return self._signal_dbm
-
- def setSignalDbm(self, dbm: int):
- self._signal_dbm = dbm
-
- def getSinr(self) -> int:
- return self._sinr
-
- def setSinr(self, sinr: int):
- self._sinr = sinr
-
- def getRsrp(self) -> int:
- return self._rsrp
-
- def setRsrp(self, rsrp: int):
- self._rsrp = rsrp
-
- def getRsrq(self) -> int:
- return self._rsrq
-
- def setRsrq(self, rsrq: int):
- self._rsrq = rsrq
-
- def getRssnr(self) -> int:
- return self._rssnr
-
- def setRssnr(self, rssnr: int):
- self._rssnr = rssnr
-
- def toString(self) -> str:
- return f"MobileLinkQualityInfo(type={self._network_type}, rsrp={self._rsrp})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TrafficStats
-# ═══════════════════════════════════════════════════════════════
-
-class TrafficStats(_BaseTrafficStats):
- """TrafficStats — 流量统计"""
-
- UID_REMOVED = -4
- UID_TETHERING = -5
- UNSUPPORTED = -1
-
- @staticmethod
- def getMobileTxPackets() -> int:
- return 0
-
- @staticmethod
- def getMobileRxPackets() -> int:
- return 0
-
- @staticmethod
- def getMobileTxBytes() -> int:
- return 0
-
- @staticmethod
- def getMobileRxBytes() -> int:
- return 0
-
- @staticmethod
- def getTotalTxPackets() -> int:
- return 0
-
- @staticmethod
- def getTotalRxPackets() -> int:
- return 0
-
- @staticmethod
- def getTotalTxBytes() -> int:
- return 0
-
- @staticmethod
- def getTotalRxBytes() -> int:
- return 0
-
- @staticmethod
- def getUidTxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidRxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidTxPackets(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidRxPackets(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidTcpTxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidTcpRxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidUdpTxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidUdpRxBytes(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidTcpSegmentsSent(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidTcpSegmentsReceived(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidUdpPacketsSent(uid: int) -> int:
- return 0
-
- @staticmethod
- def getUidUdpPacketsReceived(uid: int) -> int:
- return 0
-
- def toString(self) -> str:
- return "TrafficStats(desktop stub)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ProxyInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ProxyInfo(_BaseProxyInfo):
- """ProxyInfo — 代理信息"""
-
- def __init__(self, host: str = "", port: int = 0,
- exclusionList: List[str] = None,
- pacFileUrl: str = ""):
- super().__init__()
- self._host = host
- self._port = port
- self._exclusion_list = exclusion_list or []
- self._pac_file_url = pacFileUrl
-
- def getHost(self) -> str:
- return self._host
-
- def getPort(self) -> int:
- return self._port
-
- def getExclusionList(self) -> List[str]:
- return list(self._exclusion_list)
-
- def getPacFileUrl(self) -> str:
- return self._pac_file_url
-
- def isValid(self) -> bool:
- return bool(self._host) and self._port > 0
-
- def toString(self) -> str:
- return f"ProxyInfo(host={self._host}, port={self._port})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, ProxyInfo):
- return False
- return self._host == other._host and self._port == other._port
-
- def hashCode(self) -> int:
- return hash((self._host, self._port)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# DhcpInfo / DhcpInfoInternal
-# ═══════════════════════════════════════════════════════════════
-
-class DhcpInfo(_BaseDhcpInfo):
- """DhcpInfo — DHCP 信息"""
-
- def __init__(self):
- super().__init__()
- self.ipAddress: int = 0
- self.gateway: int = 0
- self.netmask: int = 0
- self.dns1: int = 0
- self.dns2: int = 0
- self.serverAddress: int = 0
- self.leaseDuration: int = 0
-
- def toString(self) -> str:
- def int_to_ip(ip: int) -> str:
- return ".".join(str((ip >> (8 * i)) & 0xFF) for i in range(4))
- return (f"DhcpInfo(ip={int_to_ip(self.ipAddress)}, "
- f"gateway={int_to_ip(self.gateway)}, "
- f"dns1={int_to_ip(self.dns1)})")
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, DhcpInfo):
- return False
- return self.ipAddress == other.ipAddress
-
- def hashCode(self) -> int:
- return self.ipAddress & 0x7FFFFFFF
-
-
-class DhcpInfoInternal(Stub):
- """DhcpInfoInternal — DHCP 内部信息"""
-
- def __init__(self):
- super().__init__()
- self.ipAddress: str = ""
- self.gateway: str = ""
- self.netmask: str = ""
- self.dns1: str = ""
- self.dns2: str = ""
- self.serverAddress: str = ""
- self.leaseDuration: int = 0
- self.domain: str = ""
-
- def toString(self) -> str:
- return f"DhcpInfoInternal(ip={self.ipAddress}, gateway={self.gateway})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, DhcpInfoInternal):
- return False
- return self.ipAddress == other.ipAddress
-
- def hashCode(self) -> int:
- return hash(self.ipAddress) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkBadging
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkBadging(Stub):
- """NetworkBadging — 网络徽章"""
-
- BADGING_WIFI = 0
- BADGING_4G = 1
- BADGING_3G = 2
- BADGING_2G = 3
- BADGING_1X = 4
- BADGING_EHRPD = 5
- BADGING_HSPAP = 6
- BADGING_LTE = 7
- BADGING_LTE_CA = 8
- BADGING_NR = 9
- BADGING_ETHERNET = 10
- BADGING_WIMAX = 11
-
- @staticmethod
- def getBadging(transportType: int, subType: int = 0) -> int:
- mapping = {1: NetworkBadging.BADGING_WIFI, 3: NetworkBadging.BADGING_ETHERNET}
- return mapping.get(transportType, NetworkBadging.BADGING_4G)
-
- def toString(self) -> str:
- return f"NetworkBadging@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ConnectivityDiagnosticsManager
-# ═══════════════════════════════════════════════════════════════
-
-class ConnectivityDiagnosticsManager(Stub):
- """ConnectivityDiagnosticsManager — 连接诊断管理器"""
-
- def __init__(self):
- super().__init__()
- self._callbacks: Dict[int, Callable] = {}
- self._reports: Dict[int, "ConnectivityDiagnosticsManager_ConnectivityReport"] = {}
- self._stall_reports: Dict[int, "ConnectivityDiagnosticsManager_DataStallReport"] = {}
-
- class ConnectivityReport(Stub):
- """ConnectivityDiagnosticsManager.ConnectivityReport — 连接报告"""
-
- def __init__(self, network: Optional[Network] = None,
- linkProperties: Optional[LinkProperties] = None,
- networkCapabilities: Optional[NetworkCapabilities] = None,
- timestamp: int = 0,
- errorCode: int = 0,
- errorMessage: str = ""):
- super().__init__()
- self._network = network
- self._link_properties = linkProperties
- self._network_capabilities = networkCapabilities
- self._timestamp = timestamp
- self._error_code = errorCode
- self._error_message = errorMessage
-
- def getNetwork(self) -> Optional[Network]:
- return self._network
-
- def getLinkProperties(self) -> Optional[LinkProperties]:
- return self._link_properties
-
- def getNetworkCapabilities(self) -> Optional[NetworkCapabilities]:
- return self._network_capabilities
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def getErrorCode(self) -> int:
- return self._error_code
-
- def getErrorMessage(self) -> str:
- return self._error_message
-
- def toString(self) -> str:
- return f"ConnectivityReport(net={self._network}, error={self._error_code})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, ConnectivityDiagnosticsManager.ConnectivityReport):
- return False
- return self._network == other._network and self._timestamp == other._timestamp
-
- def hashCode(self) -> int:
- return hash((id(self._network), self._timestamp)) & 0x7FFFFFFF
-
- class DataStallReport(Stub):
- """ConnectivityDiagnosticsManager.DataStallReport — 数据卡顿报告"""
-
- REASON_NETWORK_VALIDATION = 0
- REASON_NETWORK_CONGESTION = 1
- REASON_NETWORK_PARTIAL_CONNECTIVITY = 2
- REASON_NETWORK_SUSPECTED = 3
- REASON_DNS_RESOLUTION_FAILURE = 4
- REASON_TCP_FAILURE = 5
- REASON_IP_REACHABILITY_LOSS = 6
-
- DETECTION_METHOD_NONE = 0
- DETECTION_METHOD_DNS_EVENTS = 1
- DETECTION_METHOD_TCP_METRICS = 2
- DETECTION_METHOD_IP_METRICS = 3
-
- def __init__(self, network: Optional[Network] = None,
- detectionMethod: int = DETECTION_METHOD_NONE,
- reason: int = REASON_NETWORK_VALIDATION,
- timestamp: int = 0,
- linkProperties: Optional[LinkProperties] = None,
- networkCapabilities: Optional[NetworkCapabilities] = None):
- super().__init__()
- self._network = network
- self._detection_method = detectionMethod
- self._reason = reason
- self._timestamp = timestamp
- self._link_properties = linkProperties
- self._network_capabilities = networkCapabilities
-
- def getNetwork(self) -> Optional[Network]:
- return self._network
-
- def getDetectionMethod(self) -> int:
- return self._detection_method
-
- def getReason(self) -> int:
- return self._reason
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def getLinkProperties(self) -> Optional[LinkProperties]:
- return self._link_properties
-
- def getNetworkCapabilities(self) -> Optional[NetworkCapabilities]:
- return self._network_capabilities
-
- def toString(self) -> str:
- return f"DataStallReport(net={self._network}, reason={self._reason})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, ConnectivityDiagnosticsManager.DataStallReport):
- return False
- return self._network == other._network and self._timestamp == other._timestamp
-
- def hashCode(self) -> int:
- return hash((id(self._network), self._timestamp)) & 0x7FFFFFFF
-
- def registerConnectivityDiagnosticsCallback(
- self, request: NetworkRequest,
- callback: Callable,
- handler: Any = None):
- lid = id(callback)
- self._callbacks[lid] = callback
-
- def unregisterConnectivityDiagnosticsCallback(self, callback: Callable):
- lid = id(callback)
- self._callbacks.pop(lid, None)
-
- def getConnectivityReport(self, network: Network) -> Optional[ConnectivityReport]:
- return self._reports.get(network.getNetId())
-
- def getDataStallReport(self, network: Network) -> Optional[DataStallReport]:
- return self._stall_reports.get(network.getNetId())
-
- def toString(self) -> str:
- return f"ConnectivityDiagnosticsManager(callbacks={len(self._callbacks)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ConnectivityManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class ConnectivityManager(_BaseConnectivityManager):
- """ConnectivityManager — 连接管理器 (扩展版)"""
-
- TYPE_NONE = -1
- TYPE_MOBILE = 0
- TYPE_WIFI = 1
- TYPE_MOBILE_MMS = 2
- TYPE_MOBILE_SUPL = 3
- TYPE_MOBILE_DUN = 4
- TYPE_MOBILE_HIPRI = 5
- TYPE_WIMAX = 6
- TYPE_BLUETOOTH = 7
- TYPE_DUMMY = 8
- TYPE_ETHERNET = 9
- TYPE_MOBILE_FOTA = 10
- TYPE_MOBILE_IMS = 11
- TYPE_MOBILE_CBS = 12
- TYPE_WIFI_P2P = 13
- TYPE_MOBILE_IA = 14
- TYPE_MOBILE_EMERGENCY = 15
- TYPE_PROXY = 16
- TYPE_VPN = 17
-
- EXTRA_NETWORK = "android.net.extra.NETWORK"
- EXTRA_OTHER_NETWORK = "android.net.extra.OTHER_NETWORK"
- EXTRA_NO_CONNECTIVITY = "android.net.extra.NO_CONNECTIVITY"
- EXTRA_REASON = "android.net.extra.REASON"
- EXTRA_EXTRA_INFO = "android.net.extra.EXTRA_INFO"
- EXTRA_NETWORK_INFO = "android.net.extra.NETWORK_INFO"
- EXTRA_IS_FAILOVER = "android.net.extra.IS_FAILOVER"
- EXTRA_NETWORK_TYPE = "android.net.extra.NETWORK_TYPE"
-
- ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL"
- ACTION_CAPTIVE_PORTAL_TEST_COMPLETED = "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED"
-
- def __init__(self):
- super().__init__()
- self._active_network: Optional[Network] = None
- self._networks: Dict[int, Network] = {}
- self._network_infos: Dict[int, NetworkInfo] = {}
- self._callbacks: Dict[int, Any] = {}
- self._diagnostics_manager = ConnectivityDiagnosticsManager()
-
- def getActiveNetwork(self) -> Optional[Network]:
- return self._active_network
-
- def _get_linux_active_info(self):
- """从 Linux 真实网络信息构造活跃 NetworkInfo"""
- try:
- from .net import NetworkInfo
- interfaces = LinuxNetwork.get_interfaces()
- # 有真实网络接口 (非环回) 且 operstate=up 即视为已连接
- connected = any(
- (iface.get("ifname") or iface.get("name", "")) != "lo"
- and iface.get("operstate", "").lower() == "up"
- for iface in interfaces
- )
- if not connected:
- connected = LinuxNetwork.get_connectivity()
- ip = LinuxNetwork.get_ip_address()
- iface_name = ""
- net_type = ConnectivityManager.TYPE_ETHERNET
- for iface in interfaces:
- name = iface.get("ifname") or iface.get("name", "")
- state = iface.get("operstate", "")
- if name and name != "lo" and state.lower() == "up":
- iface_name = iface_name or name
- if name and name.startswith(("wl", "wlan", "wlp")):
- net_type = ConnectivityManager.TYPE_WIFI
- iface_name = name
- data = {
- "connected": connected,
- "ip": ip,
- "interface": iface_name,
- "type_name": "WIFI" if net_type == ConnectivityManager.TYPE_WIFI else "ETHERNET",
- }
- return NetworkInfo.from_linux_data(data, network_type=net_type)
- except Exception:
- return None
-
- def getActiveNetworkInfo(self) -> Optional[NetworkInfo]:
- if _USE_LINUX:
- return self._get_linux_active_info()
- if self._active_network:
- return self._network_infos.get(self._active_network.getNetId())
- return None
-
- def getNetworkInfo(self, networkType: int) -> Optional[NetworkInfo]:
- if _USE_LINUX:
- info = self._get_linux_active_info()
- if info is not None and info.getType() == networkType:
- return info
- return None
- for info in self._network_infos.values():
- if info.getType() == networkType:
- return info
- return None
-
- def getConnectivityStatus(self) -> bool:
- """返回当前网络连通性 (True=已连接)"""
- if _USE_LINUX:
- return LinuxNetwork.get_connectivity()
- return self._active_network is not None
-
- def getNetworkInfoForNetwork(self, network: Network) -> Optional[NetworkInfo]:
- return self._network_infos.get(network.getNetId())
-
- def getAllNetworks(self) -> List[Network]:
- return list(self._networks.values())
-
- def getAllNetworkInfo(self) -> List[NetworkInfo]:
- return list(self._network_infos.values())
-
- def getNetworkCapabilities(self, network: Network) -> Optional[NetworkCapabilities]:
- return network.getNetworkCapabilities()
-
- def getLinkProperties(self, network: Network) -> Optional[LinkProperties]:
- return network.getLinkProperties()
-
- def requestNetwork(self, request: NetworkRequest, callback: Any,
- handler: Any = None, timeoutMs: int = 0,
- flags: int = 0) -> "NetworkRequest":
- lid = id(callback)
- self._callbacks[lid] = callback
- return request
-
- def unregisterNetworkCallback(self, callback: Any):
- lid = id(callback)
- self._callbacks.pop(lid, None)
-
- def registerNetworkCallback(self, request: NetworkRequest, callback: Any,
- handler: Any = None):
- lid = id(callback)
- self._callbacks[lid] = callback
-
- def registerDefaultNetworkCallback(self, callback: Any, handler: Any = None):
- lid = id(callback)
- self._callbacks[lid] = callback
-
- def bindProcessToNetwork(self, network: Network) -> bool:
- return True
-
- def getProcessDefaultNetwork(self) -> Optional[Network]:
- return self._active_network
-
- def setProcessDefaultNetwork(self, network: Optional[Network]) -> bool:
- self._active_network = network
- return True
-
- def isDefaultNetworkActive(self) -> bool:
- return self._active_network is not None
-
- def addDefaultNetworkActiveListener(self, callback: Callable):
- pass
-
- def removeDefaultNetworkActiveListener(self, callback: Callable):
- pass
-
- def reportInetCondition(self, networkType: int, percentage: int):
- pass
-
- def getActiveLinkQualityInfo(self) -> Optional[LinkQualityInfo]:
- return None
-
- def getLinkQualityInfo(self, networkType: int) -> Optional[LinkQualityInfo]:
- return None
-
- def getAllLinkQualityInfo(self) -> List[LinkQualityInfo]:
- return []
-
- def getConnectivityDiagnosticsManager(self) -> ConnectivityDiagnosticsManager:
- return self._diagnostics_manager
-
- def toString(self) -> str:
- return f"ConnectivityManager(active={self._active_network})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/net_hotspot2.py b/android_pyapi/android/net_hotspot2.py
deleted file mode 100644
index 5c7cfce..0000000
--- a/android_pyapi/android/net_hotspot2.py
+++ /dev/null
@@ -1,375 +0,0 @@
-"""
-Android net.wifi.hotspot2 包 — PasspointConfiguration, HomeSp, PasspointManager,
-OsuProvider, WifiPasspointInfo, ProvisionCallback
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "PasspointConfiguration",
- "HomeSp",
- "PasspointManager",
- "OsuProvider",
- "WifiPasspointInfo",
- "ProvisionCallback",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# HomeSp
-# ═══════════════════════════════════════════════════════════════
-
-class HomeSp(Stub):
- """HomeSp — 家庭服务提供商 (桌面存根)"""
-
- def __init__(self, fqdn: str = "", friendly_name: str = ""):
- super().__init__()
- self._fqdn = fqdn
- self._friendly_name = friendly_name
- self._friendly_name_list: List[str] = [friendly_name] if friendly_name else []
- self._match_all_ois: List[int] = []
- self._match_any_ois: List[int] = []
- self._other_home_provider_networks: List["HomeSp"] = []
- self._roaming_consortium_ois: List[int] = []
- self._icon_url = ""
- self._icon: Any = None
-
- def getFqdn(self) -> str:
- """获取 FQDN"""
- return self._fqdn
-
- def getFriendlyName(self) -> str:
- """获取友好名称"""
- return self._friendly_name
-
- def getFriendlyNameList(self) -> List[str]:
- """获取友好名称列表"""
- return self._friendly_name_list.copy()
-
- def getMatchAllOis(self) -> List[int]:
- """获取匹配所有 OI"""
- return self._match_all_ois.copy()
-
- def getMatchAnyOis(self) -> List[int]:
- """获取匹配任意 OI"""
- return self._match_any_ois.copy()
-
- def getOtherHomeProviderNetworks(self) -> List["HomeSp"]:
- """获取其他家庭提供商网络"""
- return self._other_home_provider_networks.copy()
-
- def getRoamingConsortiumOis(self) -> List[int]:
- """获取漫游联盟 OI"""
- return self._roaming_consortium_ois.copy()
-
- def getIconUrl(self) -> str:
- """获取图标 URL"""
- return self._icon_url
-
- def getIcon(self) -> Any:
- """获取图标"""
- return self._icon
-
- def toString(self) -> str:
- return f"HomeSp(fqdn={self._fqdn}, name={self._friendly_name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PasspointConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class PasspointConfiguration(Stub):
- """PasspointConfiguration — Passpoint 配置 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
- self._home_sp: Optional[HomeSp] = None
- self._credential: Optional[Any] = None
- self._update_identifier: Optional[int] = None
- self._unique_id = ""
- self._osu_provisioned = False
- self._osu_provider_id = ""
- self._service_friendly_name = ""
- self._service_description = ""
- self._service_icon_url = ""
- self._user_intervention_required = False
- self._create_time: Optional[int] = None
- self._expiration_time: Optional[int] = None
-
- def getHomeSp(self) -> Optional[HomeSp]:
- """获取家庭 SP"""
- return self._home_sp
-
- def setHomeSp(self, home_sp: HomeSp) -> None:
- """设置家庭 SP"""
- self._home_sp = home_sp
-
- def getCredential(self) -> Optional[Any]:
- """获取凭据"""
- return self._credential
-
- def setCredential(self, credential: Any) -> None:
- """设置凭据"""
- self._credential = credential
-
- def getUpdateIdentifier(self) -> Optional[int]:
- """获取更新标识符"""
- return self._update_identifier
-
- def setUpdateIdentifier(self, identifier: Optional[int]) -> None:
- """设置更新标识符"""
- self._update_identifier = identifier
-
- def getUniqueId(self) -> str:
- """获取唯一 ID"""
- return self._unique_id
-
- def isOsuProvisioned(self) -> bool:
- """检查是否为 OSU 配置"""
- return self._osu_provisioned
-
- def getOsuProviderId(self) -> str:
- """获取 OSU 提供商 ID"""
- return self._osu_provider_id
-
- def setOsuProviderId(self, provider_id: str) -> None:
- """设置 OSU 提供商 ID"""
- self._osu_provider_id = provider_id
-
- def getServiceFriendlyName(self) -> str:
- """获取服务友好名称"""
- return self._service_friendly_name
-
- def setServiceFriendlyName(self, name: str) -> None:
- """设置服务友好名称"""
- self._service_friendly_name = name
-
- def getServiceDescription(self) -> str:
- """获取服务描述"""
- return self._service_description
-
- def setServiceDescription(self, description: str) -> None:
- """设置服务描述"""
- self._service_description = description
-
- def getServiceIconUrl(self) -> str:
- """获取服务图标 URL"""
- return self._service_icon_url
-
- def setServiceIconUrl(self, url: str) -> None:
- """设置服务图标 URL"""
- self._service_icon_url = url
-
- def isUserInterventionRequired(self) -> bool:
- """检查是否需要用户干预"""
- return self._user_intervention_required
-
- def setUserInterventionRequired(self, required: bool) -> None:
- """设置用户干预"""
- self._user_intervention_required = required
-
- def getCreateTime(self) -> Optional[int]:
- """获取创建时间"""
- return self._create_time
-
- def setCreateTime(self, time_millis: int) -> None:
- """设置创建时间"""
- self._create_time = time_millis
-
- def getExpirationTime(self) -> Optional[int]:
- """获取过期时间"""
- return self._expiration_time
-
- def setExpirationTime(self, time_millis: int) -> None:
- """设置过期时间"""
- self._expiration_time = time_millis
-
- def toString(self) -> str:
- return f"PasspointConfiguration(fqdn={self._home_sp.getFqdn() if self._home_sp else 'none'})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, PasspointConfiguration):
- return False
- return self._unique_id == other._unique_id
-
- def hashCode(self) -> int:
- return hash(self._unique_id) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# PasspointManager
-# ═══════════════════════════════════════════════════════════════
-
-class PasspointManager(Stub):
- """PasspointManager — Passpoint 管理器 (桌面存根)"""
-
- _instance: Optional["PasspointManager"] = None
-
- def __init__(self):
- super().__init__()
- self._providers: Dict[str, PasspointConfiguration] = {}
- self._matching_configs: List[Any] = []
- self._preferred_provider: Optional[str] = None
-
- @staticmethod
- def getInstance() -> "PasspointManager":
- if PasspointManager._instance is None:
- PasspointManager._instance = PasspointManager()
- return PasspointManager._instance
-
- def addOrUpdateProvider(self, config: PasspointConfiguration) -> None:
- """添加或更新提供商"""
- self._providers[config.getUniqueId()] = config
-
- def removeProvider(self, config: PasspointConfiguration) -> None:
- """移除提供商"""
- self._providers.pop(config.getUniqueId(), None)
-
- def getProviders(self) -> List[PasspointConfiguration]:
- """获取提供商列表"""
- return list(self._providers.values())
-
- def getMatchingWifiConfigs(self, fqdn: str) -> List[Any]:
- """获取匹配的 Wi-Fi 配置"""
- return self._matching_configs
-
- def queryPasspointIcon(self, config: PasspointConfiguration, icon_url: str) -> None:
- """查询 Passpoint 图标"""
- pass
-
- def abortQueryPasspointIcon(self, icon_url: str) -> None:
- """中止查询 Passpoint 图标"""
- pass
-
- def setIcon(self, config: PasspointConfiguration, icon: Any) -> None:
- """设置图标"""
- pass
-
- def getAnqpOsuProviders(self, config: PasspointConfiguration) -> List["OsuProvider"]:
- """获取 ANQP OSU 提供商"""
- return []
-
- def convertToWifiConfiguration(self, config: PasspointConfiguration) -> Optional[Any]:
- """转换为 Wi-Fi 配置"""
- return None
-
- def setPreferredProvider(self, config: PasspointConfiguration) -> None:
- """设置首选提供商"""
- self._preferred_provider = config.getUniqueId()
-
- def clearPreferredProvider(self) -> None:
- """清除首选提供商"""
- self._preferred_provider = None
-
- def getPasspointProviderWithPackage(self, package_name: str) -> Optional[PasspointConfiguration]:
- """获取指定包名的 Passpoint 提供商"""
- for config in self._providers.values():
- return config
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# OsuProvider
-# ═══════════════════════════════════════════════════════════════
-
-class OsuProvider(Stub):
- """OsuProvider — OSU 提供商 (桌面存根)"""
-
- OS_METHOD_SOAP_XML = 0
- OS_METHOD_OMADM = 1
-
- def __init__(self, friendly_name: str = "", service_description: str = "",
- server_uri: str = "", network_access_identifier: str = "",
- method_list: Optional[List[int]] = None):
- super().__init__()
- self._friendly_name = friendly_name
- self._service_description = service_description
- self._server_uri = server_uri
- self._network_access_identifier = network_access_identifier
- self._method_list = method_list or []
-
- def getFriendlyName(self) -> str:
- """获取友好名称"""
- return self._friendly_name
-
- def getServiceDescription(self) -> str:
- """获取服务描述"""
- return self._service_description
-
- def getServerUri(self) -> str:
- """获取服务器 URI"""
- return self._server_uri
-
- def getNetworkAccessIdentifier(self) -> str:
- """获取网络接入标识符"""
- return self._network_access_identifier
-
- def getMethodList(self) -> List[int]:
- """获取方法列表"""
- return self._method_list.copy()
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiPasspointInfo
-# ═══════════════════════════════════════════════════════════════
-
-class WifiPasspointInfo(Stub):
- """WifiPasspointInfo — Wi-Fi Passpoint 信息"""
-
- def __init__(self, fqdn: str = "", provider_friendly_name: str = ""):
- super().__init__()
- self._fqdn = fqdn
- self._provider_friendly_name = provider_friendly_name
- self._roaming_consortium_ids: List[int] = []
-
- def getFqdn(self) -> str:
- """获取 FQDN"""
- return self._fqdn
-
- def getProviderFriendlyName(self) -> str:
- """获取提供商友好名称"""
- return self._provider_friendly_name
-
- def getRoamingConsortiumIds(self) -> List[int]:
- """获取漫游联盟 ID"""
- return self._roaming_consortium_ids.copy()
-
- def matchesFqdn(self, fqdn: str) -> bool:
- """检查是否匹配 FQDN"""
- return self._fqdn == fqdn
-
- def matchesRoamingConsortiumOis(self, ois: List[int]) -> bool:
- """检查是否匹配漫游联盟 OI"""
- return any(oi in self._roaming_consortium_ids for oi in ois)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ProvisionCallback
-# ═══════════════════════════════════════════════════════════════
-
-class ProvisionCallback(Stub):
- """ProvisionCallback — 配置回调"""
-
- def __init__(self):
- super().__init__()
-
- def onProvisionFailure(self, failure_code: int) -> None:
- """配置失败回调"""
- pass
-
- def onProvisionSuccess(self) -> None:
- """配置成功回调"""
- pass
-
- def onProvisionAbort(self) -> None:
- """配置中止回调"""
- pass
\ No newline at end of file
diff --git a/android_pyapi/android/net_http.py b/android_pyapi/android/net_http.py
deleted file mode 100644
index e81f98a..0000000
--- a/android_pyapi/android/net_http.py
+++ /dev/null
@@ -1,643 +0,0 @@
-"""
-Android HTTP API — AndroidHttpClient, HttpUrlConnection, HttpResponseCache, SSLCertificateSocketFactory, TimedText
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import io
-import json
-import time
-import socket
-import hashlib
-import tempfile
-import threading
-import urllib.request
-import urllib.error
-import urllib.parse
-import ssl as _ssl
-from datetime import datetime
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable, BinaryIO
-from http.client import HTTPResponse, HTTPConnection
-from urllib.request import Request as _UrlRequest
-
-from .._core import Stub, AndroidOnlyError, _app_data_dir
-
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-HTTP_GET = "GET"
-HTTP_POST = "POST"
-HTTP_PUT = "PUT"
-HTTP_DELETE = "DELETE"
-HTTP_HEAD = "HEAD"
-HTTP_OPTIONS = "OPTIONS"
-HTTP_PATCH = "PATCH"
-HTTP_TRACE = "TRACE"
-
-HTTP_100_CONTINUE = 100
-HTTP_101_SWITCHING_PROTOCOLS = 101
-HTTP_200_OK = 200
-HTTP_201_CREATED = 201
-HTTP_202_ACCEPTED = 202
-HTTP_204_NO_CONTENT = 204
-HTTP_301_MOVED_PERMANENTLY = 301
-HTTP_302_FOUND = 302
-HTTP_304_NOT_MODIFIED = 304
-HTTP_307_TEMPORARY_REDIRECT = 307
-HTTP_400_BAD_REQUEST = 400
-HTTP_401_UNAUTHORIZED = 401
-HTTP_403_FORBIDDEN = 403
-HTTP_404_NOT_FOUND = 404
-HTTP_405_METHOD_NOT_ALLOWED = 405
-HTTP_408_REQUEST_TIMEOUT = 408
-HTTP_409_CONFLICT = 409
-HTTP_410_GONE = 410
-HTTP_429_TOO_MANY_REQUESTS = 429
-HTTP_500_INTERNAL_SERVER_ERROR = 500
-HTTP_502_BAD_GATEWAY = 502
-HTTP_503_SERVICE_UNAVAILABLE = 503
-HTTP_504_GATEWAY_TIMEOUT = 504
-
-CHUNK_SIZE = 8192
-DEFAULT_CONNECT_TIMEOUT = 30000
-DEFAULT_READ_TIMEOUT = 30000
-MAX_REDIRECTS = 20
-
-
-# ═══════════════════════════════════════════════════════════════
-# SSLCertificateSocketFactory
-# ═══════════════════════════════════════════════════════════════
-
-class SSLCertificateSocketFactory(Stub):
- """SSLCertificateSocketFactory — SSL 证书套接字工厂"""
-
- SSL_SECURITY_PROTOCOL_TLS = 1
- SSL_SECURITY_PROTOCOL_SSLv3 = 2
- SSL_SECURITY_PROTOCOL_DTLS = 3
- SSL_SECURITY_PROTOCOL_TLSv1 = 4
- SSL_SECURITY_PROTOCOL_TLSv1_1 = 5
- SSL_SECURITY_PROTOCOL_TLSv1_2 = 6
- SSL_SECURITY_PROTOCOL_TLSv1_3 = 7
-
- def __init__(self, handshakeTimeoutMillis: int = 0):
- super().__init__()
- self._handshake_timeout = handshakeTimeoutMillis
- self._security_protocol = SSLCertificateSocketFactory.SSL_SECURITY_PROTOCOL_TLS
- self._trust_all = False
- self._key_manager: Optional[Any] = None
- self._trust_manager: Optional[Any] = None
- self._secure_random: Optional[Any] = None
- self._default_ssl_context = _ssl.create_default_context()
-
- @staticmethod
- def getDefault(handshakeTimeoutMillis: int = 0) -> "SSLCertificateSocketFactory":
- return SSLCertificateSocketFactory(handshakeTimeoutMillis)
-
- @staticmethod
- def getSocketFactory() -> "SSLCertificateSocketFactory":
- return SSLCertificateSocketFactory()
-
- def createSocket(self, s: Optional[socket.socket] = None, host: str = "", port: int = 443, autoClose: bool = True) -> socket.socket:
- if s is None:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- context = _ssl.create_default_context()
- if self._trust_all:
- context.check_hostname = False
- context.verify_mode = _ssl.CERT_NONE
- return context.wrap_socket(s, server_hostname=host if host else None)
- except Exception:
- return s
-
- def setTrustAll(self, trustAll: bool) -> None:
- self._trust_all = trustAll
-
- def setKeyManager(self, km: Any) -> None:
- self._key_manager = km
-
- def setTrustManager(self, tm: Any) -> None:
- self._trust_manager = tm
-
- def setSecureRandom(self, sr: Any) -> None:
- self._secure_random = sr
-
- def getSecurityProtocol(self) -> int:
- return self._security_protocol
-
- def setSecurityProtocol(self, protocol: int) -> None:
- self._security_protocol = protocol
-
- def getHandshakeTimeout(self) -> int:
- return self._handshake_timeout
-
- def toString(self) -> str:
- return f"SSLCertificateSocketFactory(protocol={self._security_protocol})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HttpResponseCache
-# ═══════════════════════════════════════════════════════════════
-
-class HttpResponseCache(Stub):
- """HttpResponseCache — HTTP 响应缓存"""
-
- _instance: Optional["HttpResponseCache"] = None
-
- def __init__(self, directory: str, maxSize: int):
- super().__init__()
- self._directory = directory
- self._max_size = maxSize
- self._current_size = 0
- self._cache: Dict[str, Tuple[str, float, int]] = {}
- self._hit_count = 0
- self._miss_count = 0
- self._network_count = 0
- self._write_success_count = 0
- self._write_abort_count = 0
- self._lock = threading.Lock()
- os.makedirs(directory, exist_ok=True)
-
- @staticmethod
- def getDefault() -> Optional["HttpResponseCache"]:
- return HttpResponseCache._instance
-
- @staticmethod
- def install(directory: str, maxSize: int) -> "HttpResponseCache":
- cache = HttpResponseCache(directory, maxSize)
- HttpResponseCache._instance = cache
- return cache
-
- def get(self, key: str) -> Optional[Tuple[str, float]]:
- with self._lock:
- entry = self._cache.get(key)
- if entry:
- data, expiry, size = entry
- if time.time() < expiry:
- self._hit_count += 1
- return (data, expiry)
- else:
- del self._cache[key]
- self._current_size -= size
- self._miss_count += 1
- return None
- self._miss_count += 1
- return None
-
- def put(self, key: str, data: str, ttl_seconds: int = 300) -> None:
- with self._lock:
- old = self._cache.get(key)
- if old:
- self._current_size -= old[2]
- size = len(data.encode("utf-8"))
- expires = time.time() + ttl_seconds
- self._cache[key] = (data, expires, size)
- self._current_size += size
- self._write_success_count += 1
- self._evict_if_needed()
-
- def _evict_if_needed(self) -> None:
- while self._current_size > self._max_size and self._cache:
- oldest_key = min(self._cache.keys(), key=lambda k: self._cache[k][1])
- oldest = self._cache.pop(oldest_key)
- self._current_size -= oldest[2]
- self._write_abort_count += 1
-
- def flush(self) -> None:
- pass
-
- def delete(self) -> None:
- with self._lock:
- self._cache.clear()
- self._current_size = 0
- HttpResponseCache._instance = None
-
- def maxSize(self) -> int:
- return self._max_size
-
- def size(self) -> int:
- with self._lock:
- return self._current_size
-
- def hitCount(self) -> int:
- return self._hit_count
-
- def missCount(self) -> int:
- return self._miss_count
-
- def networkCount(self) -> int:
- return self._network_count
-
- def writeSuccessCount(self) -> int:
- return self._write_success_count
-
- def writeAbortCount(self) -> int:
- return self._write_abort_count
-
- def isCached(self, key: str) -> bool:
- with self._lock:
- return key in self._cache
-
- def clear(self) -> None:
- with self._lock:
- self._cache.clear()
- self._current_size = 0
-
- def toString(self) -> str:
- return (
- f"HttpResponseCache(size={self._current_size}/{self._max_size}, "
- f"hits={self._hit_count}, misses={self._miss_count})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# TimedText
-# ═══════════════════════════════════════════════════════════════
-
-class TimedText(Stub):
- """TimedText — 定时文本(字幕)"""
-
- def __init__(self, text: str = "", startMs: int = 0, endMs: int = 0):
- super().__init__()
- self._text = text
- self._start_ms = startMs
- self._end_ms = endMs
- self._style: Optional[Dict[str, Any]] = None
- self._subtitle_id = 0
- self._track_id = 0
- self._mime_type: Optional[str] = None
- self._language: Optional[str] = None
- self._flow = False
-
- def getText(self) -> str:
- return self._text
-
- def setText(self, text: str) -> None:
- self._text = text
-
- def getStartMs(self) -> int:
- return self._start_ms
-
- def setStartMs(self, startMs: int) -> None:
- self._start_ms = startMs
-
- def getEndMs(self) -> int:
- return self._end_ms
-
- def setEndMs(self, endMs: int) -> None:
- self._end_ms = endMs
-
- def getDurationMs(self) -> int:
- return self._end_ms - self._start_ms
-
- def getStyle(self) -> Optional[Dict[str, Any]]:
- return self._style
-
- def setStyle(self, style: Dict[str, Any]) -> None:
- self._style = dict(style)
-
- def getLanguage(self) -> Optional[str]:
- return self._language
-
- def setLanguage(self, lang: str) -> None:
- self._language = lang
-
- def getMimeType(self) -> Optional[str]:
- return self._mime_type
-
- def setMimeType(self, mimeType: str) -> None:
- self._mime_type = mimeType
-
- def isFlow(self) -> bool:
- return self._flow
-
- def setFlow(self, flow: bool) -> None:
- self._flow = flow
-
- def toString(self) -> str:
- return f"TimedText(text={self._text[:50]}, start={self._start_ms}, end={self._end_ms})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HttpUrlConnection (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class HttpUrlConnection(Stub):
- """HttpURLConnection (扩展) — HTTP 连接管理"""
-
- def __init__(self, url: str = ""):
- super().__init__()
- self._url = url
- self._method = HTTP_GET
- self._connect_timeout = DEFAULT_CONNECT_TIMEOUT
- self._read_timeout = DEFAULT_READ_TIMEOUT
- self._request_properties: Dict[str, str] = {}
- self._follow_redirects = True
- self._instance_follow_redirects = True
- self._use_caches = True
- self._allow_user_interaction = False
- self._do_input = True
- self._do_output = False
- self._if_modified_since = 0
- self._fixed_length = -1
- self._fixed_stream_mode = False
- self._chunk_length = 0
- self._response_code = -1
- self._response_message: Optional[str] = None
- self._content_length = -1
- self._content_type: Optional[str] = None
- self._content_encoding: Optional[str] = None
- self._expiration: Optional[int] = None
- self._date: Optional[int] = None
- self._last_modified: Optional[int] = None
- self._header_fields: Dict[str, List[str]] = {}
- self._input_stream: Optional[BinaryIO] = None
- self._output_stream: Optional[BinaryIO] = None
- self._connected = False
- self._sslsocket_factory: Optional[SSLCertificateSocketFactory] = None
-
- def setRequestMethod(self, method: str) -> None:
- self._method = method.upper()
-
- def getRequestMethod(self) -> str:
- return self._method
-
- def setConnectTimeout(self, timeoutMillis: int) -> None:
- self._connect_timeout = timeoutMillis
-
- def getConnectTimeout(self) -> int:
- return self._connect_timeout
-
- def setReadTimeout(self, timeoutMillis: int) -> None:
- self._read_timeout = timeoutMillis
-
- def getReadTimeout(self) -> int:
- return self._read_timeout
-
- def setRequestProperty(self, key: str, value: str) -> None:
- self._request_properties[key] = value
-
- def addRequestProperty(self, key: str, value: str) -> None:
- if key in self._request_properties:
- self._request_properties[key] += ", " + value
- else:
- self._request_properties[key] = value
-
- def getRequestProperty(self, key: str) -> Optional[str]:
- return self._request_properties.get(key)
-
- def getRequestProperties(self) -> Dict[str, str]:
- return dict(self._request_properties)
-
- def setInstanceFollowRedirects(self, follow: bool) -> None:
- self._instance_follow_redirects = follow
-
- def getInstanceFollowRedirects(self) -> bool:
- return self._instance_follow_redirects
-
- def setFollowRedirects(self, follow: bool) -> None:
- self._follow_redirects = follow
-
- def getFollowRedirects(self) -> bool:
- return self._follow_redirects
-
- def setUseCaches(self, use: bool) -> None:
- self._use_caches = use
-
- def getUseCaches(self) -> bool:
- return self._use_caches
-
- def setAllowUserInteraction(self, allow: bool) -> None:
- self._allow_user_interaction = allow
-
- def getAllowUserInteraction(self) -> bool:
- return self._allow_user_interaction
-
- def setDoInput(self, do: bool) -> None:
- self._do_input = do
-
- def getDoInput(self) -> bool:
- return self._do_input
-
- def setDoOutput(self, do: bool) -> None:
- self._do_output = do
-
- def getDoOutput(self) -> bool:
- return self._do_output
-
- def setIfModifiedSince(self, ifModifiedSince: int) -> None:
- self._if_modified_since = ifModifiedSince
-
- def getIfModifiedSince(self) -> int:
- return self._if_modified_since
-
- def setFixedLengthStreamingMode(self, contentLength: int) -> None:
- self._fixed_length = contentLength
- self._fixed_stream_mode = True
-
- def setChunkedStreamingMode(self, chunklen: int) -> None:
- self._chunk_length = chunklen
-
- def getHeaderField(self, name: str) -> Optional[str]:
- values = self._header_fields.get(name)
- return values[0] if values else None
-
- def getHeaderFields(self) -> Dict[str, List[str]]:
- return dict(self._header_fields)
-
- def getHeaderFieldKey(self, n: int) -> Optional[str]:
- keys = list(self._header_fields.keys())
- if 0 <= n < len(keys):
- return keys[n]
- return None
-
- def getHeaderFieldInt(self, name: str, default: int) -> int:
- val = self.getHeaderField(name)
- if val:
- try:
- return int(val)
- except ValueError:
- pass
- return default
-
- def getHeaderFieldLong(self, name: str, default: int) -> int:
- return self.getHeaderFieldInt(name, default)
-
- def getHeaderFieldDate(self, name: str, default: int) -> int:
- return default
-
- def getContentLength(self) -> int:
- return self._content_length
-
- def getContentLengthLong(self) -> int:
- return self._content_length
-
- def getContentType(self) -> Optional[str]:
- return self._content_type
-
- def getContentEncoding(self) -> Optional[str]:
- return self._content_encoding
-
- def getExpiration(self) -> int:
- return self._expiration or 0
-
- def getDate(self) -> int:
- return self._date or 0
-
- def getLastModified(self) -> int:
- return self._last_modified or 0
-
- def getResponseCode(self) -> int:
- if not self._connected:
- self.connect()
- return self._response_code
-
- def getResponseMessage(self) -> Optional[str]:
- return self._response_message
-
- def getInputStream(self) -> Optional[BinaryIO]:
- if not self._connected:
- self.connect()
- return self._input_stream
-
- def getOutputStream(self) -> Optional[BinaryIO]:
- if not self._connected:
- self.connect()
- return self._output_stream
-
- def getErrorStream(self) -> Optional[BinaryIO]:
- return None
-
- def connect(self) -> None:
- if self._connected:
- return
- self._connected = True
- try:
- req = _UrlRequest(self._url, method=self._method.encode() if hasattr(self._method, 'encode') else self._method.encode())
- for k, v in self._request_properties.items():
- req.add_header(k, v)
- self._response_code = 200
- self._response_message = "OK"
- self._content_type = "text/plain"
- self._content_length = 0
- except Exception as e:
- self._response_code = 0
- self._response_message = str(e)
-
- def disconnect(self) -> None:
- self._connected = False
- self._input_stream = None
- self._output_stream = None
-
- def getURL(self) -> str:
- return self._url
-
- def getPermission(self) -> Optional[Any]:
- return None
-
- def toString(self) -> str:
- return f"HttpURLConnection(url={self._url}, method={self._method})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AndroidHttpClient
-# ═══════════════════════════════════════════════════════════════
-
-class AndroidHttpClient(Stub):
- """AndroidHttpClient — Android HTTP 客户端 (扩展)"""
-
- def __init__(self, userAgent: str = "AndroidHttpClient"):
- super().__init__()
- self._user_agent = userAgent
- self._connect_timeout = DEFAULT_CONNECT_TIMEOUT
- self._read_timeout = DEFAULT_READ_TIMEOUT
- self._follow_redirects = True
- self._compression_enabled = True
- self._cookie_store: Dict[str, Dict[str, str]] = {}
- self._auth_cache: Dict[str, Tuple[str, str]] = {}
- self._lock = threading.Lock()
-
- @staticmethod
- def newInstance(userAgent: str = "AndroidHttpClient") -> "AndroidHttpClient":
- return AndroidHttpClient(userAgent)
-
- def execute(self, request: Any) -> Any:
- return None
-
- def executeHttp(self, request: Any, context: Any) -> Any:
- return None
-
- def execute(self, host: Any, request: Any) -> Any:
- return None
-
- def execute(self, host: Any, request: Any, context: Any) -> Any:
- return None
-
- def getConnectionManager(self) -> Any:
- return None
-
- def getCredentialsProvider(self) -> Any:
- return None
-
- def getCookieStore(self) -> Any:
- return None
-
- def getAuthSchemeRegistry(self) -> Any:
- return None
-
- def enableCurlLogging(self, tag: str, level: int) -> None:
- pass
-
- def disableCurlLogging(self) -> None:
- pass
-
- def setUserAgent(self, userAgent: str) -> None:
- self._user_agent = userAgent
-
- def getConnectTimeout(self) -> int:
- return self._connect_timeout
-
- def setConnectTimeout(self, timeout: int) -> None:
- self._connect_timeout = timeout
-
- def getReadTimeout(self) -> int:
- return self._read_timeout
-
- def setReadTimeout(self, timeout: int) -> None:
- self._read_timeout = timeout
-
- def isCompressionEnabled(self) -> bool:
- return self._compression_enabled
-
- def setCompressionEnabled(self, enabled: bool) -> None:
- self._compression_enabled = enabled
-
- def clearCredentials(self) -> None:
- with self._lock:
- self._auth_cache.clear()
-
- def clearCookies(self) -> None:
- with self._lock:
- self._cookie_store.clear()
-
- def close(self) -> None:
- pass
-
- @staticmethod
- def modifyRequestToAcceptGzipResponse(request: Any) -> Any:
- return request
-
- @staticmethod
- def getUngzippedContent(entity: Any) -> Any:
- return entity
-
- def toString(self) -> str:
- return f"AndroidHttpClient(user_agent={self._user_agent})"
\ No newline at end of file
diff --git a/android_pyapi/android/net_nsd.py b/android_pyapi/android/net_nsd.py
deleted file mode 100644
index 2b047dd..0000000
--- a/android_pyapi/android/net_nsd.py
+++ /dev/null
@@ -1,514 +0,0 @@
-"""
-Android NsdManager API — NsdManager, NsdServiceInfo, DiscoveryListener, RegistrationListener, ResolveListener
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import socket
-import uuid
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# PROTOCOL_* 常量
-PROTOCOL_DNS_SD = 0
-
-# FAILURE_* 常量
-FAILURE_ALREADY_ACTIVE = 3
-FAILURE_INTERNAL_ERROR = 0
-FAILURE_MAX_LIMIT = 4
-FAILURE_SERVICE_NOT_FOUND = 1
-FAILURE_SERVICE_NOT_RUNNING = 2
-
-# DNS_* 常量
-DNS_A = 1
-DNS_AAAA = 28
-DNS_CNAME = 5
-DNS_HINFO = 13
-DNS_MX = 15
-DNS_NS = 2
-DNS_PTR = 12
-DNS_SOA = 6
-DNS_SRV = 33
-DNS_TXT = 16
-DNS_WKS = 11
-DNS_ANY = 255
-
-# SERVICE_TYPE 常量
-SERVICE_TYPE_HTTP = "_http._tcp"
-SERVICE_TYPE_HTTPS = "_https._tcp"
-SERVICE_TYPE_FTP = "_ftp._tcp"
-SERVICE_TYPE_SSH = "_ssh._tcp"
-SERVICE_TYPE_SMTP = "_smtp._tcp"
-SERVICE_TYPE_IMAP = "_imap._tcp"
-SERVICE_TYPE_AIRPLAY = "_airplay._tcp"
-SERVICE_TYPE_GOOGLECAST = "_googlecast._tcp"
-SERVICE_TYPE_DEVICE_INFO = "_device-info._tcp"
-SERVICE_TYPE_PRINTER = "_printer._tcp"
-SERVICE_TYPE_SCANNER = "_scanner._tcp"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NsdServiceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class NsdServiceInfo(Stub):
- """NsdServiceInfo — NSD 服务信息"""
-
- def __init__(self):
- super().__init__()
- self._service_name: Optional[str] = None
- self._service_type: Optional[str] = None
- self._host: Optional[str] = None
- self._port: int = 0
- self._txt_records: Dict[str, bytes] = {}
- self._attributes: Dict[str, str] = {}
- self._network: Optional[Any] = None
- self._interface_index = 0
- self._service_id = str(uuid.uuid4())
- self._ttl = 120
- self._priority = 0
- self._weight = 0
- self._is_resolved = False
- self._addresses: List[str] = []
-
- def getServiceName(self) -> Optional[str]:
- return self._service_name
-
- def setServiceName(self, serviceName: str) -> None:
- self._service_name = serviceName
-
- def getServiceType(self) -> Optional[str]:
- return self._service_type
-
- def setServiceType(self, serviceType: str) -> None:
- self._service_type = serviceType
-
- def getHost(self) -> Optional[str]:
- return self._host
-
- def setHost(self, host: str) -> None:
- self._host = host
-
- def getPort(self) -> int:
- return self._port
-
- def setPort(self, port: int) -> None:
- self._port = port
-
- def getTxtRecords(self) -> Dict[str, bytes]:
- return dict(self._txt_records)
-
- def setTxtRecords(self, txtRecords: Dict[str, bytes]) -> None:
- self._txt_records = dict(txtRecords)
-
- def getAttributes(self) -> Dict[str, str]:
- return dict(self._attributes)
-
- def setAttribute(self, key: str, value: str) -> None:
- self._attributes[key] = value
-
- def removeAttribute(self, key: str) -> None:
- self._attributes.pop(key, None)
-
- def getNetwork(self) -> Optional[Any]:
- return self._network
-
- def setNetwork(self, network: Any) -> None:
- self._network = network
-
- def getInterfaceIndex(self) -> int:
- return self._interface_index
-
- def setInterfaceIndex(self, index: int) -> None:
- self._interface_index = index
-
- def getHostAddresses(self) -> List[str]:
- return list(self._addresses)
-
- def addHostAddress(self, address: str) -> None:
- if address not in self._addresses:
- self._addresses.append(address)
-
- def getServiceId(self) -> str:
- return self._service_id
-
- def getTtl(self) -> int:
- return self._ttl
-
- def setTtl(self, ttl: int) -> None:
- self._ttl = ttl
-
- def getPriority(self) -> int:
- return self._priority
-
- def setPriority(self, priority: int) -> None:
- self._priority = priority
-
- def getWeight(self) -> int:
- return self._weight
-
- def setWeight(self, weight: int) -> None:
- self._weight = weight
-
- def isResolved(self) -> bool:
- return self._is_resolved
-
- def setResolved(self, resolved: bool) -> None:
- self._is_resolved = resolved
-
- def getHostAddress(self) -> Optional[str]:
- if self._addresses:
- return self._addresses[0]
- return self._host
-
- def toString(self) -> str:
- return (
- f"NsdServiceInfo(name={self._service_name}, "
- f"type={self._service_type}, "
- f"host={self._host}, "
- f"port={self._port})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# NsdManager 内部 Listener 类
-# ═══════════════════════════════════════════════════════════════
-
-class NsdManagerDiscoveryListener(Stub):
- """NsdManager.DiscoveryListener — 服务发现监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onDiscoveryStarted(self, serviceType: str) -> None:
- pass
-
- def onDiscoveryStopped(self, serviceType: str) -> None:
- pass
-
- def onServiceFound(self, serviceInfo: "NsdServiceInfo") -> None:
- pass
-
- def onServiceLost(self, serviceInfo: "NsdServiceInfo") -> None:
- pass
-
- def onStartDiscoveryFailed(self, serviceType: str, errorCode: int) -> None:
- pass
-
- def onStopDiscoveryFailed(self, serviceType: str, errorCode: int) -> None:
- pass
-
- def onDiscoveryStopped(self, serviceType: str) -> None:
- pass
-
- def toString(self) -> str:
- return "NsdManager.DiscoveryListener"
-
-
-class NsdManagerRegistrationListener(Stub):
- """NsdManager.RegistrationListener — 服务注册监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onRegistrationFailed(self, serviceInfo: "NsdServiceInfo", errorCode: int) -> None:
- pass
-
- def onUnregistrationFailed(self, serviceInfo: "NsdServiceInfo", errorCode: int) -> None:
- pass
-
- def onServiceRegistered(self, serviceInfo: "NsdServiceInfo") -> None:
- pass
-
- def onServiceUnregistered(self, serviceInfo: "NsdServiceInfo") -> None:
- pass
-
- def toString(self) -> str:
- return "NsdManager.RegistrationListener"
-
-
-class NsdManagerResolveListener(Stub):
- """NsdManager.ResolveListener — 服务解析监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onResolveFailed(self, serviceInfo: "NsdServiceInfo", errorCode: int) -> None:
- pass
-
- def onServiceResolved(self, serviceInfo: "NsdServiceInfo") -> None:
- pass
-
- def toString(self) -> str:
- return "NsdManager.ResolveListener"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NsdManager
-# ═══════════════════════════════════════════════════════════════
-
-class NsdManager(Stub):
- """NsdManager — 网络服务发现管理器 (桌面存根)"""
-
- PROTOCOL_DNS_SD = PROTOCOL_DNS_SD
-
- FAILURE_ALREADY_ACTIVE = FAILURE_ALREADY_ACTIVE
- FAILURE_INTERNAL_ERROR = FAILURE_INTERNAL_ERROR
- FAILURE_MAX_LIMIT = FAILURE_MAX_LIMIT
- FAILURE_SERVICE_NOT_FOUND = FAILURE_SERVICE_NOT_FOUND
- FAILURE_SERVICE_NOT_RUNNING = FAILURE_SERVICE_NOT_RUNNING
-
- DiscoveryListener = NsdManagerDiscoveryListener
- RegistrationListener = NsdManagerRegistrationListener
- ResolveListener = NsdManagerResolveListener
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._lock = threading.Lock()
- self._registered_services: Dict[str, NsdServiceInfo] = {}
- self._discovery_listeners: Dict[str, NsdManagerDiscoveryListener] = {}
- self._discovery_active: Set[str] = set()
- self._resolved_services: Dict[str, NsdServiceInfo] = {}
- self._discovered_services: Dict[str, List[NsdServiceInfo]] = {}
- self._network_interface: Optional[str] = None
- self._socket_family = socket.AF_INET
- self._discovery_timeout = 5000
- self._is_available = True
-
- def discoverServices(
- self, serviceType: str, protocolType: int, listener: NsdManagerDiscoveryListener
- ) -> None:
- """发现指定类型的服务"""
- with self._lock:
- if serviceType in self._discovery_active:
- listener.onStartDiscoveryFailed(serviceType, FAILURE_ALREADY_ACTIVE)
- return
- self._discovery_active.add(serviceType)
- self._discovery_listeners[serviceType] = listener
- listener.onDiscoveryStarted(serviceType)
- # 模拟发现
- for srv_id, info in self._registered_services.items():
- if info.getServiceType() == serviceType:
- listener.onServiceFound(info)
-
- def stopServiceDiscovery(self, listener: NsdManagerDiscoveryListener) -> None:
- """停止服务发现"""
- with self._lock:
- to_remove = []
- for stype, lst in self._discovery_listeners.items():
- if lst is listener:
- to_remove.append(stype)
- for stype in to_remove:
- self._discovery_active.discard(stype)
- del self._discovery_listeners[stype]
- listener.onDiscoveryStopped(stype)
-
- def registerService(
- self, serviceInfo: NsdServiceInfo, protocolType: int, listener: NsdManagerRegistrationListener
- ) -> None:
- """注册本地服务"""
- with self._lock:
- srv_id = f"{serviceInfo.getServiceName()}:{serviceInfo.getServiceType()}"
- if srv_id in self._registered_services:
- listener.onRegistrationFailed(serviceInfo, FAILURE_ALREADY_ACTIVE)
- return
- self._registered_services[srv_id] = serviceInfo
- listener.onServiceRegistered(serviceInfo)
-
- def unregisterService(self, listener: NsdManagerRegistrationListener) -> None:
- """注销本地服务"""
- with self._lock:
- to_remove = []
- for srv_id, info in self._registered_services.items():
- to_remove.append(srv_id)
- for srv_id in to_remove:
- info = self._registered_services.pop(srv_id)
- listener.onServiceUnregistered(info)
-
- def resolveService(
- self, serviceInfo: NsdServiceInfo, listener: NsdManagerResolveListener
- ) -> None:
- """解析服务(获取主机和端口)"""
- with self._lock:
- srv_id = f"{serviceInfo.getServiceName()}:{serviceInfo.getServiceType()}"
- if srv_id in self._registered_services:
- resolved = self._registered_services[srv_id]
- resolved.setResolved(True)
- if not resolved.getHost():
- resolved.setHost("127.0.0.1")
- if resolved.getPort() == 0:
- resolved.setPort(8080)
- self._resolved_services[srv_id] = resolved
- listener.onServiceResolved(resolved)
- else:
- listener.onResolveFailed(serviceInfo, FAILURE_SERVICE_NOT_FOUND)
-
- def getDiscoveredServices(self, serviceType: str) -> List[NsdServiceInfo]:
- """获取已发现的服务列表"""
- with self._lock:
- return [
- info for info in self._registered_services.values()
- if info.getServiceType() == serviceType
- ]
-
- def getRegisteredServices(self) -> List[NsdServiceInfo]:
- """获取所有已注册的服务"""
- with self._lock:
- return list(self._registered_services.values())
-
- def isDiscoveryActive(self, serviceType: str) -> bool:
- """检查指定类型的发现是否活跃"""
- with self._lock:
- return serviceType in self._discovery_active
-
- def setNetworkInterface(self, iface: str) -> None:
- """设置网络接口"""
- self._network_interface = iface
-
- def getNetworkInterface(self) -> Optional[str]:
- return self._network_interface
-
- def setDiscoveryTimeout(self, timeoutMs: int) -> None:
- self._discovery_timeout = timeoutMs
-
- def getDiscoveryTimeout(self) -> int:
- return self._discovery_timeout
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def destroy(self) -> None:
- with self._lock:
- self._discovery_active.clear()
- self._discovery_listeners.clear()
- self._registered_services.clear()
- self._resolved_services.clear()
- self._is_available = False
-
- def toString(self) -> str:
- with self._lock:
- return (
- f"NsdManager(registered={len(self._registered_services)}, "
- f"active_discoveries={len(self._discovery_active)})"
- )
-
- # ═══════════════════════════════════════════════════════════
- # NsdManager 补充功能
- # ═══════════════════════════════════════════════════════════
-
- def getServiceInfo(self, serviceName: str) -> Optional[NsdServiceInfo]:
- """通过名称获取已注册的服务信息"""
- with self._lock:
- for srv_id, info in self._registered_services.items():
- if info.getServiceName() == serviceName:
- return info
- return None
-
- def removeService(self, serviceName: str) -> bool:
- """移除已注册的服务"""
- with self._lock:
- to_remove = [
- srv_id for srv_id, info in self._registered_services.items()
- if info.getServiceName() == serviceName
- ]
- for srv_id in to_remove:
- del self._registered_services[srv_id]
- return len(to_remove) > 0
-
- def getResolvedService(self, serviceName: str) -> Optional[NsdServiceInfo]:
- """获取已解析的服务"""
- with self._lock:
- for srv_id, info in self._resolved_services.items():
- if info.getServiceName() == serviceName:
- return info
- return None
-
- def getResolvedServices(self) -> List[NsdServiceInfo]:
- """获取所有已解析的服务"""
- with self._lock:
- return list(self._resolved_services.values())
-
- def getAllDiscoveredServices(self) -> List[NsdServiceInfo]:
- """获取所有已发现的服务"""
- with self._lock:
- return [
- info for info in self._registered_services.values()
- if info.isResolved()
- ]
-
- def getActiveDiscoveryCount(self) -> int:
- """获取活跃发现数量"""
- with self._lock:
- return len(self._discovery_active)
-
- def getActiveDiscoveryTypes(self) -> List[str]:
- """获取正在发现的服务类型列表"""
- with self._lock:
- return list(self._discovery_active)
-
- def createServiceInfo(
- self, serviceName: str, serviceType: str, port: int = 0
- ) -> NsdServiceInfo:
- """创建服务信息对象"""
- info = NsdServiceInfo()
- info.setServiceName(serviceName)
- info.setServiceType(serviceType)
- info.setPort(port)
- info.setHost("127.0.0.1")
- return info
-
-
-class NsdServiceInfoBuilder(Stub):
- """NsdServiceInfo.Builder — 服务信息构建器"""
-
- def __init__(self):
- super().__init__()
- self._info = NsdServiceInfo()
-
- def setServiceName(self, name: str) -> "NsdServiceInfoBuilder":
- self._info.setServiceName(name)
- return self
-
- def setServiceType(self, serviceType: str) -> "NsdServiceInfoBuilder":
- self._info.setServiceType(serviceType)
- return self
-
- def setHost(self, host: str) -> "NsdServiceInfoBuilder":
- self._info.setHost(host)
- return self
-
- def setPort(self, port: int) -> "NsdServiceInfoBuilder":
- self._info.setPort(port)
- return self
-
- def setTxtRecords(self, records: Dict[str, bytes]) -> "NsdServiceInfoBuilder":
- self._info.setTxtRecords(records)
- return self
-
- def addAttribute(self, key: str, value: str) -> "NsdServiceInfoBuilder":
- self._info.setAttribute(key, value)
- return self
-
- def setNetwork(self, network: Any) -> "NsdServiceInfoBuilder":
- self._info.setNetwork(network)
- return self
-
- def build(self) -> NsdServiceInfo:
- return self._info
-
- def toString(self) -> str:
- return f"NsdServiceInfoBuilder(name={self._info.getServiceName()})"
\ No newline at end of file
diff --git a/android_pyapi/android/net_rtp.py b/android_pyapi/android/net_rtp.py
deleted file mode 100644
index fa194e3..0000000
--- a/android_pyapi/android/net_rtp.py
+++ /dev/null
@@ -1,246 +0,0 @@
-"""
-Android net.rtp 包 — AudioGroup, AudioCodec, RtpStream, AudioStream
-方法签名完全对齐 Android SDK (此包已废弃但仍是 SDK 的一部分)
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "AudioGroup",
- "AudioCodec",
- "RtpStream",
- "AudioStream",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioGroup
-# ═══════════════════════════════════════════════════════════════
-
-class AudioGroup(Stub):
- """AudioGroup — 音频组 (桌面存根)"""
-
- ON_HOLD = 0
- MUTED = 1
- NORMAL = 2
- ECHO_SUPPRESSION = 3
-
- def __init__(self):
- super().__init__()
- self._group_mode = AudioGroup.NORMAL
- self._streams: List["AudioStream"] = []
-
- def clear(self) -> None:
- """清除所有流"""
- self._streams.clear()
-
- def getGroupMode(self) -> int:
- """获取组模式"""
- return self._group_mode
-
- def setMode(self, mode: int) -> None:
- """设置模式"""
- self._group_mode = mode
-
- def sendDtmf(self, digit: int) -> None:
- """发送 DTMF 音调"""
- pass
-
- def getRtpStream(self, index: int) -> Optional["RtpStream"]:
- """获取 RTP 流"""
- if 0 <= index < len(self._streams):
- return self._streams[index]
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioCodec
-# ═══════════════════════════════════════════════════════════════
-
-class AudioCodec(Stub):
- """AudioCodec — 音频编解码器 (桌面存根)"""
-
- AMR: "AudioCodec" = None
- PCMA: "AudioCodec" = None
- PCMU: "AudioCodec" = None
- GSM_EFR: "AudioCodec" = None
-
- MIN_FRAME_SIZE = 1
- MAX_FRAME_SIZE = 320
- FRAME_COUNT = 8
- CODEC_AMR = 0
- CODEC_PCMA = 1
- CODEC_PCMU = 2
- CODEC_GSM_EFR = 3
-
- def __init__(self, type_: int = 0, codec: str = "", codec_spec: str = "", fmtp: str = ""):
- super().__init__()
- self._type = type_
- self._codec = codec
- self._codec_spec = codec_spec
- self._fmtp = fmtp
-
- @property
- def type(self) -> int:
- """获取类型"""
- return self._type
-
- @property
- def codec(self) -> str:
- """获取编解码器名称"""
- return self._codec
-
- @property
- def codecSpec(self) -> str:
- """获取编解码器规格"""
- return self._codec_spec
-
- @property
- def fmtp(self) -> str:
- """获取 fmtp"""
- return self._fmtp
-
- @staticmethod
- def getCapabilities() -> List["AudioCodec"]:
- """获取能力列表"""
- return [AudioCodec.AMR, AudioCodec.PCMA, AudioCodec.PCMU, AudioCodec.GSM_EFR]
-
- @staticmethod
- def getCodecCapabilities(codec_type: int) -> Optional["AudioCodec"]:
- """获取指定类型的编解码器能力"""
- codecs = {
- AudioCodec.CODEC_AMR: AudioCodec.AMR,
- AudioCodec.CODEC_PCMA: AudioCodec.PCMA,
- AudioCodec.CODEC_PCMU: AudioCodec.PCMU,
- AudioCodec.CODEC_GSM_EFR: AudioCodec.GSM_EFR,
- }
- return codecs.get(codec_type)
-
- @staticmethod
- def getEncoder(codec_type: int) -> Optional["AudioCodec"]:
- """获取编码器"""
- return AudioCodec.getCodecCapabilities(codec_type)
-
- @staticmethod
- def getDecoder(codec_type: int) -> Optional["AudioCodec"]:
- """获取解码器"""
- return AudioCodec.getCodecCapabilities(codec_type)
-
- def toString(self) -> str:
- return f"AudioCodec(type={self._type}, codec={self._codec})"
-
-
-# Initialize AudioCodec constants
-AudioCodec.AMR = AudioCodec(AudioCodec.CODEC_AMR, "AMR", "AMR/8000", "")
-AudioCodec.PCMA = AudioCodec(AudioCodec.CODEC_PCMA, "PCMA", "PCMA/8000", "")
-AudioCodec.PCMU = AudioCodec(AudioCodec.CODEC_PCMU, "PCMU", "PCMU/8000", "")
-AudioCodec.GSM_EFR = AudioCodec(AudioCodec.CODEC_GSM_EFR, "GSM-EFR", "GSM-EFR/8000", "")
-
-
-# ═══════════════════════════════════════════════════════════════
-# RtpStream
-# ═══════════════════════════════════════════════════════════════
-
-class RtpStream(Stub):
- """RtpStream — RTP 流 (桌面存根)"""
-
- MODE_NORMAL = 0
- MODE_SEND_ONLY = 1
- MODE_RECEIVE_ONLY = 2
- MODE_SEND_RECEIVE = 3
- MODE_HOLD = 4
-
- def __init__(self, local_address: str = "127.0.0.1", local_port: int = 5004):
- super().__init__()
- self._local_address = local_address
- self._local_port = local_port
- self._remote_address = ""
- self._remote_port = 0
- self._mode = RtpStream.MODE_NORMAL
- self._released = False
-
- def getLocalAddress(self) -> str:
- """获取本地地址"""
- return self._local_address
-
- def getLocalPort(self) -> int:
- """获取本地端口"""
- return self._local_port
-
- def getRemoteAddress(self) -> str:
- """获取远程地址"""
- return self._remote_address
-
- def getRemotePort(self) -> int:
- """获取远程端口"""
- return self._remote_port
-
- def getMode(self) -> int:
- """获取模式"""
- return self._mode
-
- def setMode(self, mode: int) -> None:
- """设置模式"""
- self._mode = mode
-
- def associate(self, remote_address: str, remote_port: int) -> None:
- """关联远程地址端口"""
- self._remote_address = remote_address
- self._remote_port = remote_port
-
- def release(self) -> None:
- """释放资源"""
- self._released = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# AudioStream
-# ═══════════════════════════════════════════════════════════════
-
-class AudioStream(RtpStream):
- """AudioStream — 音频流 (桌面存根)"""
-
- def __init__(self, local_address: str = "127.0.0.1", local_port: int = 5006):
- super().__init__(local_address, local_port)
- self._codec: Optional[AudioCodec] = None
- self._group: Optional[AudioGroup] = None
- self._dtmf_type: int = -1
-
- def getCodec(self) -> Optional[AudioCodec]:
- """获取编解码器"""
- return self._codec
-
- def setCodec(self, codec: AudioCodec) -> None:
- """设置编解码器"""
- self._codec = codec
-
- def getGroup(self) -> Optional[AudioGroup]:
- """获取音频组"""
- return self._group
-
- def setGroup(self, group: Optional[AudioGroup]) -> None:
- """设置音频组"""
- self._group = group
-
- def getDtmfType(self) -> int:
- """获取 DTMF 类型"""
- return self._dtmf_type
-
- def setDtmfType(self, type_: int) -> None:
- """设置 DTMF 类型"""
- self._dtmf_type = type_
-
- def join(self, group: AudioGroup) -> None:
- """加入音频组"""
- self._group = group
-
- def release(self) -> None:
- super().release()
\ No newline at end of file
diff --git a/android_pyapi/android/net_sip.py b/android_pyapi/android/net_sip.py
deleted file mode 100644
index 4297908..0000000
--- a/android_pyapi/android/net_sip.py
+++ /dev/null
@@ -1,639 +0,0 @@
-"""
-Android SIP API — SipManager, SipProfile, SipSession, SipAudioCall, SipErrorCode, SipSessionAdapter
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import time
-import uuid
-import socket
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipErrorCode
-# ═══════════════════════════════════════════════════════════════
-
-class SipErrorCode(Stub):
- """SipErrorCode — SIP 错误码"""
-
- NO_ERROR = 0
- SOCKET_ERROR = -1
- SERVER_ERROR = -2
- TRANSACTION_ISSUE = -3
- TRANSACTION_TERMINATED = -4
- INVALID_REMOTE_URI = -5
- PEER_NOT_REACHABLE = -6
- CLIENT_ERROR = -7
- INVALID_CREDENTIALS = -8
- IN_PROGRESS = -9
- NOT_REACHABLE = -10
- TIME_OUT = -11
- DATA_USAGE_LIMIT = -12
- CROSS_DOMAIN_AUTHENTICATION = -13
- SERVER_UNREACHABLE = -14
- INTERNAL_SERVER_ERROR = -15
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipProfile
-# ═══════════════════════════════════════════════════════════════
-
-class SipProfile(Stub):
- """SipProfile — SIP 用户档案"""
-
- class Builder(Stub):
- """SipProfile.Builder — 构建器"""
-
- def __init__(self, uriString: str):
- super().__init__()
- self._profile = SipProfile()
- self._profile._uri_string = uriString
-
- def __init__(self, settings: "SipProfile"):
- super().__init__()
- self._profile = SipProfile()
- self._profile._uri_string = settings.getUriString()
- self._profile._display_name = settings.getDisplayName()
- self._profile._auth_user = settings.getAuthUserName()
- self._profile._password = settings.getPassword()
- self._profile._server = settings.getServer()
- self._profile._port = settings.getPort()
- self._profile._protocol = settings.getProtocol()
- self._profile._send_keepalive = settings.getSendKeepAlive()
- self._profile._auto_registration = settings.isAutoRegistrationEnabled()
-
- def setDisplayName(self, displayName: str) -> "SipProfile.Builder":
- self._profile._display_name = displayName
- return self
-
- def setAuthUserName(self, authUserName: str) -> "SipProfile.Builder":
- self._profile._auth_user = authUserName
- return self
-
- def setPassword(self, password: str) -> "SipProfile.Builder":
- self._profile._password = password
- return self
-
- def setServer(self, server: str) -> "SipProfile.Builder":
- self._profile._server = server
- return self
-
- def setPort(self, port: int) -> "SipProfile.Builder":
- self._profile._port = port
- return self
-
- def setProtocol(self, protocol: str) -> "SipProfile.Builder":
- self._profile._protocol = protocol
- return self
-
- def setSendKeepAlive(self, enable: bool) -> "SipProfile.Builder":
- self._profile._send_keepalive = enable
- return self
-
- def setAutoRegistration(self, enable: bool) -> "SipProfile.Builder":
- self._profile._auto_registration = enable
- return self
-
- def setProfilePicture(self, icon: Any) -> "SipProfile.Builder":
- self._profile._profile_picture = icon
- return self
-
- def build(self) -> "SipProfile":
- return self._profile
-
- def __init__(self):
- super().__init__()
- self._uri_string: Optional[str] = None
- self._display_name: Optional[str] = None
- self._auth_user: Optional[str] = None
- self._password: Optional[str] = None
- self._server: Optional[str] = None
- self._port: int = 5060
- self._protocol: str = "UDP"
- self._send_keepalive = False
- self._auto_registration = True
- self._profile_picture: Optional[Any] = None
- self._profile_id = str(uuid.uuid4())
- self._local_ip: Optional[str] = None
- self._registration_time = 3600
- self._is_registered = False
- self._created_at = time.time()
-
- def getUriString(self) -> Optional[str]:
- return self._uri_string
-
- def getDisplayName(self) -> Optional[str]:
- return self._display_name
-
- def getAuthUserName(self) -> Optional[str]:
- return self._auth_user
-
- def getPassword(self) -> Optional[str]:
- return self._password
-
- def getServer(self) -> Optional[str]:
- return self._server
-
- def getPort(self) -> int:
- return self._port
-
- def getProtocol(self) -> str:
- return self._protocol
-
- def getSendKeepAlive(self) -> bool:
- return self._send_keepalive
-
- def isAutoRegistrationEnabled(self) -> bool:
- return self._auto_registration
-
- def getProfilePicture(self) -> Optional[Any]:
- return self._profile_picture
-
- def getProfileId(self) -> str:
- return self._profile_id
-
- def getLocalIp(self) -> Optional[str]:
- return self._local_ip
-
- def setLocalIp(self, ip: str) -> None:
- self._local_ip = ip
-
- def isRegistered(self) -> bool:
- return self._is_registered
-
- def getRegistrationTime(self) -> int:
- return self._registration_time
-
- def setRegistrationTime(self, seconds: int) -> None:
- self._registration_time = seconds
-
- def getCreatedAt(self) -> float:
- return self._created_at
-
- def toString(self) -> str:
- return f"SipProfile(uri={self._uri_string}, display={self._display_name}, server={self._server})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipSessionAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class SipSessionAdapter(Stub):
- """SipSessionAdapter — SIP 会话适配器"""
-
- def __init__(self):
- super().__init__()
-
- def onCalling(self, session: "SipSession") -> None:
- pass
-
- def onRinging(self, session: "SipSession", caller: "SipProfile", options: Any) -> None:
- pass
-
- def onRingingBack(self, session: "SipSession") -> None:
- pass
-
- def onCallEstablished(self, session: "SipSession", sessionDescription: str) -> None:
- pass
-
- def onCallEnded(self, session: "SipSession") -> None:
- pass
-
- def onCallBusy(self, session: "SipSession") -> None:
- pass
-
- def onCallChangeFailed(self, session: "SipSession", errorCode: int, errorMessage: str) -> None:
- pass
-
- def onError(self, session: "SipSession", errorCode: int, errorMessage: str) -> None:
- pass
-
- def onRegistering(self, session: "SipSession") -> None:
- pass
-
- def onRegistrationDone(self, session: "SipSession", duration: int) -> None:
- pass
-
- def onRegistrationFailed(
- self, session: "SipSession", errorCode: int, errorMessage: str
- ) -> None:
- pass
-
- def onRegistrationTimeout(self, session: "SipSession") -> None:
- pass
-
- def toString(self) -> str:
- return "SipSessionAdapter"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipSession
-# ═══════════════════════════════════════════════════════════════
-
-class SipSession(Stub):
- """SipSession — SIP 会话"""
-
- # 会话状态
- STATE_READY_TO_CALL = 0
- STATE_INCOMING_CALL = 1
- STATE_INCOMING_CALL_ANSWERING = 2
- STATE_OUTGOING_CALL = 3
- STATE_OUTGOING_CALL_RINGING = 4
- STATE_OUTGOING_CALL_CANCELING = 5
- STATE_IN_CALL = 6
- STATE_ENDED = 7
- STATE_DEREGISTER = 8
- STATE_REGISTERING = 9
- STATE_REGISTERED = 10
- STATE_UNREGISTERED = 11
- STATE_PENDING = 12
- STATE_INVALID = -1
-
- def __init__(self):
- super().__init__()
- self._session_id = str(uuid.uuid4())
- self._local_profile: Optional[SipProfile] = None
- self._peer_profile: Optional[SipProfile] = None
- self._state = SipSession.STATE_READY_TO_CALL
- self._listener: Optional[SipSessionAdapter] = None
- self._call_id: Optional[str] = None
- self._is_in_call = False
- self._call_duration = 0
- self._start_time: Optional[float] = None
- self._peer_session_description: Optional[str] = None
- self._local_session_description: Optional[str] = None
- self._credentials: Optional[Any] = None
- self._error_code = SipErrorCode.NO_ERROR
- self._error_message: Optional[str] = None
- self._lock = threading.Lock()
-
- def getSessionId(self) -> str:
- return self._session_id
-
- def getLocalProfile(self) -> Optional[SipProfile]:
- return self._local_profile
-
- def getPeerProfile(self) -> Optional[SipProfile]:
- return self._peer_profile
-
- def setListener(self, listener: SipSessionAdapter) -> None:
- self._listener = listener
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int) -> None:
- self._state = state
-
- def isInCall(self) -> bool:
- return self._is_in_call
-
- def getCallId(self) -> Optional[str]:
- return self._call_id
-
- def getCallDuration(self) -> int:
- return self._call_duration
-
- def getLocalSessionDescription(self) -> Optional[str]:
- return self._local_session_description
-
- def setLocalSessionDescription(self, description: str) -> None:
- self._local_session_description = description
-
- def getPeerSessionDescription(self) -> Optional[str]:
- return self._peer_session_description
-
- def setPeerSessionDescription(self, description: str) -> None:
- self._peer_session_description = description
-
- def getErrorCode(self) -> int:
- return self._error_code
-
- def getErrorMessage(self) -> Optional[str]:
- return self._error_message
-
- def makeCall(self, profile: SipProfile, sessionDescription: str, timeout: int = 30) -> None:
- self._peer_profile = profile
- self._state = SipSession.STATE_OUTGOING_CALL
- self._start_time = time.time()
- self._is_in_call = True
- if self._listener:
- self._listener.onCalling(self)
- self._listener.onRingingBack(self)
- self._listener.onCallEstablished(self, sessionDescription)
-
- def answerCall(self, sessionDescription: str, timeout: int = 30) -> None:
- self._state = SipSession.STATE_IN_CALL
- self._start_time = time.time()
- self._is_in_call = True
- if self._listener:
- self._listener.onCallEstablished(self, sessionDescription)
-
- def endCall(self) -> None:
- self._state = SipSession.STATE_ENDED
- self._is_in_call = False
- if self._start_time:
- self._call_duration = int(time.time() - self._start_time)
- if self._listener:
- self._listener.onCallEnded(self)
-
- def changeCall(self, sessionDescription: str, timeout: int = 30) -> None:
- if self._listener:
- self._listener.onCallChangeFailed(self, SipErrorCode.IN_PROGRESS, "changeCall not supported")
-
- def register(self, duration: int = 3600) -> None:
- self._state = SipSession.STATE_REGISTERING
- if self._listener:
- self._listener.onRegistering(self)
- self._state = SipSession.STATE_REGISTERED
- self._listener.onRegistrationDone(self, duration)
-
- def unregister(self) -> None:
- self._state = SipSession.STATE_UNREGISTERED
-
- def isRegistered(self) -> bool:
- return self._state == SipSession.STATE_REGISTERED
-
- def toString(self) -> str:
- return f"SipSession(state={self._state}, in_call={self._is_in_call})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipAudioCall
-# ═══════════════════════════════════════════════════════════════
-
-class SipAudioCall(Stub):
- """SipAudioCall — SIP 音频通话"""
-
- class Listener(Stub):
- """SipAudioCall.Listener — 音频通话监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onReady(self, call: "SipAudioCall") -> None:
- pass
-
- def onRinging(self, call: "SipAudioCall", caller: "SipProfile") -> None:
- pass
-
- def onRingingBack(self, call: "SipAudioCall") -> None:
- pass
-
- def onCallEstablished(self, call: "SipAudioCall") -> None:
- pass
-
- def onCallEnded(self, call: "SipAudioCall") -> None:
- pass
-
- def onCallBusy(self, call: "SipAudioCall") -> None:
- pass
-
- def onCallHeld(self, call: "SipAudioCall") -> None:
- pass
-
- def onError(self, call: "SipAudioCall", errorCode: int, errorMessage: str) -> None:
- pass
-
- def onChanged(self, call: "SipAudioCall") -> None:
- pass
-
- def toString(self) -> str:
- return "SipAudioCall.Listener"
-
- def __init__(self, context: Any = None, profile: Optional[SipProfile] = None):
- super().__init__()
- self._context = context
- self._profile = profile
- self._session: Optional[SipSession] = None
- self._listener: Optional["SipAudioCall.Listener"] = None
- self._local_holder: Optional[Any] = None
- self._is_muted = False
- self._is_speaker_on = False
- self._is_in_call = False
- self._start_time: Optional[float] = None
- self._call_duration = 0
- self._audio_state = 0
-
- def setListener(self, listener: "SipAudioCall.Listener") -> None:
- self._listener = listener
-
- def makeCall(self, profile: SipProfile, sessionDescription: str, timeout: int = 30) -> "SipSession":
- session = SipSession()
- session._local_profile = self._profile
- session.makeCall(profile, sessionDescription, timeout)
- self._session = session
- self._is_in_call = True
- self._start_time = time.time()
- if self._listener:
- self._listener.onCallEstablished(self)
- return session
-
- def answerCall(self, sessionDescription: str, timeout: int = 30) -> None:
- if self._session:
- self._session.answerCall(sessionDescription, timeout)
- self._is_in_call = True
- self._start_time = time.time()
- if self._listener:
- self._listener.onCallEstablished(self)
-
- def endCall(self) -> None:
- if self._session:
- self._session.endCall()
- self._is_in_call = False
- if self._start_time:
- self._call_duration = int(time.time() - self._start_time)
- if self._listener:
- self._listener.onCallEnded(self)
-
- def holdCall(self, timeout: int = 30) -> None:
- if self._listener:
- self._listener.onCallHeld(self)
-
- def continueCall(self, timeout: int = 30) -> None:
- pass
-
- def toggleMute(self) -> None:
- self._is_muted = not self._is_muted
-
- def isMuted(self) -> bool:
- return self._is_muted
-
- def setSpeakerMode(self, speakerMode: bool) -> None:
- self._is_speaker_on = speakerMode
-
- def isSpeakerOn(self) -> bool:
- return self._is_speaker_on
-
- def isInCall(self) -> bool:
- return self._is_in_call
-
- def getCallDuration(self) -> int:
- return self._call_duration
-
- def getLocalProfile(self) -> Optional[SipProfile]:
- return self._profile
-
- def getPeerProfile(self) -> Optional[SipProfile]:
- if self._session:
- return self._session.getPeerProfile()
- return None
-
- def getSession(self) -> Optional[SipSession]:
- return self._session
-
- def setLocalHolder(self, holder: Any) -> None:
- self._local_holder = holder
-
- def toString(self) -> str:
- return f"SipAudioCall(in_call={self._is_in_call}, muted={self._is_muted})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipManager
-# ═══════════════════════════════════════════════════════════════
-
-class SipManager(Stub):
- """SipManager — SIP 管理器 (桌面存根)"""
-
- EXTRA_CALL_ID = "android.sip.extra.CALL_ID"
- EXTRA_OFFER_SD = "android.sip.extra.OFFER_SD"
- EXTRA_PROFILE = "android.sip.extra.PROFILE"
- EXTRA_RESULT = "android.sip.extra.RESULT"
- EXTRA_ERROR_CODE = "android.sip.extra.ERROR_CODE"
- EXTRA_ERROR_MESSAGE = "android.sip.extra.ERROR_MESSAGE"
-
- INCOMING_CALL_INTENT_ACTION = "android.SipDemo.INCOMING_CALL"
-
- _instance: Optional["SipManager"] = None
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._profiles: Dict[str, SipProfile] = {}
- self._sessions: Dict[str, SipSession] = {}
- self._audio_calls: Dict[str, SipAudioCall] = {}
- self._lock = threading.Lock()
- self._is_available = True
- self._is_api_supported = True
- self._sip_network_type = 0
-
- @staticmethod
- def isApiSupported(context: Any) -> bool:
- return True
-
- @staticmethod
- def isVoipSupported(context: Any) -> bool:
- return True
-
- @staticmethod
- def isSipWifiOnly(context: Any) -> bool:
- return False
-
- @staticmethod
- def get(context: Any) -> "SipManager":
- if SipManager._instance is None:
- SipManager._instance = SipManager(context)
- return SipManager._instance
-
- @staticmethod
- def getSipNetworkType(context: Any) -> int:
- return 0
-
- def open(self, profile: SipProfile) -> None:
- with self._lock:
- key = profile.getUriString() or profile.getProfileId()
- self._profiles[key] = profile
-
- def close(self, profile: SipProfile) -> None:
- with self._lock:
- key = profile.getUriString() or profile.getProfileId()
- self._profiles.pop(key, None)
-
- def isOpened(self, uri: str) -> bool:
- with self._lock:
- return uri in self._profiles
-
- def register(self, profile: SipProfile, expiryTime: int, listener: SipSessionAdapter) -> None:
- with self._lock:
- key = profile.getUriString() or profile.getProfileId()
- self._profiles[key] = profile
- profile._is_registered = True
- session = SipSession()
- session._local_profile = profile
- session._listener = listener
- self._sessions[key] = session
- listener.onRegistrationDone(session, expiryTime)
-
- def unregister(self, profile: SipProfile, listener: SipSessionAdapter) -> None:
- with self._lock:
- key = profile.getUriString() or profile.getProfileId()
- self._profiles.pop(key, None)
- session = self._sessions.pop(key, None)
- if session:
- session.setState(SipSession.STATE_UNREGISTERED)
- listener.onRegistrationTimeout(session)
-
- def isRegistered(self, uri: str) -> bool:
- with self._lock:
- profile = self._profiles.get(uri)
- return profile is not None and profile.isRegistered()
-
- def makeAudioCall(
- self, localProfile: SipProfile, peerProfile: SipProfile, listener: SipAudioCall.Listener,
- timeout: int = 30
- ) -> SipAudioCall:
- call = SipAudioCall(self._context, localProfile)
- call.setListener(listener)
- call.makeCall(peerProfile, "", timeout)
- with self._lock:
- key = peerProfile.getUriString() or str(uuid.uuid4())
- self._audio_calls[key] = call
- return call
-
- def makeAudioCall(
- self, localUri: str, peerUri: str, listener: SipAudioCall.Listener, timeout: int = 30
- ) -> SipAudioCall:
- local = SipProfile.Builder(localUri).build()
- peer = SipProfile.Builder(peerUri).build()
- return self.makeAudioCall(local, peer, listener, timeout)
-
- def takeAudioCall(self, incomingCallIntent: Any, listener: SipAudioCall.Listener) -> SipAudioCall:
- call = SipAudioCall(self._context)
- call.setListener(listener)
- return call
-
- def getSessionFor(self, intent: Any) -> Optional[SipSession]:
- return None
-
- def getProfiles(self) -> List[SipProfile]:
- with self._lock:
- return list(self._profiles.values())
-
- def getActiveSessions(self) -> List[SipSession]:
- with self._lock:
- return list(self._sessions.values())
-
- def getActiveCalls(self) -> List[SipAudioCall]:
- with self._lock:
- return list(self._audio_calls.values())
-
- def toString(self) -> str:
- return (
- f"SipManager(profiles={len(self._profiles)}, "
- f"sessions={len(self._sessions)}, "
- f"calls={len(self._audio_calls)})"
- )
\ No newline at end of file
diff --git a/android_pyapi/android/net_ssl.py b/android_pyapi/android/net_ssl.py
deleted file mode 100644
index b493c0c..0000000
--- a/android_pyapi/android/net_ssl.py
+++ /dev/null
@@ -1,406 +0,0 @@
-"""
-Android net.ssl 组件 — SSLSessionCache, SSLEngine, SSLSession, SSLContext, SSLParameters 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import ssl
-import threading
-import time as _time
-from typing import Any, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# SSLSessionCache
-# ═══════════════════════════════════════════════════════════════
-
-class SSLSessionCache(Stub):
- """SSLSessionCache — SSL 会话缓存"""
-
- def __init__(self, path: Optional[str] = None):
- super().__init__()
- self._path = path
- self._cache: Dict[str, Any] = {}
- self._lock = threading.Lock()
-
- def install(self, ssl_context: "SSLContext"):
- pass
-
- @staticmethod
- def get(ssl_session: Any) -> Optional["SSLSessionCache"]:
- return None
-
- def toString(self) -> str:
- return f"SSLSessionCache@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SSLSession
-# ═══════════════════════════════════════════════════════════════
-
-class SSLSession(Stub):
- """SSLSession — SSL 会话"""
-
- def __init__(self):
- super().__init__()
- self._creation_time: int = int(_time.time() * 1000)
- self._last_accessed_time: int = self._creation_time
- self._application_buffer_size: int = 16384
- self._packet_buffer_size: int = 16640
- self._cipher_suite: str = "TLS_AES_128_GCM_SHA256"
- self._protocol: str = "TLSv1.3"
- self._id: bytes = os.urandom(32)
- self._peer_host: str = ""
- self._peer_port: int = 443
- self._local_certificates: Optional[List[Any]] = None
- self._peer_certificates: Optional[List[Any]] = None
- self._local_principal: Any = None
- self._peer_principal: Any = None
- self._values: Dict[str, Any] = {}
- self._session_context: Optional["SSLContext"] = None
-
- def getApplicationBufferSize(self) -> int:
- return self._application_buffer_size
-
- def getCipherSuite(self) -> str:
- return self._cipher_suite
-
- def getCreationTime(self) -> int:
- return self._creation_time
-
- def getId(self) -> bytes:
- return self._id
-
- def getLastAccessedTime(self) -> int:
- return self._last_accessed_time
-
- def getLocalCertificates(self) -> Optional[List[Any]]:
- return self._local_certificates
-
- def getLocalPrincipal(self) -> Any:
- return self._local_principal
-
- def getPacketBufferSize(self) -> int:
- return self._packet_buffer_size
-
- def getPeerCertificates(self) -> Optional[List[Any]]:
- return self._peer_certificates
-
- def getPeerHost(self) -> str:
- return self._peer_host
-
- def getPeerPort(self) -> int:
- return self._peer_port
-
- def getPeerPrincipal(self) -> Any:
- return self._peer_principal
-
- def getProtocol(self) -> str:
- return self._protocol
-
- def getSessionContext(self) -> Optional["SSLContext"]:
- return self._session_context
-
- def getValue(self, name: str) -> Any:
- return self._values.get(name)
-
- def getValueNames(self) -> List[str]:
- return list(self._values.keys())
-
- def invalidate(self):
- self._last_accessed_time = 0
- self._values.clear()
-
- def putValue(self, name: str, value: Any):
- self._values[name] = value
-
- def removeValue(self, name: str):
- self._values.pop(name, None)
-
- def toString(self) -> str:
- return f"SSLSession{{protocol={self._protocol}, cipher={self._cipher_suite}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SSLParameters
-# ═══════════════════════════════════════════════════════════════
-
-class SSLParameters(Stub):
- """SSLParameters — SSL 参数"""
-
- def __init__(self):
- super().__init__()
- self._cipher_suites: List[str] = []
- self._protocols: List[str] = []
- self._want_client_auth: bool = False
- self._need_client_auth: bool = False
- self._algorithm_constraints: Any = None
- self._endpoint_identification_algorithm: Optional[str] = None
- self._server_names: List[Any] = []
- self._sni_matchers: List[Any] = []
- self._named_groups: List[str] = []
-
- def getCipherSuites(self) -> List[str]:
- return list(self._cipher_suites)
-
- def setCipherSuites(self, cipherSuites: List[str]):
- self._cipher_suites = list(cipherSuites)
-
- def getProtocols(self) -> List[str]:
- return list(self._protocols)
-
- def setProtocols(self, protocols: List[str]):
- self._protocols = list(protocols)
-
- def getWantClientAuth(self) -> bool:
- return self._want_client_auth
-
- def setWantClientAuth(self, wantClientAuth: bool):
- self._want_client_auth = wantClientAuth
-
- def getNeedClientAuth(self) -> bool:
- return self._need_client_auth
-
- def setNeedClientAuth(self, needClientAuth: bool):
- self._need_client_auth = needClientAuth
-
- def getAlgorithmConstraints(self) -> Any:
- return self._algorithm_constraints
-
- def setAlgorithmConstraints(self, constraints: Any):
- self._algorithm_constraints = constraints
-
- def getEndpointIdentificationAlgorithm(self) -> Optional[str]:
- return self._endpoint_identification_algorithm
-
- def setEndpointIdentificationAlgorithm(self, algorithm: Optional[str]):
- self._endpoint_identification_algorithm = algorithm
-
- def getServerNames(self) -> List[Any]:
- return list(self._server_names)
-
- def setServerNames(self, serverNames: List[Any]):
- self._server_names = list(serverNames)
-
- def getSNIMatchers(self) -> List[Any]:
- return list(self._sni_matchers)
-
- def setSNIMatchers(self, sniMatchers: List[Any]):
- self._sni_matchers = list(sniMatchers)
-
- def getNamedGroups(self) -> List[str]:
- return list(self._named_groups)
-
- def setNamedGroups(self, namedGroups: List[str]):
- self._named_groups = list(namedGroups)
-
- def toString(self) -> str:
- return f"SSLParameters@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SSLContext
-# ═══════════════════════════════════════════════════════════════
-
-class SSLContext(Stub):
- """SSLContext — SSL 上下文"""
-
- def __init__(self, protocol: str = "TLS"):
- super().__init__()
- self._protocol = protocol
- self._ssl_context = ssl.create_default_context()
- self._socket_factory: Any = None
- self._server_socket_factory: Any = None
- self._default_ssl_params: Optional[SSLParameters] = None
- self._supported_ssl_params: Optional[SSLParameters] = None
-
- @staticmethod
- def getInstance(protocol: str = "TLS") -> "SSLContext":
- ctx = SSLContext(protocol)
- ctx._default_ssl_params = SSLParameters()
- ctx._supported_ssl_params = SSLParameters()
- return ctx
-
- def init(self, keyManager: Any, trustManager: Any, random: Any):
- pass
-
- def getSocketFactory(self) -> Any:
- if not self._socket_factory:
- self._socket_factory = self._ssl_context.wrap_socket
- return self._socket_factory
-
- def getServerSocketFactory(self) -> Any:
- if not self._server_socket_factory:
- self._server_socket_factory = self._ssl_context.wrap_socket
- return self._server_socket_factory
-
- def createSSLEngine(self) -> "SSLEngine":
- return SSLEngine(self)
-
- def createSSLEngine(self, peerHost: str, peerPort: int) -> "SSLEngine":
- return SSLEngine(self, peerHost, peerPort)
-
- def getProtocol(self) -> str:
- return self._protocol
-
- def getSupportedSSLParameters(self) -> SSLParameters:
- if not self._supported_ssl_params:
- self._supported_ssl_params = SSLParameters()
- return self._supported_ssl_params
-
- def getDefaultSSLParameters(self) -> SSLParameters:
- if not self._default_ssl_params:
- self._default_ssl_params = SSLParameters()
- return self._default_ssl_params
-
- def toString(self) -> str:
- return f"SSLContext{{protocol={self._protocol}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SSLEngine
-# ═══════════════════════════════════════════════════════════════
-
-class SSLEngine(Stub):
- """SSLEngine — SSL 引擎"""
-
- HANDSHAKE_STATUS_NOT_STARTED = 0
- HANDSHAKE_STATUS_IN_PROGRESS = 1
- HANDSHAKE_STATUS_NEED_WRAP = 2
- HANDSHAKE_STATUS_NEED_UNWRAP = 3
- HANDSHAKE_STATUS_FINISHED = 4
- HANDSHAKE_STATUS_NEED_TASK = 5
-
- def __init__(self, context: SSLContext, peerHost: str = "", peerPort: int = 443):
- super().__init__()
- self._context = context
- self._peer_host = peerHost
- self._peer_port = peerPort
- self._handshake_status = self.HANDSHAKE_STATUS_NOT_STARTED
- self._use_client_mode: bool = True
- self._need_client_auth: bool = False
- self._want_client_auth: bool = False
- self._enabled_cipher_suites: List[str] = [
- "TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384",
- "TLS_CHACHA20_POLY1305_SHA256",
- ]
- self._enabled_protocols: List[str] = ["TLSv1.3", "TLSv1.2"]
- self._session = SSLSession()
- self._delegated_tasks: List[Any] = []
- self._application_protocol: Optional[str] = None
- self._handshake_application_protocol: Optional[str] = None
- self._hs_protocol_selector: Any = None
-
- def beginHandshake(self):
- self._handshake_status = self.HANDSHAKE_STATUS_IN_PROGRESS
-
- def closeInbound(self):
- pass
-
- def closeOutbound(self):
- pass
-
- def getDelegatedTask(self) -> Optional[Any]:
- if self._delegated_tasks:
- return self._delegated_tasks.pop(0)
- return None
-
- def getEnabledCipherSuites(self) -> List[str]:
- return list(self._enabled_cipher_suites)
-
- def getEnabledProtocols(self) -> List[str]:
- return list(self._enabled_protocols)
-
- def getHandshakeStatus(self) -> int:
- return self._handshake_status
-
- def getNeedClientAuth(self) -> bool:
- return self._need_client_auth
-
- def getSession(self) -> SSLSession:
- return self._session
-
- def getSupportedCipherSuites(self) -> List[str]:
- return list(self._enabled_cipher_suites)
-
- def getSupportedProtocols(self) -> List[str]:
- return list(self._enabled_protocols)
-
- def getUseClientMode(self) -> bool:
- return self._use_client_mode
-
- def getWantClientAuth(self) -> bool:
- return self._want_client_auth
-
- def setEnabledCipherSuites(self, suites: List[str]):
- self._enabled_cipher_suites = list(suites)
-
- def setEnabledProtocols(self, protocols: List[str]):
- self._enabled_protocols = list(protocols)
-
- def setNeedClientAuth(self, needClientAuth: bool):
- self._need_client_auth = needClientAuth
-
- def setUseClientMode(self, useClientMode: bool):
- self._use_client_mode = useClientMode
-
- def setWantClientAuth(self, wantClientAuth: bool):
- self._want_client_auth = wantClientAuth
-
- def setSSLParameters(self, params: SSLParameters):
- if params.getCipherSuites():
- self._enabled_cipher_suites = params.getCipherSuites()
- if params.getProtocols():
- self._enabled_protocols = params.getProtocols()
- self._need_client_auth = params.getNeedClientAuth()
- self._want_client_auth = params.getWantClientAuth()
-
- def getSSLParameters(self) -> SSLParameters:
- params = SSLParameters()
- params.setCipherSuites(self._enabled_cipher_suites)
- params.setProtocols(self._enabled_protocols)
- params.setNeedClientAuth(self._need_client_auth)
- params.setWantClientAuth(self._want_client_auth)
- return params
-
- def wrap(self, src: Any, dst: Any) -> Any:
- return src
-
- def unwrap(self, src: Any, dst: Any) -> Any:
- return src
-
- def getApplicationProtocol(self) -> Optional[str]:
- return self._application_protocol
-
- def getHandshakeApplicationProtocol(self) -> Optional[str]:
- return self._handshake_application_protocol
-
- def setHandshakeApplicationProtocolSelector(self, selector: Any):
- self._hs_protocol_selector = selector
-
- def getHandshakeApplicationProtocolSelector(self) -> Any:
- return self._hs_protocol_selector
-
- def toString(self) -> str:
- return f"SSLEngine{{handshake={self._handshake_status}, client={self._use_client_mode}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "SSLSessionCache",
- "SSLEngine",
- "SSLSession",
- "SSLContext",
- "SSLParameters",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/net_vpn.py b/android_pyapi/android/net_vpn.py
deleted file mode 100644
index 612e8fa..0000000
--- a/android_pyapi/android/net_vpn.py
+++ /dev/null
@@ -1,279 +0,0 @@
-"""
-Android net.vpn 包 — VpnManager, VpnService, VpnService.Builder
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "VpnManager",
- "VpnService",
- "VpnServiceBuilder",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# VpnManager
-# ═══════════════════════════════════════════════════════════════
-
-class VpnManager(Stub):
- """VpnManager — VPN 管理器 (桌面存根)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._package = ""
- self._addresses: List[str] = []
- self._routes: List[str] = []
- self._mtu = 1500
- self._session = ""
- self._configured_packages: List[str] = []
- self._blocking = False
- self._blocking_packages: List[str] = []
- self._network: Optional[Any] = None
- self._http_proxy: Optional[Any] = None
- self._underlying_networks: Optional[List[Any]] = None
-
- def setPackage(self, package_name: str) -> "VpnManager":
- """设置包名"""
- self._package = package_name
- return self
-
- def addAddress(self, address: str, prefix_length: int) -> "VpnManager":
- """添加地址"""
- self._addresses.append(f"{address}/{prefix_length}")
- return self
-
- def removeAddress(self, address: str, prefix_length: int) -> "VpnManager":
- """移除地址"""
- addr = f"{address}/{prefix_length}"
- if addr in self._addresses:
- self._addresses.remove(addr)
- return self
-
- def setRoute(self, address: str, prefix_length: int) -> "VpnManager":
- """设置路由"""
- self._routes.append(f"{address}/{prefix_length}")
- return self
-
- def setMtu(self, mtu: int) -> "VpnManager":
- """设置 MTU"""
- self._mtu = mtu
- return self
-
- def setSession(self, session: str) -> "VpnManager":
- """设置会话名称"""
- self._session = session
- return self
-
- def setConfiguredPackages(self, packages: List[str]) -> "VpnManager":
- """设置已配置的包"""
- self._configured_packages = packages
- return self
-
- def setBlocking(self, blocking: bool) -> "VpnManager":
- """设置阻塞模式"""
- self._blocking = blocking
- return self
-
- def setBlockingPackages(self, packages: List[str]) -> "VpnManager":
- """设置阻塞包"""
- self._blocking_packages = packages
- return self
-
- def establish(self) -> Optional["VpnService"]:
- """建立 VPN"""
- return VpnService(self._context)
-
- def prepare(self, context: Any) -> Optional[Any]:
- """准备 VPN"""
- return None
-
- def getNetwork(self) -> Optional[Any]:
- """获取网络"""
- return self._network
-
- def setHttpProxy(self, proxy: Any) -> "VpnManager":
- """设置 HTTP 代理"""
- self._http_proxy = proxy
- return self
-
- def setUnderlyingNetworks(self, networks: Optional[List[Any]]) -> "VpnManager":
- """设置底层网络"""
- self._underlying_networks = networks
- return self
-
- @staticmethod
- def isAlwaysOnVpnSupported(context: Any) -> bool:
- """检查是否支持始终开启 VPN"""
- return False
-
- @staticmethod
- def setAlwaysOnVpn(context: Any, vpn_component: Any, lockdown: bool) -> None:
- """设置始终开启 VPN"""
- raise AndroidOnlyError("setAlwaysOnVpn 仅在 Android 设备上可用")
-
- @staticmethod
- def getAlwaysOnVpnPackage(context: Any) -> Optional[str]:
- """获取始终开启 VPN 包名"""
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# VpnService
-# ═══════════════════════════════════════════════════════════════
-
-class VpnService(Stub):
- """VpnService — VPN 服务 (桌面存根)"""
-
- SERVICE_INTERFACE = "android.net.VpnService"
- SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._underlying_networks: Optional[List[Any]] = None
- self._tunnel: Optional[Any] = None
-
- def onStartCommand(self, intent: Any, flags: int, start_id: int) -> int:
- """启动命令"""
- return 0
-
- def onBind(self, intent: Any) -> Optional[Any]:
- """绑定"""
- return None
-
- def onRevoke(self) -> None:
- """撤销"""
- pass
-
- @staticmethod
- def prepare(context: Any) -> Optional[Any]:
- """准备 VPN"""
- return None
-
- @staticmethod
- def protect(socket: Any) -> bool:
- """保护套接字免受 VPN 路由影响"""
- return True
-
- def setUnderlyingNetworks(self, networks: Optional[List[Any]]) -> None:
- """设置底层网络"""
- self._underlying_networks = networks
-
- def toString(self) -> str:
- return "VpnService"
-
-
-# ═══════════════════════════════════════════════════════════════
-# VpnService.Builder (aliased as VpnServiceBuilder)
-# ═══════════════════════════════════════════════════════════════
-
-class VpnServiceBuilder(Stub):
- """VpnService.Builder — VPN 服务构建器 (桌面存根)"""
-
- def __init__(self, vpn_service: Optional[VpnService] = None):
- super().__init__()
- self._vpn_service = vpn_service or VpnService()
- self._mtu = 1500
- self._addresses: List[Tuple[str, int]] = []
- self._routes: List[Tuple[str, int]] = []
- self._search_domains: List[str] = []
- self._dns_servers: List[str] = []
- self._session = ""
- self._configured_packages: List[str] = []
- self._allowed_applications: List[str] = []
- self._disallowed_applications: List[str] = []
- self._blocking = False
- self._http_proxy: Optional[Any] = None
- self._underlying_networks: Optional[List[Any]] = None
- self._metered = False
-
- def setMtu(self, mtu: int) -> "VpnServiceBuilder":
- """设置 MTU"""
- self._mtu = mtu
- return self
-
- def addAddress(self, address: str, prefix_length: int) -> "VpnServiceBuilder":
- """添加地址"""
- self._addresses.append((address, prefix_length))
- return self
-
- def addRoute(self, address: str, prefix_length: int) -> "VpnServiceBuilder":
- """添加路由"""
- self._routes.append((address, prefix_length))
- return self
-
- def addSearchDomain(self, domain: str) -> "VpnServiceBuilder":
- """添加搜索域"""
- self._search_domains.append(domain)
- return self
-
- def addDnsServer(self, address: str) -> "VpnServiceBuilder":
- """添加 DNS 服务器"""
- self._dns_servers.append(address)
- return self
-
- def setSession(self, session: str) -> "VpnServiceBuilder":
- """设置会话名称"""
- self._session = session
- return self
-
- def setConfiguredPackages(self, packages: List[str]) -> "VpnServiceBuilder":
- """设置已配置的包"""
- self._configured_packages = packages
- return self
-
- def setAllowedApplications(self, packages: List[str]) -> "VpnServiceBuilder":
- """设置允许的应用"""
- self._allowed_applications = packages
- return self
-
- def setDisallowedApplications(self, packages: List[str]) -> "VpnServiceBuilder":
- """设置不允许的应用"""
- self._disallowed_applications = packages
- return self
-
- def setBlocking(self, blocking: bool) -> "VpnServiceBuilder":
- """设置阻塞模式"""
- self._blocking = blocking
- return self
-
- def setHttpProxy(self, proxy: Any) -> "VpnServiceBuilder":
- """设置 HTTP 代理"""
- self._http_proxy = proxy
- return self
-
- def setUnderlyingNetworks(self, networks: Optional[List[Any]]) -> "VpnServiceBuilder":
- """设置底层网络"""
- self._underlying_networks = networks
- return self
-
- def establish(self) -> Optional[Any]:
- """建立 VPN 隧道"""
- return None
-
- def setMetered(self, metered: bool) -> "VpnServiceBuilder":
- """设置计量连接"""
- self._metered = metered
- return self
-
- def addAllowedApplication(self, package: str) -> "VpnServiceBuilder":
- """添加允许的应用"""
- if package not in self._allowed_applications:
- self._allowed_applications.append(package)
- return self
-
- def addDisallowedApplication(self, package: str) -> "VpnServiceBuilder":
- """添加不允许的应用"""
- if package not in self._disallowed_applications:
- self._disallowed_applications.append(package)
- return self
\ No newline at end of file
diff --git a/android_pyapi/android/net_wifi.py b/android_pyapi/android/net_wifi.py
deleted file mode 100644
index 216103c..0000000
--- a/android_pyapi/android/net_wifi.py
+++ /dev/null
@@ -1,1136 +0,0 @@
-"""
-Android WiFi 组件 — WifiManager, WifiInfo, ScanResult 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-import json
-import random
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-from datetime import datetime
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-# Linux 真实实现导入
-try:
- from .._linux_impl import IS_LINUX, LinuxNetwork, HAS_IP
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# SupplicantState
-# ═══════════════════════════════════════════════════════════════
-
-class SupplicantState(Stub):
- """SupplicantState — wpa_supplicant 状态枚举"""
-
- ASSOCIATED = "ASSOCIATED"
- ASSOCIATING = "ASSOCIATING"
- COMPLETED = "COMPLETED"
- DISCONNECTED = "DISCONNECTED"
- DORMANT = "DORMANT"
- FOUR_WAY_HANDSHAKE = "FOUR_WAY_HANDSHAKE"
- GROUP_HANDSHAKE = "GROUP_HANDSHAKE"
- INACTIVE = "INACTIVE"
- INTERFACE_DISABLED = "INTERFACE_DISABLED"
- INVALID = "INVALID"
- SCANNING = "SCANNING"
- UNINITIALIZED = "UNINITIALIZED"
-
- _VALID_STATES = [
- "ASSOCIATED", "ASSOCIATING", "COMPLETED", "DISCONNECTED",
- "DORMANT", "FOUR_WAY_HANDSHAKE", "GROUP_HANDSHAKE", "INACTIVE",
- "INTERFACE_DISABLED", "INVALID", "SCANNING", "UNINITIALIZED",
- ]
-
- def __init__(self, state: str = "DISCONNECTED"):
- super().__init__()
- self._state = state if state in self._VALID_STATES else "INVALID"
-
- def getState(self) -> str:
- return self._state
-
- def toString(self) -> str:
- return self._state
-
- @staticmethod
- def isValid(state_str: str) -> bool:
- return state_str in SupplicantState._VALID_STATES
-
- def compareTo(self, other: "SupplicantState") -> int:
- if self._state == other._state:
- return 0
- return -1 if (self._VALID_STATES.index(self._state)
- < self._VALID_STATES.index(other._state)) else 1
-
- def equals(self, other) -> bool:
- if isinstance(other, SupplicantState):
- return self._state == other._state
- return False
-
- def hashCode(self) -> int:
- return hash(self._state) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiSsid
-# ═══════════════════════════════════════════════════════════════
-
-class WifiSsid(Stub):
- """WifiSsid — WiFi SSID 封装"""
-
- def __init__(self, ssid: str = ""):
- super().__init__()
- self._ssid = ssid
-
- @staticmethod
- def createFromAsciiBytes(ssid_bytes: bytes) -> "WifiSsid":
- try:
- return WifiSsid(ssid_bytes.decode("utf-8"))
- except UnicodeDecodeError:
- return WifiSsid(repr(ssid_bytes))
-
- @staticmethod
- def createFromHex(hex_str: str) -> "WifiSsid":
- try:
- decoded = bytes.fromhex(hex_str).decode("utf-8", errors="replace")
- return WifiSsid(decoded)
- except Exception:
- return WifiSsid(hex_str)
-
- def toString(self) -> str:
- return self._ssid
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class WifiConfiguration(Stub):
- """WifiConfiguration — WiFi 网络配置"""
-
- SECURITY_OPEN = 0
- SECURITY_WEP = 1
- SECURITY_PSK = 2
- SECURITY_EAP = 3
- SECURITY_SAE = 4
- SECURITY_OWE = 5
-
- class KeyMgmt(Stub):
- NONE = 0
- WPA_PSK = 1
- WPA_EAP = 2
- IEEE8021X = 3
- WPA2_PSK = 4
- OSEN = 5
- FT_PSK = 6
- FT_EAP = 7
- SAE = 8
- OWE = 9
- SUITE_B_192 = 10
- WPA3_SAE = 8
- WPA3_OWE = 9
-
- class GroupCipher(Stub):
- NONE = 0
- TKIP = 1
- CCMP = 2
- TKIP_CCMP = 3
- AES = 4
- SMS4 = 5
- GCMP_128 = 6
- GCMP_256 = 7
- BIP_GMAC_128 = 8
- BIP_GMAC_256 = 9
- BIP_CMAC_256 = 10
-
- class PairwiseCipher(Stub):
- NONE = 0
- TKIP = 1
- CCMP = 2
- NONE_ = 3
- GCMP_128 = 4
- GCMP_256 = 5
- SMS4 = 6
-
- class AuthAlgorithm(Stub):
- OPEN = 0
- SHARED = 1
- LEAP = 2
-
- class Protocol(Stub):
- RSN = 0
- WPA = 1
- OSEN = 2
-
- class Status(Stub):
- CURRENT = 0
- DISABLED = 1
- ENABLED = 2
-
- def __init__(self):
- super().__init__()
- self.SSID: Optional[str] = None
- self.BSSID: Optional[str] = None
- self.preSharedKey: Optional[str] = None
- self.status: int = WifiConfiguration.Status.DISABLED
- self.networkId: int = -1
- self.allowedKeyManagement: Set[int] = set()
- self.allowedGroupCiphers: Set[int] = set()
- self.allowedPairwiseCiphers: Set[int] = set()
- self.allowedAuthAlgorithms: Set[int] = set()
- self.allowedProtocols: Set[int] = set()
- self.hiddenSSID: bool = False
- self.priority: int = 0
- self.wepKeys: List[Optional[str]] = [None, None, None, None]
- self.wepTxKeyIndex: int = 0
- self.isEnterprise: bool = False
- self._enterprise_config: Optional["WifiEnterpriseConfig"] = None
-
- def getNetworkId(self) -> int:
- return self.networkId
-
- def toString(self) -> str:
- ssid = self.SSID or "(none)"
- return f"WifiConfiguration(SSID={ssid}, id={self.networkId})"
-
- def hashCode(self) -> int:
- return hash(self.SSID) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiEnterpriseConfig
-# ═══════════════════════════════════════════════════════════════
-
-class WifiEnterpriseConfig(Stub):
- """WifiEnterpriseConfig — 企业级 WiFi 配置"""
-
- def __init__(self):
- super().__init__()
- self._identity: str = ""
- self._password: str = ""
- self._ca_cert: Optional[str] = None
- self._client_cert: Optional[str] = None
- self._subject_match: str = ""
- self._alt_subject_match: str = ""
- self._domain_suffix_match: str = ""
- self._eap_method: int = -1
- self._phase2_method: int = -1
-
- def setIdentity(self, identity: str):
- self._identity = identity
-
- def getIdentity(self) -> str:
- return self._identity
-
- def setPassword(self, password: str):
- self._password = password
-
- def getPassword(self) -> str:
- return self._password
-
- def setCaCertificate(self, cert: Any):
- pass
-
- def getCaCertificate(self) -> Optional[Any]:
- return None
-
- def setClientCertificate(self, cert: Any):
- pass
-
- def getClientCertificate(self) -> Optional[Any]:
- return None
-
- def setSubjectMatch(self, match: str):
- self._subject_match = match
-
- def getSubjectMatch(self) -> str:
- return self._subject_match
-
- def setDomainSuffixMatch(self, match: str):
- self._domain_suffix_match = match
-
- def getDomainSuffixMatch(self) -> str:
- return self._domain_suffix_match
-
- def toString(self) -> str:
- return f"WifiEnterpriseConfig(identity={self._identity})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiInfo
-# ═══════════════════════════════════════════════════════════════
-
-class WifiInfo(Stub):
- """WifiInfo — WiFi 连接信息"""
-
- LINK_SPEED_UNITS = "Mbps"
- STANDARD_LEGACY = 1
- STANDARD_11N = 4
- STANDARD_11AC = 5
- STANDARD_11AX = 6
- STANDARD_11BE = 7
- SECURITY_TYPE_OPEN = 0
- SECURITY_TYPE_WEP = 1
- SECURITY_TYPE_PSK = 2
- SECURITY_TYPE_EAP = 3
- SECURITY_TYPE_SAE = 4
- SECURITY_TYPE_OWE = 5
- SECURITY_TYPE_WAPI_PSK = 6
- SECURITY_TYPE_PASSPOINT_R1_R2 = 7
- SECURITY_TYPE_PASSPOINT_R3 = 8
-
- INVALID_RSSI = -127
- DEFAULT_RSSI = -60
-
- def __init__(self):
- super().__init__()
- self._ssid: str = ""
- self._bssid: str = "00:00:00:00:00:00"
- self._rssi: int = self.INVALID_RSSI
- self._link_speed: int = 0
- self._frequency: int = 0
- self._ip_address: int = 0
- self._mac_address: str = "02:00:00:00:00:00"
- self._network_id: int = -1
- self._supplicant_state: SupplicantState = SupplicantState(SupplicantState.DISCONNECTED)
- self._wifi_standard: int = self.STANDARD_LEGACY
- self._is_hidden_ssid: bool = False
- self._tx_link_speed: int = 0
- self._rx_link_speed: int = 0
- self._max_rx_link_speed: int = 0
- self._max_tx_link_speed: int = 0
- self._security_type: int = self.SECURITY_TYPE_OPEN
- self._rssi_timestamp: int = 0
-
- def getSSID(self) -> str:
- return self._ssid
-
- def getBSSID(self) -> str:
- return self._bssid
-
- def getRssi(self) -> int:
- return self._rssi
-
- def getLinkSpeed(self) -> int:
- return self._link_speed
-
- def getFrequency(self) -> int:
- return self._frequency
-
- def getIpAddress(self) -> int:
- return self._ip_address
-
- def getMacAddress(self) -> str:
- return self._mac_address
-
- def getNetworkId(self) -> int:
- return self._network_id
-
- def getSupplicantState(self) -> SupplicantState:
- return self._supplicant_state
-
- def getWifiStandard(self) -> int:
- return self._wifi_standard
-
- def isHiddenSSID(self) -> bool:
- return self._is_hidden_ssid
-
- def getTxLinkSpeedMbps(self) -> int:
- return self._tx_link_speed
-
- def getRxLinkSpeedMbps(self) -> int:
- return self._rx_link_speed
-
- def getMaxSupportedRxLinkSpeedMbps(self) -> int:
- return self._max_rx_link_speed
-
- def getMaxSupportedTxLinkSpeedMbps(self) -> int:
- return self._max_tx_link_speed
-
- def getSecurityType(self) -> int:
- return self._security_type
-
- def getRssiTimestamp(self) -> int:
- return self._rssi_timestamp
-
- def toString(self) -> str:
- return (f"WifiInfo(SSID={self._ssid}, BSSID={self._bssid}, "
- f"rssi={self._rssi}, speed={self._link_speed} {self.LINK_SPEED_UNITS})")
-
- def hashCode(self) -> int:
- return hash(self._bssid) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScanResult
-# ═══════════════════════════════════════════════════════════════
-
-class ScanResult(Stub):
- """ScanResult — WiFi 扫描结果"""
-
- WIFI_BAND_24_GHZ = 0
- WIFI_BAND_5_GHZ = 1
- WIFI_BAND_6_GHZ = 2
- CHANNEL_WIDTH_20MHZ = 0
- CHANNEL_WIDTH_40MHZ = 1
- CHANNEL_WIDTH_80MHZ = 2
- CHANNEL_WIDTH_160MHZ = 3
- CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4
-
- UNSPECIFIED = -1
-
- def __init__(self):
- super().__init__()
- self.SSID: str = ""
- self.BSSID: str = ""
- self.capabilities: str = ""
- self.level: int = 0
- self.frequency: int = 0
- self.timestamp: int = 0
- self.channelWidth: int = self.CHANNEL_WIDTH_20MHZ
- self.centerFreq0: int = 0
- self.centerFreq1: int = 0
- self.operatorFriendlyName: str = ""
- self.venueName: str = ""
- self.is80211mcResponder: bool = False
- self.isPasspointNetwork: bool = False
- self._wifi_standard: int = 0
- self._seen: int = 0
- self._distance: Optional[float] = None
- self._distance_sd: Optional[float] = None
-
- def getSSID(self) -> str:
- return self.SSID
-
- def getBSSID(self) -> str:
- return self.BSSID
-
- def getCapabilities(self) -> str:
- return self.capabilities
-
- def getLevel(self) -> int:
- return self.level
-
- def getFrequency(self) -> int:
- return self.frequency
-
- def getTimestamp(self) -> int:
- return self.timestamp
-
- def getChannelWidth(self) -> int:
- return self.channelWidth
-
- def getCenterFreq0(self) -> int:
- return self.centerFreq0
-
- def getCenterFreq1(self) -> int:
- return self.centerFreq1
-
- def getOperatorFriendlyName(self) -> str:
- return self.operatorFriendlyName
-
- def getVenueName(self) -> str:
- return self.venueName
-
- def is80211mcResponder(self) -> bool:
- return self.is80211mcResponder
-
- def isPasspointNetwork(self) -> bool:
- return self.isPasspointNetwork
-
- def getWifiStandard(self) -> int:
- return self._wifi_standard
-
- def getDistance(self) -> Optional[float]:
- return self._distance
-
- def getDistanceSd(self) -> Optional[float]:
- return self._distance_sd
-
- def toString(self) -> str:
- return f"ScanResult(SSID={self.SSID}, BSSID={self.BSSID}, level={self.level})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiNetworkSpecifier
-# ═══════════════════════════════════════════════════════════════
-
-class WifiNetworkSpecifier(Stub):
- """WifiNetworkSpecifier — WiFi 网络说明符"""
-
- def __init__(self, ssid: Optional[str] = None, bssid: Optional[str] = None,
- band: int = 0, security_type: int = 0):
- super().__init__()
- self._ssid = ssid
- self._bssid = bssid
- self._band = band
- self._security_type = security_type
-
- def getSsid(self) -> Optional[str]:
- return self._ssid
-
- def getBssid(self) -> Optional[str]:
- return self._bssid
-
- def getBand(self) -> int:
- return self._band
-
- def toString(self) -> str:
- return f"WifiNetworkSpecifier(SSID={self._ssid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiNetworkSuggestion
-# ═══════════════════════════════════════════════════════════════
-
-class WifiNetworkSuggestion(Stub):
- """WifiNetworkSuggestion — WiFi 网络建议"""
-
- def __init__(self, ssid: str = "", bssid: Optional[str] = None,
- is_hidden: bool = False, priority: int = 0,
- wpa2_passphrase: Optional[str] = None,
- wpa3_passphrase: Optional[str] = None,
- is_owe: bool = False):
- super().__init__()
- self._ssid = ssid
- self._bssid = bssid
- self._is_hidden = is_hidden
- self._priority = priority
- self._wpa2_passphrase = wpa2_passphrase
- self._wpa3_passphrase = wpa3_passphrase
- self._is_owe = is_owe
-
- def getSsid(self) -> str:
- return self._ssid
-
- def getBssid(self) -> Optional[str]:
- return self._bssid
-
- def isHidden(self) -> bool:
- return self._is_hidden
-
- def getPriority(self) -> int:
- return self._priority
-
- def toString(self) -> str:
- return f"WifiNetworkSuggestion(SSID={self._ssid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiManager helpers
-# ═══════════════════════════════════════════════════════════════
-
-class WifiManagerMulticastLock(Stub):
- """WifiManager.MulticastLock"""
-
- def __init__(self, tag: str):
- super().__init__()
- self._tag = tag
- self._held = False
- self._ref_count = 0
-
- def acquire(self):
- self._held = True
- self._ref_count += 1
-
- def release(self):
- if self._ref_count > 0:
- self._ref_count -= 1
- if self._ref_count == 0:
- self._held = False
-
- def isHeld(self) -> bool:
- return self._held
-
- def toString(self) -> str:
- return f"MulticastLock(tag={self._tag}, held={self._held})"
-
-
-class WifiManagerLocalOnlyHotspotCallback(Stub):
- """WifiManager.LocalOnlyHotspotCallback"""
-
- ERROR_NO_CHANNEL = 1
- ERROR_GENERIC = 2
- ERROR_INCOMPATIBLE_MODE = 3
- ERROR_TETHERING_DISALLOWED = 4
-
- def onStarted(self, hotspot: Any):
- pass
-
- def onStopped(self):
- pass
-
- def onFailed(self, reason: int):
- pass
-
-
-class WifiManagerWpsCallback(Stub):
- """WifiManager.WpsCallback"""
-
- def onStarted(self, pin: str):
- pass
-
- def onSucceeded(self):
- pass
-
- def onFailed(self, reason: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiManager
-# ═══════════════════════════════════════════════════════════════
-
-class WifiManager(Stub):
- """WifiManager — WiFi 管理器"""
-
- WIFI_STATE_DISABLING = 0
- WIFI_STATE_DISABLED = 1
- WIFI_STATE_ENABLING = 2
- WIFI_STATE_ENABLED = 3
- WIFI_STATE_UNKNOWN = 4
-
- WIFI_MODE_FULL = 1
- WIFI_MODE_FULL_HIGH_PERF = 3
- WIFI_MODE_SCAN_ONLY = 2
-
- ERROR_AUTHENTICATING = 1
- SAP_START_FAILURE_GENERAL = 0
-
- ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"
- SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE"
- SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.SUPPLICANT_STATE_CHANGED"
- NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"
- SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS"
- WIFI_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_STATE_CHANGED"
- RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED"
- NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED"
-
- def __init__(self):
- super().__init__()
- self._wifi_state = self.WIFI_STATE_ENABLED
- self._wifi_enabled = True
- self._connection_info: Optional[WifiInfo] = None
- self._scan_results: List[ScanResult] = []
- self._configured_networks: List[WifiConfiguration] = []
- self._network_suggestions: List[WifiNetworkSuggestion] = []
- self._listeners: Dict[str, List[Any]] = {}
- self._next_network_id = 0
- self._p2p_channels: List[int] = []
-
- def getConnectionInfo(self) -> Optional[WifiInfo]:
- if _USE_LINUX:
- return self._get_linux_connection_info()
- if self._connection_info is None:
- info = WifiInfo()
- info._ssid = '"mock_wifi"'
- info._bssid = "00:1A:2B:3C:4D:5E"
- info._rssi = -55
- info._link_speed = 1300
- info._frequency = 5180
- info._network_id = 0
- info._supplicant_state = SupplicantState(SupplicantState.COMPLETED)
- self._connection_info = info
- return self._connection_info
-
- def getWifiInfo(self) -> Optional[WifiInfo]:
- """getWifiInfo — getConnectionInfo 的别名"""
- return self.getConnectionInfo()
-
- def _get_linux_connection_info(self) -> WifiInfo:
- """从 LinuxNetwork.get_wifi_info() 构造 WifiInfo"""
- info = WifiInfo()
- try:
- data = LinuxNetwork.get_wifi_info() or {}
- ssid = data.get("ssid", "")
- info._ssid = f'"{ssid}"' if ssid else ""
- info._bssid = data.get("bssid", "00:00:00:00:00:00")
- # signal 通常是 0-100, 转换为 RSSI (dBm, 约 -100..0)
- signal = data.get("signal", 0)
- if isinstance(signal, (int, float)) and signal > 0:
- info._rssi = int(-100 + (signal / 100.0) * 60)
- else:
- info._rssi = int(signal) if signal else WifiInfo.INVALID_RSSI
- iface = data.get("interface", "")
- if iface:
- info._frequency = 2412 # 默认 2.4GHz
- info._link_speed = data.get("link_speed", 0) or 0
- info._network_id = 0
- info._supplicant_state = SupplicantState(SupplicantState.COMPLETED)
- except Exception:
- pass
- return info
-
- def getScanResults(self) -> List[ScanResult]:
- if _USE_LINUX:
- results = self._linux_scan_results()
- if results is not None:
- return results
- return list(self._scan_results)
-
- def _linux_scan_results(self) -> Optional[List[ScanResult]]:
- """通过 nmcli 获取 WiFi 扫描结果 (真实实现)"""
- import subprocess
- import re
- try:
- proc = subprocess.run(
- ["nmcli", "-t", "-f", "ssid,bssid,signal,freq,security",
- "dev", "wifi", "list"],
- capture_output=True, text=True, timeout=15,
- )
- if proc.returncode != 0:
- return None
- results: List[ScanResult] = []
- seen: Set[str] = set()
- for line in proc.stdout.strip().split("\n"):
- if not line:
- continue
- # nmcli -t 模式中值内的 : 被转义为 \:, 按非转义 : 分割
- parts = re.split(r'(? 4 else ""
- results.append(sr)
- return results
- except Exception:
- return None
-
- def startScan(self) -> bool:
- return True
-
- def setWifiEnabled(self, enabled: bool) -> bool:
- if _USE_LINUX:
- import subprocess
- import shutil
- try:
- cmd = ["nmcli", "radio", "wifi", "on" if enabled else "off"]
- proc = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
- if proc.returncode != 0 and shutil.which("rfkill"):
- # 回退到 rfkill
- rfkill_cmd = (["rfkill", "unblock", "wifi"] if enabled
- else ["rfkill", "block", "wifi"])
- subprocess.run(rfkill_cmd, capture_output=True, timeout=5)
- except Exception:
- pass
- self._wifi_enabled = enabled
- self._wifi_state = self.WIFI_STATE_ENABLED if enabled else self.WIFI_STATE_DISABLED
- return True
-
- def isWifiEnabled(self) -> bool:
- if _USE_LINUX:
- return self._linux_has_wireless_interface()
- return self._wifi_enabled
-
- def _linux_has_wireless_interface(self) -> bool:
- """检查是否存在无线网络接口"""
- try:
- for iface in LinuxNetwork.get_interfaces():
- name = iface.get("ifname") or iface.get("name", "")
- if name and name.startswith(("wl", "wlan", "wlp")):
- return True
- # 回退: 检查 /sys/class/net 下的无线接口
- import os as _os
- for name in _os.listdir("/sys/class/net/") if _os.path.isdir("/sys/class/net") else []:
- if name.startswith(("wl", "wlan", "wlp")):
- return True
- except Exception:
- pass
- return False
-
- def getWifiState(self) -> int:
- return self._wifi_state
-
- def getConfiguredNetworks(self) -> List[WifiConfiguration]:
- return list(self._configured_networks)
-
- def addNetwork(self, config: WifiConfiguration) -> int:
- config.networkId = self._next_network_id
- self._next_network_id += 1
- self._configured_networks.append(config)
- return config.networkId
-
- def updateNetwork(self, config: WifiConfiguration) -> int:
- for i, c in enumerate(self._configured_networks):
- if c.networkId == config.networkId:
- self._configured_networks[i] = config
- return config.networkId
- return -1
-
- def removeNetwork(self, net_id: int) -> bool:
- self._configured_networks = [
- c for c in self._configured_networks if c.networkId != net_id
- ]
- return True
-
- def enableNetwork(self, net_id: int, disable_others: bool = False) -> bool:
- for c in self._configured_networks:
- if c.networkId == net_id:
- c.status = WifiConfiguration.Status.ENABLED
- elif disable_others:
- c.status = WifiConfiguration.Status.DISABLED
- return True
-
- def disableNetwork(self, net_id: int) -> bool:
- for c in self._configured_networks:
- if c.networkId == net_id:
- c.status = WifiConfiguration.Status.DISABLED
- return True
-
- def disconnect(self) -> bool:
- return True
-
- def reconnect(self) -> bool:
- return True
-
- def reassociate(self) -> bool:
- return True
-
- def is5GHzBandSupported(self) -> bool:
- return True
-
- def is6GHzBandSupported(self) -> bool:
- import sys
- return sys.version_info >= (3, 10)
-
- def isEasyConnectSupported(self) -> bool:
- return False
-
- def getP2pChannelList(self) -> List[int]:
- return list(self._p2p_channels)
-
- def startLocalOnlyHotspot(self, callback: WifiManagerLocalOnlyHotspotCallback, handler: Any = None):
- try:
- callback.onStarted("MockHotspot")
- except Exception:
- pass
-
- def addNetworkSuggestions(self, suggestions: List[WifiNetworkSuggestion]) -> int:
- self._network_suggestions.extend(suggestions)
- return 0 # STATUS_SUGGESTION_SUCCESS
-
- def removeNetworkSuggestions(self, suggestions: List[WifiNetworkSuggestion]) -> int:
- for s in suggestions:
- self._network_suggestions = [x for x in self._network_suggestions if x is not s]
- return 0
-
- def createMulticastLock(self, tag: str) -> WifiManagerMulticastLock:
- return WifiManagerMulticastLock(tag)
-
- def getDhcpInfo(self):
- from .net import DhcpInfo
- return DhcpInfo()
-
- def pingSupplicant(self) -> bool:
- return True
-
- def startScanActive(self) -> bool:
- return True
-
- def setScanAlwaysAvailable(self, enabled: bool):
- pass
-
- def isScanAlwaysAvailable(self) -> bool:
- return True
-
- def saveConfiguration(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"WifiManager(state={self._wifi_state})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiP2pManager
-# ═══════════════════════════════════════════════════════════════
-
-class WifiP2pDevice(Stub):
- """WifiP2pDevice — P2P 设备"""
-
- CONNECTED = 0
- INVITED = 1
- FAILED = 2
- AVAILABLE = 3
- UNAVAILABLE = 4
-
- def __init__(self):
- super().__init__()
- self.deviceAddress: str = ""
- self.deviceName: str = ""
- self.primaryDeviceType: str = ""
- self.secondaryDeviceType: str = ""
- self.wpsConfigMethods: int = 0
- self.deviceCapability: int = 0
- self.groupCapability: int = 0
- self.status: int = self.UNAVAILABLE
- self.GO_PORT: int = 0
-
- def getDeviceAddress(self) -> str:
- return self.deviceAddress
-
- def getDeviceName(self) -> str:
- return self.deviceName
-
- def isServiceDiscoveryCapable(self) -> bool:
- return True
-
- def isGroupOwner(self) -> bool:
- return self.groupCapability > 0
-
- def toString(self) -> str:
- return f"WifiP2pDevice(name={self.deviceName}, addr={self.deviceAddress})"
-
-
-class WifiP2pConfig(Stub):
- """WifiP2pConfig — P2P 配置"""
-
- class Builder(Stub):
- def __init__(self):
- super().__init__()
- self._device_address = ""
- self._network_name = ""
- self._passphrase = ""
- self._group_owner_band = 0
-
- def setDeviceAddress(self, addr: str) -> "WifiP2pConfig.Builder":
- self._device_address = addr
- return self
-
- def setNetworkName(self, name: str) -> "WifiP2pConfig.Builder":
- self._network_name = name
- return self
-
- def setPassphrase(self, passphrase: str) -> "WifiP2pConfig.Builder":
- self._passphrase = passphrase
- return self
-
- def setGroupOwnerBand(self, band: int) -> "WifiP2pConfig.Builder":
- self._group_owner_band = band
- return self
-
- def build(self) -> "WifiP2pConfig":
- config = WifiP2pConfig()
- config.deviceAddress = self._device_address
- config.networkName = self._network_name
- config.passphrase = self._passphrase
- return config
-
- def __init__(self):
- super().__init__()
- self.deviceAddress: str = ""
- self.networkName: str = ""
- self.passphrase: str = ""
-
-
-class WifiP2pGroup(Stub):
- """WifiP2pGroup — P2P 群组"""
-
- def __init__(self):
- super().__init__()
- self._network_name: str = ""
- self._is_group_owner: bool = False
- self._owner: Optional[WifiP2pDevice] = None
- self._clients: List[WifiP2pDevice] = []
- self._passphrase: str = ""
- self._interface: str = ""
-
- def getNetworkName(self) -> str:
- return self._network_name
-
- def isGroupOwner(self) -> bool:
- return self._is_group_owner
-
- def getOwner(self) -> Optional[WifiP2pDevice]:
- return self._owner
-
- def getClientList(self) -> List[WifiP2pDevice]:
- return list(self._clients)
-
- def getPassphrase(self) -> str:
- return self._passphrase
-
- def getInterface(self) -> str:
- return self._interface
-
- def toString(self) -> str:
- return f"WifiP2pGroup(name={self._network_name})"
-
-
-class WifiP2pManager(Stub):
- """WifiP2pManager — P2P 管理器"""
-
- WIFI_P2P_STATE_ENABLED_ACTION = "android.net.wifi.p2p.STATE_CHANGED"
- WIFI_P2P_STATE_CHANGED_ACTION = "android.net.wifi.p2p.STATE_CHANGED"
- WIFI_P2P_PEERS_CHANGED_ACTION = "android.net.wifi.p2p.PEERS_CHANGED"
- WIFI_P2P_CONNECTION_CHANGED_ACTION = "android.net.wifi.p2p.CONNECTION_CHANGED"
- WIFI_P2P_THIS_DEVICE_CHANGED_ACTION = "android.net.wifi.p2p.THIS_DEVICE_CHANGED"
- WIFI_P2P_DISCOVERY_CHANGED_ACTION = "android.net.wifi.p2p.DISCOVERY_CHANGED"
-
- class Channel(Stub):
- """P2P 通道"""
-
- def __init__(self):
- super().__init__()
-
- def __init__(self):
- super().__init__()
- self._channel: Optional[WifiP2pManager.Channel] = None
- self._peers: List[WifiP2pDevice] = []
-
- def initialize(self, context: Any, looper: Any, listener: Any) -> "WifiP2pManager.Channel":
- self._channel = WifiP2pManager.Channel()
- if listener:
- try:
- listener.onSuccess()
- except Exception:
- pass
- return self._channel
-
- def discoverPeers(self, channel: "WifiP2pManager.Channel", listener: Any):
- if listener:
- try:
- listener.onSuccess()
- except Exception:
- pass
-
- def discoverServices(self, channel: "WifiP2pManager.Channel", listener: Any):
- if listener:
- try:
- listener.onSuccess()
- except Exception:
- pass
-
- def requestPeers(self, channel: "WifiP2pManager.Channel", listener: Any):
- if listener:
- try:
- listener.onPeersAvailable(self._peers)
- except Exception:
- pass
-
- def requestGroupInfo(self, channel: "WifiP2pManager.Channel", listener: Any):
- if listener:
- try:
- listener.onGroupInfoAvailable(WifiP2pGroup())
- except Exception:
- pass
-
- def createGroup(self, channel: "WifiP2pManager.Channel", listener: Any):
- if listener:
- try:
- listener.onSuccess()
- except Exception:
- pass
-
- def removeGroup(self, channel: "WifiP2pManager.Channel", listener: Any):
- if listener:
- try:
- listener.onSuccess()
- except Exception:
- pass
-
- def connect(self, channel: "WifiP2pManager.Channel", config: WifiP2pConfig, listener: Any):
- if listener:
- try:
- listener.onSuccess()
- except Exception:
- pass
-
- def cancelConnect(self, channel: "WifiP2pManager.Channel", listener: Any):
- if listener:
- try:
- listener.onSuccess()
- except Exception:
- pass
-
- def stopPeerDiscovery(self, channel: "WifiP2pManager.Channel", listener: Any):
- if listener:
- try:
- listener.onSuccess()
- except Exception:
- pass
-
- def requestDeviceInfo(self, channel: "WifiP2pManager.Channel", device_address: str, listener: Any):
- if listener:
- try:
- listener.onDeviceInfoAvailable(WifiP2pDevice())
- except Exception:
- pass
-
- def setDeviceName(self, channel: "WifiP2pManager.Channel", device_name: str, listener: Any):
- if listener:
- try:
- listener.onSuccess()
- except Exception:
- pass
-
- def setWfdEnabled(self, channel: "WifiP2pManager.Channel", enabled: bool, listener: Any):
- pass
-
- def toString(self) -> str:
- return f"WifiP2pManager(peers={len(self._peers)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiConfigurationKeyMgmt / WifiConfiguration... aliases
-# ═══════════════════════════════════════════════════════════════
-
-WifiConfigurationKeyMgmt = WifiConfiguration.KeyMgmt
-WifiConfigurationGroupCipher = WifiConfiguration.GroupCipher
-WifiConfigurationPairwiseCipher = WifiConfiguration.PairwiseCipher
-WifiConfigurationAuthAlgorithm = WifiConfiguration.AuthAlgorithm
-WifiConfigurationProtocol = WifiConfiguration.Protocol
-WifiConfigurationStatus = WifiConfiguration.Status
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "WifiManager",
- "WifiInfo",
- "WifiConfiguration",
- "WifiConfigurationKeyMgmt",
- "WifiConfigurationGroupCipher",
- "WifiConfigurationPairwiseCipher",
- "WifiConfigurationAuthAlgorithm",
- "WifiConfigurationProtocol",
- "WifiConfigurationStatus",
- "ScanResult",
- "WifiSsid",
- "SupplicantState",
- "WifiEnterpriseConfig",
- "WifiNetworkSpecifier",
- "WifiNetworkSuggestion",
- "WifiManagerLocalOnlyHotspotCallback",
- "WifiManagerWpsCallback",
- "WifiManagerMulticastLock",
- "WifiP2pManager",
- "WifiP2pDevice",
- "WifiP2pConfig",
- "WifiP2pGroup",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/net_wifi_aware.py b/android_pyapi/android/net_wifi_aware.py
deleted file mode 100644
index 869e87d..0000000
--- a/android_pyapi/android/net_wifi_aware.py
+++ /dev/null
@@ -1,428 +0,0 @@
-"""
-Android net.wifi.aware 组件 — WifiAwareManager, WifiAwareSession, PublishConfig, SubscribeConfig 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import threading
-import uuid
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# Characteristics
-# ═══════════════════════════════════════════════════════════════
-
-class Characteristics(Stub):
- """Characteristics — Wi-Fi Aware 特性"""
-
- def __init__(self):
- super().__init__()
- self._max_service_name_length: int = 255
- self._max_service_specific_info_length: int = 255
- self._max_match_filter_length: int = 255
- self._max_number_of_publish_service_sessions: int = 10
- self._max_number_of_subscribe_service_sessions: int = 10
- self._max_message_length: int = 2048
- self._max_peers: int = 10
-
- def getMaxServiceNameLength(self) -> int:
- return self._max_service_name_length
-
- def getMaxServiceSpecificInfoLength(self) -> int:
- return self._max_service_specific_info_length
-
- def getMaxMatchFilterLength(self) -> int:
- return self._max_match_filter_length
-
- def getMaxNumberOfPublishServiceSessions(self) -> int:
- return self._max_number_of_publish_service_sessions
-
- def getMaxNumberOfSubscribeServiceSessions(self) -> int:
- return self._max_number_of_subscribe_service_sessions
-
- def getMaxMessageLength(self) -> int:
- return self._max_message_length
-
- def getMaxPeers(self) -> int:
- return self._max_peers
-
- def toString(self) -> str:
- return f"Characteristics@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AttachCallback
-# ═══════════════════════════════════════════════════════════════
-
-class AttachCallback(Stub):
- """AttachCallback — 连接回调"""
-
- def onAttached(self, session: "WifiAwareSession"):
- pass
-
- def onAttachFailed(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# IdentityChangedListener
-# ═══════════════════════════════════════════════════════════════
-
-class IdentityChangedListener(Stub):
- """IdentityChangedListener — 身份变更监听器"""
-
- def onIdentityChanged(self, macAddress: bytes):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# DiscoverySessionCallback
-# ═══════════════════════════════════════════════════════════════
-
-class DiscoverySessionCallback(Stub):
- """DiscoverySessionCallback — 发现会话回调"""
-
- def onServiceDiscovered(self, peerHandle: Any, serviceSpecificInfo: bytes,
- matchFilter: bytes):
- pass
-
- def onServiceDiscoveredWithinRange(self, peerHandle: Any,
- serviceSpecificInfo: bytes,
- matchFilter: bytes, rangeMm: int):
- pass
-
- def onMessageReceived(self, peerHandle: Any, message: bytes):
- pass
-
- def onMessageSendSucceeded(self, messageId: int):
- pass
-
- def onMessageSendFailed(self, messageId: int):
- pass
-
- def onSessionConfigUpdated(self):
- pass
-
- def onSessionConfigFailed(self):
- pass
-
- def onSessionTerminated(self):
- pass
-
- def onMatch(self, peerHandle: Any, serviceSpecificInfo: bytes,
- matchFilter: bytes, rangeMm: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# PublishConfig
-# ═══════════════════════════════════════════════════════════════
-
-class PublishConfig(Stub):
- """PublishConfig — 发布配置"""
-
- PUBLISH_TYPE_UNSOLICITED = 0
- PUBLISH_TYPE_SOLICITED = 1
-
- def __init__(self, service_name: str = "", service_specific_info: bytes = b"",
- match_filter: bytes = b"", terminate_notification_enabled: bool = True,
- ranging_enabled: bool = False, publish_type: int = PUBLISH_TYPE_UNSOLICITED):
- super().__init__()
- self._service_name = service_name
- self._service_specific_info = service_specific_info
- self._match_filter = match_filter
- self._terminate_notification_enabled = terminate_notification_enabled
- self._ranging_enabled = ranging_enabled
- self._publish_type = publish_type
-
- class Builder(Stub):
- """PublishConfig.Builder — 构建器"""
-
- def __init__(self):
- super().__init__()
- self._service_name: str = ""
- self._service_specific_info: bytes = b""
- self._match_filter: bytes = b""
- self._terminate_notification_enabled: bool = True
- self._ranging_enabled: bool = False
- self._publish_type: int = PublishConfig.PUBLISH_TYPE_UNSOLICITED
-
- def setServiceName(self, serviceName: str) -> "PublishConfig.Builder":
- self._service_name = serviceName
- return self
-
- def setServiceSpecificInfo(self, info: bytes) -> "PublishConfig.Builder":
- self._service_specific_info = info
- return self
-
- def setMatchFilter(self, matchFilter: bytes) -> "PublishConfig.Builder":
- self._match_filter = matchFilter
- return self
-
- def setTerminateNotificationEnabled(self, enabled: bool) -> "PublishConfig.Builder":
- self._terminate_notification_enabled = enabled
- return self
-
- def setRangingEnabled(self, enabled: bool) -> "PublishConfig.Builder":
- self._ranging_enabled = enabled
- return self
-
- def setPublishType(self, publishType: int) -> "PublishConfig.Builder":
- self._publish_type = publishType
- return self
-
- def build(self) -> "PublishConfig":
- return PublishConfig(
- self._service_name, self._service_specific_info,
- self._match_filter, self._terminate_notification_enabled,
- self._ranging_enabled, self._publish_type,
- )
-
- def toString(self) -> str:
- return f"PublishConfig{{service={self._service_name}, type={self._publish_type}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SubscribeConfig
-# ═══════════════════════════════════════════════════════════════
-
-class SubscribeConfig(Stub):
- """SubscribeConfig — 订阅配置"""
-
- SUBSCRIBE_TYPE_PASSIVE = 0
- SUBSCRIBE_TYPE_ACTIVE = 1
-
- def __init__(self, service_name: str = "", service_specific_info: bytes = b"",
- match_filter: bytes = b"", terminate_notification_enabled: bool = True,
- ranging_enabled: bool = False, subscribe_type: int = SUBSCRIBE_TYPE_PASSIVE):
- super().__init__()
- self._service_name = service_name
- self._service_specific_info = service_specific_info
- self._match_filter = match_filter
- self._terminate_notification_enabled = terminate_notification_enabled
- self._ranging_enabled = ranging_enabled
- self._subscribe_type = subscribe_type
-
- class Builder(Stub):
- """SubscribeConfig.Builder — 构建器"""
-
- def __init__(self):
- super().__init__()
- self._service_name: str = ""
- self._service_specific_info: bytes = b""
- self._match_filter: bytes = b""
- self._terminate_notification_enabled: bool = True
- self._ranging_enabled: bool = False
- self._subscribe_type: int = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE
-
- def setServiceName(self, serviceName: str) -> "SubscribeConfig.Builder":
- self._service_name = serviceName
- return self
-
- def setServiceSpecificInfo(self, info: bytes) -> "SubscribeConfig.Builder":
- self._service_specific_info = info
- return self
-
- def setMatchFilter(self, matchFilter: bytes) -> "SubscribeConfig.Builder":
- self._match_filter = matchFilter
- return self
-
- def setTerminateNotificationEnabled(self, enabled: bool) -> "SubscribeConfig.Builder":
- self._terminate_notification_enabled = enabled
- return self
-
- def setRangingEnabled(self, enabled: bool) -> "SubscribeConfig.Builder":
- self._ranging_enabled = enabled
- return self
-
- def setSubscribeType(self, subscribeType: int) -> "SubscribeConfig.Builder":
- self._subscribe_type = subscribeType
- return self
-
- def build(self) -> "SubscribeConfig":
- return SubscribeConfig(
- self._service_name, self._service_specific_info,
- self._match_filter, self._terminate_notification_enabled,
- self._ranging_enabled, self._subscribe_type,
- )
-
- def toString(self) -> str:
- return f"SubscribeConfig{{service={self._service_name}, type={self._subscribe_type}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DiscoverySession
-# ═══════════════════════════════════════════════════════════════
-
-class DiscoverySession(Stub):
- """DiscoverySession — 发现会话基类"""
-
- def __init__(self, service_name: str = ""):
- super().__init__()
- self._service_name = service_name
- self._terminate_notification_enabled: bool = True
- self._open: bool = True
-
- def sendMessage(self, peerHandle: Any, message: bytes, messageId: int):
- pass
-
- def close(self):
- self._open = False
-
- def setTerminateNotificationEnabled(self, enabled: bool):
- self._terminate_notification_enabled = enabled
-
- def toString(self) -> str:
- return f"DiscoverySession{{service={self._service_name}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PublishDiscoverySession
-# ═══════════════════════════════════════════════════════════════
-
-class PublishDiscoverySession(DiscoverySession):
- """PublishDiscoverySession — 发布发现会话"""
-
- def __init__(self, service_name: str = ""):
- super().__init__(service_name)
-
- def updatePublishConfig(self, publishConfig: PublishConfig):
- pass
-
- def toString(self) -> str:
- return f"PublishDiscoverySession{{service={self._service_name}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SubscribeDiscoverySession
-# ═══════════════════════════════════════════════════════════════
-
-class SubscribeDiscoverySession(DiscoverySession):
- """SubscribeDiscoverySession — 订阅发现会话"""
-
- def __init__(self, service_name: str = ""):
- super().__init__(service_name)
-
- def updateSubscribeConfig(self, subscribeConfig: SubscribeConfig):
- pass
-
- def toString(self) -> str:
- return f"SubscribeDiscoverySession{{service={self._service_name}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiAwareSession
-# ═══════════════════════════════════════════════════════════════
-
-class WifiAwareSession(Stub):
- """WifiAwareSession — Wi-Fi Aware 会话"""
-
- def __init__(self):
- super().__init__()
- self._open: bool = True
- self._publish_sessions: List[PublishDiscoverySession] = []
- self._subscribe_sessions: List[SubscribeDiscoverySession] = []
-
- def publish(self, publishConfig: PublishConfig,
- callback: DiscoverySessionCallback,
- handler: Any = None) -> PublishDiscoverySession:
- session = PublishDiscoverySession(publishConfig._service_name)
- self._publish_sessions.append(session)
- return session
-
- def subscribe(self, subscribeConfig: SubscribeConfig,
- callback: DiscoverySessionCallback,
- handler: Any = None) -> SubscribeDiscoverySession:
- session = SubscribeDiscoverySession(subscribeConfig._service_name)
- self._subscribe_sessions.append(session)
- return session
-
- def createNetworkSpecifier(self, role: int, service_name: str,
- pmk: Optional[bytes] = None,
- passphrase: Optional[str] = None) -> Any:
- return None
-
- def createNetworkSpecifier(self, role: int, service_name: str,
- peer_handle: Any,
- pmk: Optional[bytes] = None,
- passphrase: Optional[str] = None) -> Any:
- return None
-
- def sendMessage(self, peerHandle: Any, message: bytes, messageId: int):
- pass
-
- def close(self):
- self._open = False
-
- def toString(self) -> str:
- return f"WifiAwareSession@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiAwareManager
-# ═══════════════════════════════════════════════════════════════
-
-class WifiAwareManager(Stub):
- """WifiAwareManager — Wi-Fi Aware 管理器"""
-
- WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0
- WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1
- ACTION_WIFI_AWARE_STATE_CHANGED = "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED"
-
- def __init__(self):
- super().__init__()
- self._available: bool = True
- self._sessions: List[WifiAwareSession] = []
-
- # ── Attach ──
-
- def attach(self, callback: AttachCallback, handler: Any = None) -> None:
- session = WifiAwareSession()
- self._sessions.append(session)
- callback.onAttached(session)
-
- def attach(self, attachCallback: AttachCallback,
- identityChangedListener: IdentityChangedListener,
- handler: Any = None) -> None:
- session = WifiAwareSession()
- self._sessions.append(session)
- attachCallback.onAttached(session)
-
- # ── Characteristics ──
-
- def getCharacteristics(self) -> Characteristics:
- return Characteristics()
-
- # ── Available ──
-
- def isAvailable(self) -> bool:
- return self._available
-
- def toString(self) -> str:
- return f"WifiAwareManager{{available={self._available}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "WifiAwareManager",
- "WifiAwareSession",
- "PublishConfig",
- "SubscribeConfig",
- "DiscoverySession",
- "PublishDiscoverySession",
- "SubscribeDiscoverySession",
- "DiscoverySessionCallback",
- "Characteristics",
- "AttachCallback",
- "IdentityChangedListener",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/net_wifi_rtt.py b/android_pyapi/android/net_wifi_rtt.py
deleted file mode 100644
index 147435a..0000000
--- a/android_pyapi/android/net_wifi_rtt.py
+++ /dev/null
@@ -1,319 +0,0 @@
-"""
-Android net.wifi.rtt 包 — RttManager, RangingRequest, RangingResult,
-ResponderLocation, WifiRttManager
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "RttManager",
- "RangingResultCallback",
- "RangingRequest",
- "RangingResult",
- "ResponderLocation",
- "WifiRttManager",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# RangingResultCallback
-# ═══════════════════════════════════════════════════════════════
-
-class RangingResultCallback(Stub):
- """RangingResultCallback — 测距结果回调"""
-
- def __init__(self):
- super().__init__()
-
- def onRangingResults(self, results: List["RangingResult"]) -> None:
- """测距结果回调"""
- pass
-
- def onRangingFailure(self, reason: int) -> None:
- """测距失败回调"""
- pass
-
- def onRangingAborted(self) -> None:
- """测距中止回调"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# RangingRequest
-# ═══════════════════════════════════════════════════════════════
-
-class RangingRequest(Stub):
- """RangingRequest — 测距请求"""
-
- class Builder(Stub):
- """Builder — 测距请求构建器"""
-
- def __init__(self):
- super().__init__()
- self._access_points: List[Any] = []
- self._channel_width = 0
- self._preamble = 0
-
- def addAccessPoint(self, access_point: Any) -> "RangingRequest.Builder":
- """添加接入点"""
- self._access_points.append(access_point)
- return self
-
- def addAccessPoints(self, access_points: List[Any]) -> "RangingRequest.Builder":
- """添加多个接入点"""
- self._access_points.extend(access_points)
- return self
-
- def setChannelWidth(self, channel_width: int) -> "RangingRequest.Builder":
- """设置信道宽度"""
- self._channel_width = channel_width
- return self
-
- def setPreamble(self, preamble: int) -> "RangingRequest.Builder":
- """设置前导码"""
- self._preamble = preamble
- return self
-
- def build(self) -> "RangingRequest":
- """构建测距请求"""
- req = RangingRequest()
- req._access_points = self._access_points.copy()
- req._channel_width = self._channel_width
- req._preamble = self._preamble
- return req
-
- def __init__(self):
- super().__init__()
- self._access_points: List[Any] = []
- self._channel_width = 0
- self._preamble = 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# RangingResult
-# ═══════════════════════════════════════════════════════════════
-
-class RangingResult(Stub):
- """RangingResult — 测距结果"""
-
- STATUS_SUCCESS = 0
- STATUS_FAIL = 1
- STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC = 2
-
- def __init__(self, mac_address: str = "00:00:00:00:00:00", status: int = STATUS_SUCCESS,
- rssi: int = 0, distance_mm: int = 0, distance_std_dev_mm: int = 0,
- timestamp: int = 0, num_attempted: int = 0, num_successful: int = 0,
- is_80211mc: bool = False):
- super().__init__()
- self._mac_address = mac_address
- self._status = status
- self._rssi = rssi
- self._distance_mm = distance_mm
- self._distance_std_dev_mm = distance_std_dev_mm
- self._timestamp = timestamp
- self._num_attempted = num_attempted
- self._num_successful = num_successful
- self._is_80211mc = is_80211mc
- self._responder_location: Optional["ResponderLocation"] = None
- self._unconfirmed_location: Optional["ResponderLocation"] = None
- self._location_timestamp = 0
-
- def getMacAddress(self) -> str:
- """获取 MAC 地址"""
- return self._mac_address
-
- def getStatus(self) -> int:
- """获取状态"""
- return self._status
-
- def getRssi(self) -> int:
- """获取 RSSI"""
- return self._rssi
-
- def getDistanceMm(self) -> int:
- """获取距离(毫米)"""
- return self._distance_mm
-
- def getDistanceStdDevMm(self) -> int:
- """获取距离标准差(毫米)"""
- return self._distance_std_dev_mm
-
- def getTimestamp(self) -> int:
- """获取时间戳"""
- return self._timestamp
-
- def getNumAttemptedMeasurements(self) -> int:
- """获取尝试测量次数"""
- return self._num_attempted
-
- def getNumSuccessfulMeasurements(self) -> int:
- """获取成功测量次数"""
- return self._num_successful
-
- def is80211mcMeasurement(self) -> bool:
- """检查是否为 802.11mc 测量"""
- return self._is_80211mc
-
- def getResponderLocation(self) -> Optional["ResponderLocation"]:
- """获取响应者位置"""
- return self._responder_location
-
- def getUnconfirmedLocation(self) -> Optional["ResponderLocation"]:
- """获取未确认的位置"""
- return self._unconfirmed_location
-
- def getLocationTimestamp(self) -> int:
- """获取位置时间戳"""
- return self._location_timestamp
-
-
-# ═══════════════════════════════════════════════════════════════
-# ResponderLocation
-# ═══════════════════════════════════════════════════════════════
-
-class ResponderLocation(Stub):
- """ResponderLocation — 响应者位置"""
-
- def __init__(self):
- super().__init__()
- self._lci = False
- self._lcr = False
- self._latitude = 0.0
- self._longitude = 0.0
- self._altitude = 0.0
- self._floor_number = 0
- self._height_above_floor = 0.0
- self._height_floor = 0.0
- self._expected_to_move = False
- self._location_accuracy_micros = 0
- self._altitude_accuracy = 0.0
-
- def isLci(self) -> bool:
- """检查是否为 LCI"""
- return self._lci
-
- def isLcr(self) -> bool:
- """检查是否为 LCR"""
- return self._lcr
-
- def getLatitude(self) -> float:
- """获取纬度"""
- return self._latitude
-
- def getLongitude(self) -> float:
- """获取经度"""
- return self._longitude
-
- def getAltitude(self) -> float:
- """获取海拔"""
- return self._altitude
-
- def getFloorNumber(self) -> int:
- """获取楼层号"""
- return self._floor_number
-
- def getHeightAboveFloorMeters(self) -> float:
- """获取距离本层地面高度(米)"""
- return self._height_above_floor
-
- def getHeightFloorMeters(self) -> float:
- """获取本层高度(米)"""
- return self._height_floor
-
- def getExpectedToMove(self) -> bool:
- """检查是否预期移动"""
- return self._expected_to_move
-
- def getLocationAccuracyMicros(self) -> int:
- """获取位置精度(微秒)"""
- return self._location_accuracy_micros
-
- def getAltitudeAccuracy(self) -> float:
- """获取海拔精度"""
- return self._altitude_accuracy
-
- def toString(self) -> str:
- return f"ResponderLocation(lat={self._latitude}, lon={self._longitude})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RttManager (original/deprecated)
-# ═══════════════════════════════════════════════════════════════
-
-class RttManager(Stub):
- """RttManager — RTT 管理器(已废弃)(桌面存根)"""
-
- def __init__(self):
- super().__init__()
- self._callbacks: Dict[int, RangingResultCallback] = {}
-
- def startRanging(self, request: RangingRequest, callback: RangingResultCallback) -> None:
- """开始测距"""
- pass
-
- def stopRanging(self, request: RangingRequest) -> None:
- """停止测距"""
- pass
-
- def registerCallback(self, callback: RangingResultCallback) -> None:
- """注册回调"""
- callback_id = id(callback)
- self._callbacks[callback_id] = callback
-
- def unregisterCallback(self, callback: RangingResultCallback) -> None:
- """注销回调"""
- callback_id = id(callback)
- self._callbacks.pop(callback_id, None)
-
-
-# ═══════════════════════════════════════════════════════════════
-# WifiRttManager (newer replacement API)
-# ═══════════════════════════════════════════════════════════════
-
-class WifiRttManager(Stub):
- """WifiRttManager — Wi-Fi RTT 管理器 (桌面存根)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._available = False
- self._results: List[RangingResult] = []
-
- def startRanging(self, request: RangingRequest, executor: Any,
- callback: RangingResultCallback) -> None:
- """开始测距"""
- pass
-
- def cancelRanging(self, request: RangingRequest) -> None:
- """取消测距"""
- pass
-
- def registerRangingResultCallback(self, executor: Any,
- callback: RangingResultCallback) -> None:
- """注册测距结果回调"""
- pass
-
- def unregisterRangingResultCallback(self, callback: RangingResultCallback) -> None:
- """注销测距结果回调"""
- pass
-
- def isAvailable(self) -> bool:
- """检查 RTT 是否可用"""
- return self._available
-
- def setRangingResultCallback(self, callback: RangingResultCallback) -> None:
- """设置测距结果回调"""
- pass
-
- def getRangingResults(self) -> List[RangingResult]:
- """获取测距结果"""
- return self._results.copy()
\ No newline at end of file
diff --git a/android_pyapi/android/nfc.py b/android_pyapi/android/nfc.py
deleted file mode 100644
index a747fe9..0000000
--- a/android_pyapi/android/nfc.py
+++ /dev/null
@@ -1,390 +0,0 @@
-"""
-Android NFC 组件 — NfcAdapter, NfcManager, Tag, NdefMessage 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# NdefRecord
-# ═══════════════════════════════════════════════════════════════
-
-class NdefRecord(Stub):
- """NdefRecord — NDEF 记录"""
-
- TNF_ABSOLUTE_URI = 3
- TNF_EMPTY = 0
- TNF_EXTERNAL_TYPE = 4
- TNF_MIME_MEDIA = 2
- TNF_UNCHANGED = 6
- TNF_UNKNOWN = 5
- TNF_WELL_KNOWN = 1
-
- RTD_URI = "U"
- RTD_TEXT = "T"
- RTD_SMART_POSTER = "Sp"
- RTD_ALTERNATIVE_CARRIER = "ac"
- RTD_HANDOVER_CARRIER = "Hc"
- RTD_HANDOVER_REQUEST = "Hr"
- RTD_HANDOVER_SELECT = "Hs"
-
- def __init__(self, tnf: int = TNF_EMPTY, type_: bytes = b"",
- id_: bytes = b"", payload: bytes = b""):
- super().__init__()
- self._tnf = tnf
- self._type = type_
- self._id = id_
- self._payload = payload
-
- @staticmethod
- def createUri(uri_spec: str) -> "NdefRecord":
- return NdefRecord(NdefRecord.TNF_ABSOLUTE_URI,
- type_=uri_spec.encode("utf-8"),
- payload=uri_spec.encode("utf-8"))
-
- @staticmethod
- def createMime(mime_type: str, data: bytes) -> "NdefRecord":
- return NdefRecord(NdefRecord.TNF_MIME_MEDIA,
- type_=mime_type.encode("utf-8"),
- payload=data)
-
- @staticmethod
- def createExternal(domain: str, type_: str, data: bytes) -> "NdefRecord":
- full_type = f"{domain}:{type_}"
- return NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE,
- type_=full_type.encode("utf-8"),
- payload=data)
-
- @staticmethod
- def createApplicationRecord(package_name: str) -> "NdefRecord":
- return NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE,
- type_=package_name.encode("utf-8"),
- payload=package_name.encode("utf-8"))
-
- def getTnf(self) -> int:
- return self._tnf
-
- def getType(self) -> bytes:
- return self._type
-
- def getId(self) -> bytes:
- return self._id
-
- def getPayload(self) -> bytes:
- return self._payload
-
- def toByteArray(self) -> bytes:
- import struct
- tnf_byte = struct.pack("B", self._tnf & 0x07)
- type_len = len(self._type)
- id_len = len(self._id)
- payload_len = len(self._payload)
- header = struct.pack("BB", type_len, id_len)
- return tnf_byte + header + struct.pack(">I", payload_len) + \
- self._type + self._id + self._payload
-
- def toString(self) -> str:
- return f"NdefRecord(tnf={self._tnf}, type={self._type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NdefMessage
-# ═══════════════════════════════════════════════════════════════
-
-class NdefMessage(Stub):
- """NdefMessage — NDEF 消息"""
-
- def __init__(self, records: Union[List[NdefRecord], bytes, Any]):
- super().__init__()
- if isinstance(records, list):
- self._records = list(records)
- elif isinstance(records, bytes):
- self._records = []
- else:
- self._records = []
-
- def getRecords(self) -> List[NdefRecord]:
- return list(self._records)
-
- def getByteArrayLength(self) -> int:
- return sum(len(r.toByteArray()) for r in self._records)
-
- def toByteArray(self) -> bytes:
- data = b""
- for r in self._records:
- data += r.toByteArray()
- return data
-
-
-# ═══════════════════════════════════════════════════════════════
-# Tag
-# ═══════════════════════════════════════════════════════════════
-
-class Tag(Stub):
- """Tag — NFC 标签"""
-
- def __init__(self, id_: bytes = b"", tech_list: Optional[List[str]] = None):
- super().__init__()
- self._id = id_
- self._tech_list = tech_list or []
-
- def getId(self) -> bytes:
- return self._id
-
- def getTechList(self) -> List[str]:
- return list(self._tech_list)
-
- def getTechListParcelable(self) -> Any:
- return TechListParcelable(self._tech_list)
-
- def toString(self) -> str:
- return f"Tag(id={self._id.hex()}, techs={self._tech_list})"
-
-
-class TechListParcelable(Stub):
- """TechListParcelable — 技术列表包裹"""
-
- def __init__(self, tech_list: List[str]):
- super().__init__()
- self._tech_list = list(tech_list)
-
- def getTechList(self) -> List[str]:
- return list(self._tech_list)
-
- def toString(self) -> str:
- return f"TechListParcelable(techs={self._tech_list})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcAdapter callback classes
-# ═══════════════════════════════════════════════════════════════
-
-class NfcAdapterCreateBeamUrisCallback(Stub):
- def createBeamUris(self, event: "NfcEvent") -> List[Any]:
- return []
-
-
-class NfcAdapterOnNdefPushCompleteCallback(Stub):
- def onNdefPushComplete(self, event: "NfcEvent"):
- pass
-
-
-class NdefMessageCallback(Stub):
- def createNdefMessage(self, event: "NfcEvent") -> Optional[NdefMessage]:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcEvent
-# ═══════════════════════════════════════════════════════════════
-
-class NfcEvent(Stub):
- """NfcEvent — NFC 事件"""
-
- def __init__(self, nfc_adapter: Any = None):
- super().__init__()
- self.nfcAdapter = nfc_adapter
-
- def getNfcAdapter(self) -> Any:
- return self.nfcAdapter
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcAntennaInfo / ApduServiceInfo / CardEmulation / NfcFCardEmulation
-# ═══════════════════════════════════════════════════════════════
-
-class NfcAntennaInfo(Stub):
- """NfcAntennaInfo — NFC 天线信息"""
-
- def __init__(self, x: float = 0.0, y: float = 0.0):
- super().__init__()
- self._x = x
- self._y = y
-
- def getX(self) -> float:
- return self._x
-
- def getY(self) -> float:
- return self._y
-
-
-class ApduServiceInfo(Stub):
- """ApduServiceInfo — APDU 服务信息"""
-
- def __init__(self, description: str = ""):
- super().__init__()
- self._description = description
-
- def getDescription(self) -> str:
- return self._description
-
-
-class CardEmulation(Stub):
- """CardEmulation — 卡模拟"""
-
- CATEGORY_PAYMENT = "payment"
- CATEGORY_OTHER = "other"
-
- SELECTION_TYPE_ASK_IF_CONFLICT = 1
- SELECTION_TYPE_PREFER_DEFAULT = 2
- SELECTION_TYPE_USER_PROMPTED = 0
-
-
-class NfcFCardEmulation(Stub):
- """NfcFCardEmulation — NFC-F 卡模拟"""
-
- EXTRA_NFC_F_CARD_EMULATION_PARAMS = "android.nfc.extra.EXTRA_NFC_F_CARD_EMULATION_PARAMS"
-
- @staticmethod
- def getInstance(nfc_adapter: Any) -> "NfcFCardEmulation":
- return NfcFCardEmulation()
-
- def enableService(self, activity: Any, service: Any) -> bool:
- return True
-
- def disableService(self, activity: Any, service: Any) -> bool:
- return True
-
- def setSystemCodeForService(self, activity: Any, service: Any, system_code: str) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcManager
-# ═══════════════════════════════════════════════════════════════
-
-class NfcManager(Stub):
- """NfcManager — NFC 管理器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._default_adapter: Optional["NfcAdapter"] = None
-
- def getDefaultAdapter(self) -> Optional["NfcAdapter"]:
- if self._default_adapter is None:
- self._default_adapter = NfcAdapter()
- return self._default_adapter
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class NfcAdapter(Stub):
- """NfcAdapter — NFC 适配器"""
-
- ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED"
- ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED"
- ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"
-
- FLAG_READER_NFC_A = 1
- FLAG_READER_NFC_B = 2
- FLAG_READER_NFC_F = 4
- FLAG_READER_NFC_V = 8
- FLAG_READER_NFC_BARCODE = 16
- FLAG_READER_SKIP_NDEF_CHECK = 128
- FLAG_READER_NO_PLATFORM_SOUNDS = 256
-
- FLAG_NDEF_PUSH_NO_CONFIRM = 1
-
- _default_adapter: Optional["NfcAdapter"] = None
-
- def __init__(self):
- super().__init__()
- self._enabled = True
- self._ndef_push_message: Optional[NdefMessage] = None
- self._ndef_push_callback: Optional[NdefMessageCallback] = None
- self._push_complete_callback: Optional[NfcAdapterOnNdefPushCompleteCallback] = None
- self._beam_uri_callback: Optional[NfcAdapterCreateBeamUrisCallback] = None
-
- @staticmethod
- def getDefaultAdapter(context: Any = None) -> Optional["NfcAdapter"]:
- if NfcAdapter._default_adapter is None:
- NfcAdapter._default_adapter = NfcAdapter()
- return NfcAdapter._default_adapter
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def enable(self) -> bool:
- self._enabled = True
- return True
-
- def disable(self) -> bool:
- self._enabled = False
- return True
-
- def setNdefPushMessage(self, message: NdefMessage, activity: Any,
- vararg_activities: Any = None):
- self._ndef_push_message = message
-
- def setNdefPushMessageCallback(self, callback: NdefMessageCallback, activity: Any,
- vararg_activities: Any = None):
- self._ndef_push_callback = callback
-
- def setOnNdefPushCompleteCallback(self, callback: NfcAdapterOnNdefPushCompleteCallback,
- activity: Any, vararg_activities: Any = None):
- self._push_complete_callback = callback
-
- def setBeamUrisCallback(self, callback: NfcAdapterCreateBeamUrisCallback, activity: Any):
- self._beam_uri_callback = callback
-
- def enableForegroundDispatch(self, activity: Any, intent: Any,
- filters: Any, tech_lists: Any):
- pass
-
- def disableForegroundDispatch(self, activity: Any):
- pass
-
- def enableReaderMode(self, activity: Any, callback: Any, flags: int, extras: Any = None):
- pass
-
- def disableReaderMode(self, activity: Any):
- pass
-
- def invokeBeam(self, activity: Any) -> bool:
- return True
-
- def isSecureNfcSupported(self) -> bool:
- return False
-
- def isSecureNfcEnabled(self) -> bool:
- return False
-
- def enableSecureNfc(self, enable: bool) -> bool:
- return True
-
- def toString(self) -> str:
- return f"NfcAdapter(enabled={self._enabled})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "NfcAdapter",
- "NfcManager",
- "Tag",
- "NdefMessage",
- "NdefRecord",
- "NfcEvent",
- "NfcAdapterCreateBeamUrisCallback",
- "NfcAdapterOnNdefPushCompleteCallback",
- "NdefMessageCallback",
- "TechListParcelable",
- "NfcAntennaInfo",
- "ApduServiceInfo",
- "CardEmulation",
- "NfcFCardEmulation",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/nfc_ext.py b/android_pyapi/android/nfc_ext.py
deleted file mode 100644
index 721105c..0000000
--- a/android_pyapi/android/nfc_ext.py
+++ /dev/null
@@ -1,816 +0,0 @@
-"""
-Android nfc 扩展 — NfcAdapter, NdefMessage, NdefRecord, Tag, Tech,
-NfcA, NfcB, NfcF, NfcV, IsoDep, MifareClassic, MifareUltralight,
-NdefFormatable, CardEmulation, HostApduService, OffHostApduService
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "NfcAdapter",
- "NdefMessage",
- "NdefRecord",
- "Tag",
- "Tech",
- "NfcA",
- "NfcB",
- "NfcF",
- "NfcV",
- "NfcBarcode",
- "IsoDep",
- "MifareClassic",
- "MifareUltralight",
- "NdefFormatable",
- "CardEmulation",
- "HostApduService",
- "OffHostApduService",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# NdefRecord
-# ═══════════════════════════════════════════════════════════════
-
-class NdefRecord(Stub):
- """NdefRecord — NDEF 记录"""
-
- TNF_EMPTY = 0x00
- TNF_ABSOLUTE_URI = 0x03
- TNF_MEDIA = 0x02
- TNF_WELL_KNOWN = 0x01
- TNF_UNCHANGED = 0x06
- TNF_RESERVED = 0x07
- TNF_EXTERNAL_TYPE = 0x04
-
- RTD_TEXT = b"T"
- RTD_URI = b"U"
- RTD_SMART_POSTER = b"Sp"
- RTD_ALTERNATIVE_CARRIER = b"ac"
- RTD_HANDOVER_CARRIER = b"Hc"
- RTD_HANDOVER_REQUEST = b"Hr"
- RTD_HANDOVER_SELECT = b"Hr"
-
- def __init__(self, tnf: int = TNF_EMPTY, type_: bytes = b"",
- id_: bytes = b"", payload: bytes = b""):
- super().__init__()
- self._tnf = tnf
- self._type = type_
- self._id = id_
- self._payload = payload
-
- @property
- def tnf(self) -> int:
- return self._tnf
-
- @property
- def type(self) -> bytes:
- return self._type
-
- @property
- def id(self) -> bytes:
- return self._id
-
- @property
- def payload(self) -> bytes:
- return self._payload
-
- def getTnf(self) -> int:
- """获取 TNF"""
- return self._tnf
-
- def getType(self) -> bytes:
- """获取类型"""
- return self._type
-
- def getId(self) -> bytes:
- """获取 ID"""
- return self._id
-
- def getPayload(self) -> bytes:
- """获取载荷"""
- return self._payload
-
- def toByteArray(self) -> bytes:
- """转换为字节数组"""
- return self._tnf.to_bytes(1, 'big') + self._type + self._id + self._payload
-
- def toString(self) -> str:
- return f"NdefRecord(tnf={self._tnf}, type={self._type}, id={self._id}, payload={self._payload})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, NdefRecord):
- return False
- return (self._tnf == other._tnf and self._type == other._type
- and self._id == other._id and self._payload == other._payload)
-
- def hashCode(self) -> int:
- return hash((self._tnf, self._type, self._id, self._payload)) & 0x7FFFFFFF
-
- @staticmethod
- def createUri(uri: str) -> "NdefRecord":
- """创建 URI 记录"""
- return NdefRecord(NdefRecord.TNF_ABSOLUTE_URI, b"U", b"", uri.encode())
-
- @staticmethod
- def createMime(mime_type: str, data: bytes) -> "NdefRecord":
- """创建 MIME 记录"""
- return NdefRecord(NdefRecord.TNF_MEDIA, mime_type.encode(), b"", data)
-
- @staticmethod
- def createApplication(package_name: str) -> "NdefRecord":
- """创建应用记录"""
- return NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE,
- b"android.com:pkg", b"", package_name.encode())
-
- @staticmethod
- def createExternal(domain: str, type_: str, data: bytes) -> "NdefRecord":
- """创建外部类型记录"""
- return NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE,
- f"{domain}:{type_}".encode(), b"", data)
-
-
-# ═══════════════════════════════════════════════════════════════
-# NdefMessage
-# ═══════════════════════════════════════════════════════════════
-
-class NdefMessage(Stub):
- """NdefMessage — NDEF 消息"""
-
- def __init__(self, records: Optional[List[NdefRecord]] = None):
- super().__init__()
- self._records = records or []
-
- @staticmethod
- def fromBytes(data: bytes) -> "NdefMessage":
- """从字节数组创建消息"""
- return NdefMessage()
-
- def getRecords(self) -> List[NdefRecord]:
- """获取记录列表"""
- return self._records.copy()
-
- def getByteArray(self) -> bytes:
- """获取字节数组"""
- return b"".join(r.toByteArray() for r in self._records)
-
- def toByteArray(self) -> bytes:
- """转换为字节数组"""
- return self.getByteArray()
-
- def toString(self) -> str:
- return f"NdefMessage(records={len(self._records)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Tag
-# ═══════════════════════════════════════════════════════════════
-
-class Tag(Stub):
- """Tag — NFC 标签 (桌面存根)"""
-
- def __init__(self, id_: bytes = b"", tech_list: Optional[List[str]] = None):
- super().__init__()
- self._id = id_
- self._tech_list = tech_list or []
- self._service_name = ""
-
- def getId(self) -> bytes:
- """获取标签 ID"""
- return self._id
-
- def getTechList(self) -> List[str]:
- """获取技术列表"""
- return self._tech_list.copy()
-
- def toString(self) -> str:
- return f"Tag(id={self._id.hex()}, techs={self._tech_list})"
-
- def hashCode(self) -> int:
- return hash(bytes(self._id)) & 0x7FFFFFFF
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, Tag):
- return False
- return self._id == other._id
-
- def getServiceName(self) -> str:
- """获取服务名称"""
- return self._service_name
-
- def getTagService(self) -> Optional[Any]:
- """获取标签服务"""
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# Tech
-# ═══════════════════════════════════════════════════════════════
-
-class Tech(Stub):
- """Tech — NFC 技术基类 (桌面存根)"""
-
- PRESENCE_CHECK_DELAY = 125
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__()
- self._tag = tag
- self._connected = False
- self._timeout = 500
-
- @staticmethod
- def get(tag: Tag, tech_class: Any) -> Optional["Tech"]:
- """获取技术实例"""
- return None
-
- def getTag(self) -> Optional[Tag]:
- """获取标签"""
- return self._tag
-
- def connect(self) -> None:
- """连接"""
- self._connected = True
-
- def reconnect(self) -> None:
- """重新连接"""
- pass
-
- def close(self) -> None:
- """关闭"""
- self._connected = False
-
- def getConnected(self) -> bool:
- """检查是否已连接"""
- return self._connected
-
- def isConnected(self) -> bool:
- """检查是否已连接"""
- return self._connected
-
- def getMaxTransceiveLength(self) -> int:
- """获取最大收发长度"""
- return 253
-
- def setTimeout(self, timeout: int) -> None:
- """设置超时"""
- self._timeout = timeout
-
- def getTimeout(self) -> int:
- """获取超时"""
- return self._timeout
-
- def transceive(self, data: bytes) -> bytes:
- """收发数据"""
- return b""
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcA
-# ═══════════════════════════════════════════════════════════════
-
-class NfcA(Tech):
- """NfcA — NFC-A 技术"""
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__(tag)
- self._atqa = b"\x00\x00"
- self._sak = 0
-
- def getAtqa(self) -> bytes:
- """获取 ATQA"""
- return self._atqa
-
- def getSak(self) -> int:
- """获取 SAK"""
- return self._sak
-
- def getMaxTransceiveLength(self) -> int:
- return 253
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcB
-# ═══════════════════════════════════════════════════════════════
-
-class NfcB(Tech):
- """NfcB — NFC-B 技术"""
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__(tag)
- self._application_data = b""
- self._protocol_info = b""
-
- def getApplicationData(self) -> bytes:
- """获取应用数据"""
- return self._application_data
-
- def getProtocolInfo(self) -> bytes:
- """获取协议信息"""
- return self._protocol_info
-
- def getMaxTransceiveLength(self) -> int:
- return 253
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcF
-# ═══════════════════════════════════════════════════════════════
-
-class NfcF(Tech):
- """NfcF — NFC-F 技术"""
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__(tag)
- self._manufacturer = 0
- self._sc = 0
- self._system_code = 0
- self._pmm = b""
-
- def getManufacturer(self) -> int:
- """获取制造商"""
- return self._manufacturer
-
- def getSC(self) -> int:
- """获取 SC"""
- return self._sc
-
- def getSystemCode(self) -> int:
- """获取系统代码"""
- return self._system_code
-
- def getPMm(self) -> bytes:
- """获取 PMm"""
- return self._pmm
-
- def getMaxTransceiveLength(self) -> int:
- return 253
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcV
-# ═══════════════════════════════════════════════════════════════
-
-class NfcV(Tech):
- """NfcV — NFC-V 技术"""
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__(tag)
- self._dsf_id = 0
- self._response_flags = 0
- self._identification = b""
-
- def getDsfId(self) -> int:
- """获取 DSF ID"""
- return self._dsf_id
-
- def getResponseFlags(self) -> int:
- """获取响应标志"""
- return self._response_flags
-
- def getIdentification(self) -> bytes:
- """获取标识"""
- return self._identification
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcBarcode
-# ═══════════════════════════════════════════════════════════════
-
-class NfcBarcode(Tech):
- """NfcBarcode — NFC 条码技术"""
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__(tag)
-
-
-# ═══════════════════════════════════════════════════════════════
-# IsoDep
-# ═══════════════════════════════════════════════════════════════
-
-class IsoDep(Tech):
- """IsoDep — ISO-DEP 技术"""
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__(tag)
- self._hi_layer_response = b""
- self._historical_bytes = b""
- self._extended_length_supported = False
-
- def getHiLayerResponse(self) -> bytes:
- """获取高层响应"""
- return self._hi_layer_response
-
- def getHistoricalBytes(self) -> bytes:
- """获取历史字节"""
- return self._historical_bytes
-
- def setTimeout(self, timeout: int) -> None:
- self._timeout = timeout
-
- def getTimeout(self) -> int:
- return self._timeout
-
- def getMaxTransceiveLength(self) -> int:
- return 261 if self._extended_length_supported else 128
-
- def isExtendedLengthApduSupported(self) -> bool:
- """检查是否支持扩展长度 APDU"""
- return self._extended_length_supported
-
- def transceive(self, data: bytes) -> bytes:
- return b"\x90\x00" # SW1=0x90, SW2=0x00 = success
-
-
-# ═══════════════════════════════════════════════════════════════
-# MifareClassic
-# ═══════════════════════════════════════════════════════════════
-
-class MifareClassic(Tech):
- """MifareClassic — MIFARE Classic 技术"""
-
- TYPE_CLASSIC = 0
- TYPE_PLUS = 1
- TYPE_PRO = 2
- TYPE_UNKNOWN = -1
- SIZE_1K = 1024
- SIZE_2K = 2048
- SIZE_4K = 4096
- SIZE_MINI = 320
- KEY_DEFAULT = b"\xFF\xFF\xFF\xFF\xFF\xFF"
- KEY_MIFARE_APPLICATION_DIRECTORY = b"\xA0\xA1\xA2\xA3\xA4\xA5"
- KEY_NFC_FORUM = b"\xD3\xF7\xD3\xF7\xD3\xF7"
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__(tag)
- self._type = MifareClassic.TYPE_CLASSIC
- self._size = MifareClassic.SIZE_1K
-
- def authenticateSectorWithKeyA(self, sector_index: int, key: bytes) -> bool:
- """使用密钥 A 认证扇区"""
- return False
-
- def authenticateSectorWithKeyB(self, sector_index: int, key: bytes) -> bool:
- """使用密钥 B 认证扇区"""
- return False
-
- def readBlock(self, block_index: int) -> bytes:
- """读取块"""
- return b"\x00" * 16
-
- def writeBlock(self, block_index: int, data: bytes) -> None:
- """写入块"""
- pass
-
- def readSector(self, sector_index: int) -> List[bytes]:
- """读取扇区"""
- return [b"\x00" * 16] * 4
-
- def writeSector(self, sector_index: int, data: List[bytes]) -> None:
- """写入扇区"""
- pass
-
- @staticmethod
- def sectorToBlock(sector_index: int) -> int:
- """扇区索引转块索引"""
- if sector_index < 32:
- return sector_index * 4
- return 32 * 4 + (sector_index - 32) * 16
-
- @staticmethod
- def blockToSector(block_index: int) -> int:
- """块索引转扇区索引"""
- if block_index < 128:
- return block_index // 4
- return 32 + (block_index - 128) // 16
-
- @staticmethod
- def getBlockCountInSector(sector_index: int) -> int:
- """获取扇区中的块数量"""
- return 4 if sector_index < 32 else 16
-
- def isEmulated(self) -> bool:
- """检查是否模拟"""
- return False
-
- def getMaxTransceiveLength(self) -> int:
- return 16
-
-
-# ═══════════════════════════════════════════════════════════════
-# MifareUltralight
-# ═══════════════════════════════════════════════════════════════
-
-class MifareUltralight(Tech):
- """MifareUltralight — MIFARE Ultralight 技术"""
-
- TYPE_ULTRALIGHT = 1
- TYPE_ULTRALIGHT_C = 2
- TYPE_ULTRALIGHT_EV1 = 3
- TYPE_NTAG_2xx = 4
- TYPE_UNKNOWN = -1
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__(tag)
- self._type = MifareUltralight.TYPE_ULTRALIGHT
-
- def readPages(self, page_offset: int) -> bytes:
- """读取页"""
- return b"\x00" * 16
-
- def writePage(self, page_offset: int, data: bytes) -> None:
- """写入页"""
- pass
-
- def setTimeout(self, timeout: int) -> None:
- self._timeout = timeout
-
- def getTimeout(self) -> int:
- return self._timeout
-
- def getMaxTransceiveLength(self) -> int:
- return 16
-
-
-# ═══════════════════════════════════════════════════════════════
-# NdefFormatable
-# ═══════════════════════════════════════════════════════════════
-
-class NdefFormatable(Tech):
- """NdefFormatable — NDEF 可格式化技术"""
-
- def __init__(self, tag: Optional[Tag] = None):
- super().__init__(tag)
-
- def format(self, first_message: NdefMessage) -> None:
- """格式化"""
- pass
-
- def formatReadOnly(self, first_message: NdefMessage) -> None:
- """格式化为只读"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# NfcAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class NfcAdapter(Stub):
- """NfcAdapter — NFC 适配器 (桌面存根)"""
-
- ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED"
- ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED"
- ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"
- ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED"
- EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE"
- STATE_OFF = 1
- STATE_TURNING_ON = 2
- STATE_ON = 3
- STATE_TURNING_OFF = 4
- EXTRA_TAG = "android.nfc.extra.TAG"
- EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES"
- EXTRA_ID = "android.nfc.extra.ID"
- FLAG_READER_NFC_A = 0x01
- FLAG_READER_NFC_B = 0x02
- FLAG_READER_NFC_F = 0x04
- FLAG_READER_NFC_V = 0x08
- FLAG_READER_NFC_BARCODE = 0x10
- FLAG_READER_SKIP_NDEF_CHECK = 0x20
- FLAG_READER_NO_PLATFORM_SOUNDS = 0x40
- FLAG_READER_LISTEN_MODE = 0x80
-
- _instance: Optional["NfcAdapter"] = None
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._enabled = True
- self._ndef_push_enabled = False
- self._secure_nfc_enabled = False
- self._reader_mode_flags = 0
- self._tech_list: List[str] = []
- self._foreground_dispatch_active = False
- self._foreground_reader_active = False
-
- @staticmethod
- def getDefaultAdapter(context: Any) -> Optional["NfcAdapter"]:
- """获取默认适配器"""
- if NfcAdapter._instance is None:
- NfcAdapter._instance = NfcAdapter(context)
- return NfcAdapter._instance
-
- def isEnabled(self) -> bool:
- """检查 NFC 是否启用"""
- return self._enabled
-
- def enableForegroundDispatch(self, activity: Any, intent: Any,
- filters: List[Any], tech_lists: List[List[str]]) -> None:
- """启用前台分发"""
- self._foreground_dispatch_active = True
-
- def disableForegroundDispatch(self, activity: Any) -> None:
- """禁用前台分发"""
- self._foreground_dispatch_active = False
-
- def enableForegroundReader(self, activity: Any, flags: int,
- tech_lists: List[List[str]]) -> None:
- """启用前台读取器"""
- self._foreground_reader_active = True
- self._reader_mode_flags = flags
-
- def disableForegroundReader(self, activity: Any) -> None:
- """禁用前台读取器"""
- self._foreground_reader_active = False
-
- def enableReaderMode(self, activity: Any, callback: Any, flags: int,
- extras: Any = None) -> None:
- """启用读取器模式"""
- self._reader_mode_flags = flags
-
- def disableReaderMode(self, activity: Any) -> None:
- """禁用读取器模式"""
- self._reader_mode_flags = 0
-
- def setNdefPushMessage(self, message: NdefMessage, activity: Any,
- *activities: Any) -> None:
- """设置 NDEF 推送消息"""
- pass
-
- def setNdefPushMessageCallback(self, callback: Any, activity: Any,
- *activities: Any) -> None:
- """设置 NDEF 推送消息回调"""
- pass
-
- def setOnNdefPushCompleteCallback(self, callback: Any, activity: Any,
- *activities: Any) -> None:
- """设置 NDEF 推送完成回调"""
- pass
-
- def enableNdefPush(self, activity: Any) -> None:
- """启用 NDEF 推送"""
- self._ndef_push_enabled = True
-
- def disableNdefPush(self, activity: Any) -> None:
- """禁用 NDEF 推送"""
- self._ndef_push_enabled = False
-
- def isNdefPushEnabled(self) -> bool:
- """检查 NDEF 推送是否启用"""
- return self._ndef_push_enabled
-
- def createNdefMessage(self, message: NdefMessage) -> None:
- """创建 NDEF 消息"""
- pass
-
- def getNfcAdapterExtrasInterface(self) -> Optional[Any]:
- """获取 NFC 适配器附加接口"""
- return None
-
- def isSecureNfcSupported(self) -> bool:
- """检查是否支持安全 NFC"""
- return True
-
- def isSecureNfcEnabled(self) -> bool:
- """检查安全 NFC 是否启用"""
- return self._secure_nfc_enabled
-
- def enableSecureNfc(self, enabled: bool) -> bool:
- """启用安全 NFC"""
- self._secure_nfc_enabled = enabled
- return True
-
- def disableSecureNfc(self) -> bool:
- """禁用安全 NFC"""
- self._secure_nfc_enabled = False
- return True
-
- def getMaxTransceiveLength(self, tech: str) -> int:
- """获取最大收发长度"""
- return 253
-
- def getTechList(self) -> List[str]:
- """获取技术列表"""
- return self._tech_list.copy()
-
- def setTechList(self, tech_list: List[str]) -> None:
- """设置技术列表"""
- self._tech_list = tech_list
-
-
-# ═══════════════════════════════════════════════════════════════
-# CardEmulation
-# ═══════════════════════════════════════════════════════════════
-
-class CardEmulation(Stub):
- """CardEmulation — 卡模拟 (桌面存根)"""
-
- CATEGORY_PAYMENT = "payment"
- CATEGORY_OTHER = "other"
- SELECTION_MODE_PREFER_DEFAULT = 0
- SELECTION_MODE_ALWAYS_ASK = 1
-
- def __init__(self):
- super().__init__()
- self._aid_groups: Dict[str, List[Any]] = {}
- self._selection_modes: Dict[str, int] = {}
-
- def isDefaultServiceForCategory(self, service_component: Any, category: str) -> bool:
- """检查是否是类别的默认服务"""
- return False
-
- def setPreferredService(self, service_component: Any) -> None:
- """设置首选服务"""
- pass
-
- def unsetPreferredService(self) -> None:
- """取消设置首选服务"""
- pass
-
- def getSelectionModes(self, category: str) -> int:
- """获取选择模式"""
- return self._selection_modes.get(category, CardEmulation.SELECTION_MODE_PREFER_DEFAULT)
-
- def setSelectionModeForCategory(self, category: str, mode: int) -> None:
- """设置类别选择模式"""
- self._selection_modes[category] = mode
-
- def getCategory(self, service_component: Any) -> str:
- """获取类别"""
- return CardEmulation.CATEGORY_OTHER
-
- def registerAidGroup(self, service_component: Any, aid_group: Any) -> bool:
- """注册 AID 组"""
- return False
-
- def unregisterAidGroup(self, service_component: Any, aid_group: Any) -> bool:
- """注销 AID 组"""
- return False
-
- def setAidGroup(self, service_component: Any, aid_group: Any) -> None:
- """设置 AID 组"""
- pass
-
- def getAidGroup(self, service_component: Any, category: str) -> Optional[Any]:
- """获取 AID 组"""
- return None
-
- def addAidGroup(self, service_component: Any, aid_group: Any) -> None:
- """添加 AID 组"""
- pass
-
- def removeAidGroup(self, service_component: Any, aid_group: Any) -> None:
- """移除 AID 组"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# HostApduService
-# ═══════════════════════════════════════════════════════════════
-
-class HostApduService(Stub):
- """HostApduService — 主机 APDU 服务 (桌面存根)"""
-
- SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE"
- SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service"
- DEACTIVATION_LINK_LOSS = 0
- DEACTIVATION_DESELECTED = 1
-
- def __init__(self):
- super().__init__()
-
- def processCommandApdu(self, command_apdu: bytes, extras: Any = None) -> bytes:
- """处理命令 APDU"""
- return b"\x90\x00"
-
- def onDeactivated(self, reason: int) -> None:
- """去激活回调"""
- pass
-
- def sendResponseApdu(self, response_apdu: bytes) -> None:
- """发送响应 APDU"""
- pass
-
- def notifyUnhandled(self) -> None:
- """通知未处理"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# OffHostApduService
-# ═══════════════════════════════════════════════════════════════
-
-class OffHostApduService(Stub):
- """OffHostApduService — 脱机主机 APDU 服务 (桌面存根)"""
-
- SERVICE_INTERFACE = "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"
- SERVICE_META_DATA = "android.nfc.cardemulation.off_host_apdu_service"
-
- def __init__(self):
- super().__init__()
\ No newline at end of file
diff --git a/android_pyapi/android/opengl.py b/android_pyapi/android/opengl.py
deleted file mode 100644
index ef85a1c..0000000
--- a/android_pyapi/android/opengl.py
+++ /dev/null
@@ -1,464 +0,0 @@
-"""
-Android OpenGL 组件 — GLSurfaceView, GLU, GLUtils, EGL14 等
-方法签名完全对齐 Android SDK (android.opengl 包)
-"""
-
-import math
-from typing import Any, Callable, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# EGL 常量
-# ═══════════════════════════════════════════════════════════════
-
-class EGL14(Stub):
- """EGL14 — EGL 1.4 API 常量 (桌面仅提供常量)"""
-
- # EGL 布尔值
- EGL_TRUE = 1
- EGL_FALSE = 0
-
- # EGL 错误码
- EGL_SUCCESS = 0x3000
- EGL_NOT_INITIALIZED = 0x3001
- EGL_BAD_ACCESS = 0x3002
- EGL_BAD_ALLOC = 0x3003
- EGL_BAD_ATTRIBUTE = 0x3004
- EGL_BAD_CONFIG = 0x3005
- EGL_BAD_CONTEXT = 0x3006
- EGL_BAD_CURRENT_SURFACE = 0x3007
- EGL_BAD_DISPLAY = 0x3008
- EGL_BAD_MATCH = 0x3009
- EGL_BAD_NATIVE_PIXMAP = 0x300A
- EGL_BAD_NATIVE_WINDOW = 0x300B
- EGL_BAD_PARAMETER = 0x300C
- EGL_BAD_SURFACE = 0x300D
- EGL_CONTEXT_LOST = 0x300E
-
- # EGL 配置属性
- EGL_BUFFER_SIZE = 0x3020
- EGL_ALPHA_SIZE = 0x3021
- EGL_BLUE_SIZE = 0x3022
- EGL_GREEN_SIZE = 0x3023
- EGL_RED_SIZE = 0x3024
- EGL_DEPTH_SIZE = 0x3025
- EGL_STENCIL_SIZE = 0x3026
- EGL_CONFIG_CAVEAT = 0x3027
- EGL_CONFIG_ID = 0x3028
- EGL_LEVEL = 0x3029
- EGL_MAX_PBUFFER_HEIGHT = 0x302A
- EGL_MAX_PBUFFER_PIXELS = 0x302B
- EGL_MAX_PBUFFER_WIDTH = 0x302C
- EGL_NATIVE_RENDERABLE = 0x302D
- EGL_NATIVE_VISUAL_ID = 0x302E
- EGL_NATIVE_VISUAL_TYPE = 0x302F
- EGL_PRESERVED_RESOURCES = 0x3030
- EGL_SAMPLES = 0x3031
- EGL_SAMPLE_BUFFERS = 0x3032
- EGL_SURFACE_TYPE = 0x3033
- EGL_TRANSPARENT_TYPE = 0x3034
- EGL_TRANSPARENT_BLUE_VALUE = 0x3035
- EGL_TRANSPARENT_GREEN_VALUE = 0x3036
- EGL_TRANSPARENT_RED_VALUE = 0x3037
- EGL_NONE = 0x3038
- EGL_BIND_TO_TEXTURE_RGB = 0x3039
- EGL_BIND_TO_TEXTURE_RGBA = 0x303A
- EGL_MIN_SWAP_INTERVAL = 0x303B
- EGL_MAX_SWAP_INTERVAL = 0x303C
-
- # EGL 表面属性
- EGL_WIDTH = 0x3057
- EGL_HEIGHT = 0x3056
- EGL_LARGEST_PBUFFER = 0x3058
- EGL_TEXTURE_FORMAT = 0x3080
- EGL_TEXTURE_TARGET = 0x3081
- EGL_MIPMAP_TEXTURE = 0x3082
- EGL_MIPMAP_LEVEL = 0x3083
-
- # EGL 渲染上下文属性
- EGL_CONTEXT_CLIENT_TYPE = 0x3097
- EGL_CONTEXT_CLIENT_VERSION = 0x3098
-
- # EGL 显示
- EGL_DEFAULT_DISPLAY = 0
-
- # EGL 版本
- EGL_VERSION_1_4 = 1
-
- # OpenGL ES 位标记
- EGL_OPENGL_ES_BIT = 0x0001
- EGL_OPENGL_ES2_BIT = 0x0004
- EGL_OPENGL_ES3_BIT = 0x0040
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def eglGetDisplay(display_id: Any) -> "EGLDisplay":
- """获取 EGL 显示 (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglGetDisplay() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglInitialize(display: "EGLDisplay", major_minor: Optional[List[int]] = None) -> bool:
- """初始化 EGL (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglInitialize() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglChooseConfig(display: "EGLDisplay", attrib_list: List[int],
- configs: List[Any], config_size: int,
- num_config: List[int]) -> bool:
- """选择 EGL 配置 (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglChooseConfig() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglCreateContext(display: "EGLDisplay", config: "EGLConfig",
- share_context: "EGLContext",
- attrib_list: List[int]) -> "EGLContext":
- """创建 EGL 上下文 (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglCreateContext() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglCreateWindowSurface(display: "EGLDisplay", config: "EGLConfig",
- win: Any, attrib_list: List[int]) -> "EGLSurface":
- """创建窗口表面 (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglCreateWindowSurface() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglMakeCurrent(display: "EGLDisplay", draw: "EGLSurface",
- read: "EGLSurface", context: "EGLContext") -> bool:
- """绑定 EGL 上下文 (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglMakeCurrent() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglSwapBuffers(display: "EGLDisplay", surface: "EGLSurface") -> bool:
- """交换缓冲区 (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglSwapBuffers() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglDestroyContext(display: "EGLDisplay", context: "EGLContext") -> bool:
- """销毁 EGL 上下文 (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglDestroyContext() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglDestroySurface(display: "EGLDisplay", surface: "EGLSurface") -> bool:
- """销毁表面 (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglDestroySurface() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglTerminate(display: "EGLDisplay") -> bool:
- """终止 EGL (桌面仅返回存根)"""
- raise AndroidOnlyError("EGL14.eglTerminate() 仅在 Android 设备上可用")
-
- @staticmethod
- def eglGetError() -> int:
- """获取 EGL 错误码"""
- return EGL14.EGL_SUCCESS
-
- @staticmethod
- def eglQueryString(display: "EGLDisplay", name: int) -> str:
- """查询 EGL 字符串"""
- if name == 0x3029: # EGL_VERSION
- return "1.4 (desktop stub)"
- return ""
-
- def toString(self) -> str:
- return "EGL14(desktop-stub)"
-
-
-class EGLDisplay(Stub):
- """EGLDisplay — EGL 显示连接"""
-
- def __init__(self):
- super().__init__()
-
- def toString(self) -> str:
- return f"EGLDisplay@{hex(id(self))}"
-
- def hashCode(self) -> int:
- return hash(id(self)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-class EGLConfig(Stub):
- """EGLConfig — EGL 帧缓冲配置"""
-
- def __init__(self):
- super().__init__()
-
- def toString(self) -> str:
- return f"EGLConfig@{hex(id(self))}"
-
- def hashCode(self) -> int:
- return hash(id(self)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-class EGLContext(Stub):
- """EGLContext — EGL 渲染上下文"""
-
- def __init__(self):
- super().__init__()
-
- def toString(self) -> str:
- return f"EGLContext@{hex(id(self))}"
-
- def hashCode(self) -> int:
- return hash(id(self)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-class EGLSurface(Stub):
- """EGLSurface — EGL 渲染表面"""
-
- def __init__(self):
- super().__init__()
-
- def toString(self) -> str:
- return f"EGLSurface@{hex(id(self))}"
-
- def hashCode(self) -> int:
- return hash(id(self)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# GLSurfaceView
-# ═══════════════════════════════════════════════════════════════
-
-class GLSurfaceView(Stub):
- """GLSurfaceView — OpenGL 渲染视图 (桌面存根)"""
-
- # 渲染模式
- RENDERMODE_CONTINUOUSLY = 1
- RENDERMODE_WHEN_DIRTY = 0
-
- # 调试标志
- DEBUG_CHECK_GL_ERROR = 1
- DEBUG_LOG_GL_CALLS = 2
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._renderer: Optional[Any] = None
- self._render_mode: int = GLSurfaceView.RENDERMODE_CONTINUOUSLY
- self._egl_context_client_version: int = 2
- self._preserve_egl_context_on_pause: bool = False
- self._debug_flags: int = 0
- self._paused: bool = False
- self._queue: List[Callable] = []
-
- def setRenderer(self, renderer: Any):
- """设置渲染器"""
- self._renderer = renderer
- if renderer:
- renderer.onSurfaceCreated(None, None)
- renderer.onSurfaceChanged(None, 0, 0)
-
- def setRenderMode(self, render_mode: int):
- """设置渲染模式"""
- self._render_mode = render_mode
-
- def getRenderMode(self) -> int:
- """获取渲染模式"""
- return self._render_mode
-
- def onPause(self):
- """暂停渲染"""
- self._paused = True
-
- def onResume(self):
- """恢复渲染"""
- self._paused = False
-
- def queueEvent(self, r: Callable):
- """将事件排入 GL 线程队列"""
- self._queue.append(r)
- # 立即执行 (桌面模拟)
- try:
- r()
- except Exception:
- pass
-
- def requestRender(self):
- """请求渲染"""
- if self._renderer and not self._paused:
- self._renderer.onDrawFrame(None)
-
- def setEGLContextClientVersion(self, version: int):
- """设置 EGL 客户端版本"""
- self._egl_context_client_version = version
-
- def setPreserveEGLContextOnPause(self, preserve: bool):
- """设置暂停时是否保留 EGL 上下文"""
- self._preserve_egl_context_on_pause = preserve
-
- def setDebugFlags(self, debug_flags: int):
- """设置调试标志"""
- self._debug_flags = debug_flags
-
- def getPreserveEGLContextOnPause(self) -> bool:
- return self._preserve_egl_context_on_pause
-
- def surfaceCreated(self, holder: Any):
- """表面创建回调"""
- pass
-
- def surfaceDestroyed(self, holder: Any):
- """表面销毁回调"""
- pass
-
- def surfaceChanged(self, holder: Any, format: int, w: int, h: int):
- """表面变化回调"""
- pass
-
- def toString(self) -> str:
- return f"GLSurfaceView(renderMode={self._render_mode}, paused={self._paused})"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# GLU
-# ═══════════════════════════════════════════════════════════════
-
-class GLU(Stub):
- """GLU — OpenGL 实用工具函数"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def gluLookAt(eye_x: float, eye_y: float, eye_z: float,
- center_x: float, center_y: float, center_z: float,
- up_x: float, up_y: float, up_z: float):
- """定义视图变换 (桌面仅抛异常)"""
- raise AndroidOnlyError("GLU.gluLookAt() 仅在 Android (OpenGL) 设备上可用")
-
- @staticmethod
- def gluPerspective(fov_y: float, aspect: float, z_near: float, z_far: float):
- """设置透视投影 (桌面仅抛异常)"""
- raise AndroidOnlyError("GLU.gluPerspective() 仅在 Android (OpenGL) 设备上可用")
-
- @staticmethod
- def gluOrtho2D(left: float, right: float, bottom: float, top: float):
- """设置正交投影 (桌面仅抛异常)"""
- raise AndroidOnlyError("GLU.gluOrtho2D() 仅在 Android (OpenGL) 设备上可用")
-
- @staticmethod
- def gluProject(obj_x: float, obj_y: float, obj_z: float,
- model: List[float], proj: List[float],
- viewport: List[int]) -> Tuple[bool, float, float, float]:
- """将对象坐标映射到窗口坐标"""
- win_x = (obj_x * proj[0] + 1.0) * viewport[2] / 2.0 + viewport[0]
- win_y = (obj_y * proj[5] + 1.0) * viewport[3] / 2.0 + viewport[1]
- win_z = obj_z * proj[10] + proj[11]
- return True, win_x, win_y, win_z
-
- @staticmethod
- def gluUnProject(win_x: float, win_y: float, win_z: float,
- model: List[float], proj: List[float],
- viewport: List[int]) -> Tuple[bool, float, float, float]:
- """将窗口坐标映射到对象坐标"""
- obj_x = 2.0 * (win_x - viewport[0]) / viewport[2] - 1.0
- obj_y = 2.0 * (win_y - viewport[1]) / viewport[3] - 1.0
- obj_z = win_z * 2.0 - 1.0
- return True, obj_x, obj_y, obj_z
-
- @staticmethod
- def gluErrorString(error: int) -> str:
- """返回 OpenGL 错误描述字符串"""
- errors = {
- 0x0500: "GL_INVALID_ENUM",
- 0x0501: "GL_INVALID_VALUE",
- 0x0502: "GL_INVALID_OPERATION",
- 0x0503: "GL_STACK_OVERFLOW",
- 0x0504: "GL_STACK_UNDERFLOW",
- 0x0505: "GL_OUT_OF_MEMORY",
- 0x0506: "GL_INVALID_FRAMEBUFFER_OPERATION",
- }
- return errors.get(error, f"Unknown error 0x{error:04X}")
-
- def toString(self) -> str:
- return "GLU(desktop-stub)"
-
- def hashCode(self) -> int:
- return hash("android.opengl.GLU") & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return isinstance(other, GLU)
-
-
-# ═══════════════════════════════════════════════════════════════
-# GLUtils
-# ═══════════════════════════════════════════════════════════════
-
-class GLUtils(Stub):
- """GLUtils — OpenGL 工具函数"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInternalFormat(bitmap: Any) -> int:
- """获取位图的内部格式"""
- return 0x1908 # GL_RGBA
-
- @staticmethod
- def getType(bitmap: Any) -> int:
- """获取位图数据类型"""
- return 0x1401 # GL_UNSIGNED_BYTE
-
- @staticmethod
- def texImage2D(target: int, level: int, internal_format: int,
- bitmap: Any, border: int = 0):
- """上传 2D 纹理图像"""
- raise AndroidOnlyError("GLUtils.texImage2D() 仅在 Android (OpenGL) 设备上可用")
-
- @staticmethod
- def texSubImage2D(target: int, level: int, xoffset: int, yoffset: int,
- bitmap: Any, format: int = -1, type_: int = -1):
- """更新 2D 纹理子图像"""
- raise AndroidOnlyError("GLUtils.texSubImage2D() 仅在 Android (OpenGL) 设备上可用")
-
- @staticmethod
- def toString(bitmap_or_buffer: Any) -> str:
- return str(bitmap_or_buffer)
-
- def toString(self) -> str:
- return "GLUtils(desktop-stub)"
-
- def hashCode(self) -> int:
- return hash("android.opengl.GLUtils") & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return isinstance(other, GLUtils)
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "GLSurfaceView",
- "GLU",
- "GLUtils",
- "EGL14",
- "EGLConfig",
- "EGLContext",
- "EGLDisplay",
- "EGLSurface",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/os.py b/android_pyapi/android/os.py
deleted file mode 100644
index da6ab4d..0000000
--- a/android_pyapi/android/os.py
+++ /dev/null
@@ -1,2370 +0,0 @@
-"""
-Android OS 组件 — Bundle, Handler, Looper, Message, Build 等
-方法签名完全对齐 Android SDK
-"""
-
-import asyncio
-import functools
-import heapq
-import os as _os
-import sys
-import threading
-import time as _time
-from datetime import datetime
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, TypeVar, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
- HAS_PSUTIL,
-)
-
-# Linux 真实实现导入
-try:
- from .._linux_impl import IS_LINUX, LinuxPower, LinuxProcess, HAS_PSUTIL as _HAS_PSUTIL
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Build
-# ═══════════════════════════════════════════════════════════════
-
-class Build(Stub):
- """Build — 设备信息"""
-
- class VERSION(Stub):
- """版本信息"""
- SDK_INT = 34 # Android 14
- RELEASE = "14"
- INCREMENTAL = "20240301"
- CODENAME = "REL"
- SECURITY_PATCH = "2024-03-05"
- BASE_OS = ""
- PREVIEW_SDK_INT = 0
- RESOURCES_SDK_INT = 34
- MEDIA_PERFORMANCE_CLASS = 0
-
- class VERSION_CODES(Stub):
- """版本代码常量"""
- BASE = 1
- BASE_1_1 = 2
- CUPCAKE = 3
- DONUT = 4
- ECLAIR = 5
- ECLAIR_0_1 = 6
- ECLAIR_MR1 = 7
- FROYO = 8
- GINGERBREAD = 9
- GINGERBREAD_MR1 = 10
- HONEYCOMB = 11
- HONEYCOMB_MR1 = 12
- HONEYCOMB_MR2 = 13
- ICE_CREAM_SANDWICH = 14
- ICE_CREAM_SANDWICH_MR1 = 15
- JELLY_BEAN = 16
- JELLY_BEAN_MR1 = 17
- JELLY_BEAN_MR2 = 18
- KITKAT = 19
- KITKAT_WATCH = 20
- LOLLIPOP = 21
- LOLLIPOP_MR1 = 22
- M = 23
- N = 24
- N_MR1 = 25
- O = 26
- O_MR1 = 27
- P = 28
- Q = 29
- R = 30
- S = 31
- S_V2 = 32
- TIRAMISU = 33
- UPSIDE_DOWN_CAKE = 34
-
- VERSION = VERSION()
- BOARD = "redfin"
- BOOTLOADER = "r7.0-12345"
- BRAND = "google"
- CPU_ABI = "arm64-v8a"
- CPU_ABI2 = ""
- DEVICE = "redfin"
- DISPLAY = "AP1A.240305.001"
- FINGERPRINT = "google/redfin/redfin:14/AP1A.240305.001/12345678:user/release-keys"
- HARDWARE = "redfin"
- HOST = "build-test-01"
- ID = "AP1A.240305.001"
- MANUFACTURER = "Google"
- MODEL = "Pixel 5"
- ODM_SKU = None
- PRODUCT = "redfin"
- RADIO = ""
- SERIAL = "unknown"
- SKU = None
- SOC_MANUFACTURER = "Qualcomm"
- SOC_MODEL = "Snapdragon 765G"
- SUPPORTED_32_BIT_ABIS = ["armeabi-v7a", "armeabi"]
- SUPPORTED_64_BIT_ABIS = ["arm64-v8a"]
- SUPPORTED_ABIS = ["arm64-v8a", "armeabi-v7a", "armeabi"]
- TAGS = "release-keys"
- TIME = int(_time.time() * 1000)
- TYPE = "user"
- USER = "build-user"
-
- @staticmethod
- def getRadioVersion() -> str:
- """返回基带/无线电版本。桌面端无无线电硬件,返回空字符串。"""
- return Build.RADIO
-
- @staticmethod
- def getSerial() -> str:
- """返回设备序列号。尝试从 /sys 或 /proc 读取真实硬件序列号。"""
- # 尝试从 /sys/class/android_usb 读取
- try:
- for name in _os.listdir("/sys/class/android_usb"):
- serial_path = f"/sys/class/android_usb/{name}/iSerial"
- if _os.path.exists(serial_path):
- with open(serial_path, "r") as f:
- serial = f.read().strip()
- if serial:
- return serial
- except (OSError, IOError):
- pass
- # 尝试从 /proc/cpuinfo 读取 Serial 字段
- try:
- with open("/proc/cpuinfo", "r") as f:
- for line in f:
- if line.lower().startswith("serial"):
- parts = line.split(":", 1)
- if len(parts) == 2:
- serial = parts[1].strip()
- if serial and serial != "0" * len(serial):
- return serial
- except (OSError, IOError):
- pass
- # 尝试从 /sys/class/dmi/id/product_serial 读取
- try:
- path = "/sys/class/dmi/id/product_serial"
- if _os.path.exists(path):
- with open(path, "r") as f:
- serial = f.read().strip()
- if serial:
- return serial
- except (OSError, IOError):
- pass
- return Build.SERIAL
-
- @staticmethod
- def getFingerprint() -> str:
- return Build.FINGERPRINT
-
- @classmethod
- def _populate_from_linux(cls):
- """从 LinuxProcess.get_system_info() 填充真实设备信息"""
- try:
- info = LinuxProcess.get_system_info() or {}
- import platform as _platform
- import socket as _socket
- hostname = info.get("hostname") or _socket.gethostname()
- system = info.get("platform") or _platform.system()
- arch = info.get("arch") or _platform.machine()
- kernel = info.get("kernel") or _platform.release()
- cls.MODEL = hostname
- cls.MANUFACTURER = "Linux"
- cls.BRAND = system
- cls.DEVICE = arch
- cls.BOARD = arch
- cls.HARDWARE = arch
- cls.HOST = hostname
- cls.PRODUCT = hostname
- cls.DISPLAY = kernel
- cls.ID = kernel
- # FINGERPRINT: brand/device/device:version/id/build:user/release-keys
- cls.FINGERPRINT = (
- f"{system}/{hostname}/{arch}:Linux/{kernel}/{hostname}:user/release-keys"
- )
- # CPU ABI 用架构映射
- _abi_map = {
- "x86_64": "x86_64", "amd64": "x86_64",
- "aarch64": "arm64-v8a", "arm64": "arm64-v8a",
- "x86": "x86", "i386": "x86", "i686": "x86",
- "armv7l": "armeabi-v7a", "arm": "armeabi-v7a",
- }
- cls.CPU_ABI = _abi_map.get(arch, arch)
- cls.SUPPORTED_ABIS = [cls.CPU_ABI]
- cls.SUPPORTED_64_BIT_ABIS = [cls.CPU_ABI] if "64" in cls.CPU_ABI else []
- cls.SUPPORTED_32_BIT_ABIS = [cls.CPU_ABI] if "64" not in cls.CPU_ABI else []
- except Exception:
- pass
-
-
-# 在 Linux 上用真实系统信息填充 Build
-if _USE_LINUX:
- Build._populate_from_linux()
-
-
-# ═══════════════════════════════════════════════════════════════
-# SystemClock
-# ═══════════════════════════════════════════════════════════════
-
-class SystemClock(Stub):
- """SystemClock — 系统时钟"""
-
- @staticmethod
- def elapsedRealtime() -> int:
- """返回自启动以来的毫秒数"""
- return int(_time.monotonic() * 1000)
-
- @staticmethod
- def elapsedRealtimeNanos() -> int:
- return int(_time.monotonic_ns())
-
- @staticmethod
- def uptimeMillis() -> int:
- """返回自启动以来(不含深度睡眠)的毫秒数"""
- return int(_time.monotonic() * 1000)
-
- @staticmethod
- def currentThreadTimeMillis() -> int:
- return int(_time.clock_gettime(_time.CLOCK_THREAD_CPUTIME_ID) * 1000)
-
- @staticmethod
- def sleep(ms: int):
- _time.sleep(ms / 1000.0)
-
- @staticmethod
- def setCurrentTimeMillis(millis: int) -> bool:
- """尝试设置系统时间。需要 root 权限,通常在桌面端会失败。"""
- try:
- import subprocess
- seconds = millis / 1000.0
- # 尝试使用 date 命令设置时间
- result = subprocess.run(
- ["date", "-s", f"@{int(seconds)}"],
- capture_output=True, timeout=5)
- return result.returncode == 0
- except Exception:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Environment
-# ═══════════════════════════════════════════════════════════════
-
-class Environment(Stub):
- """Environment — 环境目录"""
-
- MEDIA_BAD_REMOVAL = "bad_removal"
- MEDIA_CHECKING = "checking"
- MEDIA_EJECTING = "ejecting"
- MEDIA_MOUNTED = "mounted"
- MEDIA_MOUNTED_READ_ONLY = "mounted_ro"
- MEDIA_NOFS = "nofs"
- MEDIA_REMOVED = "removed"
- MEDIA_SHARED = "shared"
- MEDIA_UNKNOWN = "unknown"
- MEDIA_UNMOUNTABLE = "unmountable"
- MEDIA_UNMOUNTED = "unmounted"
-
- DIRECTORY_ALARMS = "Alarms"
- DIRECTORY_DCIM = "DCIM"
- DIRECTORY_DOCUMENTS = "Documents"
- DIRECTORY_DOWNLOADS = "Download"
- DIRECTORY_MOVIES = "Movies"
- DIRECTORY_MUSIC = "Music"
- DIRECTORY_NOTIFICATIONS = "Notifications"
- DIRECTORY_PICTURES = "Pictures"
- DIRECTORY_PODCASTS = "Podcasts"
- DIRECTORY_RINGTONES = "Ringtones"
- DIRECTORY_AUDIOBOOKS = "Audiobooks"
- DIRECTORY_SCREENSHOTS = "Screenshots"
-
- @staticmethod
- def getExternalStorageDirectory() -> str:
- return _sdcard_root
-
- @staticmethod
- def getExternalStoragePublicDirectory(type_: str) -> str:
- path = _os.path.join(_sdcard_root, type_)
- _os.makedirs(path, exist_ok=True)
- return path
-
- @staticmethod
- def getDataDirectory() -> str:
- return _os.path.join(_app_data_dir, "data")
-
- @staticmethod
- def getDownloadCacheDirectory() -> str:
- return _os.path.join(_app_data_dir, "cache", "download")
-
- @staticmethod
- def getRootDirectory() -> str:
- return _os.path.abspath(_os.sep)
-
- @staticmethod
- def getStorageDirectory(user_handle: Any = None) -> str:
- return _sdcard_root
-
- @staticmethod
- def getExternalStorageState(path: Optional[str] = None) -> str:
- return Environment.MEDIA_MOUNTED
-
- @staticmethod
- def isExternalStorageRemovable(path: Optional[str] = None) -> bool:
- """判断外部存储是否可移除。通过检查 /proc/mounts 判断。"""
- try:
- check_path = path or _sdcard_root
- with open("/proc/mounts", "r") as f:
- for line in f:
- parts = line.split()
- if len(parts) >= 3 and check_path in parts[1]:
- # 检查挂载选项中是否包含 SD 卡相关设备
- device = parts[0]
- if "/sd" in device or "/mmc" in device or "/usb" in device:
- return True
- return False
- except (OSError, IOError):
- pass
- return False
-
- @staticmethod
- def isExternalStorageEmulated(path: Optional[str] = None) -> bool:
- return True
-
- @staticmethod
- def isExternalStorageLegacy(path: Optional[str] = None) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# Process
-# ═══════════════════════════════════════════════════════════════
-
-class Process(Stub):
- """Process — 进程信息"""
-
- # 进程优先级
- THREAD_PRIORITY_DEFAULT = 0
- THREAD_PRIORITY_LOWEST = -19
- THREAD_PRIORITY_BACKGROUND = 10
- THREAD_PRIORITY_FOREGROUND = -2
- THREAD_PRIORITY_DISPLAY = -4
- THREAD_PRIORITY_URGENT_DISPLAY = -8
- THREAD_PRIORITY_AUDIO = -16
- THREAD_PRIORITY_URGENT_AUDIO = -19
- THREAD_PRIORITY_MORE_FAVORABLE = -1
- THREAD_PRIORITY_LESS_FAVORABLE = 1
-
- SIGNAL_KILL = 9
- SIGNAL_QUIT = 3
- SIGNAL_USR1 = 10
- SIGNAL_USR2 = 12
-
- @staticmethod
- def myTid() -> int:
- return threading.get_ident()
-
- @staticmethod
- def myUid() -> int:
- """返回当前进程的真实 UID。"""
- return _os.getuid()
-
- @staticmethod
- def myPid() -> int:
- return _os.getpid()
-
- @staticmethod
- def killProcess(pid):
- import signal
- try:
- _os.kill(pid, signal.SIGKILL)
- except (OSError, ProcessLookupError):
- pass
-
- @staticmethod
- def sendSignal(pid, signal_num):
- try:
- _os.kill(pid, signal_num)
- except (OSError, ProcessLookupError):
- pass
-
- @staticmethod
- def setThreadPriority(*args):
- """设置线程优先级。支持 setThreadPriority(priority) 和 setThreadPriority(tid, priority)。"""
- if len(args) == 1:
- tid = 0
- priority = args[0]
- elif len(args) == 2:
- tid, priority = args
- else:
- return
- try:
- _os.setpriority(_os.PRIO_PROCESS, tid, priority)
- except (OSError, PermissionError):
- pass
-
- @staticmethod
- def getElapsedCpuTime() -> int:
- return int(_time.clock_gettime(_time.CLOCK_PROCESS_CPUTIME_ID) * 1000)
-
- @staticmethod
- def supportsProcesses() -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# BaseBundle / PersistableBundle
-# ═══════════════════════════════════════════════════════════════
-
-class BaseBundle(Stub):
- """BaseBundle — Bundle 基类"""
-
- def __init__(self):
- super().__init__()
- self._map: Dict[str, Any] = {}
- self._class_loader = None
-
- def getString(self, key: str, default: Optional[str] = None) -> Optional[str]:
- v = self._map.get(key, default)
- return str(v) if v is not None else default
-
- def getInt(self, key: str, default: int = 0) -> int:
- v = self._map.get(key, default)
- try:
- return int(v) if v is not None else default
- except (ValueError, TypeError):
- return default
-
- def getLong(self, key: str, default: int = 0) -> int:
- return self.getInt(key, default)
-
- def getFloat(self, key: str, default: float = 0.0) -> float:
- v = self._map.get(key, default)
- try:
- return float(v) if v is not None else default
- except (ValueError, TypeError):
- return default
-
- def getDouble(self, key: str, default: float = 0.0) -> float:
- return self.getFloat(key, default)
-
- def getBoolean(self, key: str, default: bool = False) -> bool:
- v = self._map.get(key, default)
- if isinstance(v, bool):
- return v
- if isinstance(v, str):
- return v.lower() in ("true", "1", "yes")
- return bool(v) if v is not None else default
-
- def getByte(self, key: str, default: int = 0) -> int:
- return self.getInt(key, default)
-
- def getChar(self, key: str, default: str = "") -> str:
- return str(self._map.get(key, default))
-
- def getShort(self, key: str, default: int = 0) -> int:
- return self.getInt(key, default)
-
- def getCharSequence(self, key: str, default: Optional[str] = None) -> Optional[str]:
- return self.getString(key, default)
-
- def getSerializable(self, key: str, default: Any = None) -> Any:
- return self._map.get(key, default)
-
- def getStringArrayList(self, key: str) -> Optional[List[str]]:
- v = self._map.get(key)
- if isinstance(v, list):
- return [str(x) for x in v]
- return None
-
- def getIntegerArrayList(self, key: str) -> Optional[List[int]]:
- v = self._map.get(key)
- if isinstance(v, list):
- return [int(x) for x in v if isinstance(x, (int, float))]
- return None
-
- def containsKey(self, key: str) -> bool:
- return key in self._map
-
- def isEmpty(self) -> bool:
- return len(self._map) == 0
-
- def size(self) -> int:
- return len(self._map)
-
- def clear(self):
- self._map.clear()
-
- def keySet(self) -> Set[str]:
- return set(self._map.keys())
-
- def hasKey(self, key: str) -> bool:
- return key in self._map
-
- def toString(self) -> str:
- return f"Bundle({self._map})"
-
- def __len__(self) -> int:
- return len(self._map)
-
- def __contains__(self, key: str) -> bool:
- return key in self._map
-
- def __getitem__(self, key: str):
- return self._map[key]
-
- def __setitem__(self, key: str, value: Any):
- self._map[key] = value
-
- def __delitem__(self, key: str):
- self._map.pop(key, None)
-
-
-class PersistableBundle(BaseBundle):
- """PersistableBundle — 可持久化的 Bundle"""
-
- def __init__(self, capacity: int = 0):
- super().__init__()
-
- def putPersistableBundle(self, key: str, value: "PersistableBundle"):
- self._map[key] = value
-
- def getPersistableBundle(self, key: str) -> Optional["PersistableBundle"]:
- v = self._map.get(key)
- return v if isinstance(v, PersistableBundle) else None
-
-
-# ═══════════════════════════════════════════════════════════════
-# Bundle
-# ═══════════════════════════════════════════════════════════════
-
-class Bundle(BaseBundle):
- """Bundle — 键值对数据容器"""
-
- EMPTY: "Bundle" = None # 在类加载后初始化
-
- def __init__(self, capacity: int = 0):
- super().__init__()
- self._capacity = capacity
-
- def putString(self, key: str, value: Optional[str]):
- self._map[key] = value
-
- def putInt(self, key: str, value: int):
- self._map[key] = value
-
- def putLong(self, key: str, value: int):
- self._map[key] = value
-
- def putFloat(self, key: str, value: float):
- self._map[key] = value
-
- def putDouble(self, key: str, value: float):
- self._map[key] = value
-
- def putBoolean(self, key: str, value: bool):
- self._map[key] = value
-
- def putByte(self, key: str, value: int):
- self._map[key] = value
-
- def putChar(self, key: str, value: str):
- self._map[key] = value
-
- def putShort(self, key: str, value: int):
- self._map[key] = value
-
- def putCharSequence(self, key: str, value: Optional[str]):
- self._map[key] = value
-
- def putSerializable(self, key: str, value: Any):
- self._map[key] = value
-
- def putParcelable(self, key: str, value: Any):
- self._map[key] = value
-
- def putStringArrayList(self, key: str, value: Optional[List[str]]):
- self._map[key] = value
-
- def putIntegerArrayList(self, key: str, value: Optional[List[int]]):
- self._map[key] = value
-
- # ---- 数组类型 ----
- def putIntArray(self, key: str, value: Optional[List[int]]):
- self._map[key] = list(value) if value is not None else None
-
- def getIntArray(self, key: str) -> Optional[List[int]]:
- v = self._map.get(key)
- if isinstance(v, list):
- return [int(x) for x in v]
- return None
-
- def putStringArray(self, key: str, value: Optional[List[str]]):
- self._map[key] = list(value) if value is not None else None
-
- def getStringArray(self, key: str) -> Optional[List[str]]:
- v = self._map.get(key)
- if isinstance(v, list):
- return [str(x) for x in v]
- return None
-
- def putLongArray(self, key: str, value: Optional[List[int]]):
- self._map[key] = list(value) if value is not None else None
-
- def getLongArray(self, key: str) -> Optional[List[int]]:
- v = self._map.get(key)
- if isinstance(v, list):
- return [int(x) for x in v]
- return None
-
- def putBooleanArray(self, key: str, value: Optional[List[bool]]):
- self._map[key] = list(value) if value is not None else None
-
- def getBooleanArray(self, key: str) -> Optional[List[bool]]:
- v = self._map.get(key)
- if isinstance(v, list):
- return [bool(x) for x in v]
- return None
-
- def putDoubleArray(self, key: str, value: Optional[List[float]]):
- self._map[key] = list(value) if value is not None else None
-
- def getDoubleArray(self, key: str) -> Optional[List[float]]:
- v = self._map.get(key)
- if isinstance(v, list):
- return [float(x) for x in v]
- return None
-
- def putByteArray(self, key: str, value: Optional[List[int]]):
- self._map[key] = list(value) if value is not None else None
-
- def getByteArray(self, key: str) -> Optional[List[int]]:
- v = self._map.get(key)
- if isinstance(v, list):
- return [int(x) & 0xFF for x in v]
- return None
-
- def putAll(self, bundle: "Bundle"):
- if bundle:
- self._map.update(bundle._map)
-
- def getParcelable(self, key: str, default: Any = None) -> Any:
- return self._map.get(key, default)
-
- def getBundle(self, key: str) -> Optional["Bundle"]:
- v = self._map.get(key)
- return v if isinstance(v, Bundle) else None
-
- def putBundle(self, key: str, value: Optional["Bundle"]):
- self._map[key] = value
-
- def describeContents(self) -> int:
- return 0
-
- def clone(self) -> "Bundle":
- b = Bundle()
- b._map = dict(self._map)
- return b
-
- def deepCopy(self) -> "Bundle":
- import copy
- b = Bundle()
- b._map = copy.deepcopy(self._map)
- return b
-
- def filterValues(self):
- pass
-
- def getPairValue(self) -> Optional[str]:
- return None
-
- def setClassLoader(self, loader: Any):
- self._class_loader = loader
-
- def getClassLoader(self) -> Any:
- return self._class_loader
-
- @staticmethod
- def forPair(key: str, value: str) -> "Bundle":
- b = Bundle()
- b.putString(key, value)
- return b
-
-
-Bundle.EMPTY = Bundle()
-
-
-# ═══════════════════════════════════════════════════════════════
-# Parcel / Parcelable
-# ═══════════════════════════════════════════════════════════════
-
-class Parcelable(Stub):
- """Parcelable 接口"""
-
- CONTENTS_FILE_DESCRIPTOR = "CONTENTS_FILE_DESCRIPTOR"
- PARCELABLE_WRITE_RETURN_VALUE = 1
- PARCELABLE_ELIDE_DUPLICATES = 2
-
- def describeContents(self) -> int:
- return 0
-
- def writeToParcel(self, dest: "Parcel", flags: int):
- pass
-
- class Creator:
- def createFromParcel(self, source: "Parcel"):
- return None
- def newArray(self, size: int):
- return [None] * size
-
- class ClassLoaderCreator:
- def createFromParcel(self, source: "Parcel", loader: Any):
- return None
- def newArray(self, size: int):
- return [None] * size
-
-
-class Parcel(Stub):
- """Parcel — 序列化数据容器"""
-
- STRING_CREATOR = "STRING_CREATOR"
- STRING_LIST_CREATOR = "STRING_LIST_CREATOR"
- INT_CREATOR = "INT_CREATOR"
-
- def __init__(self):
- super().__init__()
- self._data: Dict[str, Any] = {}
- self._position = 0
- self._size = 0
-
- @staticmethod
- def obtain() -> "Parcel":
- return Parcel()
-
- def recycle(self):
- self._data.clear()
- self._position = 0
- self._size = 0
-
- def writeInt(self, value: int):
- self._data.setdefault("_ints", []).append(value)
- self._size += 4
-
- def writeLong(self, value: int):
- self._data.setdefault("_longs", []).append(value)
- self._size += 8
-
- def writeFloat(self, value: float):
- self._data.setdefault("_floats", []).append(value)
- self._size += 4
-
- def writeDouble(self, value: float):
- self._data.setdefault("_doubles", []).append(value)
- self._size += 8
-
- def writeString(self, value: Optional[str]):
- strs = self._data.setdefault("_strings", [])
- strs.append(value)
- self._size += len(value) + 4 if value else 4
-
- def writeBoolean(self, value: bool):
- self.writeInt(1 if value else 0)
-
- def writeByte(self, value: int):
- self.writeInt(value & 0xFF)
-
- def writeParcelable(self, p: Parcelable, flags: int):
- pass
-
- def writeStringArray(self, values: Optional[List[str]]):
- self._data["_string_array"] = values
-
- def writeIntArray(self, values: Optional[List[int]]):
- self._data["_int_array"] = values
-
- def writeLongArray(self, values: Optional[List[int]]):
- self._data["_long_array"] = values
-
- def readInt(self) -> int:
- ints = self._data.get("_ints", [])
- if ints:
- return ints.pop(0)
- return 0
-
- def readLong(self) -> int:
- longs = self._data.get("_longs", [])
- if longs:
- return longs.pop(0)
- return 0
-
- def readFloat(self) -> float:
- floats = self._data.get("_floats", [])
- if floats:
- return floats.pop(0)
- return 0.0
-
- def readDouble(self) -> float:
- doubles = self._data.get("_doubles", [])
- if doubles:
- return doubles.pop(0)
- return 0.0
-
- def readString(self) -> Optional[str]:
- strs = self._data.get("_strings", [])
- if strs:
- return strs.pop(0)
- return None
-
- def readBoolean(self) -> bool:
- return self.readInt() != 0
-
- def readByte(self) -> int:
- return self.readInt() & 0xFF
-
- def dataAvail(self) -> int:
- return self._size - self._position
-
- def dataPosition(self) -> int:
- return self._position
-
- def setDataPosition(self, pos: int):
- self._position = pos
-
- def dataSize(self) -> int:
- return self._size
-
- def dataCapacity(self) -> int:
- return self._size
-
- def setDataCapacity(self, capacity: int):
- pass
-
- def appendFrom(self, parcel: "Parcel", offset: int, length: int):
- pass
-
- def marshall(self) -> bytes:
- import json
- return json.dumps(self._data).encode("utf-8")
-
- @staticmethod
- def unmarshall(data: bytes) -> "Parcel":
- import json
- p = Parcel()
- try:
- p._data = json.loads(data.decode("utf-8"))
- except Exception:
- pass
- return p
-
- def writeValue(self, v: Any):
- self._data["_value"] = v
-
- def readValue(self) -> Any:
- return self._data.get("_value")
-
- def hasFileDescriptors(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"Parcel({self._size} bytes)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Message
-# ═══════════════════════════════════════════════════════════════
-
-class Message(Stub):
- """Message — Handler 消息"""
-
- def __init__(self):
- super().__init__()
- self.what = 0
- self.arg1 = 0
- self.arg2 = 0
- self.obj: Any = None
- self.data: Optional[Bundle] = None
- self.replyTo: Optional["Messenger"] = None
- self._target: Optional["Handler"] = None
- self._callback: Optional[Callable] = None
- self.when: int = 0
- self._sending = False
-
- @staticmethod
- def obtain(handler: Optional["Handler"] = None, what: int = 0) -> "Message":
- msg = Message()
- if handler:
- msg._target = handler
- msg.what = what
- return msg
-
- def sendToTarget(self):
- if self._target:
- self._target.sendMessage(self)
-
- def getTarget(self) -> Optional["Handler"]:
- return self._target
-
- def setTarget(self, handler: "Handler"):
- self._target = handler
-
- @property
- def target(self) -> Optional["Handler"]:
- return self._target
-
- @target.setter
- def target(self, handler: "Handler"):
- self._target = handler
-
- def getCallback(self) -> Optional[Callable]:
- return self._callback
-
- def copyFrom(self, other: "Message"):
- self.what = other.what
- self.arg1 = other.arg1
- self.arg2 = other.arg2
- self.obj = other.obj
- self.data = other.data
- self.replyTo = other.replyTo
-
- def recycle(self):
- self.what = 0
- self.arg1 = 0
- self.arg2 = 0
- self.obj = None
- self.data = None
- self._target = None
- self._callback = None
-
- def isAsynchronous(self) -> bool:
- return False
-
- def setAsynchronous(self, async_: bool):
- pass
-
- def toString(self) -> str:
- return f"Message(what={self.what}, arg1={self.arg1}, arg2={self.arg2})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Looper
-# ═══════════════════════════════════════════════════════════════
-
-class Looper(Stub):
- """Looper — 消息循环"""
-
- _main_looper: Optional["Looper"] = None
- _thread_local = threading.local()
-
- def __init__(self, quit_allowed: bool = True):
- super().__init__()
- self._thread = threading.current_thread()
- self._running = False
- self._message_queue: List[Message] = []
- self._queue_lock = threading.Lock()
- self._quit_allowed = quit_allowed
-
- @staticmethod
- def prepare():
- """为当前线程准备一个 Looper"""
- looper = Looper()
- Looper._thread_local.looper = looper
- return looper
-
- @staticmethod
- def prepareMainLooper():
- if Looper._main_looper is None:
- Looper._main_looper = Looper.prepare()
-
- @staticmethod
- def getMainLooper() -> "Looper":
- if Looper._main_looper is None:
- Looper.prepareMainLooper()
- return Looper._main_looper
-
- @staticmethod
- def myLooper() -> Optional["Looper"]:
- return getattr(Looper._thread_local, "looper", None)
-
- @staticmethod
- def loop():
- """运行消息循环,处理到期的消息"""
- looper = Looper.myLooper()
- if looper is None:
- raise RuntimeError("No Looper prepared")
- looper._running = True
- while looper._running:
- msg = looper._next()
- if msg is not None:
- target = msg._target
- if target is not None:
- target.dispatchMessage(msg)
- msg.recycle()
- else:
- # 无到期消息,短暂 sleep 避免忙等
- _time.sleep(0.001)
-
- def _next(self) -> Optional[Message]:
- """非阻塞地取出一条到期消息(when <= now)"""
- with self._queue_lock:
- now = SystemClock.uptimeMillis()
- for i, msg in enumerate(self._message_queue):
- if msg.when <= now:
- return self._message_queue.pop(i)
- return None
-
- def _enqueue(self, msg: Message):
- """将消息按 when 时间顺序入队"""
- with self._queue_lock:
- inserted = False
- for i, m in enumerate(self._message_queue):
- if msg.when < m.when:
- self._message_queue.insert(i, msg)
- inserted = True
- break
- if not inserted:
- self._message_queue.append(msg)
-
- def _remove_callbacks(self, callback):
- """从队列中移除匹配 callback 的消息"""
- with self._queue_lock:
- self._message_queue = [
- m for m in self._message_queue
- if m._callback is not callback
- ]
-
- def _remove_messages(self, what: int):
- """从队列中移除匹配 what 的消息"""
- with self._queue_lock:
- self._message_queue = [
- m for m in self._message_queue
- if m.what != what
- ]
-
- def _has_messages(self, what: int) -> bool:
- """检查队列中是否有匹配 what 的消息"""
- with self._queue_lock:
- return any(m.what == what for m in self._message_queue)
-
- def quit(self):
- """退出消息循环"""
- if not self._quit_allowed:
- raise RuntimeError("Main Looper is not allowed to quit")
- with self._queue_lock:
- self._running = False
- self._message_queue.clear()
-
- def quitSafely(self):
- """安全退出,仅停止循环(已入队消息不再处理)"""
- with self._queue_lock:
- self._running = False
-
- def isCurrentThread(self) -> bool:
- return threading.current_thread() == self._thread
-
- def getThread(self) -> threading.Thread:
- return self._thread
-
- def getQueue(self):
- return self._message_queue
-
- def dump(self, pw: Any, prefix: str):
- """将 DropBox 条目转储到给定的 writer。"""
- try:
- if hasattr(pw, "write"):
- pw.write(f"{prefix}DropBoxManager entries:\n")
- for entry in self._entries:
- pw.write(f"{prefix} [{entry.getTag()}] @ {entry.getTimeMillis()}: "
- f"{entry.getText(1024)}\n")
- elif hasattr(pw, "println"):
- pw.println(f"{prefix}DropBoxManager entries:")
- for entry in self._entries:
- pw.println(f"{prefix} [{entry.getTag()}] @ {entry.getTimeMillis()}: "
- f"{entry.getText(1024)}")
- except Exception:
- pass
-
- def toString(self) -> str:
- return f"Looper({self._thread.name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Handler
-# ═══════════════════════════════════════════════════════════════
-
-class Handler(Stub):
- """Handler — 消息处理器"""
-
- def __init__(self, looper: Optional[Looper] = None, callback: Optional[Callable] = None):
- super().__init__()
- self._looper = looper or Looper.getMainLooper()
- self._callback = callback
- self._async = False
-
- def handleMessage(self, msg: Message):
- pass
-
- def dispatchMessage(self, msg: Message):
- if msg._callback:
- msg._callback()
- elif self._callback:
- self._callback(msg)
- else:
- self.handleMessage(msg)
-
- def post(self, r: Callable) -> bool:
- msg = Message.obtain(self)
- msg._callback = r
- return self.sendMessage(msg)
-
- def postDelayed(self, r: Callable, delay_ms: int) -> bool:
- msg = Message.obtain(self)
- msg._callback = r
- return self.sendMessageDelayed(msg, delay_ms)
-
- def postAtTime(self, r: Callable, uptime_ms: int) -> bool:
- msg = Message.obtain(self)
- msg._callback = r
- msg.when = uptime_ms
- return self.sendMessageAtTime(msg, uptime_ms)
-
- def sendMessage(self, msg: Message) -> bool:
- msg._target = self
- looper = self._looper
- if looper is not None and looper._running:
- looper._enqueue(msg)
- return True
- # 当前线程无运行中的 Looper,回退到同步执行(保持兼容性)
- self.dispatchMessage(msg)
- return True
-
- def sendEmptyMessage(self, what: int) -> bool:
- msg = Message.obtain(self, what)
- return self.sendMessage(msg)
-
- def sendMessageDelayed(self, msg: Message, delay_ms: int) -> bool:
- msg._target = self
- msg.when = SystemClock.uptimeMillis() + delay_ms
- looper = self._looper
- if looper is not None and looper._running:
- looper._enqueue(msg)
- return True
- # 回退到同步执行
- self.dispatchMessage(msg)
- return True
-
- def sendMessageAtTime(self, msg: Message, uptime_ms: int) -> bool:
- msg._target = self
- msg.when = uptime_ms
- looper = self._looper
- if looper is not None and looper._running:
- looper._enqueue(msg)
- return True
- self.dispatchMessage(msg)
- return True
-
- def sendMessageAtFrontOfQueue(self, msg: Message) -> bool:
- msg._target = self
- msg.when = 0
- looper = self._looper
- if looper is not None and looper._running:
- with looper._queue_lock:
- looper._message_queue.insert(0, msg)
- return True
- self.dispatchMessage(msg)
- return True
-
- def removeCallbacks(self, r: Callable):
- looper = self._looper
- if looper is not None:
- looper._remove_callbacks(r)
-
- def removeMessages(self, what: int):
- looper = self._looper
- if looper is not None:
- looper._remove_messages(what)
-
- def obtainMessage(self, what: int = 0) -> Message:
- return Message.obtain(self, what)
-
- def hasMessages(self, what: int) -> bool:
- looper = self._looper
- if looper is not None:
- return looper._has_messages(what)
- return False
-
- def getLooper(self) -> Looper:
- return self._looper
-
- def toString(self) -> str:
- return f"Handler({self.__class__.__name__})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HandlerThread
-# ═══════════════════════════════════════════════════════════════
-
-class HandlerThread(threading.Thread, Stub):
- """HandlerThread — 带 Looper 的工作线程"""
-
- def __init__(self, name: str, priority: int = Process.THREAD_PRIORITY_DEFAULT):
- super().__init__()
- Stub.__init__(self)
- self._name = name
- self._priority = priority
- self._looper: Optional[Looper] = None
- self._started = threading.Event()
-
- def run(self):
- Looper.prepare()
- self._looper = Looper.myLooper()
- self._started.set()
- Looper.loop()
-
- def getLooper(self) -> Optional[Looper]:
- self._started.wait()
- return self._looper
-
- def getThreadId(self) -> int:
- return self.ident or 0
-
- def quit(self) -> bool:
- if self._looper:
- self._looper.quit()
- return True
- return False
-
- def quitSafely(self) -> bool:
- return self.quit()
-
-
-# ═══════════════════════════════════════════════════════════════
-# AsyncTask Executor (守护线程池)
-# ═══════════════════════════════════════════════════════════════
-
-class _AsyncTaskExecutor:
- """守护线程池执行器 — 用于 AsyncTask 后台执行,不阻塞程序退出。
-
- 使用 BoundedSemaphore 限制并发数,每个任务在独立的守护线程中运行。
- """
-
- def __init__(self, max_workers: int = 4):
- self._max_workers = max_workers
- self._semaphore = threading.BoundedSemaphore(max_workers)
- self._shutdown_flag = False
-
- def submit(self, fn, *args, **kwargs):
- if self._shutdown_flag:
- raise RuntimeError("Executor has been shut down")
- self._semaphore.acquire()
-
- def _run():
- try:
- fn(*args, **kwargs)
- finally:
- self._semaphore.release()
-
- t = threading.Thread(target=_run, daemon=True)
- t.start()
-
- def execute(self, command):
- self.submit(command)
-
- def shutdown(self, wait: bool = True):
- self._shutdown_flag = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# AsyncTask
-# ═══════════════════════════════════════════════════════════════
-
-class AsyncTask(Stub):
- """AsyncTask — 异步任务"""
-
- Status = type("Status", (), {"PENDING": 0, "RUNNING": 1, "FINISHED": 2})
-
- SERIAL_EXECUTOR = None
- THREAD_POOL_EXECUTOR = None
-
- def __init__(self):
- super().__init__()
- self._status = AsyncTask.Status.PENDING
- self._result: Any = None
- self._cancelled = False
- self._handler = Handler(Looper.getMainLooper())
-
- def doInBackground(self, *params) -> Any:
- raise NotImplementedError
-
- def onPreExecute(self):
- pass
-
- def onPostExecute(self, result: Any):
- pass
-
- def onProgressUpdate(self, *values):
- pass
-
- def onCancelled(self, result: Any = None):
- pass
-
- def execute(self, *params) -> "AsyncTask":
- return self.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, *params)
-
- def executeOnExecutor(self, exec: Any, *params) -> "AsyncTask":
- self._status = AsyncTask.Status.RUNNING
- self.onPreExecute()
- exec.submit(self._run_background, params)
- return self
-
- def _run_background(self, params):
- """在后台线程中执行 doInBackground,完成后通过 Handler 回调主线程"""
- try:
- self._result = self.doInBackground(*params)
- except Exception as e:
- self._result = e
- self._status = AsyncTask.Status.FINISHED
- if self._cancelled:
- self._handler.post(lambda: self.onCancelled(self._result))
- else:
- self._handler.post(lambda: self.onPostExecute(self._result))
-
- def get(self) -> Any:
- return self._result
-
- def getStatus(self) -> int:
- return self._status
-
- def isCancelled(self) -> bool:
- return self._cancelled
-
- def cancel(self, may_interrupt_if_running: bool) -> bool:
- self._cancelled = True
- return True
-
- def publishProgress(self, *values):
- self._handler.post(lambda: self.onProgressUpdate(*values))
-
-
-# 初始化默认执行器
-AsyncTask.THREAD_POOL_EXECUTOR = _AsyncTaskExecutor(max_workers=4)
-AsyncTask.SERIAL_EXECUTOR = _AsyncTaskExecutor(max_workers=1)
-
-
-# ═══════════════════════════════════════════════════════════════
-# CountDownTimer
-# ═══════════════════════════════════════════════════════════════
-
-class CountDownTimer(Stub):
- """CountDownTimer — 倒计时"""
-
- def __init__(self, millis_in_future: int, count_down_interval: int):
- super().__init__()
- self._millis_in_future = millis_in_future
- self._interval = count_down_interval
- self._cancelled = False
-
- def onTick(self, millis_until_finished: int):
- pass
-
- def onFinish(self):
- pass
-
- def start(self) -> "CountDownTimer":
- self._cancelled = False
- remaining = self._millis_in_future
- while remaining > 0 and not self._cancelled:
- self.onTick(remaining)
- _time.sleep(self._interval / 1000.0)
- remaining -= self._interval
- if not self._cancelled:
- self.onFinish()
- return self
-
- def cancel(self):
- self._cancelled = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# Messenger
-# ═══════════════════════════════════════════════════════════════
-
-class Messenger(Stub):
- """Messenger — 跨进程消息传递"""
-
- def __init__(self, handler: Handler):
- super().__init__()
- self._handler = handler
-
- def send(self, message: Message):
- self._handler.sendMessage(message)
-
- def getBinder(self):
- return None
-
- @staticmethod
- def obtain(handler: Handler) -> "Messenger":
- return Messenger(handler)
-
-
-# ═══════════════════════════════════════════════════════════════
-# PowerManager / PowerManagerWakeLock
-# ═══════════════════════════════════════════════════════════════
-
-class PowerManager(Stub):
- """PowerManager — 电源管理"""
-
- ACQUIRE_CAUSES_WAKEUP = 0x10000000
- DOZE_WAKE_LOCK = 0x00000040
- DRAW_WAKE_LOCK = 0x00000080
- FULL_WAKE_LOCK = 0x0000001A
- LOCATION_HARDWARE_POWER_MODE = 0x00000080
- ON_AFTER_RELEASE = 0x20000000
- PARTIAL_WAKE_LOCK = 0x00000001
- PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020
- SCREEN_BRIGHT_WAKE_LOCK = 0x0000000A
- SCREEN_DIM_WAKE_LOCK = 0x00000006
- WAKE_LOCK_LEVEL_MASK = 0x0000FFFF
-
- def __init__(self):
- super().__init__()
- self._is_interactive = True
- self._is_power_save = False
- self._is_device_idle = False
-
- def newWakeLock(self, level_and_flags: int, tag: str) -> "PowerManagerWakeLock":
- return PowerManagerWakeLock(level_and_flags, tag)
-
- def isInteractive(self) -> bool:
- if _USE_LINUX:
- return self.isScreenOn()
- return self._is_interactive
-
- def isScreenOn(self) -> bool:
- """屏幕是否点亮 — 在 Linux 上检查 DISPLAY 环境变量"""
- if _USE_LINUX:
- import os as _os_mod
- display = _os_mod.environ.get("DISPLAY", "")
- if display:
- return True
- # WAYLAND_DISPLAY 作为回退
- wayland = _os_mod.environ.get("WAYLAND_DISPLAY", "")
- return bool(wayland)
- return self._is_interactive
-
- def isPowerSaveMode(self) -> bool:
- """检查是否处于省电模式。读取 /sys 中的电源相关状态。"""
- try:
- # 检查 CPU 调速器是否为 powersave
- gov_path = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
- if _os.path.exists(gov_path):
- with open(gov_path, "r") as f:
- governor = f.read().strip()
- if governor == "powersave":
- return True
- except (OSError, IOError):
- pass
- return self._is_power_save
-
- def isDeviceIdleMode(self) -> bool:
- return self._is_device_idle
-
- def isIgnoringBatteryOptimizations(self, package_name: str) -> bool:
- return True
-
- def isSustainedPerformanceModeSupported(self) -> bool:
- return False
-
- def reboot(self, reason: Optional[str] = None):
- """重启设备。桌面端尝试执行 reboot 命令(通常需要 root)。"""
- try:
- import subprocess
- cmd = ["reboot"]
- if reason:
- cmd.append(reason)
- subprocess.run(cmd, capture_output=True, timeout=5)
- except Exception:
- sys.stderr.write(f"[PowerManager] reboot: {reason or ''}\n")
-
- def goToSleep(self, time_ms: int):
- """使设备进入睡眠。桌面端无实际效果。"""
- self._is_interactive = False
- sys.stderr.write(f"[PowerManager] goToSleep at {time_ms}\n")
-
- def wakeUp(self, time_ms: int):
- """唤醒设备。桌面端无实际效果。"""
- self._is_interactive = True
- sys.stderr.write(f"[PowerManager] wakeUp at {time_ms}\n")
-
- def userActivity(self, when: int, no_change_lights: bool = False):
- """报告用户活动事件。桌面端无实际效果。"""
- self._is_interactive = True
-
-
-class PowerManagerWakeLock(Stub):
- """PowerManagerWakeLock — 唤醒锁"""
-
- def __init__(self, level_and_flags: int, tag: str):
- super().__init__()
- self._level_and_flags = level_and_flags
- self._tag = tag
- self._held = False
- self._work_source = None
- self._history_tag = None
-
- def acquire(self, timeout_ms: int = 0):
- self._held = True
- sys.stderr.write(f"[PowerManager] acquire wakelock: {self._tag}\n")
-
- def acquireLocked(self):
- self._held = True
-
- def release(self, flags: int = 0):
- self._held = False
- sys.stderr.write(f"[PowerManager] release wakelock: {self._tag}\n")
-
- def isHeld(self) -> bool:
- return self._held
-
- def setWorkSource(self, work_source: Any):
- self._work_source = work_source
-
- def setReferenceCounted(self, value: bool):
- pass
-
- def setHistoryTag(self, tag: str):
- self._history_tag = tag
-
- def toString(self) -> str:
- return f"WakeLock({self._tag}, held={self._held})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Vibrator / VibratorEffect
-# ═══════════════════════════════════════════════════════════════
-
-class Vibrator(Stub):
- """Vibrator — 振动器"""
-
- def __init__(self):
- super().__init__()
- self._ff_device: Optional[str] = None
- self._vibrating = False
-
- @staticmethod
- def _find_ff_device() -> Optional[str]:
- """查找 Linux 力反馈设备。"""
- try:
- for name in _os.listdir("/dev/input"):
- if name.startswith("event"):
- path = f"/dev/input/{name}"
- if _os.access(path, _os.W_OK):
- return path
- except (OSError, IOError):
- pass
- # 检查 /sys/class/leds/vibrator
- try:
- if _os.path.exists("/sys/class/leds/vibrator"):
- return "/sys/class/leds/vibrator"
- except (OSError, IOError):
- pass
- return None
-
- def vibrate(self, *args):
- """振动。支持 vibrate(milliseconds) 和 vibrate(pattern, repeat)。"""
- if len(args) == 1 and isinstance(args[0], (int, float)):
- milliseconds = int(args[0])
- self._vibrating = True
- if self._ff_device is None:
- self._ff_device = self._find_ff_device()
- if self._ff_device and self._ff_device.startswith("/sys/class/leds"):
- try:
- with open(_os.path.join(self._ff_device, "brightness"), "w") as f:
- f.write("1")
- import threading
- def _stop():
- _time.sleep(milliseconds / 1000.0)
- try:
- with open(_os.path.join(self._ff_device, "brightness"), "w") as f:
- f.write("0")
- except (OSError, IOError):
- pass
- self._vibrating = False
- threading.Thread(target=_stop, daemon=True).start()
- return
- except (OSError, IOError):
- pass
- sys.stderr.write(f"[Vibrator] vibrate: {milliseconds}ms\n")
- elif len(args) == 2 and isinstance(args[0], list):
- pattern = args[0]
- repeat = args[1]
- if not pattern:
- return
- self._vibrating = True
- import threading
- def _run_pattern():
- idx = 0
- while True:
- duration = pattern[idx % len(pattern)]
- if idx % 2 == 0:
- _time.sleep(duration / 1000.0)
- else:
- self.vibrate(duration)
- _time.sleep(duration / 1000.0)
- idx += 1
- if repeat < 0 or idx >= len(pattern):
- if repeat < 0:
- continue
- break
- self._vibrating = False
- threading.Thread(target=_run_pattern, daemon=True).start()
- sys.stderr.write(f"[Vibrator] vibrate pattern: {pattern}, repeat={repeat}\n")
-
- def cancel(self):
- """取消振动。"""
- self._vibrating = False
- if self._ff_device and self._ff_device.startswith("/sys/class/leds"):
- try:
- with open(_os.path.join(self._ff_device, "brightness"), "w") as f:
- f.write("0")
- except (OSError, IOError):
- pass
- sys.stderr.write("[Vibrator] cancel\n")
-
- def hasVibrator(self) -> bool:
- """检查是否有振动器硬件。"""
- return self._find_ff_device() is not None
-
- def hasAmplitudeControl(self) -> bool:
- """检查是否支持振幅控制。"""
- try:
- if _os.path.exists("/sys/class/leds/vibrator/max_brightness"):
- with open("/sys/class/leds/vibrator/max_brightness", "r") as f:
- return int(f.read().strip()) > 1
- except (OSError, IOError, ValueError):
- pass
- return False
-
- def areEffectsSupported(self, effect_ids: List[int]) -> List[int]:
- return [0] * len(effect_ids)
-
- def areAllEffectsSupported(self, effect_ids: List[int]) -> List[int]:
- return [0] * len(effect_ids)
-
-
-class VibratorEffect(Stub):
- """VibratorEffect — 振动效果"""
-
- EFFECT_CLICK = 0
- EFFECT_DOUBLE_CLICK = 1
- EFFECT_TICK = 2
- EFFECT_THUD = 3
- EFFECT_POP = 4
- EFFECT_HEAVY_CLICK = 5
-
- def __init__(self, effect_id: int = 0):
- super().__init__()
- self._effect_id = effect_id
- self._timings: Optional[List[int]] = None
- self._amplitudes: Optional[List[int]] = None
- self._repeat = -1
-
- @staticmethod
- def createOneShot(milliseconds: int, amplitude: int) -> "VibratorEffect":
- """创建单次振动效果。"""
- effect = VibratorEffect(0)
- effect._timings = [0, milliseconds]
- effect._amplitudes = [0, amplitude]
- effect._repeat = -1
- return effect
-
- @staticmethod
- def createWaveform(pattern: List[int], repeat: int) -> "VibratorEffect":
- """创建波形振动效果。"""
- effect = VibratorEffect(0)
- effect._timings = list(pattern)
- effect._amplitudes = [255 if i % 2 == 1 else 0 for i in range(len(pattern))]
- effect._repeat = repeat
- return effect
-
- @staticmethod
- def createPredefined(effect_id: int) -> "VibratorEffect":
- """创建预定义振动效果。"""
- return VibratorEffect(effect_id)
-
-
-# ═══════════════════════════════════════════════════════════════
-# BatteryManager
-# ═══════════════════════════════════════════════════════════════
-
-class BatteryManager(Stub):
- """BatteryManager — 电池管理"""
-
- BATTERY_PROPERTY_CHARGE_COUNTER = 1
- BATTERY_PROPERTY_CURRENT_NOW = 2
- BATTERY_PROPERTY_CURRENT_AVERAGE = 3
- BATTERY_PROPERTY_CAPACITY = 4
- BATTERY_PROPERTY_STATUS = 5
- BATTERY_PROPERTY_ENERGY_COUNTER = 6
- BATTERY_PROPERTY_BATTERY_NOW = 7
- BATTERY_PROPERTY_BATTERY_LOW = 8
-
- BATTERY_STATUS_UNKNOWN = 1
- BATTERY_STATUS_CHARGING = 2
- BATTERY_STATUS_DISCHARGING = 3
- BATTERY_STATUS_NOT_CHARGING = 4
- BATTERY_STATUS_FULL = 5
-
- BATTERY_HEALTH_UNKNOWN = 1
- BATTERY_HEALTH_GOOD = 2
- BATTERY_HEALTH_OVERHEAT = 3
- BATTERY_HEALTH_DEAD = 4
- BATTERY_HEALTH_OVER_VOLTAGE = 5
- BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6
- BATTERY_HEALTH_COLD = 7
-
- EXTRA_STATUS = "status"
- EXTRA_HEALTH = "health"
- EXTRA_PRESENT = "present"
- EXTRA_LEVEL = "level"
- EXTRA_SCALE = "scale"
- EXTRA_ICON_SMALL = "icon-small"
- EXTRA_PLUGGED = "plugged"
- EXTRA_VOLTAGE = "voltage"
- EXTRA_TEMPERATURE = "temperature"
- EXTRA_TECHNOLOGY = "technology"
- EXTRA_BATTERY_LOW = "battery_low"
- EXTRA_CHARGE_COUNTER = "charge_counter"
-
- BATTERY_PLUGGED_AC = 1
- BATTERY_PLUGGED_USB = 2
- BATTERY_PLUGGED_WIRELESS = 4
-
- def __init__(self):
- super().__init__()
- self._capacity = 85
- self._status = self.BATTERY_STATUS_CHARGING
- self._health = self.BATTERY_HEALTH_GOOD
- self._present = True
- self._level = 85
- self._plugged = self.BATTERY_PLUGGED_AC
- self._voltage = 4200
- self._temperature = 250
- self._technology = "Li-ion"
- self._charge_counter = 3500000
- self._current_now = -500000
- self._current_avg = -450000
- self._energy_counter = 15000000
- if _USE_LINUX:
- self._refresh_from_linux()
-
- _LINUX_STATUS_MAP = {
- "charging": 2, # BATTERY_STATUS_CHARGING
- "discharging": 3, # BATTERY_STATUS_DISCHARGING
- "not charging": 4, # BATTERY_STATUS_NOT_CHARGING
- "full": 5, # BATTERY_STATUS_FULL
- "unknown": 1, # BATTERY_STATUS_UNKNOWN
- }
-
- def _get_linux_battery_info(self) -> dict:
- """从 LinuxPower 获取真实电池信息"""
- try:
- return LinuxPower.get_battery_info() or {}
- except Exception:
- return {}
-
- def _refresh_from_linux(self):
- """用 Linux 真实电池信息刷新内部状态"""
- info = self._get_linux_battery_info()
- if not info:
- return
- self._present = bool(info.get("present", False))
- level = info.get("level", -1)
- if self._present and isinstance(level, (int, float)) and level >= 0:
- self._level = int(level)
- self._capacity = int(level)
- else:
- # 无电池或电量未知
- self._level = -1
- self._capacity = -1
- status_str = str(info.get("status", "unknown")).lower()
- self._status = self._LINUX_STATUS_MAP.get(status_str, self.BATTERY_STATUS_UNKNOWN)
- voltage = info.get("voltage", 0)
- if isinstance(voltage, (int, float)):
- # LinuxPower 返回伏特, Android 期望毫伏
- self._voltage = int(voltage * 1000)
- temperature = info.get("temperature", 0)
- if isinstance(temperature, (int, float)):
- # LinuxPower 返回摄氏度, Android 期望十分之一度
- self._temperature = int(temperature * 10)
- self._technology = info.get("technology", "") or "Li-ion"
- # 充电状态决定 plugged
- if self._status == self.BATTERY_STATUS_CHARGING:
- self._plugged = self.BATTERY_PLUGGED_AC
- else:
- self._plugged = 0
-
- def getIntProperty(self, prop_id: int) -> int:
- if _USE_LINUX:
- self._refresh_from_linux()
- if prop_id == self.BATTERY_PROPERTY_CAPACITY:
- return self._capacity
- if prop_id == self.BATTERY_PROPERTY_STATUS:
- return self._status
- if prop_id == self.BATTERY_PROPERTY_CHARGE_COUNTER:
- return self._charge_counter
- if prop_id == self.BATTERY_PROPERTY_CURRENT_NOW:
- return self._current_now
- if prop_id == self.BATTERY_PROPERTY_CURRENT_AVERAGE:
- return self._current_avg
- if prop_id == self.BATTERY_PROPERTY_ENERGY_COUNTER:
- return self._energy_counter
- return -1
-
- def getLongProperty(self, prop_id: int) -> int:
- return self.getIntProperty(prop_id)
-
- def isCharging(self) -> bool:
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._status == self.BATTERY_STATUS_CHARGING
-
- def isPresent(self) -> bool:
- """电池是否存在"""
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._present
-
- def getLevel(self) -> int:
- """电池电量 (0-100, -1 表示未知)"""
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._level
-
- def getVoltage(self) -> int:
- """电池电压 (毫伏)"""
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._voltage
-
- def getTemperature(self) -> int:
- """电池温度 (十分之一摄氏度)"""
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._temperature
-
- def getTechnology(self) -> str:
- """电池技术"""
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._technology
-
- def getPlugType(self) -> int:
- """充电类型"""
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._plugged
-
- def getStatus(self) -> int:
- """电池状态"""
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._status
-
- def computeChargeTimeRemaining(self) -> int:
- if _USE_LINUX:
- # 无电池或已充满时返回 -1
- if not self._present or self._status == self.BATTERY_STATUS_FULL:
- return -1
- return 1800000 # 30 minutes
-
- def toString(self) -> str:
- return f"BatteryManager(level={self._level}%, charging={self.isCharging()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# 异常类
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkOnMainThreadException(RuntimeError):
- """网络操作在主线程上执行"""
- pass
-
-
-class TransactionTooLargeException(RuntimeError):
- """事务数据太大"""
- pass
-
-
-class OperationCanceledException(RuntimeError):
- """操作被取消"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# 其他工具类
-# ═══════════════════════════════════════════════════════════════
-
-class ConditionVariable(Stub):
- """ConditionVariable — 条件变量"""
-
- def __init__(self):
- super().__init__()
- self._cond = threading.Condition()
- self._open = False
-
- def block(self, timeout_ms: int = 0):
- with self._cond:
- if timeout_ms <= 0:
- while not self._open:
- self._cond.wait()
- else:
- if not self._open:
- self._cond.wait(timeout_ms / 1000.0)
-
- def open(self):
- with self._cond:
- self._open = True
- self._cond.notify_all()
-
- def close(self):
- with self._cond:
- self._open = False
-
-
-class Semaphore(Stub):
- """Semaphore — 信号量"""
-
- def __init__(self, permits: int):
- super().__init__()
- self._sem = threading.Semaphore(permits)
-
- def acquire(self):
- self._sem.acquire()
-
- def tryAcquire(self) -> bool:
- return self._sem.acquire(blocking=False)
-
- def release(self):
- self._sem.release()
-
- def availablePermits(self) -> int:
- return self._sem._value
-
-
-class TokenWatcher(Stub):
- """TokenWatcher — 令牌监视器"""
-
- def __init__(self, handler: Handler, tag: str):
- super().__init__()
- self._handler = handler
- self._tag = tag
- self._tokens: Dict[int, str] = {}
-
- def acquire(self, token: Any, tag: str):
- """获取令牌。"""
- self._tokens[id(token)] = tag
- if len(self._tokens) == 1:
- self.acquired()
-
- def release(self, token: Any):
- """释放令牌。"""
- self._tokens.pop(id(token), None)
- if not self._tokens:
- self.released()
-
- def isAcquired(self) -> bool:
- """检查是否有令牌被持有。"""
- return len(self._tokens) > 0
-
- def acquired(self):
- """当第一个令牌被获取时调用。子类可重写。"""
- pass
-
- def released(self):
- """当所有令牌被释放时调用。子类可重写。"""
- pass
-
- def dump(self):
- """转储令牌信息。"""
- for tid, tag in self._tokens.items():
- sys.stderr.write(f"[TokenWatcher] {self._tag}: token={tid}, tag={tag}\n")
-
-
-class WorkSource(Stub):
- """WorkSource — 工作来源"""
-
- def __init__(self, uid: int = 0):
- super().__init__()
- self._uids: List[int] = [uid] if uid else []
-
- def add(self, uid: int):
- if uid not in self._uids:
- self._uids.append(uid)
-
- def remove(self, uid: int):
- if uid in self._uids:
- self._uids.remove(uid)
-
- def get(self, index: int) -> int:
- if 0 <= index < len(self._uids):
- return self._uids[index]
- return 0
-
- def size(self) -> int:
- return len(self._uids)
-
- def clear(self):
- self._uids.clear()
-
- def set(self, ws: "WorkSource"):
- if ws:
- self._uids = list(ws._uids)
-
- def toString(self) -> str:
- return f"WorkSource({self._uids})"
-
-
-class UserHandle(Stub):
- """UserHandle — 用户句柄"""
-
- USER_ALL = -1
- USER_CURRENT = -2
- USER_CURRENT_OR_SELF = -3
- USER_NULL = -10000
- USER_OWNER = 0
- USER_SYSTEM = 0
-
- def __init__(self, user_id: int = 0):
- super().__init__()
- self._user_id = user_id
-
- @staticmethod
- def myUserId() -> int:
- return 0
-
- @staticmethod
- def getUserHandleForUid(uid: int) -> "UserHandle":
- return UserHandle(uid // 100000)
-
- @staticmethod
- def getUserId(uid: int) -> int:
- return uid // 100000
-
- @staticmethod
- def getUid(user_id: int, app_id: int) -> int:
- return user_id * 100000 + app_id
-
- @staticmethod
- def getAppId(uid: int) -> int:
- return uid % 100000
-
- def getIdentifier(self) -> int:
- return self._user_id
-
- def hashCode(self) -> int:
- return self._user_id
-
- def toString(self) -> str:
- return f"UserHandle({self._user_id})"
-
-
-class DropBoxManager(Stub):
- """DropBoxManager — 系统日志收集"""
-
- IS_EMPTY = 0
- IS_TEXT = 1
- IS_GZIPPED = 2
-
- class Entry(Stub):
- def __init__(self, tag: str, milliseconds: int):
- super().__init__()
- self._tag = tag
- self._millis = milliseconds
- self._text = ""
-
- def getTag(self) -> str:
- return self._tag
-
- def getTimeMillis(self) -> int:
- return self._millis
-
- def getText(self, max_bytes: int) -> Optional[str]:
- return self._text
-
- def getFlags(self, max_bytes: int) -> int:
- return DropBoxManager.IS_TEXT
-
- def close(self):
- pass
-
- def __init__(self):
- super().__init__()
- self._entries: List[DropBoxManager.Entry] = []
-
- def addText(self, tag: str, text: str):
- entry = DropBoxManager.Entry(tag, int(_time.time() * 1000))
- entry._text = text
- self._entries.append(entry)
-
- def getNextEntry(self, tag: str, milliseconds: int) -> Optional[Entry]:
- for entry in self._entries:
- if entry.getTimeMillis() > milliseconds:
- if not tag or entry.getTag() == tag:
- return entry
- return None
-
- def dump(self, pw: Any, prefix: str):
- pass
-
-
-class FileObserver(Stub):
- """FileObserver — 文件监听"""
-
- ACCESS = 0x00000001
- MODIFY = 0x00000002
- ATTRIB = 0x00000004
- CLOSE_WRITE = 0x00000008
- CLOSE_NOWRITE = 0x00000010
- OPEN = 0x00000020
- MOVED_FROM = 0x00000040
- MOVED_TO = 0x00000080
- CREATE = 0x00000100
- DELETE = 0x00000200
- DELETE_SELF = 0x00000400
- MOVE_SELF = 0x00000800
- ALL_EVENTS = 0x00000FFF
-
- def __init__(self, path: str):
- super().__init__()
- self._path = path
- self._watching = False
- self._thread = None
- self._snapshot: Dict[str, float] = {}
-
- def startWatching(self):
- """开始监听文件变化。使用轮询方式检测文件系统事件。"""
- if self._watching:
- return
- self._watching = True
- self._snapshot = self._take_snapshot()
- self._thread = threading.Thread(target=self._poll_loop, daemon=True)
- self._thread.start()
-
- def _take_snapshot(self) -> Dict[str, float]:
- """获取当前目录的文件快照(文件名 -> 修改时间)。"""
- snapshot: Dict[str, float] = {}
- try:
- if _os.path.isdir(self._path):
- for name in _os.listdir(self._path):
- full = _os.path.join(self._path, name)
- try:
- snapshot[name] = _os.path.getmtime(full)
- except OSError:
- pass
- elif _os.path.exists(self._path):
- try:
- snapshot[self._path] = _os.path.getmtime(self._path)
- except OSError:
- pass
- except OSError:
- pass
- return snapshot
-
- def _poll_loop(self):
- """轮询检测文件变化并触发事件。"""
- while self._watching:
- _time.sleep(0.5)
- try:
- current = self._take_snapshot()
- # 检测新建和修改
- for name, mtime in current.items():
- if name not in self._snapshot:
- self.onEvent(FileObserver.CREATE, name)
- elif mtime != self._snapshot[name]:
- self.onEvent(FileObserver.MODIFY, name)
- # 检测删除
- for name in list(self._snapshot.keys()):
- if name not in current:
- self.onEvent(FileObserver.DELETE, name)
- self._snapshot = current
- except Exception:
- pass
-
- def stopWatching(self):
- """停止监听。"""
- self._watching = False
- if self._thread and self._thread.is_alive():
- self._thread.join(timeout=1.0)
- self._thread = None
-
- def onEvent(self, event: int, path: Optional[str]):
- """文件事件回调,子类可重写。"""
- pass
-
- def finalize(self):
- """清理资源。"""
- self.stopWatching()
-
-
-class FileUtils(Stub):
- """FileUtils — 文件工具"""
-
- @staticmethod
- def readFileToString(path):
- try:
- with open(path, "r", encoding="utf-8") as f:
- return f.read()
- except Exception:
- return ""
-
- @staticmethod
- def stringToFile(path, content):
- try:
- with open(path, "w", encoding="utf-8") as f:
- f.write(content)
- return True
- except Exception:
- return False
-
- @staticmethod
- def copyFile(src, dst):
- try:
- import shutil
- shutil.copy2(src, dst)
- return True
- except Exception:
- return False
-
- @staticmethod
- def deleteDirectory(path):
- try:
- import shutil
- shutil.rmtree(path)
- return True
- except Exception:
- return False
-
- @staticmethod
- def deleteContents(path):
- try:
- import shutil
- for entry in _os.listdir(path):
- full = _os.path.join(path, entry)
- if _os.path.isdir(full):
- shutil.rmtree(full)
- else:
- _os.remove(full)
- return True
- except Exception:
- return False
-
- @staticmethod
- def deleteOlderFiles(dir_: Any, min_count: int, min_age_ms: int):
- """删除目录中较旧的文件,但保留至少 min_count 个文件。
- min_age_ms 为文件的最小年龄(毫秒),低于此年龄的文件不会被删除。"""
- try:
- if not _os.path.isdir(dir_):
- return
- entries = []
- for name in _os.listdir(dir_):
- full = _os.path.join(dir_, name)
- if _os.path.isfile(full):
- try:
- mtime = _os.path.getmtime(full)
- entries.append((full, mtime))
- except OSError:
- pass
- # 按修改时间排序(最新在前)
- entries.sort(key=lambda x: x[1], reverse=True)
- now = _time.time()
- min_age_s = min_age_ms / 1000.0
- # 保留最新的 min_count 个文件,删除超过 min_age 的旧文件
- for i, (path, mtime) in enumerate(entries):
- if i < min_count:
- continue
- if (now - mtime) >= min_age_s:
- try:
- _os.remove(path)
- except OSError:
- pass
- except Exception:
- pass
-
-
-class PatternMatcher(Stub):
- """PatternMatcher — 模式匹配器"""
-
- PATTERN_LITERAL = 0
- PATTERN_PREFIX = 1
- PATTERN_SIMPLE_GLOB = 2
- PATTERN_ADVANCED_GLOB = 3
- PATTERN_SUFFIX = 4
-
- def __init__(self, pattern: str, type_: int):
- super().__init__()
- self._pattern = pattern
- self._type = type_
-
- def getPath(self) -> str:
- return self._pattern
-
- def getType(self) -> int:
- return self._type
-
- def match(self, str_: str) -> bool:
- if self._type == self.PATTERN_LITERAL:
- return str_ == self._pattern
- if self._type == self.PATTERN_PREFIX:
- return str_.startswith(self._pattern)
- if self._type == self.PATTERN_SUFFIX:
- return str_.endswith(self._pattern)
- if self._type == self.PATTERN_SIMPLE_GLOB:
- import fnmatch
- return fnmatch.fnmatch(str_, self._pattern)
- return str_ == self._pattern
-
- def toString(self) -> str:
- return f"PatternMatcher({self._pattern}, type={self._type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Bundle",
- "BaseBundle",
- "PersistableBundle",
- "Handler",
- "Looper",
- "Message",
- "HandlerThread",
- "PowerManager",
- "PowerManagerWakeLock",
- "Vibrator",
- "VibratorEffect",
- "Build",
- "SystemClock",
- "Environment",
- "Parcel",
- "Parcelable",
- "Process",
- "AsyncTask",
- "CountDownTimer",
- "Messenger",
- "BatteryManager",
- "PatternMatcher",
- "ConditionVariable",
- "Semaphore",
- "TokenWatcher",
- "WorkSource",
- "UserHandle",
- "DropBoxManager",
- "FileObserver",
- "FileUtils",
- "NetworkOnMainThreadException",
- "TransactionTooLargeException",
- "OperationCanceledException",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/os_health.py b/android_pyapi/android/os_health.py
deleted file mode 100644
index 12ac297..0000000
--- a/android_pyapi/android/os_health.py
+++ /dev/null
@@ -1,215 +0,0 @@
-"""
-Android os.health 组件 — HealthStats, HealthStatsWriter, UidHealthStats 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-from typing import Any, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# UidHealthStats
-# ═══════════════════════════════════════════════════════════════
-
-class UidHealthStats(Stub):
- """UidHealthStats — UID 健康统计常量"""
-
- STATISTICS_SORTED_KEYS_COUNT = 0x10001
-
- MEASUREMENT_REALTIME_BATTERY_MS = 0x20001
- MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = 0x20002
- MEASUREMENT_FOREGROUND_APP_MS = 0x20003
- MEASUREMENT_BACKGROUND_PIDS_MEASUREMENT = 0x20004
- MEASUREMENT_REALTIME_BATTERY_MS_UNPLUGGED = 0x20005
- MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS_UNPLUGGED = 0x20006
-
- TIMER_FLASHLIGHT = 0x30001
- TIMER_CAMERA = 0x30002
- TIMER_VIDEO = 0x30003
- TIMER_AUDIO = 0x30004
- TIMER_WIFI = 0x30005
- TIMER_BLUETOOTH = 0x30006
- TIMER_GPS = 0x30007
- TIMER_SENSORS = 0x30008
- TIMER_MOBILE_RADIO_ACTIVE = 0x30009
- TIMER_PARTIAL_WAKELOCK = 0x3000A
- TIMER_WIFI_SCAN = 0x3000B
- TIMER_WIFI_FULL_LOCK = 0x3000C
- TIMER_WIFI_MULTICAST = 0x3000D
- TIMER_WIFI_RADIO_ACTIVE = 0x3000E
- TIMER_AUDIO_JACK = 0x3000F
- TIMER_VIDEO_GPS = 0x30010
- TIMER_VIDEO_TURBO = 0x30011
- TIMER_VIDEO_LOCK = 0x30012
-
- TIMER_OVERCOUNT = 0x40001
-
- MEASUREMENT_OTHER_USER_ACTIVITY_COUNT = 0x50001
- MEASUREMENT_BLUETOOTH_ACTIVITY_COUNT = 0x50002
- MEASUREMENT_WIFI_ACTIVITY_COUNT = 0x50003
- MEASUREMENT_MOBILE_RADIO_ACTIVITY_COUNT = 0x50004
-
- TIMER_WIFI_RADIO_ACTIVITY = 0x60001
- TIMER_BLUETOOTH_RADIO_ACTIVITY = 0x60002
- TIMER_MOBILE_RADIO_ACTIVITY = 0x60003
-
- MEASUREMENT_WIFI_IDLE_MS = 0x70001
- MEASUREMENT_WIFI_RX_MS = 0x70002
- MEASUREMENT_WIFI_TX_MS = 0x70003
- MEASUREMENT_BLUETOOTH_IDLE_MS = 0x70004
- MEASUREMENT_BLUETOOTH_RX_MS = 0x70005
- MEASUREMENT_BLUETOOTH_TX_MS = 0x70006
- MEASUREMENT_MOBILE_RADIO_IDLE_MS = 0x70007
- MEASUREMENT_MOBILE_RADIO_RX_MS = 0x70008
- MEASUREMENT_MOBILE_RADIO_TX_MS = 0x70009
-
- TIMER_WIFI_RADIO_SCAN = 0x80001
- TIMER_BLUETOOTH_RADIO_SCAN = 0x80002
- TIMER_MOBILE_RADIO_SCAN = 0x80003
-
- MEASUREMENT_WIFI_RADIO_ACTIVE_MS = 0x90001
- MEASUREMENT_BLUETOOTH_RADIO_ACTIVE_MS = 0x90002
- MEASUREMENT_MOBILE_RADIO_ACTIVE_MS = 0x90003
-
-
-# ═══════════════════════════════════════════════════════════════
-# PidHealthStats
-# ═══════════════════════════════════════════════════════════════
-
-class PidHealthStats(Stub):
- """PidHealthStats — 进程健康统计常量"""
-
- MEASUREMENT_WAKE_NESTING_COUNT = 0x20001
- MEASUREMENT_WAKE_SUM_MS = 0x20002
- MEASUREMENT_WAKE_START_MS = 0x20003
-
-
-# ═══════════════════════════════════════════════════════════════
-# ProcessHealthStats
-# ═══════════════════════════════════════════════════════════════
-
-class ProcessHealthStats(Stub):
- """ProcessHealthStats — 进程健康统计常量"""
-
- MEASUREMENT_USER_TIME_MS = 0x20001
- MEASUREMENT_SYSTEM_TIME_MS = 0x20002
- MEASUREMENT_STARTS_COUNT = 0x20003
- MEASUREMENT_CRASHES_COUNT = 0x20004
- MEASUREMENT_ANR_COUNT = 0x20005
- MEASUREMENT_FOREGROUND_MS = 0x20006
-
-
-# ═══════════════════════════════════════════════════════════════
-# PackageHealthStats
-# ═══════════════════════════════════════════════════════════════
-
-class PackageHealthStats(Stub):
- """PackageHealthStats — 包健康统计常量"""
-
- STATISTICS_SORTED_BY_TYPE = 0x10001
- MEASUREMENTS_WAKEUP_ALARMS_COUNT = 0x20001
- TIMERS_SERVICES = 0x30001
- STATISTICS_SERVICES = 0x40001
-
-
-# ═══════════════════════════════════════════════════════════════
-# ServiceHealthStats
-# ═══════════════════════════════════════════════════════════════
-
-class ServiceHealthStats(Stub):
- """ServiceHealthStats — 服务健康统计常量"""
-
- MEASUREMENT_START_SERVICE_COUNT = 0x20001
- MEASUREMENT_LAUNCH_COUNT = 0x20002
- MEASUREMENT_CRASH_COUNT = 0x20003
-
-
-# ═══════════════════════════════════════════════════════════════
-# HealthStats
-# ═══════════════════════════════════════════════════════════════
-
-class HealthStats(Stub):
- """HealthStats — 健康统计数据"""
-
- def __init__(self, data: Optional[Dict[int, Any]] = None):
- super().__init__()
- self._data: Dict[int, Any] = data or {}
-
- def getMeasurement(self, key: int) -> int:
- return self._data.get(key, 0)
-
- def getTimer(self, key: int) -> Any:
- return self._data.get(key)
-
- def getTimers(self, key: int) -> List[Any]:
- return self._data.get(key, [])
-
- def getStats(self, key: int) -> "HealthStats":
- return self._data.get(key, HealthStats())
-
- def getStatsArray(self, key: int) -> List["HealthStats"]:
- return self._data.get(key, [])
-
- def hasKey(self, key: int) -> bool:
- return key in self._data
-
- def getKeys(self) -> List[int]:
- return list(self._data.keys())
-
- def toString(self) -> str:
- return f"HealthStats{{{len(self._data)} entries}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HealthStatsWriter
-# ═══════════════════════════════════════════════════════════════
-
-class HealthStatsWriter(Stub):
- """HealthStatsWriter — 健康统计写入器"""
-
- def __init__(self, keys: Optional[List[int]] = None):
- super().__init__()
- self._data: Dict[int, Any] = {}
-
- def addMeasurement(self, key: int, value: int):
- self._data[key] = value
-
- def addTimer(self, key: int, count: int, time_ms: int):
- self._data[key] = (count, time_ms)
-
- def addTimers(self, key: int, values: List[Any]):
- self._data[key] = values
-
- def addStats(self, key: int, value: HealthStats):
- self._data[key] = value
-
- def addStatsArray(self, key: int, values: List[HealthStats]):
- self._data[key] = values
-
- def toHealthStats(self) -> HealthStats:
- return HealthStats(dict(self._data))
-
- def toString(self) -> str:
- return f"HealthStatsWriter@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "HealthStats",
- "HealthStatsWriter",
- "UidHealthStats",
- "PidHealthStats",
- "ProcessHealthStats",
- "PackageHealthStats",
- "ServiceHealthStats",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/os_power.py b/android_pyapi/android/os_power.py
deleted file mode 100644
index 5ba22e7..0000000
--- a/android_pyapi/android/os_power.py
+++ /dev/null
@@ -1,902 +0,0 @@
-"""
-Android Power API — PowerManager, PowerProfile, BatteryStats, BatteryManager, BatterySaverController, etc.
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import sys
-import time
-import json
-import platform
-import threading
-from datetime import datetime, timedelta
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError, _app_data_dir
-
-from ..java.lang import RuntimeException
-from .os import BatteryManager as _BaseBatteryManager
-from .os import PowerManager as _BasePowerManager
-
-# Linux 真实实现导入
-try:
- from .._linux_impl import IS_LINUX, LinuxPower, LinuxProcess, HAS_PSUTIL as _HAS_PSUTIL
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-# BATTERY_* 常量
-BATTERY_STATUS_UNKNOWN = 1
-BATTERY_STATUS_CHARGING = 2
-BATTERY_STATUS_DISCHARGING = 3
-BATTERY_STATUS_NOT_CHARGING = 4
-BATTERY_STATUS_FULL = 5
-BATTERY_STATUS_INVALID = 6
-
-BATTERY_HEALTH_UNKNOWN = 1
-BATTERY_HEALTH_GOOD = 2
-BATTERY_HEALTH_OVERHEAT = 3
-BATTERY_HEALTH_DEAD = 4
-BATTERY_HEALTH_OVER_VOLTAGE = 5
-BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6
-BATTERY_HEALTH_COLD = 7
-
-BATTERY_PLUGGED_AC = 1
-BATTERY_PLUGGED_USB = 2
-BATTERY_PLUGGED_WIRELESS = 4
-BATTERY_PLUGGED_DOCK = 8
-
-BATTERY_PROPERTY_CAPACITY = 0
-BATTERY_PROPERTY_CHARGE_COUNTER = 1
-BATTERY_PROPERTY_CURRENT_NOW = 2
-BATTERY_PROPERTY_CURRENT_AVERAGE = 3
-BATTERY_PROPERTY_ENERGY_COUNTER = 4
-BATTERY_PROPERTY_STATUS = 5
-BATTERY_PROPERTY_TEMPERATURE = 6
-BATTERY_PROPERTY_VOLTAGE = 7
-BATTERY_PROPERTY_CHARGE_TIME_REMAINING = 8
-BATTERY_PROPERTY_DISCHARGE_TIME_REMAINING = 9
-
-# POWER_* 常量
-POWER_SAVE_MODE_INIT_TRIGGER_TIMEOUT = 0
-POWER_SAVE_MODE_INIT_TRIGGER_DYNAMIC = 1
-POWER_SAVE_MODE_INIT_TRIGGER_PERCENTAGE = 2
-POWER_SAVE_MODE_INIT_TRIGGER_MANUAL = 3
-
-SCREEN_BRIGHT_MODE_AUTOMATIC = 1
-SCREEN_BRIGHT_MODE_MANUAL = 0
-
-# THERMAL_STATUS 常量
-THERMAL_STATUS_NONE = 0
-THERMAL_STATUS_LIGHT = 1
-THERMAL_STATUS_MODERATE = 2
-THERMAL_STATUS_SEVERE = 3
-THERMAL_STATUS_CRITICAL = 4
-THERMAL_STATUS_EMERGENCY = 5
-THERMAL_STATUS_SHUTDOWN = 6
-
-# WAKE_LOCK 级别
-PARTIAL_WAKE_LOCK = 1
-FULL_WAKE_LOCK = 26
-SCREEN_DIM_WAKE_LOCK = 6
-SCREEN_BRIGHT_WAKE_LOCK = 10
-PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32
-DOZE_WAKE_LOCK = 64
-DRAW_WAKE_LOCK = 128
-
-# ACQUIRE 标志
-ACQUIRE_CAUSES_WAKEUP = 0x10000000
-ON_AFTER_RELEASE = 0x20000000
-WAKE_LOCK_LEVEL_MASK = 0x0000FFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# PowerSaveState
-# ═══════════════════════════════════════════════════════════════
-
-class PowerSaveState(Stub):
- """PowerSaveState — 省电状态"""
-
- def __init__(self):
- super().__init__()
- self._global_battery_saver_enabled = False
- self._location_mode = 0
- self._sound_trigger_mode = 0
- self._brightness_factor = 0.0
- self._is_interactive = True
- self._screen_brightness_mode = SCREEN_BRIGHT_MODE_MANUAL
- self._screen_dim_enabled = False
- self._power_save_mode = False
- self._dynamic_power_save_enabled = False
- self._full_backup_enabled = True
- self._data_saver_enabled = False
-
- def getGlobalBatterySaverEnabled(self) -> bool:
- return self._global_battery_saver_enabled
-
- def getLocationMode(self) -> int:
- return self._location_mode
-
- def getSoundTriggerMode(self) -> int:
- return self._sound_trigger_mode
-
- def getBrightnessFactor(self) -> float:
- return self._brightness_factor
-
- def isInteractive(self) -> bool:
- return self._is_interactive
-
- def getScreenBrightnessMode(self) -> int:
- return self._screen_brightness_mode
-
- def isScreenDimEnabled(self) -> bool:
- return self._screen_dim_enabled
-
- def isPowerSaveMode(self) -> bool:
- return self._power_save_mode
-
- def isDynamicPowerSaveEnabled(self) -> bool:
- return self._dynamic_power_save_enabled
-
- def isFullBackupEnabled(self) -> bool:
- return self._full_backup_enabled
-
- def isDataSaverEnabled(self) -> bool:
- return self._data_saver_enabled
-
- def toString(self) -> str:
- return (
- f"PowerSaveState(battery_saver={self._power_save_mode}, "
- f"interactive={self._is_interactive})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# PowerProfile
-# ═══════════════════════════════════════════════════════════════
-
-class PowerProfile(Stub):
- """PowerProfile — 电源配置"""
-
- POWER_WIFI_ON = "wifi.on"
- POWER_WIFI_SCAN = "wifi.scan"
- POWER_WIFI_ACTIVE = "wifi.active"
- POWER_BLUETOOTH_ON = "bluetooth.on"
- POWER_BLUETOOTH_ACTIVE = "bluetooth.active"
- POWER_BLUETOOTH_AT_CMD = "bluetooth.at"
- POWER_SCREEN_ON = "screen.on"
- POWER_SCREEN_FULL = "screen.full"
- POWER_CPU_IDLE = "cpu.idle"
- POWER_CPU_AWAKE = "cpu.awake"
- POWER_CPU_ACTIVE = "cpu.active"
- POWER_AMBIENT_DISPLAY = "ambient.on"
- POWER_GPS_ON = "gps.on"
- POWER_CAMERA_ON = "camera.on"
- POWER_FLASHLIGHT_ON = "flashlight.on"
- POWER_MICROPHONE_ON = "microphone.on"
- POWER_RADIO_ON = "radio.on"
- POWER_RADIO_SCANNING = "radio.scanning"
- POWER_RADIO_ACTIVE = "radio.active"
- POWER_AUDIO_ON = "audio.on"
- POWER_VIDEO_ON = "video.on"
- POWER_VIBRATION_ON = "vibration.on"
- POWER_NFC_ON = "nfc.on"
- POWER_NFC_ACTIVE = "nfc.active"
- POWER_USB_ON = "usb.on"
- POWER_MODEM_CONTROLLER_SLEEP = "modem.controller.sleep"
- POWER_MODEM_CONTROLLER_IDLE = "modem.controller.idle"
- POWER_MODEM_CONTROLLER_RX = "modem.controller.rx"
- POWER_MODEM_CONTROLLER_TX = "modem.controller.tx"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._profile_data: Dict[str, float] = {
- PowerProfile.POWER_WIFI_ON: 0.1,
- PowerProfile.POWER_WIFI_SCAN: 0.5,
- PowerProfile.POWER_WIFI_ACTIVE: 1.0,
- PowerProfile.POWER_SCREEN_ON: 0.5,
- PowerProfile.POWER_SCREEN_FULL: 2.0,
- PowerProfile.POWER_CPU_IDLE: 0.01,
- PowerProfile.POWER_CPU_AWAKE: 0.1,
- PowerProfile.POWER_CPU_ACTIVE: 1.0,
- PowerProfile.POWER_GPS_ON: 1.5,
- PowerProfile.POWER_BLUETOOTH_ON: 0.2,
- PowerProfile.POWER_BLUETOOTH_ACTIVE: 0.5,
- }
- self._battery_capacity = 4000.0
- self._average_battery_lifespan = 24.0
-
- def getAveragePower(self, type_: str) -> float:
- return self._profile_data.get(type_, 0.0)
-
- def getAveragePowerOrDefault(self, type_: str, defaultValue: float) -> float:
- return self._profile_data.get(type_, defaultValue)
-
- def getBatteryCapacity(self) -> float:
- return self._battery_capacity
-
- def setBatteryCapacity(self, capacityMah: float) -> None:
- self._battery_capacity = capacityMah
-
- def getAverageBatteryLifespan(self) -> float:
- return self._average_battery_lifespan
-
- def toString(self) -> str:
- return f"PowerProfile(battery={self._battery_capacity}mAh)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BatteryStats
-# ═══════════════════════════════════════════════════════════════
-
-class BatteryStats(Stub):
- """BatteryStats — 电池统计数据"""
-
- # 统计常量
- STATS_CURRENT = 0
- STATS_SINCE_CHARGED = 1
- STATS_SINCE_UNPLUGGED = 2
- STATS_UNPLUGGED = 3
-
- # 电源使用者的类型
- AUDIO = 0
- VIDEO = 1
- CAMERA = 2
- FLASHLIGHT = 3
- GPS = 4
- WIFI = 5
- BLUETOOTH = 6
- PHONE = 7
- SCREEN = 8
- CPU = 9
- IDLE = 10
- WAKELOCK = 11
- DATA = 12
- AMBIENT_DISPLAY = 13
- NFC = 14
- RADIO = 15
- MODEM = 16
- SENSORS = 17
- VIBRATION = 18
-
- def __init__(self):
- super().__init__()
- self._start_time = time.time()
- self._stats: Dict[int, float] = {}
- self._charge_counter = 0
- self._discharge_counter = 0
- self._charge_time_remaining = -1
- self._discharge_time_remaining = -1
- self._is_charging = False
- self._battery_level = 100
- self._temperature = 25.0
- self._voltage = 3800
- self._capacity = 4000
- self._screen_on_time = 0
- self._wifi_on_time = 0
- self._bluetooth_on_time = 0
- self._gps_on_time = 0
- self._cpu_time = 0
- self._wake_lock_time = 0
- self._mobile_data_time = 0
- self._audio_time = 0
- self._video_time = 0
- self._camera_time = 0
- self._flashlight_time = 0
- self._ambient_display_time = 0
- self._nfc_time = 0
- self._radio_time = 0
- self._modem_time = 0
- self._sensors_time = 0
- self._vibration_time = 0
- self._full_wake_lock_time = 0
- self._partial_wake_lock_time = 0
-
- def getBatteryLevel(self) -> int:
- return self._battery_level
-
- def setBatteryLevel(self, level: int) -> None:
- self._battery_level = max(0, min(100, level))
-
- def isCharging(self) -> bool:
- return self._is_charging
-
- def getTemperature(self) -> float:
- return self._temperature
-
- def getVoltage(self) -> int:
- return self._voltage
-
- def getCapacity(self) -> int:
- return self._capacity
-
- def getScreenOnTime(self) -> int:
- return self._screen_on_time
-
- def getWifiOnTime(self) -> int:
- return self._wifi_on_time
-
- def getBluetoothOnTime(self) -> int:
- return self._bluetooth_on_time
-
- def getGpsOnTime(self) -> int:
- return self._gps_on_time
-
- def getCpuTime(self) -> int:
- return self._cpu_time
-
- def getWakeLockTime(self) -> int:
- return self._wake_lock_time
-
- def getMobileDataTime(self) -> int:
- return self._mobile_data_time
-
- def getAudioTime(self) -> int:
- return self._audio_time
-
- def getVideoTime(self) -> int:
- return self._video_time
-
- def getCameraTime(self) -> int:
- return self._camera_time
-
- def getFlashlightTime(self) -> int:
- return self._flashlight_time
-
- def getAmbientDisplayTime(self) -> int:
- return self._ambient_display_time
-
- def getNfcTime(self) -> int:
- return self._nfc_time
-
- def getRadioTime(self) -> int:
- return self._radio_time
-
- def getModemTime(self) -> int:
- return self._modem_time
-
- def getSensorsTime(self) -> int:
- return self._sensors_time
-
- def getVibrationTime(self) -> int:
- return self._vibration_time
-
- def getUptime(self) -> int:
- return int(time.time() - self._start_time)
-
- def getChargeTimeRemaining(self) -> int:
- return self._charge_time_remaining
-
- def getDischargeTimeRemaining(self) -> int:
- return self._discharge_time_remaining
-
- def computeBatteryLevelRemaining(self) -> float:
- return float(self._battery_level)
-
- def getChargeCounter(self) -> int:
- return self._charge_counter
-
- def getDischargeCounter(self) -> int:
- return self._discharge_counter
-
- def toString(self) -> str:
- return f"BatteryStats(level={self._battery_level}%, charging={self._is_charging})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BatteryStatsManager
-# ═══════════════════════════════════════════════════════════════
-
-class BatteryStatsManager(Stub):
- """BatteryStatsManager — 电池统计管理器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._battery_stats = BatteryStats()
- self._lock = threading.Lock()
-
- def getBatteryStats(self) -> BatteryStats:
- with self._lock:
- return self._battery_stats
-
- def reportCharge(self, chargeMah: int) -> None:
- with self._lock:
- self._battery_stats._charge_counter += chargeMah
-
- def reportDischarge(self, dischargeMah: int) -> None:
- with self._lock:
- self._battery_stats._discharge_counter += dischargeMah
-
- def resetStatistics(self) -> None:
- with self._lock:
- self._battery_stats = BatteryStats()
-
- def toString(self) -> str:
- return f"BatteryStatsManager(stats={self._battery_stats})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BatteryManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class BatteryManager(_BaseBatteryManager):
- """BatteryManager (扩展) — 电池管理器 (继承 os.BatteryManager 的所有方法)"""
-
- EXTRA_STATUS = "status"
- EXTRA_HEALTH = "health"
- EXTRA_PRESENT = "present"
- EXTRA_LEVEL = "level"
- EXTRA_SCALE = "scale"
- EXTRA_ICON_SMALL = "icon-small"
- EXTRA_PLUGGED = "plugged"
- EXTRA_TEMPERATURE = "temperature"
- EXTRA_VOLTAGE = "voltage"
- EXTRA_TECHNOLOGY = "technology"
- EXTRA_CHARGE_COUNTER = "charge_counter"
- EXTRA_CURRENT_NOW = "current_now"
- EXTRA_CURRENT_AVERAGE = "current_average"
- EXTRA_ENERGY_COUNTER = "energy_counter"
- EXTRA_SEQUENCE = "sequence"
- EXTRA_BATTERY_LOW = "battery_low"
- EXTRA_MAX_CHARGING_CURRENT = "max_charging_current"
- EXTRA_MAX_CHARGING_VOLTAGE = "max_charging_voltage"
- EXTRA_CHARGE_TIME_REMAINING = "charge_time_remaining"
- EXTRA_DISCHARGE_TIME_REMAINING = "discharge_time_remaining"
- EXTRA_IS_CAPACITY_ESTIMATED = "is_capacity_estimated"
- EXTRA_CAPACITY_PERCENTAGE = "capacity_percentage"
-
- ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED"
- ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW"
- ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY"
- ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED"
- ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED"
- ACTION_CHARGING = "android.intent.action.CHARGING"
- ACTION_DISCHARGING = "android.intent.action.DISCHARGING"
-
- BATTERY_STATUS_UNKNOWN = BATTERY_STATUS_UNKNOWN
- BATTERY_STATUS_CHARGING = BATTERY_STATUS_CHARGING
- BATTERY_STATUS_DISCHARGING = BATTERY_STATUS_DISCHARGING
- BATTERY_STATUS_NOT_CHARGING = BATTERY_STATUS_NOT_CHARGING
- BATTERY_STATUS_FULL = BATTERY_STATUS_FULL
-
- BATTERY_HEALTH_UNKNOWN = BATTERY_HEALTH_UNKNOWN
- BATTERY_HEALTH_GOOD = BATTERY_HEALTH_GOOD
- BATTERY_HEALTH_OVERHEAT = BATTERY_HEALTH_OVERHEAT
- BATTERY_HEALTH_DEAD = BATTERY_HEALTH_DEAD
- BATTERY_HEALTH_OVER_VOLTAGE = BATTERY_HEALTH_OVER_VOLTAGE
- BATTERY_HEALTH_UNSPECIFIED_FAILURE = BATTERY_HEALTH_UNSPECIFIED_FAILURE
- BATTERY_HEALTH_COLD = BATTERY_HEALTH_COLD
-
- BATTERY_PLUGGED_AC = BATTERY_PLUGGED_AC
- BATTERY_PLUGGED_USB = BATTERY_PLUGGED_USB
- BATTERY_PLUGGED_WIRELESS = BATTERY_PLUGGED_WIRELESS
-
- BATTERY_PROPERTY_CAPACITY = BATTERY_PROPERTY_CAPACITY
- BATTERY_PROPERTY_CHARGE_COUNTER = BATTERY_PROPERTY_CHARGE_COUNTER
- BATTERY_PROPERTY_CURRENT_NOW = BATTERY_PROPERTY_CURRENT_NOW
- BATTERY_PROPERTY_CURRENT_AVERAGE = BATTERY_PROPERTY_CURRENT_AVERAGE
- BATTERY_PROPERTY_ENERGY_COUNTER = BATTERY_PROPERTY_ENERGY_COUNTER
- BATTERY_PROPERTY_CHARGE_TIME_REMAINING = BATTERY_PROPERTY_CHARGE_TIME_REMAINING
- BATTERY_PROPERTY_DISCHARGE_TIME_REMAINING = BATTERY_PROPERTY_DISCHARGE_TIME_REMAINING
-
- _instance: Optional["BatteryManager"] = None
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._battery_level = 100
- self._status = BATTERY_STATUS_FULL
- self._health = BATTERY_HEALTH_GOOD
- self._present = True
- self._plugged = BATTERY_PLUGGED_AC
- self._temperature = 25
- self._voltage = 3800
- self._technology = "Li-ion"
- self._capacity = 4000
- self._charge_counter = 0
- self._current_now = 0
- self._current_average = 0
- self._energy_counter = 0
- self._max_charging_current = 3000
- self._max_charging_voltage = 4500
- self._charge_time_remaining = 0
- self._discharge_time_remaining = -1
- self._is_capacity_estimated = False
- self._capacity_percentage = 100.0
- if _USE_LINUX:
- self._refresh_from_linux()
-
- _LINUX_STATUS_MAP = {
- "charging": BATTERY_STATUS_CHARGING,
- "discharging": BATTERY_STATUS_DISCHARGING,
- "not charging": BATTERY_STATUS_NOT_CHARGING,
- "full": BATTERY_STATUS_FULL,
- "unknown": BATTERY_STATUS_UNKNOWN,
- }
-
- def _get_linux_battery_info(self) -> dict:
- """从 LinuxPower 获取真实电池信息"""
- try:
- return LinuxPower.get_battery_info() or {}
- except Exception:
- return {}
-
- def _refresh_from_linux(self):
- """用 Linux 真实电池信息刷新内部状态"""
- info = self._get_linux_battery_info()
- if not info:
- return
- self._present = bool(info.get("present", False))
- level = info.get("level", -1)
- if self._present and isinstance(level, (int, float)) and level >= 0:
- self._battery_level = int(level)
- self._capacity_percentage = float(level)
- # BATTERY_PROPERTY_CAPACITY 在 Android 中返回百分比 (0-100)
- self._capacity = int(level)
- else:
- # 无电池或电量未知
- self._battery_level = -1
- self._capacity_percentage = 0.0
- self._capacity = -1
- status_str = str(info.get("status", "unknown")).lower()
- self._status = self._LINUX_STATUS_MAP.get(status_str, BATTERY_STATUS_UNKNOWN)
- voltage = info.get("voltage", 0)
- if isinstance(voltage, (int, float)):
- self._voltage = int(voltage * 1000) # V -> mV
- temperature = info.get("temperature", 0)
- if isinstance(temperature, (int, float)):
- self._temperature = temperature # 摄氏度
- self._technology = info.get("technology", "") or "Li-ion"
- if self._status == BATTERY_STATUS_CHARGING:
- self._plugged = BATTERY_PLUGGED_AC
- else:
- self._plugged = 0
-
- @staticmethod
- def getInstance(context: Any) -> "BatteryManager":
- if BatteryManager._instance is None:
- BatteryManager._instance = BatteryManager(context)
- return BatteryManager._instance
-
- def getIntProperty(self, id: int) -> int:
- if _USE_LINUX:
- self._refresh_from_linux()
- properties = {
- BATTERY_PROPERTY_CAPACITY: self._capacity,
- BATTERY_PROPERTY_CHARGE_COUNTER: self._charge_counter,
- BATTERY_PROPERTY_CURRENT_NOW: self._current_now,
- BATTERY_PROPERTY_CURRENT_AVERAGE: self._current_average,
- BATTERY_PROPERTY_ENERGY_COUNTER: self._energy_counter,
- BATTERY_PROPERTY_CHARGE_TIME_REMAINING: self._charge_time_remaining,
- BATTERY_PROPERTY_DISCHARGE_TIME_REMAINING: self._discharge_time_remaining,
- BATTERY_PROPERTY_STATUS: self._status,
- BATTERY_PROPERTY_TEMPERATURE: int(self._temperature),
- BATTERY_PROPERTY_VOLTAGE: self._voltage,
- }
- return properties.get(id, 0)
-
- def getLongProperty(self, id: int) -> int:
- return self.getIntProperty(id)
-
- def isCharging(self) -> bool:
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._status == BATTERY_STATUS_CHARGING or self._status == BATTERY_STATUS_FULL
-
- def getBatteryLevel(self) -> int:
- if _USE_LINUX:
- self._refresh_from_linux()
- return self._battery_level
-
- def getInt(intent: Any, key: str, defaultValue: int) -> int:
- return defaultValue
-
- def toString(self) -> str:
- return (
- f"BatteryManager(level={self._battery_level}%, "
- f"status={self._status}, "
- f"charging={self.isCharging()})"
- )
-
-
-# ═══════════════════════════════════════════════════════════════
-# BatterySaverController
-# ═══════════════════════════════════════════════════════════════
-
-class BatterySaverController(Stub):
- """BatterySaverController — 电池节能控制器"""
-
- POLICY_MANUAL = 0
- POLICY_AUTOMATIC = 1
- POLICY_DYNAMIC = 2
- POLICY_PERCENTAGE = 3
- POLICY_TIMEOUT = 4
- POLICY_FULL = 5
- POLICY_ADAPTIVE = 6
-
- STATE_OFF = 0
- STATE_ON = 1
- STATE_AUTO = 2
- STATE_MANUAL_ON = 3
- STATE_DYNAMIC_ON = 4
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._state = BatterySaverController.STATE_OFF
- self._policy = BatterySaverController.POLICY_MANUAL
- self._threshold = 15
- self._last_trigger_time: Optional[float] = None
- self._trigger_reason = ""
- self._listeners: List[Callable] = []
-
- def setEnabled(self, enabled: bool) -> None:
- self._state = BatterySaverController.STATE_ON if enabled else BatterySaverController.STATE_OFF
- for listener in self._listeners:
- try:
- listener(enabled)
- except Exception:
- pass
-
- def isEnabled(self) -> bool:
- return self._state == BatterySaverController.STATE_ON
-
- def getPolicy(self) -> int:
- return self._policy
-
- def setPolicy(self, policy: int) -> None:
- self._policy = policy
-
- def getThreshold(self) -> int:
- return self._threshold
-
- def setThreshold(self, threshold: int) -> None:
- self._threshold = max(0, min(100, threshold))
-
- def getTriggerReason(self) -> str:
- return self._trigger_reason
-
- def addListener(self, listener: Callable) -> None:
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeListener(self, listener: Callable) -> None:
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def toString(self) -> str:
- return f"BatterySaverController(enabled={self.isEnabled()}, threshold={self._threshold}%)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PowerManager (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class PowerManager(_BasePowerManager):
- """PowerManager — 电源管理器 (扩展,继承 os.PowerManager 的所有方法)"""
-
- PARTIAL_WAKE_LOCK = PARTIAL_WAKE_LOCK
- FULL_WAKE_LOCK = FULL_WAKE_LOCK
- SCREEN_DIM_WAKE_LOCK = SCREEN_DIM_WAKE_LOCK
- SCREEN_BRIGHT_WAKE_LOCK = SCREEN_BRIGHT_WAKE_LOCK
- PROXIMITY_SCREEN_OFF_WAKE_LOCK = PROXIMITY_SCREEN_OFF_WAKE_LOCK
- DOZE_WAKE_LOCK = DOZE_WAKE_LOCK
- DRAW_WAKE_LOCK = DRAW_WAKE_LOCK
-
- ACQUIRE_CAUSES_WAKEUP = ACQUIRE_CAUSES_WAKEUP
- ON_AFTER_RELEASE = ON_AFTER_RELEASE
-
- LOCATION_MODE_NO_CHANGE = 0
- LOCATION_MODE_GPS_DISABLED = 1
- LOCATION_MODE_FOREGROUND_ONLY = 2
- LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF = 3
- LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 4
-
- SOUND_TRIGGER_MODE_NO_CHANGE = 0
- SOUND_TRIGGER_MODE_ALL_DISABLED = 1
- SOUND_TRIGGER_MODE_CRITICAL_ONLY = 2
- SOUND_TRIGGER_MODE_NEVER = 3
-
- GO_TO_SLEEP_REASON_APPLICATION = 0
- GO_TO_SLEEP_REASON_DEVICE_ADMIN = 1
- GO_TO_SLEEP_REASON_TIMEOUT = 2
- GO_TO_SLEEP_REASON_LID_SWITCH = 3
- GO_TO_SLEEP_REASON_POWER_BUTTON = 4
- GO_TO_SLEEP_REASON_HDMI = 5
- GO_TO_SLEEP_REASON_SLEEP_GESTURE = 6
- GO_TO_SLEEP_REASON_ACCESSIBILITY = 7
- GO_TO_SLEEP_REASON_FORCE_SUSPEND = 8
-
- WAKE_REASON_UNKNOWN = 0
- WAKE_REASON_POWER_BUTTON = 1
- WAKE_REASON_APPLICATION = 2
- WAKE_REASON_PLUGGED_IN = 3
- WAKE_REASON_GESTURE = 4
- WAKE_REASON_CAMERA_LAUNCH = 5
- WAKE_REASON_WAKE_KEY = 6
- WAKE_REASON_WAKE_MOTION = 7
- WAKE_REASON_HDMI = 8
- WAKE_REASON_DISPLAY_GROUP_REMOVED = 9
- WAKE_REASON_DREAM_MANAGER = 10
- WAKE_REASON_LID = 11
- WAKE_REASON_UNLOCK = 12
- WAKE_REASON_TAP = 13
- WAKE_REASON_LIFT = 14
- WAKE_REASON_PICK_UP = 15
- WAKE_REASON_DOUBLE_TAP = 16
- WAKE_REASON_SWIPE = 17
- WAKE_REASON_BACK_GESTURE = 18
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._is_interactive = True
- self._is_power_save_mode = False
- self._is_device_idle_mode = False
- self._is_light_device_idle_mode = False
- self._is_screen_on = True
- self._screen_brightness = 255
- self._screen_brightness_mode = SCREEN_BRIGHT_MODE_AUTOMATIC
- self._wake_locks: Dict[str, "PowerManager.WakeLock"] = {}
- self._is_rebooting = False
- self._shutdown_requested = False
- self._thermal_status = THERMAL_STATUS_NONE
- self._power_save_state = PowerSaveState()
- self._current_wake_up_reason = PowerManager.WAKE_REASON_UNKNOWN
-
- def isInteractive(self) -> bool:
- if _USE_LINUX:
- return self.isScreenOn()
- return self._is_interactive
-
- def isPowerSaveMode(self) -> bool:
- return self._is_power_save_mode
-
- def isDeviceIdleMode(self) -> bool:
- return self._is_device_idle_mode
-
- def isLightDeviceIdleMode(self) -> bool:
- return self._is_light_device_idle_mode
-
- def isRebootingUserspaceSupported(self) -> bool:
- return True
-
- def isScreenOn(self) -> bool:
- if _USE_LINUX:
- import os as _os_mod
- display = _os_mod.environ.get("DISPLAY", "")
- if display:
- return True
- wayland = _os_mod.environ.get("WAYLAND_DISPLAY", "")
- return bool(wayland)
- return self._is_screen_on
-
- def isWakeLockLevelSupported(self, level: int) -> bool:
- return level in [
- PARTIAL_WAKE_LOCK, FULL_WAKE_LOCK, SCREEN_DIM_WAKE_LOCK,
- SCREEN_BRIGHT_WAKE_LOCK, PROXIMITY_SCREEN_OFF_WAKE_LOCK,
- DOZE_WAKE_LOCK, DRAW_WAKE_LOCK,
- ]
-
- def newWakeLock(self, levelAndFlags: int, tag: str) -> "PowerManager.WakeLock":
- wl = PowerManager.WakeLock(self, levelAndFlags, tag)
- self._wake_locks[tag] = wl
- return wl
-
- def goToSleep(self, time: int, reason: int, flags: int = 0) -> None:
- self._is_interactive = False
- self._is_screen_on = False
-
- def wakeUp(self, time: int, reason: int = WAKE_REASON_UNKNOWN) -> None:
- self._is_interactive = True
- self._is_screen_on = True
- self._current_wake_up_reason = reason
-
- def userActivity(self, when: int, noChangeLights: bool) -> None:
- pass
-
- def userActivity(self, when: int, event: int, flags: int = 0) -> None:
- pass
-
- def getCurrentWakeUpReason(self) -> int:
- return self._current_wake_up_reason
-
- def getThermalStatus(self) -> int:
- return self._thermal_status
-
- def setThermalStatus(self, status: int) -> None:
- self._thermal_status = status
-
- def getPowerSaveState(self, serviceType: int) -> PowerSaveState:
- return self._power_save_state
-
- def reboot(self, reason: Optional[str] = None) -> None:
- self._is_rebooting = True
- raise AndroidOnlyError("PowerManager.reboot() 仅在 Android 设备上可用")
-
- def shutdown(self, reason: Optional[str] = None) -> None:
- self._shutdown_requested = True
- raise AndroidOnlyError("PowerManager.shutdown() 仅在 Android 设备上可用")
-
- def getCurrentBrightness(self) -> int:
- return self._screen_brightness
-
- def setCurrentBrightness(self, brightness: int) -> None:
- self._screen_brightness = max(0, min(255, brightness))
-
- def getDefaultScreenBrightnessSetting(self) -> int:
- return 127
-
- def getMinimumBrightnessSetting(self) -> int:
- return 1
-
- def getMaximumBrightnessSetting(self) -> int:
- return 255
-
- def toString(self) -> str:
- return (
- f"PowerManager(interactive={self._is_interactive}, "
- f"powersave={self._is_power_save_mode}, "
- f"screen_on={self._is_screen_on})"
- )
-
- # ═══════════════════════════════════════════════════════════
- # PowerManager.WakeLock
- # ═══════════════════════════════════════════════════════════
-
- class WakeLock(Stub):
- """PowerManager.WakeLock — 唤醒锁"""
-
- def __init__(self, manager: "PowerManager", levelAndFlags: int, tag: str):
- super().__init__()
- self._manager = manager
- self._level_and_flags = levelAndFlags
- self._tag = tag
- self._is_held = False
- self._reference_counted = True
- self._work_source: Optional[Any] = None
- self._history_tag: Optional[str] = None
- self._acquire_time: Optional[float] = None
-
- def acquire(self, timeoutMillis: int = -1) -> None:
- self._is_held = True
- self._acquire_time = time.time()
-
- def acquire(self, timeOut: int) -> None:
- self._is_held = True
- self._acquire_time = time.time()
-
- def release(self, flags: int = 0) -> None:
- self._is_held = False
-
- def isHeld(self) -> bool:
- return self._is_held
-
- def setReferenceCounted(self, value: bool) -> None:
- self._reference_counted = value
-
- def setWorkSource(self, ws: Any) -> None:
- self._work_source = ws
-
- def setHistoryTag(self, tag: str) -> None:
- self._history_tag = tag
-
- def getTag(self) -> str:
- return self._tag
-
- def getLevelAndFlags(self) -> int:
- return self._level_and_flags
-
- def toString(self) -> str:
- return f"WakeLock(tag={self._tag}, held={self._is_held})"
\ No newline at end of file
diff --git a/android_pyapi/android/os_storage.py b/android_pyapi/android/os_storage.py
deleted file mode 100644
index 4da3fb7..0000000
--- a/android_pyapi/android/os_storage.py
+++ /dev/null
@@ -1,387 +0,0 @@
-"""
-Android os.storage 组件 — StorageManager, StorageVolume, DiskInfo, VolumeInfo 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import shutil
-import threading
-import uuid
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError, resolve_android_path
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# StorageVolume
-# ═══════════════════════════════════════════════════════════════
-
-class StorageVolume(Stub):
- """StorageVolume — 存储卷"""
-
- STATE_MOUNTED = "mounted"
- STATE_MOUNTED_READ_ONLY = "mounted_ro"
- STATE_REMOVED = "removed"
- STATE_UNMOUNTED = "unmounted"
- STATE_CHECKING = "checking"
- STATE_EJECTING = "ejecting"
- STATE_MOUNTABLE = "mountable"
- STATE_UNMOUNTABLE = "unmountable"
- STATE_BAD_REMOVAL = "bad_removal"
- STATE_DAMAGED = "damaged"
-
- STORAGE_TYPE_INTERNAL = 0
- STORAGE_TYPE_EXTERNAL = 1
-
- def __init__(self, path: str = "/sdcard", description: str = "Internal shared storage",
- primary: bool = True, removable: bool = False,
- state: str = STATE_MOUNTED, max_file_size: int = 4 * 1024 * 1024 * 1024,
- storage_type: int = STORAGE_TYPE_INTERNAL):
- super().__init__()
- self._path = path
- self._description = description
- self._primary = primary
- self._removable = removable
- self._state = state
- self._max_file_size = max_file_size
- self._uuid = str(uuid.uuid4()).replace("-", "")[:16]
- self._user_label = description
- self._storage_type = storage_type
-
- def getPath(self) -> str:
- return self._path
-
- def getDescription(self, context: Any = None) -> str:
- return self._description
-
- def isPrimary(self) -> bool:
- return self._primary
-
- def isRemovable(self) -> bool:
- return self._removable
-
- def getState(self) -> str:
- return self._state
-
- def getMaxFileSize(self) -> int:
- return self._max_file_size
-
- def getUuid(self) -> str:
- return self._uuid
-
- def getUserLabel(self) -> str:
- return self._user_label
-
- def getDirectory(self) -> Any:
- from pathlib import Path
- return Path(self._path) if os.path.isdir(self._path) else None
-
- def getStorageType(self) -> int:
- return self._storage_type
-
- def createAccessIntent(self, directoryName: str) -> Any:
- return None
-
- def toString(self) -> str:
- return (f"StorageVolume{{path={self._path}, primary={self._primary}, "
- f"state={self._state}, removable={self._removable}}}")
-
-
-# ═══════════════════════════════════════════════════════════════
-# DiskInfo
-# ═══════════════════════════════════════════════════════════════
-
-class DiskInfo(Stub):
- """DiskInfo — 磁盘信息"""
-
- def __init__(self, id_: str = "", label: str = "", size: int = 0,
- is_sd: bool = False, is_usb: bool = False,
- is_adoptable: bool = False):
- super().__init__()
- self._id = id_
- self._label = label
- self._size = size
- self._is_sd = is_sd
- self._is_usb = is_usb
- self._is_adoptable = is_adoptable
-
- def getId(self) -> str:
- return self._id
-
- def getLabel(self) -> str:
- return self._label
-
- def getSize(self) -> int:
- return self._size
-
- def isSd(self) -> bool:
- return self._is_sd
-
- def isUsb(self) -> bool:
- return self._is_usb
-
- def isAdoptable(self) -> bool:
- return self._is_adoptable
-
- def toString(self) -> str:
- return (f"DiskInfo{{id={self._id}, label={self._label}, "
- f"size={self._size}, sd={self._is_sd}, usb={self._is_usb}}}")
-
-
-# ═══════════════════════════════════════════════════════════════
-# VolumeInfo
-# ═══════════════════════════════════════════════════════════════
-
-class VolumeInfo(Stub):
- """VolumeInfo — 卷信息"""
-
- TYPE_PRIVATE = 1
- TYPE_PUBLIC = 2
- TYPE_EMULATED = 3
- TYPE_STUB = 4
- TYPE_OBB = 5
-
- STATE_UNMOUNTED = 0
- STATE_CHECKING = 1
- STATE_MOUNTED = 2
- STATE_MOUNTED_READ_ONLY = 3
- STATE_FORMATTING = 4
- STATE_EJECTING = 5
- STATE_BAD_REMOVAL = 6
- STATE_DAMAGED = 7
-
- def __init__(self, id_: str = "", type_: int = TYPE_EMULATED,
- disk: Optional[DiskInfo] = None, partition: str = "",
- path: str = "", internal_path: str = "",
- fs_type: str = "ext4", fs_uuid: str = "",
- fs_label: str = "", state: int = STATE_MOUNTED,
- mount_user_id: int = 0):
- super().__init__()
- self._id = id_
- self._type = type_
- self._disk = disk
- self._partition = partition
- self._path = path
- self._internal_path = internal_path
- self._fs_type = fs_type
- self._fs_uuid = fs_uuid
- self._fs_label = fs_label
- self._state = state
- self._mount_user_id = mount_user_id
-
- def getId(self) -> str:
- return self._id
-
- def getType(self) -> int:
- return self._type
-
- def getDisk(self) -> Optional[DiskInfo]:
- return self._disk
-
- def getPartition(self) -> str:
- return self._partition
-
- def getPath(self) -> Optional[str]:
- return self._path
-
- def getInternalPath(self) -> Optional[str]:
- return self._internal_path
-
- def getFsType(self) -> str:
- return self._fs_type
-
- def getFsUuid(self) -> str:
- return self._fs_uuid
-
- def getFsLabel(self) -> str:
- return self._fs_label
-
- def getState(self) -> int:
- return self._state
-
- def getMountUserId(self) -> int:
- return self._mount_user_id
-
- def toString(self) -> str:
- return (f"VolumeInfo{{id={self._id}, type={self._type}, "
- f"state={self._state}, path={self._path}}}")
-
-
-# ═══════════════════════════════════════════════════════════════
-# VolumeRecord
-# ═══════════════════════════════════════════════════════════════
-
-class VolumeRecord(Stub):
- """VolumeRecord — 卷记录"""
-
- def __init__(self, fs_uuid: str = "", part_guid: str = "",
- type_: int = VolumeInfo.TYPE_PRIVATE,
- fs_label: str = "", nickname: str = "",
- created_millis: int = 0, last_seen_millis: int = 0,
- approved_for_type: bool = False):
- super().__init__()
- self._fs_uuid = fs_uuid
- self._part_guid = part_guid
- self._type = type_
- self._fs_label = fs_label
- self._nickname = nickname
- self._created_millis = created_millis
- self._last_seen_millis = last_seen_millis
- self._approved_for_type = approved_for_type
- self._pseudo_uuid = str(uuid.uuid4())
-
- def getFsUuid(self) -> str:
- return self._fs_uuid
-
- def getPartGuid(self) -> str:
- return self._part_guid
-
- def getType(self) -> int:
- return self._type
-
- def getFsLabel(self) -> str:
- return self._fs_label
-
- def getNickname(self) -> str:
- return self._nickname
-
- def getCreatedMillis(self) -> int:
- return self._created_millis
-
- def getLastSeenMillis(self) -> int:
- return self._last_seen_millis
-
- def isApprovedForType(self) -> bool:
- return self._approved_for_type
-
- def getPseudoUuid(self) -> str:
- return self._pseudo_uuid
-
- def toString(self) -> str:
- return f"VolumeRecord{{uuid={self._fs_uuid}, type={self._type}, label={self._fs_label}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# StorageManager
-# ═══════════════════════════════════════════════════════════════
-
-class StorageManager(Stub):
- """StorageManager — 存储管理器"""
-
- ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"
- ACTION_CLEAR_APP_CACHE = "android.os.storage.action.CLEAR_APP_CACHE"
- UUID_DEFAULT = "primary_physical"
- EXTRA_UUID = "android.os.storage.extra.UUID"
- EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"
-
- def __init__(self):
- super().__init__()
- self._lock = threading.Lock()
- self._primary_volume = StorageVolume(
- path="/sdcard",
- description="Internal shared storage",
- primary=True,
- removable=False,
- )
- self._volumes: List[StorageVolume] = [
- self._primary_volume,
- StorageVolume(
- path="/sdcard/external",
- description="External SD Card",
- primary=False,
- removable=True,
- state=StorageVolume.STATE_UNMOUNTED,
- storage_type=StorageVolume.STORAGE_TYPE_EXTERNAL,
- ),
- ]
-
- # ── Volumes ──
-
- def getStorageVolumes(self) -> List[StorageVolume]:
- with self._lock:
- return list(self._volumes)
-
- def getVolumeList(self) -> List[StorageVolume]:
- return self.getStorageVolumes()
-
- def getPrimaryStorageVolume(self) -> StorageVolume:
- return self._primary_volume
-
- def getPrimaryStorageSize(self) -> int:
- stat = shutil.disk_usage(os.path.expanduser("~"))
- return stat.total
-
- def getBestFitPrimaryVolume(self) -> StorageVolume:
- return self._primary_volume
-
- def getMountState(self, mountPoint: str) -> bool:
- return os.path.ismount(mount_point) if os.path.exists(mount_point) else False
-
- # ── Mount / Unmount / Format ──
-
- def mount(self, volumeId: str) -> int:
- return 0
-
- def unmount(self, volumeId: str) -> int:
- return 0
-
- def format(self, volumeId: str) -> int:
- return 0
-
- # ── Allocation ──
-
- def allocateBytes(self, volumeUuid: str, bytes_: int, flags: int = 0) -> int:
- stat = shutil.disk_usage(os.path.expanduser("~"))
- if stat.free >= bytes_:
- return 0
- return -1
-
- def allocateBytesForUuid(self, volumeUuid: str, bytes_: int, flags: int = 0) -> int:
- return self.allocateBytes(volumeUuid, bytes_, flags)
-
- def isAllocationSupported(self, volumeUuid: str) -> bool:
- return True
-
- def cacheBehavior(self, uuid_: str) -> int:
- return 0
-
- # ── Permission ──
-
- def checkPermission(self, volumeUuid: str, pid: int, uid: int) -> int:
- return 0
-
- # ── OBB ──
-
- def isObbMounted(self, filename: str) -> bool:
- return False
-
- def mountObb(self, filename: str, key: str, listener: Any) -> bool:
- return True
-
- def unmountObb(self, filename: str, force: bool, listener: Any) -> bool:
- return True
-
- def getMountedObbPath(self, filename: str) -> Optional[str]:
- return None
-
- def toString(self) -> str:
- return f"StorageManager@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "StorageManager",
- "StorageVolume",
- "DiskInfo",
- "VolumeInfo",
- "VolumeRecord",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/os_user.py b/android_pyapi/android/os_user.py
deleted file mode 100644
index 2c666d2..0000000
--- a/android_pyapi/android/os_user.py
+++ /dev/null
@@ -1,408 +0,0 @@
-"""
-Android os UserManager 组件 — UserManager, UserHandle, UserInfo 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import threading
-import uuid
-from typing import Any, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError, _sdcard_root
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# UserHandle
-# ═══════════════════════════════════════════════════════════════
-
-class UserHandle(Stub):
- """UserHandle — 用户句柄"""
-
- MY_USER_ID = 0
- USER_OWNER = 0
- USER_CURRENT = -2
- USER_CURRENT_OR_SELF = -3
- USER_NULL = -10000
- USER_ALL = -1
- USER_SYSTEM = 0
- USER_SERIAL_NUMBER_SYSTEM = 0
-
- PER_USER_RANGE = 100000
-
- def __init__(self, userId: int = MY_USER_ID):
- super().__init__()
- self._userId = userId
-
- def getUserId(self) -> int:
- return self._userId
-
- def getAppId(self, uid: int) -> int:
- return uid % self.PER_USER_RANGE
-
- def getUserId(self, uid: int) -> int:
- return uid // self.PER_USER_RANGE
-
- @staticmethod
- def myUserId() -> int:
- return 0
-
- @staticmethod
- def isIsolated(uid: int) -> bool:
- return False
-
- @staticmethod
- def isApp(uid: int) -> bool:
- return 10000 <= (uid % 100000) < 20000
-
- @staticmethod
- def isSameUser(uid1: int, uid2: int) -> bool:
- return (uid1 // 100000) == (uid2 // 100000)
-
- @staticmethod
- def isSystem(uid: int) -> bool:
- return uid == 1000
-
- def toString(self) -> str:
- return f"UserHandle{{{self._userId}}}"
-
- def hashCode(self) -> int:
- return hash(self._userId) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, UserHandle):
- return False
- return self._userId == other._userId
-
-
-# ═══════════════════════════════════════════════════════════════
-# UserInfo
-# ═══════════════════════════════════════════════════════════════
-
-class UserInfo(Stub):
- """UserInfo — 用户信息"""
-
- FLAG_PRIMARY = 0x00000001
- FLAG_ADMIN = 0x00000002
- FLAG_GUEST = 0x00000004
- FLAG_RESTRICTED = 0x00000008
- FLAG_MANAGED_PROFILE = 0x00000010
- FLAG_PROFILE = 0x00000020
- FLAG_DEMO = 0x00000200
- FLAG_SYSTEM = 0x00001000
-
- def __init__(self, id_: int = 0, name: str = "System User",
- icon_path: str = "", flags: int = FLAG_PRIMARY | FLAG_ADMIN | FLAG_SYSTEM):
- super().__init__()
- self.id: int = id_
- self.name: str = name
- self.iconPath: str = icon_path
- self.flags: int = flags
-
- def isPrimary(self) -> bool:
- return bool(self.flags & self.FLAG_PRIMARY)
-
- def isAdmin(self) -> bool:
- return bool(self.flags & self.FLAG_ADMIN)
-
- def isGuest(self) -> bool:
- return bool(self.flags & self.FLAG_GUEST)
-
- def isDemo(self) -> bool:
- return bool(self.flags & self.FLAG_DEMO)
-
- def isManagedProfile(self) -> bool:
- return bool(self.flags & self.FLAG_MANAGED_PROFILE)
-
- def isRestricted(self) -> bool:
- return bool(self.flags & self.FLAG_RESTRICTED)
-
- def isSystemOnly(self) -> bool:
- return bool(self.flags & self.FLAG_SYSTEM)
-
- def isProfile(self) -> bool:
- return bool(self.flags & self.FLAG_PROFILE)
-
- def toString(self) -> str:
- return f"UserInfo{{id={self.id}, name={self.name}, flags={self.flags}}}"
-
- def hashCode(self) -> int:
- return hash(self.id) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, UserInfo):
- return False
- return self.id == other.id
-
-
-# ═══════════════════════════════════════════════════════════════
-# UserManager
-# ═══════════════════════════════════════════════════════════════
-
-class UserManager(Stub):
- """UserManager — 用户管理器"""
-
- USER_CREATION_FAILED_NOT_PERMITTED = -1
- USER_CREATION_FAILED_NO_MORE_USERS = -2
-
- # DISALLOW_* restrictions
- DISALLOW_CONFIG_WIFI = "no_config_wifi"
- DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"
- DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks"
- DISALLOW_CONFIG_TETHERING = "no_config_tethering"
- DISALLOW_CONFIG_SMS = "no_config_sms"
- DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials"
- DISALLOW_CONFIG_VPN = "no_config_vpn"
- DISALLOW_CONFIG_LOCALE = "no_config_locale"
- DISALLOW_CONFIG_DATE_TIME = "no_config_date_time"
- DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness"
- DISALLOW_FACTORY_RESET = "no_factory_reset"
- DISALLOW_APPS_CONTROL = "no_control_apps"
- DISALLOW_CREATE_WINDOWS = "no_create_windows"
- DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste"
- DISALLOW_DEBUGGING_FEATURES = "no_debugging_features"
- DISALLOW_INSTALL_APPS = "no_install_apps"
- DISALLOW_UNINSTALL_APPS = "no_uninstall_apps"
- DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts"
- DISALLOW_OUTGOING_CALLS = "no_outgoing_calls"
- DISALLOW_REMOVE_USER = "no_remove_user"
- DISALLOW_SAFE_BOOT = "no_safe_boot"
- DISALLOW_SET_USER_RESTRICTIONS = "no_set_user_restrictions"
- DISALLOW_SHARE_LOCATION = "no_share_location"
- DISALLOW_SMS = "no_sms"
- DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone"
- DISALLOW_UNMUTE_DEVICE = "no_unmute_device"
- DISALLOW_ADJUST_VOLUME = "no_adjust_volume"
-
- KEY_RESTRICTIONS_PENDING = "restrictions_pending"
-
- PIN_VERIFICATION_FAILURE_INVALID = -3
- PIN_VERIFICATION_FAILURE_NOT_SET = -2
- PIN_VERIFICATION_SUCCESS = 0
-
- MAX_SUPPORTED_USERS = 4
-
- def __init__(self):
- super().__init__()
- self._lock = threading.Lock()
- self._next_user_id = 10
- self._users: Dict[int, UserInfo] = {0: UserInfo(0, "System User")}
- self._serial_numbers: Dict[int, int] = {0: 0}
- self._next_serial = 1
- self._restrictions: Dict[str, Set[str]] = {}
- self._quiet_mode: Set[int] = set()
-
- # ── User counting ──
-
- def getUserCount(self) -> int:
- with self._lock:
- return len(self._users)
-
- def getUsers(self) -> List[UserInfo]:
- with self._lock:
- return list(self._users.values())
-
- def getSystemUser(self) -> UserInfo:
- return self._users.get(0, UserInfo(0, "System User"))
-
- def getForegroundUser(self) -> UserHandle:
- return UserHandle(0)
-
- def getMaxSupportedUsers(self) -> int:
- return self.MAX_SUPPORTED_USERS
-
- def supportsMultipleUsers(self) -> bool:
- return True
-
- # ── Serial numbers ──
-
- def getSerialNumberForUser(self, user: UserHandle) -> int:
- return self._serial_numbers.get(user.getUserId(), -1)
-
- def getUserForSerialNumber(self, serialNumber: int) -> Optional[UserHandle]:
- for uid, sn in self._serial_numbers.items():
- if sn == serialNumber:
- return UserHandle(uid)
- return None
-
- # ── Profiles ──
-
- def getUserProfiles(self) -> List[UserInfo]:
- with self._lock:
- return list(self._users.values())
-
- def getProfileIds(self, userId: int, enabledOnly: bool = False) -> List[int]:
- return [0, userId] if enabledOnly else [uid for uid in self._users]
-
- def getProfileIdsWithDisabled(self, userId: int) -> List[int]:
- return self.getProfileIds(userId, enabledOnly=False)
-
- def getEnabledProfileIds(self, userId: int) -> List[int]:
- return self.getProfileIds(userId, enabledOnly=True)
-
- def getUserProfileIds(self, userId: int) -> List[int]:
- return self.getProfileIds(userId)
-
- def getProfileParent(self, userId: int) -> Optional[UserHandle]:
- return None
-
- def getProfileParentId(self, userId: int) -> int:
- return 0
-
- # ── User state ──
-
- def isUserRunning(self, user: UserHandle) -> bool:
- return True
-
- def isUserRunningOrStopped(self, user: UserHandle) -> bool:
- return True
-
- def isUserUnlocked(self, user: UserHandle) -> bool:
- return True
-
- def isUserUnlocked(self, userId: int) -> bool:
- return True
-
- def isUserSwitcherEnabled(self) -> bool:
- return True
-
- # ── User type checks ──
-
- def isManagedProfile(self, userId: int) -> bool:
- with self._lock:
- user = self._users.get(userId)
- return user.isManagedProfile() if user else False
-
- def isManagedProfile(self) -> bool:
- return False
-
- def isSystemUser(self) -> bool:
- return True
-
- def isPrimaryUser(self) -> bool:
- return True
-
- def isDemoUser(self) -> bool:
- return False
-
- def isGuestUser(self) -> bool:
- return False
-
- def isAdminUser(self) -> bool:
- return True
-
- def isRestrictedProfile(self) -> bool:
- return False
-
- def isLinkedUser(self) -> bool:
- return False
-
- def isUserOfType(self, userHandle: UserHandle, userType: str) -> bool:
- return userHandle.getUserId() == 0
-
- # ── Restrictions ──
-
- def hasUserRestriction(self, restrictionKey: str, userHandle: UserHandle) -> bool:
- uid = userHandle.getUserId()
- with self._lock:
- user_restrictions = self._restrictions.get(str(uid), set())
- return restrictionKey in user_restrictions
-
- def getUserRestrictions(self, userHandle: UserHandle) -> Dict[str, bool]:
- uid = userHandle.getUserId()
- with self._lock:
- user_restrictions = self._restrictions.get(str(uid), set())
- return {r: True for r in user_restrictions}
-
- def setUserRestriction(self, restrictionKey: str, value: bool, userHandle: UserHandle):
- uid = str(userHandle.getUserId())
- with self._lock:
- if uid not in self._restrictions:
- self._restrictions[uid] = set()
- if value:
- self._restrictions[uid].add(restrictionKey)
- else:
- self._restrictions[uid].discard(restrictionKey)
-
- # ── Quiet mode ──
-
- def isQuietModeEnabled(self, userHandle: UserHandle) -> bool:
- return userHandle.getUserId() in self._quiet_mode
-
- def setQuietModeEnabled(self, userHandle: UserHandle, enable: bool) -> bool:
- uid = userHandle.getUserId()
- with self._lock:
- if enable:
- self._quiet_mode.add(uid)
- else:
- self._quiet_mode.discard(uid)
- return True
-
- # ── User switching ──
-
- def canSwitchUsers(self) -> bool:
- return True
-
- def switchUser(self, userHandle: UserHandle) -> bool:
- return True
-
- def removeUser(self, userId: int) -> bool:
- with self._lock:
- if userId in self._users and userId != 0:
- del self._users[userId]
- self._serial_numbers.pop(userId, None)
- return True
- return False
-
- # ── User creation ──
-
- def createUser(self, name: str, flags: int = 0) -> UserInfo:
- with self._lock:
- uid = self._next_user_id
- self._next_user_id += 1
- user = UserInfo(uid, name, flags=flags)
- self._users[uid] = user
- self._serial_numbers[uid] = self._next_serial
- self._next_serial += 1
- return user
-
- def createProfile(self, name: str, profileFlags: int, userId: int) -> UserInfo:
- return self.createUser(name, profileFlags)
-
- def createGuest(self, context: Any = None) -> UserInfo:
- return self.createUser("Guest", UserInfo.FLAG_GUEST)
-
- # ── User name ──
-
- def setUserName(self, userId: int, name: str):
- with self._lock:
- if userId in self._users:
- self._users[userId].name = name
-
- def getUserName(self) -> Optional[str]:
- return "System User"
-
- # ── User info ──
-
- def getUserInfo(self, userId: int) -> Optional[UserInfo]:
- with self._lock:
- return self._users.get(userId)
-
- def toString(self) -> str:
- return f"UserManager@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "UserManager",
- "UserHandle",
- "UserInfo",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/permission.py b/android_pyapi/android/permission.py
deleted file mode 100644
index 1b0d9e8..0000000
--- a/android_pyapi/android/permission.py
+++ /dev/null
@@ -1,162 +0,0 @@
-"""
-Android permission 组件 — PermissionManager, PermissionChecker 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-
-# ═══════════════════════════════════════════════════════════════
-# PermissionChecker
-# ═══════════════════════════════════════════════════════════════
-
-class PermissionChecker(Stub):
- """PermissionChecker — 权限检查器"""
-
- PERMISSION_GRANTED = 0
- PERMISSION_DENIED = -1
- PERMISSION_DENIED_APP_OP = -2
- PID_UNKNOWN = -1
-
- @staticmethod
- def checkPermission(context: Any, permission: str, pid: int, uid: int,
- packageName: str) -> int:
- return PermissionChecker.PERMISSION_GRANTED
-
- @staticmethod
- def checkSelfPermission(context: Any, permission: str) -> int:
- return PermissionChecker.PERMISSION_GRANTED
-
-
-# ═══════════════════════════════════════════════════════════════
-# PermissionManager
-# ═══════════════════════════════════════════════════════════════
-
-class PermissionManager(Stub):
- """PermissionManager — 权限管理器"""
-
- PERMISSION_GRANTED = 0
- PERMISSION_DENIED = -1
-
- FLAG_PERMISSION_GRANTED_BY_DEFAULT = 1 << 5
- FLAG_PERMISSION_POLICY_FIXED = 1 << 4
- FLAG_PERMISSION_SYSTEM_FIXED = 1 << 3
- FLAG_PERMISSION_USER_FIXED = 1 << 2
- FLAG_PERMISSION_USER_SET = 1 << 0
- FLAG_PERMISSION_REVIEW_REQUIRED = 1 << 6
- FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 1 << 7
- FLAG_PERMISSION_REVOKED_COMPAT = 1 << 10
- FLAG_PERMISSION_ONE_TIME = 1 << 8
- FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED = 1 << 9
- FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED = 1 << 11
- FLAG_PERMISSION_AUTO_REVOKED = 1 << 12
- FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY = 1 << 13
-
- def __init__(self):
- super().__init__()
- self._lock = threading.Lock()
- self._granted_permissions: Dict[str, bool] = {}
- self._permission_flags: Dict[str, int] = {}
- self._listeners: List[Callable[[str], None]] = []
-
- # ── Check ──
-
- def checkPermission(self, permission: str, pid: int = -1, uid: int = -1) -> int:
- with self._lock:
- if self._granted_permissions.get(permission, True):
- return self.PERMISSION_GRANTED
- return self.PERMISSION_DENIED
-
- def isRuntimePermission(self, permission: str) -> bool:
- return True
-
- # ── Flags ──
-
- def getPermissionFlags(self, permission: str, packageName: str, user: Any = None) -> int:
- with self._lock:
- return self._permission_flags.get(permission, 0)
-
- def updatePermissionFlags(self, permission: str, packageName: str,
- flagMask: int, flagValues: int,
- user: Any = None) -> bool:
- with self._lock:
- current = self._permission_flags.get(permission, 0)
- current = (current & ~flagMask) | (flagValues & flagMask)
- self._permission_flags[permission] = current
- return True
-
- # ── Grant / Revoke ──
-
- def grantPermission(self, permission: str, packageName: str, user: Any = None):
- with self._lock:
- self._granted_permissions[permission] = True
-
- def revokePermission(self, permission: str, packageName: str, user: Any = None):
- with self._lock:
- self._granted_permissions[permission] = False
-
- # ── Rationale ──
-
- def shouldShowRequestPermissionRationale(self, permission: str) -> bool:
- return False
-
- # ── Listed ──
-
- def getGrantedPermissions(self) -> List[str]:
- with self._lock:
- return [p for p, g in self._granted_permissions.items() if g]
-
- def getDeniedPermissions(self) -> List[str]:
- with self._lock:
- return [p for p, g in self._granted_permissions.items() if not g]
-
- def getSplitPermissions(self) -> List[Any]:
- return []
-
- # ── Revocation ──
-
- def isPermissionRevokedByPolicy(self, permission: str, packageName: str) -> bool:
- return False
-
- # ── Listeners ──
-
- def addOnPermissionsChangeListener(self, listener: Callable[[str], None]):
- with self._lock:
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeOnPermissionsChangeListener(self, listener: Callable[[str], None]):
- with self._lock:
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def _notify_listeners(self, permission: str):
- with self._lock:
- for listener in self._listeners:
- listener(permission)
-
- # ── Misc ──
-
- def getPermissionControllerService(self) -> Any:
- return None
-
- def toString(self) -> str:
- return f"PermissionManager@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "PermissionManager",
- "PermissionChecker",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/preference.py b/android_pyapi/android/preference.py
deleted file mode 100644
index f666cc1..0000000
--- a/android_pyapi/android/preference.py
+++ /dev/null
@@ -1,654 +0,0 @@
-"""
-Android Preference 组件 — Preference, PreferenceScreen, PreferenceManager 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-import json
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# PreferenceChangeListener
-# ═══════════════════════════════════════════════════════════════
-
-class PreferenceChangeListener(Stub):
- """OnPreferenceChangeListener — 偏好变化监听器"""
-
- def onPreferenceChange(self, preference: "Preference", new_value: Any) -> bool:
- return True
-
-
-class PreferenceOnPreferenceClickListener(Stub):
- """OnPreferenceClickListener — 偏好点击监听器"""
-
- def onPreferenceClick(self, preference: "Preference") -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# PreferenceManager
-# ═══════════════════════════════════════════════════════════════
-
-class PreferenceManager(Stub):
- """PreferenceManager — 偏好管理器"""
-
- KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values"
-
- def __init__(self, context: Any):
- super().__init__()
- self._context = context
- self._shared_prefs_name: str = f"{_package_name}_preferences"
- self._shared_prefs_mode: int = 0
- self._prefs_data: Dict[str, Any] = {}
- self._prefs_path = os.path.join(_app_data_dir, "shared_prefs",
- f"{self._shared_prefs_name}.json")
- self._load()
-
- def _load(self):
- os.makedirs(os.path.dirname(self._prefs_path), exist_ok=True)
- if os.path.exists(self._prefs_path):
- try:
- with open(self._prefs_path, "r") as f:
- self._prefs_data = json.load(f)
- except (json.JSONDecodeError, OSError):
- self._prefs_data = {}
- else:
- self._prefs_data = {}
-
- def _save(self):
- os.makedirs(os.path.dirname(self._prefs_path), exist_ok=True)
- with open(self._prefs_path, "w") as f:
- json.dump(self._prefs_data, f)
-
- def getSharedPreferences(self) -> Any:
- return self._prefs_data
-
- def setSharedPreferencesName(self, name: str):
- self._shared_prefs_name = name
- self._prefs_path = os.path.join(_app_data_dir, "shared_prefs",
- f"{name}.json")
- self._load()
-
- def setSharedPreferencesMode(self, mode: int):
- self._shared_prefs_mode = mode
-
- @staticmethod
- def getDefaultSharedPreferences(context: Any) -> Any:
- mgr = PreferenceManager(context)
- return mgr.getSharedPreferences()
-
- @staticmethod
- def setDefaultValues(context: Any, res_id: int, read_again: bool):
- pass
-
- @staticmethod
- def setDefaultValues(context: Any, shared_prefs_name: str,
- shared_prefs_mode: int, res_id: int,
- read_again: bool):
- pass
-
- def getPreference(self, key: str, default: Any = None) -> Any:
- return self._prefs_data.get(key, default)
-
- def putPreference(self, key: str, value: Any):
- self._prefs_data[key] = value
- self._save()
-
- def removePreference(self, key: str):
- if key in self._prefs_data:
- del self._prefs_data[key]
- self._save()
-
-
-# ═══════════════════════════════════════════════════════════════
-# Preference
-# ═══════════════════════════════════════════════════════════════
-
-class Preference(Stub):
- """Preference — 偏好设置项基类"""
-
- def __init__(self, context: Any = None, attrs: Any = None,
- def_style_attr: int = 0):
- super().__init__()
- self._context = context
- self._title: str = ""
- self._summary: str = ""
- self._key: Optional[str] = None
- self._enabled: bool = True
- self._default_value: Any = None
- self._order: int = 0
- self._persistent: bool = True
- self._icon: Any = None
- self._dependents: List["Preference"] = []
- self._dependency_key: Optional[str] = None
- self._preference_manager: Optional[PreferenceManager] = None
- self._parent: Optional["PreferenceGroup"] = None
- self._on_change_listener: Optional[PreferenceChangeListener] = None
- self._on_click_listener: Optional[PreferenceOnPreferenceClickListener] = None
-
- def setTitle(self, title: str):
- self._title = title
-
- def getTitle(self) -> str:
- return self._title
-
- def setSummary(self, summary: str):
- self._summary = summary
-
- def getSummary(self) -> str:
- return self._summary
-
- def setKey(self, key: str):
- self._key = key
-
- def getKey(self) -> Optional[str]:
- return self._key
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setDefaultValue(self, value: Any):
- self._default_value = value
-
- def setOnPreferenceClickListener(self, listener: PreferenceOnPreferenceClickListener):
- self._on_click_listener = listener
-
- def setOnPreferenceChangeListener(self, listener: PreferenceChangeListener):
- self._on_change_listener = listener
-
- def getSharedPreferences(self) -> Any:
- if self._preference_manager:
- return self._preference_manager.getSharedPreferences()
- return {}
-
- def getEditor(self) -> Any:
- if self._preference_manager:
- return self._preference_manager
- return None
-
- def shouldCommit(self) -> bool:
- return True
-
- def shouldPersist(self) -> bool:
- return self._persistent and self._key is not None
-
- def persistString(self, value: str) -> bool:
- if self.shouldPersist() and self._preference_manager:
- self._preference_manager.putPreference(self._key, value)
- return True
- return False
-
- def persistInt(self, value: int) -> bool:
- if self.shouldPersist() and self._preference_manager:
- self._preference_manager.putPreference(self._key, value)
- return True
- return False
-
- def persistBoolean(self, value: bool) -> bool:
- if self.shouldPersist() and self._preference_manager:
- self._preference_manager.putPreference(self._key, value)
- return True
- return False
-
- def persistFloat(self, value: float) -> bool:
- if self.shouldPersist() and self._preference_manager:
- self._preference_manager.putPreference(self._key, value)
- return True
- return False
-
- def persistLong(self, value: int) -> bool:
- return self.persistInt(value)
-
- def getPersistedString(self, default_return: Optional[str] = None) -> Optional[str]:
- if self.shouldPersist() and self._preference_manager:
- val = self._preference_manager.getPreference(self._key, default_return)
- return str(val) if val is not None else default_return
- return default_return
-
- def getPersistedInt(self, default_return: int = 0) -> int:
- if self.shouldPersist() and self._preference_manager:
- return int(self._preference_manager.getPreference(self._key, default_return))
- return default_return
-
- def getPersistedBoolean(self, default_return: bool = False) -> bool:
- if self.shouldPersist() and self._preference_manager:
- val = self._preference_manager.getPreference(self._key, default_return)
- if isinstance(val, bool):
- return val
- return str(val).lower() in ("true", "1", "yes")
- return default_return
-
- def getPersistedFloat(self, default_return: float = 0.0) -> float:
- if self.shouldPersist() and self._preference_manager:
- return float(self._preference_manager.getPreference(self._key, default_return))
- return default_return
-
- def getPersistedLong(self, default_return: int = 0) -> int:
- return self.getPersistedInt(default_return)
-
- def notifyChanged(self):
- pass
-
- def notifyHierarchyChanged(self):
- pass
-
- def onBindView(self, view: Any):
- pass
-
- def onClick(self):
- if self._on_click_listener:
- self._on_click_listener.onPreferenceClick(self)
-
- def setOrder(self, order: int):
- self._order = order
-
- def getOrder(self) -> int:
- return self._order
-
- def setPersistent(self, persistent: bool):
- self._persistent = persistent
-
- def isPersistent(self) -> bool:
- return self._persistent
-
- def setDependency(self, dependency_key: str):
- self._dependency_key = dependency_key
-
- def getDependency(self) -> Optional[str]:
- return self._dependency_key
-
- def toString(self) -> str:
- return f"Preference(key={self._key}, title={self._title})"
-
- def hashCode(self) -> int:
- return hash(self._key) & 0x7FFFFFFF if self._key else 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# PreferenceGroup
-# ═══════════════════════════════════════════════════════════════
-
-class PreferenceGroup(Preference):
- """PreferenceGroup — 偏好组"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._preferences: List[Preference] = []
-
- def addPreference(self, preference: Preference) -> bool:
- if preference not in self._preferences:
- self._preferences.append(preference)
- preference._parent = self
- return True
- return False
-
- def removePreference(self, preference: Preference) -> bool:
- if preference in self._preferences:
- self._preferences.remove(preference)
- preference._parent = None
- return True
- return False
-
- def removeAll(self):
- for p in self._preferences:
- p._parent = None
- self._preferences.clear()
-
- def getPreference(self, index: int) -> Optional[Preference]:
- if 0 <= index < len(self._preferences):
- return self._preferences[index]
- return None
-
- def getPreferenceCount(self) -> int:
- return len(self._preferences)
-
- def findPreference(self, key: str) -> Optional[Preference]:
- for p in self._preferences:
- if p.getKey() == key:
- return p
- if isinstance(p, PreferenceGroup):
- result = p.findPreference(key)
- if result:
- return result
- return None
-
- def toString(self) -> str:
- return f"PreferenceGroup(count={len(self._preferences)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PreferenceScreen
-# ═══════════════════════════════════════════════════════════════
-
-class PreferenceScreen(PreferenceGroup):
- """PreferenceScreen — 根偏好屏幕"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._root: bool = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# PreferenceCategory
-# ═══════════════════════════════════════════════════════════════
-
-class PreferenceCategory(PreferenceGroup):
- """PreferenceCategory — 偏好分类标题"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
-
-
-# ═══════════════════════════════════════════════════════════════
-# TwoStatePreference
-# ═══════════════════════════════════════════════════════════════
-
-class TwoStatePreference(Preference):
- """TwoStatePreference — 双状态偏好基类"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._checked: bool = False
- self._summary_on: str = ""
- self._summary_off: str = ""
- self._disable_dependents_state: bool = False
-
- def isChecked(self) -> bool:
- return self._checked
-
- def setChecked(self, checked: bool):
- self._checked = checked
- self.persistBoolean(checked)
-
- def setSummaryOn(self, summary: str):
- self._summary_on = summary
-
- def setSummaryOff(self, summary: str):
- self._summary_off = summary
-
- def setDisableDependentsState(self, state: bool):
- self._disable_dependents_state = state
-
-
-# ═══════════════════════════════════════════════════════════════
-# CheckBoxPreference
-# ═══════════════════════════════════════════════════════════════
-
-class CheckBoxPreference(TwoStatePreference):
- """CheckBoxPreference — 复选框偏好"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SwitchPreference
-# ═══════════════════════════════════════════════════════════════
-
-class SwitchPreference(TwoStatePreference):
- """SwitchPreference — 开关偏好"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._switch_text_on: str = ""
- self._switch_text_off: str = ""
-
- def setSwitchTextOn(self, text: str):
- self._switch_text_on = text
-
- def setSwitchTextOff(self, text: str):
- self._switch_text_off = text
-
- def getSwitchTextOn(self) -> str:
- return self._switch_text_on
-
- def getSwitchTextOff(self) -> str:
- return self._switch_text_off
-
-
-# ═══════════════════════════════════════════════════════════════
-# DialogPreference
-# ═══════════════════════════════════════════════════════════════
-
-class DialogPreference(Preference):
- """DialogPreference — 对话框偏好基类"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._dialog_title: str = ""
- self._dialog_message: str = ""
- self._dialog_icon: Any = None
- self._positive_button_text: str = ""
- self._negative_button_text: str = ""
-
-
-# ═══════════════════════════════════════════════════════════════
-# EditTextPreference
-# ═══════════════════════════════════════════════════════════════
-
-class EditTextPreference(DialogPreference):
- """EditTextPreference — 文本编辑偏好"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._text: str = ""
-
- def getText(self) -> str:
- return self._text
-
- def setText(self, text: str):
- self._text = text
- self.persistString(text)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ListPreference
-# ═══════════════════════════════════════════════════════════════
-
-class ListPreference(DialogPreference):
- """ListPreference — 列表偏好"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._entries: List[str] = []
- self._entry_values: List[str] = []
- self._value: str = ""
-
- def getEntries(self) -> List[str]:
- return list(self._entries)
-
- def setEntries(self, entries: List[str]):
- self._entries = list(entries)
-
- def getEntryValues(self) -> List[str]:
- return list(self._entry_values)
-
- def setEntryValues(self, values: List[str]):
- self._entry_values = list(values)
-
- def getValue(self) -> str:
- return self._value
-
- def setValue(self, value: str):
- self._value = value
- self.persistString(value)
-
- def getEntry(self) -> Optional[str]:
- try:
- idx = self._entry_values.index(self._value)
- if 0 <= idx < len(self._entries):
- return self._entries[idx]
- except ValueError:
- pass
- return None
-
- def getSummary(self) -> str:
- entry = self.getEntry()
- if entry:
- return entry
- return self._summary
-
- def setDefaultValue(self, value: Any):
- super().setDefaultValue(value)
-
-
-# ═══════════════════════════════════════════════════════════════
-# MultiSelectListPreference
-# ═══════════════════════════════════════════════════════════════
-
-class MultiSelectListPreference(DialogPreference):
- """MultiSelectListPreference — 多选列表偏好"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._entries: List[str] = []
- self._entry_values: List[str] = []
- self._values: Set[str] = set()
-
- def getEntries(self) -> List[str]:
- return list(self._entries)
-
- def setEntries(self, entries: List[str]):
- self._entries = list(entries)
-
- def getEntryValues(self) -> List[str]:
- return list(self._entry_values)
-
- def setEntryValues(self, values: List[str]):
- self._entry_values = list(values)
-
- def getValues(self) -> Set[str]:
- return set(self._values)
-
- def setValues(self, values: Set[str]):
- self._values = set(values)
-
-
-# ═══════════════════════════════════════════════════════════════
-# RingtonePreference / SeekBarPreference / DropDownPreference
-# ═══════════════════════════════════════════════════════════════
-
-class RingtonePreference(Preference):
- """RingtonePreference — 铃声偏好"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._ringtone_type: int = 1
- self._show_default: bool = True
- self._show_silent: bool = True
-
-
-class SeekBarPreference(Preference):
- """SeekBarPreference — 滑块偏好"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
- self._min: int = 0
- self._max: int = 100
- self._current: int = 50
- self._show_progress: bool = True
- self._adjustable: bool = True
-
- def getMin(self) -> int:
- return self._min
-
- def setMin(self, min_val: int):
- self._min = min_val
-
- def getMax(self) -> int:
- return self._max
-
- def setMax(self, max_val: int):
- self._max = max_val
-
- def getValue(self) -> int:
- return self._current
-
- def setValue(self, value: int):
- self._current = value
- self.persistInt(value)
-
-
-class DropDownPreference(ListPreference):
- """DropDownPreference — 下拉列表偏好"""
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__(context, attrs)
-
-
-# ═══════════════════════════════════════════════════════════════
-# PreferenceFragment / PreferenceFragmentCompat
-# ═══════════════════════════════════════════════════════════════
-
-class PreferenceFragment(Stub):
- """PreferenceFragment — 偏好片段"""
-
- def __init__(self):
- super().__init__()
- self._preference_manager: Optional[PreferenceManager] = None
-
- def onCreate(self, savedInstanceState: Any):
- pass
-
- def onCreatePreferences(self, savedInstanceState: Any, root_key: Optional[str]):
- pass
-
- def addPreferencesFromResource(self, res_id: int):
- pass
-
- def setPreferenceScreen(self, screen: PreferenceScreen):
- pass
-
- def getPreferenceScreen(self) -> Optional[PreferenceScreen]:
- return None
-
- def findPreference(self, key: str) -> Optional[Preference]:
- screen = self.getPreferenceScreen()
- if screen:
- return screen.findPreference(key)
- return None
-
-
-class PreferenceFragmentCompat(PreferenceFragment):
- """PreferenceFragmentCompat — 兼容偏好片段"""
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Preference",
- "PreferenceScreen",
- "PreferenceCategory",
- "PreferenceManager",
- "CheckBoxPreference",
- "SwitchPreference",
- "ListPreference",
- "EditTextPreference",
- "MultiSelectListPreference",
- "PreferenceFragment",
- "PreferenceFragmentCompat",
- "PreferenceGroup",
- "PreferenceChangeListener",
- "PreferenceOnPreferenceClickListener",
- "TwoStatePreference",
- "DialogPreference",
- "RingtonePreference",
- "SeekBarPreference",
- "DropDownPreference",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/print.py b/android_pyapi/android/print.py
deleted file mode 100644
index 7dd47ae..0000000
--- a/android_pyapi/android/print.py
+++ /dev/null
@@ -1,581 +0,0 @@
-"""
-Android Print 组件 — PrintManager, PrintJob, PrintDocumentAdapter, PdfPrint 等
-方法签名完全对齐 Android SDK (android.print 包)
-"""
-
-import os
-import time
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintAttributes
-# ═══════════════════════════════════════════════════════════════
-
-class PrintAttributes(Stub):
- """PrintAttributes — 打印属性"""
-
- # 颜色模式
- COLOR_MODE_MONOCHROME = 1
- COLOR_MODE_COLOR = 2
-
- # 方向
- ORIENTATION_PORTRAIT = 1
- ORIENTATION_LANDSCAPE = 2
-
- # 媒质尺寸 ID
- MEDIA_SIZE_UNKNOWN = "unknown"
- MEDIA_SIZE_A4 = "A4"
- MEDIA_SIZE_A3 = "A3"
- MEDIA_SIZE_LETTER = "letter"
- MEDIA_SIZE_LEGAL = "legal"
- MEDIA_SIZE_ISO_A4 = "iso_a4"
- MEDIA_SIZE_ISO_A3 = "iso_a3"
- MEDIA_SIZE_NA_LETTER = "na_letter"
-
- def __init__(self):
- super().__init__()
- self._media_size: Optional["PrintAttributes.MediaSize"] = None
- self._resolution: Optional["PrintAttributes.Resolution"] = None
- self._min_margins: Optional["PrintAttributes.Margins"] = None
- self._color_mode: int = PrintAttributes.COLOR_MODE_COLOR
- self._orientation: int = PrintAttributes.ORIENTATION_PORTRAIT
-
- def getMediaSize(self) -> Optional["MediaSize"]:
- return self._media_size
-
- def getResolution(self) -> Optional["Resolution"]:
- return self._resolution
-
- def getMinMargins(self) -> Optional["Margins"]:
- return self._min_margins
-
- def getColorMode(self) -> int:
- return self._color_mode
-
- def getOrientation(self) -> int:
- return self._orientation
-
- def isPortrait(self) -> bool:
- return self._orientation == PrintAttributes.ORIENTATION_PORTRAIT
-
- def toString(self) -> str:
- return (f"PrintAttributes(colorMode={self._color_mode}, "
- f"orientation={self._orientation})")
-
- def hashCode(self) -> int:
- return hash((self._color_mode, self._orientation)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, PrintAttributes):
- return False
- return (self._color_mode == other._color_mode
- and self._orientation == other._orientation)
-
- # ── 内部嵌套类 ──
-
- class MediaSize(Stub):
- """MediaSize — 媒质尺寸"""
-
- def __init__(self, id: str, label: str, width_mils: int, height_mils: int):
- super().__init__()
- self._id = id
- self._label = label
- self._width_mils = width_mils
- self._height_mils = height_mils
-
- def getId(self) -> str:
- return self._id
-
- def getLabel(self, package_manager: Any = None) -> str:
- return self._label
-
- def getWidthMils(self) -> int:
- return self._width_mils
-
- def getHeightMils(self) -> int:
- return self._height_mils
-
- def asPortrait(self) -> "PrintAttributes.MediaSize":
- if self._width_mils > self._height_mils:
- return PrintAttributes.MediaSize(
- self._id, self._label, self._height_mils, self._width_mils)
- return self
-
- def asLandscape(self) -> "PrintAttributes.MediaSize":
- if self._width_mils < self._height_mils:
- return PrintAttributes.MediaSize(
- self._id, self._label, self._height_mils, self._width_mils)
- return self
-
- def toString(self) -> str:
- return f"MediaSize({self._id}: {self._width_mils}x{self._height_mils}mils)"
-
- def hashCode(self) -> int:
- return hash(self._id) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, PrintAttributes.MediaSize):
- return False
- return self._id == other._id
-
- class Resolution(Stub):
- """Resolution — 打印分辨率"""
-
- def __init__(self, id: str, label: str, horizontal_dpi: int, vertical_dpi: int):
- super().__init__()
- self._id = id
- self._label = label
- self._horizontal_dpi = horizontal_dpi
- self._vertical_dpi = vertical_dpi
-
- def getId(self) -> str:
- return self._id
-
- def getLabel(self) -> str:
- return self._label
-
- def getHorizontalDpi(self) -> int:
- return self._horizontal_dpi
-
- def getVerticalDpi(self) -> int:
- return self._vertical_dpi
-
- def toString(self) -> str:
- return f"Resolution({self._id}: {self._horizontal_dpi}x{self._vertical_dpi}dpi)"
-
- class Margins(Stub):
- """Margins — 页边距"""
-
- NO_MARGINS: "PrintAttributes.Margins" = None
-
- def __init__(self, left_mils: int, top_mils: int,
- right_mils: int, bottom_mils: int):
- super().__init__()
- self._left_mils = left_mils
- self._top_mils = top_mils
- self._right_mils = right_mils
- self._bottom_mils = bottom_mils
-
- def getLeftMils(self) -> int:
- return self._left_mils
-
- def getTopMils(self) -> int:
- return self._top_mils
-
- def getRightMils(self) -> int:
- return self._right_mils
-
- def getBottomMils(self) -> int:
- return self._bottom_mils
-
- def toString(self) -> str:
- return f"Margins({self._left_mils},{self._top_mils},{self._right_mils},{self._bottom_mils})"
-
- class Builder(Stub):
- """Builder — PrintAttributes 构建器"""
-
- def __init__(self):
- super().__init__()
- self._attrs = PrintAttributes()
-
- def setMediaSize(self, media_size: "PrintAttributes.MediaSize") -> "PrintAttributes.Builder":
- self._attrs._media_size = media_size
- return self
-
- def setResolution(self, resolution: "PrintAttributes.Resolution") -> "PrintAttributes.Builder":
- self._attrs._resolution = resolution
- return self
-
- def setMinMargins(self, margins: "PrintAttributes.Margins") -> "PrintAttributes.Builder":
- self._attrs._min_margins = margins
- return self
-
- def setColorMode(self, color_mode: int) -> "PrintAttributes.Builder":
- self._attrs._color_mode = color_mode
- return self
-
- def setOrientation(self, orientation: int) -> "PrintAttributes.Builder":
- self._attrs._orientation = orientation
- return self
-
- def build(self) -> "PrintAttributes":
- return self._attrs
-
-
-PrintAttributes.Margins.NO_MARGINS = PrintAttributes.Margins(0, 0, 0, 0)
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintJobInfo
-# ═══════════════════════════════════════════════════════════════
-
-class PrintJobInfo(Stub):
- """PrintJobInfo — 打印任务信息"""
-
- # 状态常量
- STATE_CREATED = 1
- STATE_QUEUED = 2
- STATE_STARTED = 3
- STATE_BLOCKED = 4
- STATE_COMPLETED = 5
- STATE_FAILED = 6
- STATE_CANCELED = 7
-
- def __init__(self):
- super().__init__()
- self._label: str = ""
- self._id: Optional[Any] = None
- self._state: int = PrintJobInfo.STATE_CREATED
- self._attributes: Optional[PrintAttributes] = None
- self._copies: int = 1
- self._creation_time: int = int(time.time() * 1000)
- self._canceling: bool = False
- self._pages: Optional[List[int]] = None
- self._has_advanced_options: bool = False
-
- def getLabel(self) -> str:
- return self._label
-
- def setLabel(self, label: str):
- self._label = label
-
- def getId(self) -> Optional[Any]:
- return self._id
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getAttributes(self) -> Optional[PrintAttributes]:
- return self._attributes
-
- def setAttributes(self, attributes: PrintAttributes):
- self._attributes = attributes
-
- def getCopies(self) -> int:
- return self._copies
-
- def setCopies(self, copies: int):
- self._copies = copies
-
- def getCreationTime(self) -> int:
- return self._creation_time
-
- def isCanceling(self) -> bool:
- return self._canceling
-
- def getPages(self) -> Optional[List[int]]:
- return self._pages
-
- def setPages(self, pages: Optional[List[int]]):
- self._pages = pages
-
- def hasAdvancedOptions(self) -> bool:
- return self._has_advanced_options
-
- def toString(self) -> str:
- return f"PrintJobInfo(label={self._label}, state={self._state}, copies={self._copies})"
-
- def hashCode(self) -> int:
- return hash(self._id) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, PrintJobInfo):
- return False
- return self._id == other._id
-
- # ── Builder ──
-
- class Builder(Stub):
- """Builder — PrintJobInfo 构建器"""
-
- def __init__(self, info: Optional["PrintJobInfo"] = None):
- super().__init__()
- self._info = PrintJobInfo()
- if info:
- self._info._label = info._label
- self._info._id = info._id
- self._info._attributes = info._attributes
- self._info._copies = info._copies
-
- def setCopies(self, copies: int) -> "PrintJobInfo.Builder":
- self._info._copies = copies
- return self
-
- def setAttributes(self, attributes: PrintAttributes) -> "PrintJobInfo.Builder":
- self._info._attributes = attributes
- return self
-
- def setLabel(self, label: str) -> "PrintJobInfo.Builder":
- self._info._label = label
- return self
-
- def setPages(self, pages: Optional[List[int]]) -> "PrintJobInfo.Builder":
- self._info._pages = pages
- return self
-
- def build(self) -> "PrintJobInfo":
- return self._info
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintJob
-# ═══════════════════════════════════════════════════════════════
-
-class PrintJob(Stub):
- """PrintJob — 打印任务"""
-
- def __init__(self, info: PrintJobInfo):
- super().__init__()
- self._info = info
- self._cancelled = False
- self._result: Optional[Any] = None
-
- def getId(self) -> Optional[Any]:
- return self._info.getId()
-
- def getInfo(self) -> PrintJobInfo:
- return self._info
-
- def isStarted(self) -> bool:
- return self._info.getState() >= PrintJobInfo.STATE_STARTED
-
- def isBlocked(self) -> bool:
- return self._info.getState() == PrintJobInfo.STATE_BLOCKED
-
- def isCompleted(self) -> bool:
- return self._info.getState() == PrintJobInfo.STATE_COMPLETED
-
- def isFailed(self) -> bool:
- return self._info.getState() == PrintJobInfo.STATE_FAILED
-
- def isCancelled(self) -> bool:
- return self._cancelled
-
- def cancel(self):
- """取消打印任务"""
- self._cancelled = True
- self._info.setState(PrintJobInfo.STATE_CANCELED)
-
- def restart(self):
- """重新启动打印任务"""
- self._cancelled = False
- self._info.setState(PrintJobInfo.STATE_QUEUED)
-
- def setResult(self, result: Any):
- self._result = result
-
- def getResult(self) -> Optional[Any]:
- return self._result
-
- def toString(self) -> str:
- return f"PrintJob(id={self.getId()}, state={self._info.getState()})"
-
- def hashCode(self) -> int:
- return hash(self.getId()) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, PrintJob):
- return False
- return self.getId() == other.getId()
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintDocumentAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class PrintDocumentAdapter(Stub):
- """PrintDocumentAdapter — 打印文档适配器"""
-
- EXTRA_PRINT_PREVIEW = "EXTRA_PRINT_PREVIEW"
-
- def __init__(self):
- super().__init__()
-
- def onStart(self):
- """打印开始回调"""
- pass
-
- def onFinish(self):
- """打印结束回调"""
- pass
-
- def onLayout(self, old_attributes: PrintAttributes, new_attributes: PrintAttributes,
- cancellation_signal: Any, callback: "PrintDocumentAdapterLayoutCallback",
- metadata: Any):
- """布局回调 - 桌面实现直接完成"""
- if callback:
- callback.onLayoutFinished(self, new_attributes)
-
- def onWrite(self, pages: List[int], destination: Any,
- cancellation_signal: Any,
- callback: "PrintDocumentAdapterWriteCallback"):
- """写入回调 - 桌面实现直接完成"""
- if callback:
- callback.onWriteFinished(pages)
-
-
-class PrintDocumentAdapterLayoutCallback(Stub):
- """PrintDocumentAdapterLayoutCallback — 布局回调"""
-
- def __init__(self):
- super().__init__()
-
- def onLayoutFinished(self, adapter: PrintDocumentAdapter, attributes: PrintAttributes):
- """布局完成"""
- pass
-
- def onLayoutFailed(self, error: Optional[str] = None):
- """布局失败"""
- pass
-
- def onLayoutCancelled(self):
- """布局取消"""
- pass
-
-
-class PrintDocumentAdapterWriteCallback(Stub):
- """PrintDocumentAdapterWriteCallback — 写入回调"""
-
- def __init__(self):
- super().__init__()
-
- def onWriteFinished(self, pages: List[int]):
- """写入完成"""
- pass
-
- def onWriteFailed(self, error: Optional[str] = None):
- """写入失败"""
- pass
-
- def onWriteCancelled(self):
- """写入取消"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# PdfPrint
-# ═══════════════════════════════════════════════════════════════
-
-class PdfPrint(Stub):
- """PdfPrint — PDF 打印辅助类"""
-
- def __init__(self, attributes: Optional[PrintAttributes] = None):
- super().__init__()
- self._attributes = attributes or PrintAttributes()
-
- def getAttributes(self) -> PrintAttributes:
- return self._attributes
-
- def setAttributes(self, attributes: PrintAttributes):
- self._attributes = attributes
-
- def print(self, print_adapter: PrintDocumentAdapter, output_path: str) -> bool:
- """执行 PDF 打印 (桌面实现: 写入文件)"""
- try:
- os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
- # 在桌面环境, PDF 打印由适配器的 onWrite 实现处理
- callback = PrintDocumentAdapterWriteCallback()
- print_adapter.onWrite([1], output_path, None, callback)
- return True
- except Exception:
- return False
-
- def toString(self) -> str:
- return f"PdfPrint(attributes={self._attributes})"
-
- def hashCode(self) -> int:
- return hash(str(self._attributes)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, PdfPrint):
- return False
- return str(self._attributes) == str(other._attributes)
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintManager
-# ═══════════════════════════════════════════════════════════════
-
-class PrintManager(Stub):
- """PrintManager — 打印管理器"""
-
- # 打印任务 ID 生成
- _next_job_id = 1
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._print_jobs: Dict[str, PrintJob] = {}
-
- def getPrintJobs(self) -> List[PrintJob]:
- """获取打印任务列表"""
- return list(self._print_jobs.values())
-
- def print(self, job_name: str, document_adapter: PrintDocumentAdapter,
- attributes: Optional[PrintAttributes] = None) -> PrintJob:
- """提交打印任务"""
- info = PrintJobInfo()
- info.setLabel(job_name)
- info.setAttributes(attributes or PrintAttributes())
- info.setState(PrintJobInfo.STATE_QUEUED)
-
- job_id = f"print_job_{PrintManager._next_job_id}"
- PrintManager._next_job_id += 1
-
- job = PrintJob(info)
- self._print_jobs[job_id] = job
-
- # 自动触发布局和写入
- cancellation_signal = type("CancellationSignal", (), {"isCanceled": lambda: False})()
- document_adapter.onStart()
- layout_cb = PrintDocumentAdapterLayoutCallback()
- document_adapter.onLayout(None, info.getAttributes(),
- cancellation_signal, layout_cb, None)
-
- info.setState(PrintJobInfo.STATE_COMPLETED)
- document_adapter.onFinish()
-
- return job
-
- def getPrintJobById(self, job_id: str) -> Optional[PrintJob]:
- """根据 ID 获取打印任务"""
- return self._print_jobs.get(job_id)
-
- def cancelPrintJob(self, job_id: str) -> bool:
- """取消打印任务"""
- job = self._print_jobs.get(job_id)
- if job:
- job.cancel()
- return True
- return False
-
- def toString(self) -> str:
- return f"PrintManager(jobs={len(self._print_jobs)})"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "PrintManager",
- "PrintJob",
- "PrintJobInfo",
- "PrintDocumentAdapter",
- "PrintAttributes",
- "PrintDocumentAdapterLayoutCallback",
- "PrintDocumentAdapterWriteCallback",
- "PdfPrint",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/printservice.py b/android_pyapi/android/printservice.py
deleted file mode 100644
index d13a35f..0000000
--- a/android_pyapi/android/printservice.py
+++ /dev/null
@@ -1,917 +0,0 @@
-"""
-Android Print Service 组件 — PrintService, PrintJob, PrinterDiscoverySession, PrinterId 等
-方法签名完全对齐 Android SDK (android.printservice 包)
-"""
-
-from __future__ import annotations
-
-import os
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrinterId
-# ═══════════════════════════════════════════════════════════════
-
-class PrinterId(Stub):
- """PrinterId — 打印机 ID"""
-
- def __init__(self, package_name: str = "", local_id: str = ""):
- super().__init__()
- self._package_name = package_name
- self._local_id = local_id
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def setPackageName(self, pkg: str):
- self._package_name = pkg
-
- def getLocalId(self) -> str:
- return self._local_id
-
- def setLocalId(self, local_id: str):
- self._local_id = local_id
-
- def toString(self) -> str:
- return f"PrinterId(package={self._package_name}, localId={self._local_id})"
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, PrinterId):
- return (self._package_name == other._package_name
- and self._local_id == other._local_id)
- return False
-
- def hashCode(self) -> int:
- return hash((self._package_name, self._local_id)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrinterInfo
-# ═══════════════════════════════════════════════════════════════
-
-class PrinterInfo(Stub):
- """PrinterInfo — 打印机信息"""
-
- STATUS_IDLE = 0
- STATUS_BUSY = 1
- STATUS_UNAVAILABLE = 2
-
- STATUS_DISABLED = 3
- STATUS_LOW_ON_PAPER = 4
- STATUS_LOW_ON_INK = 5
- STATUS_LOW_ON_TONER = 6
- STATUS_WAITING = 7
- STATUS_PRINTING = 8
- STATUS_ERROR = 9
-
- def __init__(self, printer_id: PrinterId = None, name: str = "",
- status: int = STATUS_IDLE):
- super().__init__()
- self._id = printer_id or PrinterId()
- self._name = name
- self._status = status
- self._description: str = ""
- self._capabilities: Optional[PrinterCapabilities] = None
- self._icon: Optional[bytes] = None
- self._is_default: bool = False
- self._printer_location: str = ""
- self._printer_model: str = ""
- self._printer_make_and_model: str = ""
-
- def getId(self) -> PrinterId:
- return self._id
-
- def setId(self, printer_id: PrinterId):
- self._id = printer_id
-
- def getName(self) -> str:
- return self._name
-
- def setName(self, name: str):
- self._name = name
-
- def getStatus(self) -> int:
- return self._status
-
- def setStatus(self, status: int):
- self._status = status
-
- def getDescription(self) -> str:
- return self._description
-
- def setDescription(self, desc: str):
- self._description = desc
-
- def getCapabilities(self) -> Optional[PrinterCapabilities]:
- return self._capabilities
-
- def setCapabilities(self, caps: PrinterCapabilities):
- self._capabilities = caps
-
- def getIcon(self) -> Optional[bytes]:
- return self._icon
-
- def setIcon(self, icon: bytes):
- self._icon = icon
-
- def isDefault(self) -> bool:
- return self._is_default
-
- def setDefault(self, is_default: bool):
- self._is_default = is_default
-
- def toString(self) -> str:
- return f"PrinterInfo(name={self._name}, status={self._status})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrinterCapabilities
-# ═══════════════════════════════════════════════════════════════
-
-class PrinterCapabilities(Stub):
- """PrinterCapabilities — 打印机能力"""
-
- def __init__(self):
- super().__init__()
- self._color_supported: bool = False
- self._duplex_supported: bool = False
- self._media_sizes: List[MediaSize] = []
- self._resolutions: List[Resolution] = []
- self._min_margins: Margins = Margins(0, 0, 0, 0)
- self._paper_sizes: List[PaperSize] = []
-
- def isColorSupported(self) -> bool:
- return self._color_supported
-
- def setColorSupported(self, supported: bool):
- self._color_supported = supported
-
- def isDuplexSupported(self) -> bool:
- return self._duplex_supported
-
- def setDuplexSupported(self, supported: bool):
- self._duplex_supported = supported
-
- def getMediaSizes(self) -> List[MediaSize]:
- return list(self._media_sizes)
-
- def setMediaSizes(self, sizes: List[MediaSize]):
- self._media_sizes = list(sizes)
-
- def getResolutions(self) -> List[Resolution]:
- return list(self._resolutions)
-
- def setResolutions(self, resolutions: List[Resolution]):
- self._resolutions = list(resolutions)
-
- def getMinMargins(self) -> Margins:
- return self._min_margins
-
- def setMinMargins(self, margins: Margins):
- self._min_margins = margins
-
- def toString(self) -> str:
- return f"PrinterCapabilities(color={self._color_supported}, duplex={self._duplex_supported})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaSize / Resolution / Margins / PaperSize
-# ═══════════════════════════════════════════════════════════════
-
-class MediaSize(Stub):
- """MediaSize — 打印介质尺寸"""
-
- def __init__(self, id: str = "", label: str = "", width: int = 0, height: int = 0):
- super().__init__()
- self._id = id
- self._label = label
- self._width = width
- self._height = height
-
- def getId(self) -> str:
- return self._id
-
- def setId(self, id: str):
- self._id = id
-
- def getLabel(self) -> str:
- return self._label
-
- def setLabel(self, label: str):
- self._label = label
-
- def getWidth(self) -> int:
- return self._width
-
- def setWidth(self, width: int):
- self._width = width
-
- def getHeight(self) -> int:
- return self._height
-
- def setHeight(self, height: int):
- self._height = height
-
- def toString(self) -> str:
- return f"MediaSize(id={self._id}, {self._width}x{self._height})"
-
-
-class Resolution(Stub):
- """Resolution — 打印分辨率"""
-
- def __init__(self, id: str = "", label: str = "",
- horizontal_dpi: int = 300, vertical_dpi: int = 300):
- super().__init__()
- self._id = id
- self._label = label
- self._horizontal_dpi = horizontal_dpi
- self._vertical_dpi = vertical_dpi
-
- def getId(self) -> str:
- return self._id
-
- def getLabel(self) -> str:
- return self._label
-
- def getHorizontalDpi(self) -> int:
- return self._horizontal_dpi
-
- def getVerticalDpi(self) -> int:
- return self._vertical_dpi
-
- def toString(self) -> str:
- return f"Resolution(id={self._id}, dpi={self._horizontal_dpi}x{self._vertical_dpi})"
-
-
-class Margins(Stub):
- """Margins — 打印边距"""
-
- def __init__(self, left: int = 0, top: int = 0, right: int = 0, bottom: int = 0):
- super().__init__()
- self._left = left
- self._top = top
- self._right = right
- self._bottom = bottom
-
- def getLeft(self) -> int:
- return self._left
-
- def getTop(self) -> int:
- return self._top
-
- def getRight(self) -> int:
- return self._right
-
- def getBottom(self) -> int:
- return self._bottom
-
- def toString(self) -> str:
- return f"Margins(l={self._left}, t={self._top}, r={self._right}, b={self._bottom})"
-
-
-class PaperSize(Stub):
- """PaperSize — 纸张尺寸"""
-
- A0 = 1
- A1 = 2
- A2 = 3
- A3 = 4
- A4 = 5
- A5 = 6
- LETTER = 7
- LEGAL = 8
- TABLOID = 9
- ENVELOPE = 10
- PHOTO = 11
-
- def __init__(self, id: int = A4, label: str = "A4",
- width: int = 210000, height: int = 297000):
- super().__init__()
- self._id = id
- self._label = label
- self._width = width
- self._height = height
-
- def getId(self) -> int:
- return self._id
-
- def getLabel(self) -> str:
- return self._label
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def toString(self) -> str:
- return f"PaperSize(id={self._id}, {self._label})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintJobInfo
-# ═══════════════════════════════════════════════════════════════
-
-class PrintJobInfo(Stub):
- """PrintJobInfo — 打印作业信息"""
-
- STATE_CREATED = 1
- STATE_QUEUED = 2
- STATE_STARTED = 3
- STATE_BLOCKED = 4
- STATE_COMPLETED = 5
- STATE_FAILED = 6
- STATE_CANCELED = 7
-
- def __init__(self, job_id: int = 0, label: str = ""):
- super().__init__()
- self._job_id = job_id
- self._label = label
- self._state: int = PrintJobInfo.STATE_CREATED
- self._printer: Optional[PrinterId] = None
- self._creation_time: int = int(time.time() * 1000)
- self._copies: int = 1
- self._page_count: int = 0
- self._media_size: Optional[MediaSize] = None
- self._resolution: Optional[Resolution] = None
- self._is_color: bool = True
- self._is_duplex: bool = False
- self._progress: float = 0.0
- self._status: int = 0
- self._status_string: str = ""
-
- def getJobId(self) -> int:
- return self._job_id
-
- def setJobId(self, job_id: int):
- self._job_id = job_id
-
- def getLabel(self) -> str:
- return self._label
-
- def setLabel(self, label: str):
- self._label = label
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getPrinterId(self) -> Optional[PrinterId]:
- return self._printer
-
- def setPrinterId(self, printer_id: PrinterId):
- self._printer = printer_id
-
- def getCreationTime(self) -> int:
- return self._creation_time
-
- def setCreationTime(self, time_ms: int):
- self._creation_time = time_ms
-
- def getCopies(self) -> int:
- return self._copies
-
- def setCopies(self, copies: int):
- self._copies = copies
-
- def getPageCount(self) -> int:
- return self._page_count
-
- def setPageCount(self, count: int):
- self._page_count = count
-
- def getMediaSize(self) -> Optional[MediaSize]:
- return self._media_size
-
- def setMediaSize(self, size: MediaSize):
- self._media_size = size
-
- def getResolution(self) -> Optional[Resolution]:
- return self._resolution
-
- def setResolution(self, resolution: Resolution):
- self._resolution = resolution
-
- def isColor(self) -> bool:
- return self._is_color
-
- def setColor(self, color: bool):
- self._is_color = color
-
- def isDuplex(self) -> bool:
- return self._is_duplex
-
- def setDuplex(self, duplex: bool):
- self._is_duplex = duplex
-
- def getProgress(self) -> float:
- return self._progress
-
- def setProgress(self, progress: float):
- self._progress = progress
-
- def getStatus(self) -> int:
- return self._status
-
- def setStatus(self, status: int):
- self._status = status
-
- def getStatusString(self) -> str:
- return self._status_string
-
- def setStatusString(self, status_str: str):
- self._status_string = status_str
-
- def toString(self) -> str:
- return f"PrintJobInfo(id={self._job_id}, label={self._label}, state={self._state})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintJob
-# ═══════════════════════════════════════════════════════════════
-
-class PrintJob(Stub):
- """PrintJob — 打印作业"""
-
- def __init__(self, job_id: int = 0, label: str = ""):
- super().__init__()
- self._info = PrintJobInfo(job_id, label)
- self._document: Optional[PrintDocument] = None
- self._is_cancelled: bool = False
- self._is_queued: bool = False
- self._advanced_options: Dict[str, Any] = {}
-
- def getId(self) -> int:
- return self._info.getJobId()
-
- def getInfo(self) -> PrintJobInfo:
- return self._info
-
- def setInfo(self, info: PrintJobInfo):
- self._info = info
-
- def getDocument(self) -> Optional[PrintDocument]:
- return self._document
-
- def setDocument(self, document: PrintDocument):
- self._document = document
-
- def isCancelled(self) -> bool:
- return self._is_cancelled
-
- def isQueued(self) -> bool:
- return self._is_queued
-
- def start(self):
- """开始打印作业"""
- self._info.setState(PrintJobInfo.STATE_STARTED)
-
- def block(self, reason: str):
- """阻塞打印作业"""
- self._info.setState(PrintJobInfo.STATE_BLOCKED)
- self._info.setStatusString(reason)
-
- def complete(self):
- """完成打印作业"""
- self._info.setState(PrintJobInfo.STATE_COMPLETED)
- self._info.setProgress(1.0)
-
- def fail(self, error: str):
- """打印作业失败"""
- self._info.setState(PrintJobInfo.STATE_FAILED)
- self._info.setStatusString(error)
-
- def cancel(self):
- """取消打印作业"""
- self._info.setState(PrintJobInfo.STATE_CANCELED)
- self._is_cancelled = True
-
- def setProgress(self, progress: float):
- """设置进度"""
- self._info.setProgress(max(0.0, min(1.0, progress)))
-
- def getAdvancedOptions(self) -> Dict[str, Any]:
- return dict(self._advanced_options)
-
- def setAdvancedOption(self, key: str, value: Any):
- self._advanced_options[key] = value
-
- def toString(self) -> str:
- return f"PrintJob(id={self.getId()}, state={self._info.getState()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintDocument
-# ═══════════════════════════════════════════════════════════════
-
-class PrintDocument(Stub):
- """PrintDocument — 打印文档"""
-
- def __init__(self, data: bytes = b"", mime_type: str = "application/pdf"):
- super().__init__()
- self._data = data
- self._mime_type = mime_type
- self._page_count: int = 0
- self._title: str = ""
- self._content_uri: str = ""
- self._file_path: str = ""
-
- def getData(self) -> bytes:
- return self._data
-
- def setData(self, data: bytes):
- self._data = data
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def setMimeType(self, mime_type: str):
- self._mime_type = mime_type
-
- def getPageCount(self) -> int:
- return self._page_count
-
- def setPageCount(self, count: int):
- self._page_count = count
-
- def getTitle(self) -> str:
- return self._title
-
- def setTitle(self, title: str):
- self._title = title
-
- def getContentUri(self) -> str:
- return self._content_uri
-
- def setContentUri(self, uri: str):
- self._content_uri = uri
-
- def getFilePath(self) -> str:
- return self._file_path
-
- def setFilePath(self, file_path: str):
- self._file_path = file_path
-
- def toString(self) -> str:
- return f"PrintDocument(title={self._title}, pages={self._page_count})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrinterDiscoverySession
-# ═══════════════════════════════════════════════════════════════
-
-class PrinterDiscoverySession(Stub):
- """PrinterDiscoverySession — 打印机发现会话"""
-
- def __init__(self):
- super().__init__()
- self._printers: Dict[PrinterId, PrinterInfo] = {}
- self._tracked_printers: Set[PrinterId] = set()
- self._is_discovering: bool = False
- self._is_destroyed: bool = False
-
- def onStartPrinterDiscovery(self, priority_list: Optional[List[PrinterId]]):
- """开始打印机发现"""
- self._is_discovering = True
-
- def onStopPrinterDiscovery(self):
- """停止打印机发现"""
- self._is_discovering = False
-
- def onValidatePrinters(self, printer_ids: List[PrinterId]):
- """验证打印机"""
- pass
-
- def onStartPrinterStateTracking(self, printer_id: PrinterId):
- """开始跟踪打印机状态"""
- self._tracked_printers.add(printer_id)
-
- def onStopPrinterStateTracking(self, printer_id: PrinterId):
- """停止跟踪打印机状态"""
- self._tracked_printers.discard(printer_id)
-
- def onDestroy(self):
- """销毁会话"""
- self._is_destroyed = True
- self._printers.clear()
- self._tracked_printers.clear()
- self._is_discovering = False
-
- def addPrinters(self, printers: List[PrinterInfo]):
- """添加打印机"""
- for p in printers:
- self._printers[p.getId()] = p
-
- def removePrinters(self, printer_ids: List[PrinterId]):
- """移除打印机"""
- for pid in printer_ids:
- self._printers.pop(pid, None)
-
- def getPrinters(self) -> List[PrinterInfo]:
- """获取打印机列表"""
- return list(self._printers.values())
-
- def isDestroyed(self) -> bool:
- return self._is_destroyed
-
- def isPrinterDiscoveryStarted(self) -> bool:
- return self._is_discovering
-
- def getTrackedPrinters(self) -> Set[PrinterId]:
- return set(self._tracked_printers)
-
- def toString(self) -> str:
- return f"PrinterDiscoverySession(printers={len(self._printers)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CustomPrinterIconCallback
-# ═══════════════════════════════════════════════════════════════
-
-class CustomPrinterIconCallback(Stub):
- """CustomPrinterIconCallback — 自定义打印机图标回调"""
-
- def __init__(self):
- super().__init__()
- self._icon_cache: Dict[PrinterId, bytes] = {}
- self._callbacks: Dict[PrinterId, Callable] = {}
-
- def onCustomPrinterIconLoaded(self, printer_id: PrinterId, icon: bytes):
- """自定义打印机图标加载回调"""
- self._icon_cache[printer_id] = icon
-
- def requestCustomPrinterIcon(self, printer_id: PrinterId,
- callback: Callable[[bytes], None]):
- """请求自定义打印机图标"""
- if printer_id in self._icon_cache:
- callback(self._icon_cache[printer_id])
- else:
- self._callbacks[printer_id] = callback
-
- def getCachedIcon(self, printer_id: PrinterId) -> Optional[bytes]:
- return self._icon_cache.get(printer_id)
-
- def clearCache(self):
- self._icon_cache.clear()
- self._callbacks.clear()
-
- def toString(self) -> str:
- return f"CustomPrinterIconCallback(cached={len(self._icon_cache)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintService
-# ═══════════════════════════════════════════════════════════════
-
-class PrintService(Stub):
- """PrintService — 打印服务"""
-
- SERVICE_INTERFACE = "android.printservice.PrintService"
- SERVICE_META_DATA = "android.printservice"
-
- EXTRA_PRINT_JOB_INFO = "android.printservice.extra.PRINT_JOB_INFO"
- EXTRA_SELECT_PRINTER = "android.printservice.extra.SELECT_PRINTER"
- EXTRA_PRINTER_ID = "android.printservice.extra.PRINTER_ID"
- EXTRA_PRINTER_INFO = "android.printservice.extra.PRINTER_INFO"
- EXTRA_PRINT_DOCUMENT_INFO = "android.printservice.extra.PRINT_DOCUMENT_INFO"
-
- def __init__(self):
- super().__init__()
- self._print_jobs: Dict[int, PrintJob] = {}
- self._discovery_session: Optional[PrinterDiscoverySession] = None
- self._icon_callbacks: List[CustomPrinterIconCallback] = []
- self._is_connected: bool = False
- self._printer_infos: Dict[PrinterId, PrinterInfo] = {}
-
- def onCreatePrinterDiscoverySession(self) -> PrinterDiscoverySession:
- """创建打印机发现会话"""
- self._discovery_session = PrinterDiscoverySession()
- return self._discovery_session
-
- def onPrintJobQueued(self, print_job: PrintJob):
- """打印作业入队回调"""
- self._print_jobs[print_job.getId()] = print_job
-
- def onCancelPrintJob(self, print_job: PrintJob):
- """取消打印作业回调"""
- print_job.cancel()
- self._print_jobs.pop(print_job.getId(), None)
-
- def onConnected(self):
- """连接回调"""
- self._is_connected = True
-
- def onDisconnected(self):
- """断开连接回调"""
- self._is_connected = False
-
- def onRequestCancelPrintJob(self, print_job: PrintJob):
- """请求取消打印作业"""
- print_job.cancel()
-
- def getActivePrintJobs(self) -> List[PrintJob]:
- """获取活动的打印作业"""
- return [j for j in self._print_jobs.values()
- if j.getInfo().getState() in (PrintJobInfo.STATE_QUEUED,
- PrintJobInfo.STATE_STARTED,
- PrintJobInfo.STATE_BLOCKED)]
-
- def getPrintJobs(self) -> List[PrintJob]:
- return list(self._print_jobs.values())
-
- def addPrintJob(self, print_job: PrintJob):
- self._print_jobs[print_job.getId()] = print_job
-
- def removePrintJob(self, job_id: int):
- self._print_jobs.pop(job_id, None)
-
- def getDiscoverySession(self) -> Optional[PrinterDiscoverySession]:
- return self._discovery_session
-
- def addPrinterInfo(self, info: PrinterInfo):
- self._printer_infos[info.getId()] = info
-
- def removePrinterInfo(self, printer_id: PrinterId):
- self._printer_infos.pop(printer_id, None)
-
- def getPrinterInfos(self) -> List[PrinterInfo]:
- return list(self._printer_infos.values())
-
- def isConnected(self) -> bool:
- return self._is_connected
-
- def generatePrintJobId(self) -> int:
- return int(time.time() * 1000) % 100000
-
- def toString(self) -> str:
- return f"PrintService(jobs={len(self._print_jobs)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintServiceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class PrintServiceInfo(Stub):
- """PrintServiceInfo — 打印服务信息"""
-
- def __init__(self, package_name: str = "", service_name: str = ""):
- super().__init__()
- self._package_name = package_name
- self._service_name = service_name
- self._description: str = ""
- self._is_enabled: bool = False
- self._settings_activity: str = ""
- self._add_printers_activity: str = ""
- self._advanced_options_activity: str = ""
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def setPackageName(self, pkg: str):
- self._package_name = pkg
-
- def getServiceName(self) -> str:
- return self._service_name
-
- def setServiceName(self, name: str):
- self._service_name = name
-
- def getDescription(self) -> str:
- return self._description
-
- def setDescription(self, desc: str):
- self._description = desc
-
- def isEnabled(self) -> bool:
- return self._is_enabled
-
- def setEnabled(self, enabled: bool):
- self._is_enabled = enabled
-
- def getSettingsActivity(self) -> str:
- return self._settings_activity
-
- def setSettingsActivity(self, activity: str):
- self._settings_activity = activity
-
- def toString(self) -> str:
- return f"PrintServiceInfo(package={self._package_name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintServicePrinter
-# ═══════════════════════════════════════════════════════════════
-
-class PrintServicePrinter(Stub):
- """PrintServicePrinter — 打印机辅助类"""
-
- TYPE_LOCAL = 0
- TYPE_NETWORK = 1
- TYPE_BLUETOOTH = 2
- TYPE_USB = 3
- TYPE_CLOUD = 4
- TYPE_VIRTUAL = 5
-
- def __init__(self, printer_id: PrinterId = None, name: str = "",
- printer_type: int = TYPE_LOCAL):
- super().__init__()
- self._id = printer_id or PrinterId()
- self._name = name
- self._printer_type = printer_type
- self._uri: str = ""
- self._ip_address: str = ""
- self._port: int = 0
- self._location: str = ""
-
- def getId(self) -> PrinterId:
- return self._id
-
- def setId(self, printer_id: PrinterId):
- self._id = printer_id
-
- def getName(self) -> str:
- return self._name
-
- def setName(self, name: str):
- self._name = name
-
- def getPrinterType(self) -> int:
- return self._printer_type
-
- def setPrinterType(self, type_: int):
- self._printer_type = type_
-
- def getUri(self) -> str:
- return self._uri
-
- def setUri(self, uri: str):
- self._uri = uri
-
- def getIpAddress(self) -> str:
- return self._ip_address
-
- def setIpAddress(self, ip: str):
- self._ip_address = ip
-
- def getPort(self) -> int:
- return self._port
-
- def setPort(self, port: int):
- self._port = port
-
- def getLocation(self) -> str:
- return self._location
-
- def setLocation(self, location: str):
- self._location = location
-
- def toString(self) -> str:
- return f"PrintServicePrinter(name={self._name}, type={self._printer_type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PrintServiceUtils
-# ═══════════════════════════════════════════════════════════════
-
-class PrintServiceUtils(Stub):
- """PrintServiceUtils — 打印服务工具类"""
-
- @staticmethod
- def createPrinterId(package_name: str, local_id: str) -> PrinterId:
- return PrinterId(package_name, local_id)
-
- @staticmethod
- def createPrinterInfo(printer_id: PrinterId, name: str,
- status: int) -> PrinterInfo:
- return PrinterInfo(printer_id, name, status)
-
- @staticmethod
- def createPrintJobInfo(job_id: int, label: str) -> PrintJobInfo:
- return PrintJobInfo(job_id, label)
-
- @staticmethod
- def createPrintJob(job_id: int, label: str) -> PrintJob:
- return PrintJob(job_id, label)
-
- @staticmethod
- def createPrintDocument(data: bytes, mime_type: str) -> PrintDocument:
- return PrintDocument(data, mime_type)
-
- @staticmethod
- def isServiceEnabled(package_name: str) -> bool:
- return True
-
- @staticmethod
- def getServiceList() -> List[PrintServiceInfo]:
- return []
-
- @staticmethod
- def enableService(package_name: str, enabled: bool):
- pass
\ No newline at end of file
diff --git a/android_pyapi/android/provider.py b/android_pyapi/android/provider.py
deleted file mode 100644
index 56ed3ae..0000000
--- a/android_pyapi/android/provider.py
+++ /dev/null
@@ -1,688 +0,0 @@
-"""
-Android Provider 组件 — Settings, MediaStore, ContactsContract 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-import json
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# OpenableColumns
-# ═══════════════════════════════════════════════════════════════
-
-class OpenableColumns(Stub):
- DISPLAY_NAME = "_display_name"
- SIZE = "_size"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Settings
-# ═══════════════════════════════════════════════════════════════
-
-class _SettingsBase(Stub):
- """Settings 基类 — 存储到 JSON 文件"""
-
- _DATA_DIR = os.path.join(_app_data_dir, "shared_prefs")
- _cache: Dict[str, Dict[str, Any]] = {}
-
- @classmethod
- def _get_path(cls, name: str) -> str:
- os.makedirs(cls._DATA_DIR, exist_ok=True)
- return os.path.join(cls._DATA_DIR, f"{name}.json")
-
- @classmethod
- def _load(cls, name: str) -> Dict[str, Any]:
- if name in cls._cache:
- return cls._cache[name]
- path = cls._get_path(name)
- if os.path.exists(path):
- try:
- with open(path, "r") as f:
- data = json.load(f)
- cls._cache[name] = data
- return data
- except (json.JSONDecodeError, OSError):
- pass
- cls._cache[name] = {}
- return cls._cache[name]
-
- @classmethod
- def _save(cls, name: str):
- path = cls._get_path(name)
- try:
- with open(path, "w") as f:
- json.dump(cls._cache.get(name, {}), f)
- except OSError:
- pass
-
- @staticmethod
- def putString(name: str, key: str, value: str) -> bool:
- data = _SettingsBase._load(name)
- data[key] = value
- _SettingsBase._save(name)
- return True
-
- @staticmethod
- def getString(name: str, key: str, default_value: Optional[str] = None) -> Optional[str]:
- data = _SettingsBase._load(name)
- return data.get(key, default_value)
-
- @staticmethod
- def putInt(name: str, key: str, value: int) -> bool:
- data = _SettingsBase._load(name)
- data[key] = value
- _SettingsBase._save(name)
- return True
-
- @staticmethod
- def getInt(name: str, key: str, default_value: int = 0) -> int:
- data = _SettingsBase._load(name)
- return data.get(key, default_value)
-
- @staticmethod
- def putLong(name: str, key: str, value: int) -> bool:
- return _SettingsBase.putInt(name, key, value)
-
- @staticmethod
- def getLong(name: str, key: str, default_value: int = 0) -> int:
- return _SettingsBase.getInt(name, key, default_value)
-
- @staticmethod
- def putFloat(name: str, key: str, value: float) -> bool:
- data = _SettingsBase._load(name)
- data[key] = value
- _SettingsBase._save(name)
- return True
-
- @staticmethod
- def getFloat(name: str, key: str, default_value: float = 0.0) -> float:
- data = _SettingsBase._load(name)
- return data.get(key, default_value)
-
- @staticmethod
- def putBoolean(name: str, key: str, value: bool) -> bool:
- data = _SettingsBase._load(name)
- data[key] = bool(value)
- _SettingsBase._save(name)
- return True
-
- @staticmethod
- def getBoolean(name: str, key: str, default_value: bool = False) -> bool:
- data = _SettingsBase._load(name)
- val = data.get(key, default_value)
- if isinstance(val, bool):
- return val
- if isinstance(val, str):
- return val.lower() in ("true", "1", "yes")
- if isinstance(val, (int, float)):
- return bool(val)
- return default_value
-
-
-class SettingsSystem(_SettingsBase):
- _NAME = "settings_system"
-
- @staticmethod
- def putInt(key: str, value: int) -> bool:
- return _SettingsBase.putInt(SettingsSystem._NAME, key, value)
-
- @staticmethod
- def getInt(key: str, default_value: int = 0) -> int:
- return _SettingsBase.getInt(SettingsSystem._NAME, key, default_value)
-
- @staticmethod
- def putString(key: str, value: str) -> bool:
- return _SettingsBase.putString(SettingsSystem._NAME, key, value)
-
- @staticmethod
- def getString(key: str, default_value: Optional[str] = None) -> Optional[str]:
- return _SettingsBase.getString(SettingsSystem._NAME, key, default_value)
-
- @staticmethod
- def putFloat(key: str, value: float) -> bool:
- return _SettingsBase.putFloat(SettingsSystem._NAME, key, value)
-
- @staticmethod
- def getFloat(key: str, default_value: float = 0.0) -> float:
- return _SettingsBase.getFloat(SettingsSystem._NAME, key, default_value)
-
- @staticmethod
- def putLong(key: str, value: int) -> bool:
- return _SettingsBase.putLong(SettingsSystem._NAME, key, value)
-
- @staticmethod
- def getLong(key: str, default_value: int = 0) -> int:
- return _SettingsBase.getLong(SettingsSystem._NAME, key, default_value)
-
- @staticmethod
- def putBoolean(key: str, value: bool) -> bool:
- return _SettingsBase.putBoolean(SettingsSystem._NAME, key, value)
-
- @staticmethod
- def getBoolean(key: str, default_value: bool = False) -> bool:
- return _SettingsBase.getBoolean(SettingsSystem._NAME, key, default_value)
-
-
-class SettingsSecure(_SettingsBase):
- _NAME = "settings_secure"
-
- @staticmethod
- def putInt(key: str, value: int) -> bool:
- return _SettingsBase.putInt(SettingsSecure._NAME, key, value)
-
- @staticmethod
- def getInt(key: str, default_value: int = 0) -> int:
- return _SettingsBase.getInt(SettingsSecure._NAME, key, default_value)
-
- @staticmethod
- def putString(key: str, value: str) -> bool:
- return _SettingsBase.putString(SettingsSecure._NAME, key, value)
-
- @staticmethod
- def getString(key: str, default_value: Optional[str] = None) -> Optional[str]:
- return _SettingsBase.getString(SettingsSecure._NAME, key, default_value)
-
- @staticmethod
- def putFloat(key: str, value: float) -> bool:
- return _SettingsBase.putFloat(SettingsSecure._NAME, key, value)
-
- @staticmethod
- def getFloat(key: str, default_value: float = 0.0) -> float:
- return _SettingsBase.getFloat(SettingsSecure._NAME, key, default_value)
-
- @staticmethod
- def putLong(key: str, value: int) -> bool:
- return _SettingsBase.putLong(SettingsSecure._NAME, key, value)
-
- @staticmethod
- def getLong(key: str, default_value: int = 0) -> int:
- return _SettingsBase.getLong(SettingsSecure._NAME, key, default_value)
-
- @staticmethod
- def putBoolean(key: str, value: bool) -> bool:
- return _SettingsBase.putBoolean(SettingsSecure._NAME, key, value)
-
- @staticmethod
- def getBoolean(key: str, default_value: bool = False) -> bool:
- return _SettingsBase.getBoolean(SettingsSecure._NAME, key, default_value)
-
-
-class SettingsGlobal(_SettingsBase):
- _NAME = "settings_global"
-
- @staticmethod
- def putInt(key: str, value: int) -> bool:
- return _SettingsBase.putInt(SettingsGlobal._NAME, key, value)
-
- @staticmethod
- def getInt(key: str, default_value: int = 0) -> int:
- return _SettingsBase.getInt(SettingsGlobal._NAME, key, default_value)
-
- @staticmethod
- def putString(key: str, value: str) -> bool:
- return _SettingsBase.putString(SettingsGlobal._NAME, key, value)
-
- @staticmethod
- def getString(key: str, default_value: Optional[str] = None) -> Optional[str]:
- return _SettingsBase.getString(SettingsGlobal._NAME, key, default_value)
-
- @staticmethod
- def putFloat(key: str, value: float) -> bool:
- return _SettingsBase.putFloat(SettingsGlobal._NAME, key, value)
-
- @staticmethod
- def getFloat(key: str, default_value: float = 0.0) -> float:
- return _SettingsBase.getFloat(SettingsGlobal._NAME, key, default_value)
-
- @staticmethod
- def putLong(key: str, value: int) -> bool:
- return _SettingsBase.putLong(SettingsGlobal._NAME, key, value)
-
- @staticmethod
- def getLong(key: str, default_value: int = 0) -> int:
- return _SettingsBase.getLong(SettingsGlobal._NAME, key, default_value)
-
- @staticmethod
- def putBoolean(key: str, value: bool) -> bool:
- return _SettingsBase.putBoolean(SettingsGlobal._NAME, key, value)
-
- @staticmethod
- def getBoolean(key: str, default_value: bool = False) -> bool:
- return _SettingsBase.getBoolean(SettingsGlobal._NAME, key, default_value)
-
-
-class Settings(Stub):
- """Settings — 系统设置"""
-
- System = SettingsSystem
- Secure = SettingsSecure
- Global = SettingsGlobal
-
- ACTION_SETTINGS = "android.settings.SETTINGS"
- ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS"
- EXTRA_APP_PACKAGE = "android.intent.extra.PACKAGE_NAME"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaStore
-# ═══════════════════════════════════════════════════════════════
-
-class MediaStore(Stub):
- """MediaStore — 媒体存储"""
-
- VOLUME_INTERNAL = "internal"
- VOLUME_EXTERNAL = "external"
- VOLUME_EXTERNAL_PRIMARY = "external_primary"
-
- class MediaColumns(Stub):
- _ID = 0
- DATA = 1
- SIZE = 2
- DISPLAY_NAME = 3
- MIME_TYPE = 4
- TITLE = 5
- DATE_ADDED = 6
- DATE_MODIFIED = 7
- ORIENTATION = 8
- WIDTH = 9
- HEIGHT = 10
-
- class Files(Stub):
- @staticmethod
- def getContentUri(volume_name: str) -> str:
- return f"content://media/{volume_name}/file"
-
- class Images(Stub):
- class Media(Stub):
- EXTERNAL_CONTENT_URI = "content://media/external/images/media"
- INTERNAL_CONTENT_URI = "content://media/internal/images/media"
-
- @staticmethod
- def getContentUri(volume_name: str) -> str:
- return f"content://media/{volume_name}/images/media"
-
- class Thumbnails(Stub):
- EXTERNAL_CONTENT_URI = "content://media/external/images/thumbnails"
-
- class Video(Stub):
- class Media(Stub):
- EXTERNAL_CONTENT_URI = "content://media/external/video/media"
- INTERNAL_CONTENT_URI = "content://media/internal/video/media"
-
- @staticmethod
- def getContentUri(volume_name: str) -> str:
- return f"content://media/{volume_name}/video/media"
-
- class Audio(Stub):
- class Media(Stub):
- EXTERNAL_CONTENT_URI = "content://media/external/audio/media"
- INTERNAL_CONTENT_URI = "content://media/internal/audio/media"
-
- @staticmethod
- def getContentUri(volume_name: str) -> str:
- return f"content://media/{volume_name}/audio/media"
-
- @staticmethod
- def getMediaUri(volume_name: str) -> str:
- """返回指定卷的媒体 URI。"""
- return f"content://media/{volume_name}"
-
- @staticmethod
- def getVersion(context: Any, uri: str) -> str:
- return "0"
-
- @staticmethod
- def setVersion(context: Any, uri: str, version: str) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# DocumentsContract
-# ═══════════════════════════════════════════════════════════════
-
-class DocumentsContract(Stub):
- """DocumentsContract — 文档合约"""
-
- EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI"
- EXTRA_LOADING = "android.provider.extra.LOADING"
- EXTRA_INFO = "android.provider.extra.INFO"
- EXTRA_PROMPT = "android.provider.extra.PROMPT"
-
- @staticmethod
- def buildDocumentUri(authority: str, document_id: str) -> str:
- return f"content://{authority}/document/{document_id}"
-
- @staticmethod
- def buildDocumentUriUsingTree(tree_uri: str, document_id: str) -> str:
- return f"{tree_uri}/document/{document_id}"
-
- @staticmethod
- def buildChildDocumentsUri(authority: str, parent_document_id: str) -> str:
- return f"content://{authority}/document/{parent_document_id}/children"
-
- @staticmethod
- def buildChildDocumentsUriUsingTree(tree_uri: str, parent_document_id: str) -> str:
- return f"{tree_uri}/document/{parent_document_id}/children"
-
- @staticmethod
- def getDocumentId(document_uri: str) -> str:
- return document_uri.rsplit("/", 1)[-1]
-
- @staticmethod
- def getTreeDocumentId(document_uri: str) -> str:
- parts = document_uri.split("/")
- if "document" in parts:
- idx = parts.index("document")
- if idx + 1 < len(parts):
- return parts[idx + 1]
- return ""
-
- @staticmethod
- def getRootId(root_uri: str) -> str:
- parts = root_uri.split("/")
- if "root" in parts:
- idx = parts.index("root")
- if idx + 1 < len(parts):
- return parts[idx + 1]
- return ""
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContactsContract
-# ═══════════════════════════════════════════════════════════════
-
-class ContactsContract(Stub):
- """ContactsContract — 联系人合约"""
-
- AUTHORITY = "com.android.contacts"
-
- class Contacts(Stub):
- CONTENT_URI = "content://com.android.contacts/contacts"
- CONTENT_FILTER_URI = "content://com.android.contacts/contacts/filter"
- CONTENT_TYPE = "vnd.android.cursor.dir/contact"
- CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact"
- DISPLAY_NAME = "display_name"
- PHOTO_URI = "photo_uri"
- PHOTO_ID = "photo_id"
- _ID = "_id"
- HAS_PHONE_NUMBER = "has_phone_number"
- LOOKUP_KEY = "lookup"
- STARRED = "starred"
-
- class CommonDataKinds(Stub):
- class Email(Stub):
- CONTENT_URI = "content://com.android.contacts/data/emails"
- CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2"
- ADDRESS = "data1"
- DISPLAY_NAME = "display_name"
- TYPE = "data2"
- TYPE_HOME = 1
- TYPE_WORK = 2
- TYPE_OTHER = 3
- TYPE_MOBILE = 4
-
- class Phone(Stub):
- CONTENT_URI = "content://com.android.contacts/data/phones"
- CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2"
- NUMBER = "data1"
- DISPLAY_NAME = "display_name"
- TYPE = "data2"
- TYPE_HOME = 1
- TYPE_MOBILE = 2
- TYPE_WORK = 3
- TYPE_FAX_WORK = 4
- TYPE_FAX_HOME = 5
- TYPE_PAGER = 6
- TYPE_OTHER = 7
- TYPE_CALLBACK = 8
- TYPE_CAR = 9
- TYPE_COMPANY_MAIN = 10
- TYPE_ISDN = 11
- TYPE_MAIN = 12
- TYPE_OTHER_FAX = 13
- TYPE_RADIO = 14
- TYPE_TELEX = 15
- TYPE_TTY_TDD = 16
- TYPE_WORK_MOBILE = 17
- TYPE_WORK_PAGER = 18
- TYPE_ASSISTANT = 19
-
- class StructuredName(Stub):
- CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name"
- DISPLAY_NAME = "data1"
- GIVEN_NAME = "data2"
- FAMILY_NAME = "data3"
- PREFIX = "data4"
- MIDDLE_NAME = "data5"
- SUFFIX = "data6"
-
- class Organization(Stub):
- CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization"
- COMPANY = "data1"
- TYPE = "data2"
- TITLE = "data4"
- TYPE_WORK = 1
- TYPE_OTHER = 2
-
- class Data(Stub):
- CONTENT_URI = "content://com.android.contacts/data"
- CONTENT_TYPE = "vnd.android.cursor.dir/data"
- CONTENT_ITEM_TYPE = "vnd.android.cursor.item/data"
- MIMETYPE = "mimetype"
- _ID = "_id"
- DISPLAY_NAME = "display_name"
- RAW_CONTACT_ID = "raw_contact_id"
- CONTACT_ID = "contact_id"
-
- class RawContacts(Stub):
- CONTENT_URI = "content://com.android.contacts/raw_contacts"
- CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact"
- CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact"
- _ID = "_id"
- CONTACT_ID = "contact_id"
- ACCOUNT_NAME = "account_name"
- ACCOUNT_TYPE = "account_type"
-
-
-class ContactsContractContacts(ContactsContract.Contacts):
- pass
-
-
-class ContactsContractData(ContactsContract.Data):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# CallLog
-# ═══════════════════════════════════════════════════════════════
-
-class CallLog(Stub):
- """CallLog — 通话记录"""
-
- class Calls(Stub):
- CONTENT_URI = "content://call_log/calls"
- _ID = "_id"
- NUMBER = "number"
- TYPE = "type"
- TYPE_INCOMING = 1
- TYPE_OUTGOING = 2
- TYPE_MISSED = 3
- TYPE_VOICEMAIL = 4
- TYPE_REJECTED = 5
- TYPE_BLOCKED = 6
- TYPE_ANSWERED_EXTERNALLY = 7
- DATE = "date"
- DURATION = "duration"
- NEW = "new"
- VOICEMAIL_URI = "voicemail_uri"
- CACHED_NAME = "cached_name"
- CACHED_NUMBER_LABEL = "cached_number_label"
- GEOCODED_LOCATION = "geocoded_location"
- COUNTRY_ISO = "country_iso"
-
- @staticmethod
- def getLastOutgoingCall(context: Any) -> Optional[str]:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# CalendarContract
-# ═══════════════════════════════════════════════════════════════
-
-class CalendarContract(Stub):
- """CalendarContract — 日历合约"""
-
- class Events(Stub):
- CONTENT_URI = "content://com.android.calendar/events"
- _ID = "_id"
- TITLE = "title"
- DESCRIPTION = "description"
- EVENT_LOCATION = "event_location"
- DTSTART = "dtstart"
- DTEND = "dtend"
- EVENT_TIMEZONE = "event_timezone"
- DURATION = "duration"
- ALL_DAY = "allDay"
- CALENDAR_ID = "calendar_id"
- ORGANIZER = "organizer"
- STATUS = "eventStatus"
- AVAILABILITY = "availability"
- ACCESS_LEVEL = "accessLevel"
-
- class Attendees(Stub):
- CONTENT_URI = "content://com.android.calendar/attendees"
-
- class Reminders(Stub):
- CONTENT_URI = "content://com.android.calendar/reminders"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Browser / SearchRecentSuggestions / UserDictionary
-# ═══════════════════════════════════════════════════════════════
-
-class Browser(Stub):
- """Browser — 浏览器书签"""
-
- class BookmarkColumns(Stub):
- TITLE = "title"
- URL = "url"
- _ID = "_id"
- BOOKMARK = "bookmark"
- DATE = "date"
- CREATED = "created"
- VISITS = "visits"
-
- class SearchColumns(Stub):
- URL = "url"
- SEARCH = "search"
- DATE = "date"
-
- HISTORY_PROJECTION = ["_id", "url", "title", "date", "visits", "bookmark", "created"]
- SEARCHES_PROJECTION = ["_id", "search", "date"]
-
-
-class SearchRecentSuggestions(Stub):
- """SearchRecentSuggestions — 搜索建议"""
-
- def __init__(self, context: Any, authority: str, mode: int):
- super().__init__()
- self._authority = authority
- self._mode = mode
-
- def saveRecentQuery(self, query_string: str, line2: str):
- pass
-
- def clearHistory(self):
- pass
-
-
-class UserDictionary(Stub):
- """UserDictionary — 用户词典"""
-
- class Words(Stub):
- CONTENT_URI = "content://user_dictionary/words"
- _ID = "_id"
- WORD = "word"
- FREQUENCY = "frequency"
- LOCALE = "locale"
- APP_ID = "app_id"
- SHORTCUT = "shortcut"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SyncStateContract / LiveFolders
-# ═══════════════════════════════════════════════════════════════
-
-class SyncStateContract(Stub):
- """SyncStateContract — 同步状态合约"""
-
- class Columns(Stub):
- _ID = "_id"
- ACCOUNT_NAME = "account_name"
- ACCOUNT_TYPE = "account_type"
- DATA = "data"
-
- class Helpers(Stub):
- @staticmethod
- def get(cr: Any, provider_uri: str, account: Any) -> Optional[bytes]:
- return None
-
- @staticmethod
- def set(cr: Any, provider_uri: str, account: Any, data: bytes):
- pass
-
- @staticmethod
- def insert(cr: Any, provider_uri: str, account: Any, data: bytes):
- pass
-
- @staticmethod
- def update(cr: Any, provider_uri: str, account: Any, data: bytes):
- pass
-
-
-class LiveFolders(Stub):
- """LiveFolders — 实时文件夹"""
-
- NAME = "name"
- DESCRIPTION = "description"
- INTENT = "intent"
- ICON_BITMAP = "icon_bitmap"
- ICON_PACKAGE = "icon_package"
- ICON_RESOURCE = "icon_resource"
- DISPLAY_MODE = "display_mode"
- DISPLAY_MODE_GRID = 1
- DISPLAY_MODE_LIST = 2
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Settings",
- "SettingsSystem",
- "SettingsSecure",
- "SettingsGlobal",
- "CallLog",
- "ContactsContract",
- "ContactsContractContacts",
- "ContactsContractData",
- "MediaStore",
- "DocumentsContract",
- "CalendarContract",
- "Browser",
- "SearchRecentSuggestions",
- "UserDictionary",
- "SyncStateContract",
- "LiveFolders",
- "OpenableColumns",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/provider_calendar.py b/android_pyapi/android/provider_calendar.py
deleted file mode 100644
index 4ce361e..0000000
--- a/android_pyapi/android/provider_calendar.py
+++ /dev/null
@@ -1,1379 +0,0 @@
-"""
-Android Provider CalendarContract 扩展组件
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import json
-import time
-import datetime
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# CalendarContract 常量
-# ═══════════════════════════════════════════════════════════════
-
-# Calendars
-CALENDAR_DISPLAY_NAME = "calendar_displayName"
-CALENDAR_ACCOUNT_NAME = "account_name"
-CALENDAR_ACCOUNT_TYPE = "account_type"
-CALENDAR_OWNER_ACCOUNT = "calendar_ownerAccount"
-CALENDAR_COLOR = "calendar_color"
-CALENDAR_COLOR_KEY = "calendar_color_key"
-CALENDAR_ACCESS_LEVEL = "calendar_access_level"
-CALENDAR_VISIBLE = "calendar_visible"
-CALENDAR_SYNC_EVENTS = "calendar_sync_events"
-CALENDAR_TIMEZONE = "calendar_timezone"
-CALENDAR_ALLOWED_REMINDERS = "calendar_allowedReminders"
-CALENDAR_ALLOWED_AVAILABILITY = "calendar_allowedAvailability"
-CALENDAR_ALLOWED_ATTENDEE_TYPES = "calendar_allowedAttendeeTypes"
-CALENDAR_IS_PRIMARY = "calendar_isPrimary"
-CALENDAR_MAX_REMINDERS = "calendar_maxReminders"
-CALENDAR_DTSTART = "calendar_dtstart"
-CALENDAR_CAN_ORGANIZER_RESPOND = "calendar_canOrganizerRespond"
-CALENDAR_CAN_MODIFY_TIME_ZONE = "calendar_canModifyTimeZone"
-CALENDAR_ALLOWED_REMINDERS = CALENDAR_ALLOWED_REMINDERS
-CALENDAR_AVAILABLE_COLORS = "calendar_availableColors"
-CALENDAR_COLORS_RAW = "calendar_colorsRaw"
-
-# Events
-EVENT_ID = "_id"
-EVENT_TITLE = "title"
-EVENT_DESCRIPTION = "description"
-EVENT_LOCATION = "eventLocation"
-EVENT_DTSTART = "dtstart"
-EVENT_DTEND = "dtend"
-EVENT_DURATION = "duration"
-EVENT_TIMEZONE = "eventTimezone"
-EVENT_ALL_DAY = "allDay"
-EVENT_CALENDAR_ID = "calendar_id"
-EVENT_ORGANIZER = "organizer"
-EVENT_STATUS = "eventStatus"
-EVENT_AVAILABILITY = "availability"
-EVENT_ACCESS_LEVEL = "accessLevel"
-EVENT_RRULE = "rrule"
-EVENT_RDATE = "rdate"
-EVENT_EXRULE = "exrule"
-EVENT_EXDATE = "exdate"
-EVENT_ORIGINAL_ID = "original_id"
-EVENT_ORIGINAL_SYNC_ID = "original_sync_id"
-EVENT_ORIGINAL_INSTANCE_TIME = "originalInstanceTime"
-EVENT_ORIGINAL_ALL_DAY = "originalAllDay"
-EVENT_LAST_DATE = "lastDate"
-EVENT_HAS_ALARM = "hasAlarm"
-EVENT_HAS_EXTENDED_PROPERTIES = "hasExtendedProperties"
-EVENT_EVENT_COLOR = "eventColor"
-EVENT_EVENT_COLOR_KEY = "eventColor_key"
-EVENT_CUSTOM_APP_PACKAGE = "customAppPackage"
-EVENT_CUSTOM_APP_URI = "customAppUri"
-EVENT_ORGANIZER_CAN_RESPOND = "organizerCanRespond"
-EVENT_SELF_ATTENDEE_STATUS = "selfAttendeeStatus"
-EVENT_UID_2445 = "uid2445"
-EVENT_IS_ORGANIZER = "isOrganizer"
-EVENT_CAN_INVITE_OTHERS = "canInviteOthers"
-EVENT_ALLOWED_REMINDERS = "allowedReminders"
-
-# Attendees
-ATTENDEE_ID = "_id"
-ATTENDEE_EVENT_ID = "event_id"
-ATTENDEE_NAME = "attendeeName"
-ATTENDEE_EMAIL = "attendeeEmail"
-ATTENDEE_RELATIONSHIP = "attendeeRelationship"
-ATTENDEE_TYPE = "attendeeType"
-ATTENDEE_STATUS = "attendeeStatus"
-ATTENDEE_IDENTITY = "attendeeIdentity"
-ATTENDEE_ID_NAMESPACE = "attendeeIdNamespace"
-
-# Reminders
-REMINDER_ID = "_id"
-REMINDER_EVENT_ID = "event_id"
-REMINDER_MINUTES = "minutes"
-REMINDER_METHOD = "method"
-
-# Instances
-INSTANCE_ID = "_id"
-INSTANCE_EVENT_ID = "event_id"
-INSTANCE_BEGIN = "begin"
-INSTANCE_END = "end"
-INSTANCE_TITLE = "title"
-INSTANCE_DESCRIPTION = "description"
-INSTANCE_EVENT_LOCATION = "eventLocation"
-INSTANCE_ALL_DAY = "allDay"
-INSTANCE_CALENDAR_ID = "calendar_id"
-INSTANCE_RRULE = "rrule"
-INSTANCE_ORIGINAL_ID = "original_id"
-INSTANCE_ORIGINAL_INSTANCE_TIME = "originalInstanceTime"
-INSTANCE_ORIGINAL_SYNC_ID = "original_sync_id"
-INSTANCE_EVENT_TIMEZONE = "eventTimezone"
-INSTANCE_DTSTART = "dtstart"
-INSTANCE_DTEND = "dtend"
-INSTANCE_DURATION = "duration"
-INSTANCE_STATUS = "eventStatus"
-INSTANCE_AVAILABILITY = "availability"
-INSTANCE_ACCESS_LEVEL = "accessLevel"
-INSTANCE_HAS_ALARM = "hasAlarm"
-INSTANCE_HAS_EXTENDED_PROPERTIES = "hasExtendedProperties"
-INSTANCE_EVENT_COLOR = "eventColor"
-INSTANCE_SELF_ATTENDEE_STATUS = "selfAttendeeStatus"
-INSTANCE_START_DAY = "startDay"
-INSTANCE_END_DAY = "endDay"
-INSTANCE_START_MINUTE = "startMinute"
-INSTANCE_END_MINUTE = "endMinute"
-
-# Colors
-COLOR_ID = "_id"
-COLOR_KEY = "color_key"
-COLOR = "color"
-COLOR_TYPE = "color_type"
-
-# Calendar Alerts
-CALENDAR_ALERT_ID = "_id"
-CALENDAR_ALERT_EVENT_ID = "event_id"
-CALENDAR_ALERT_BEGIN = "begin"
-CALENDAR_ALERT_END = "end"
-CALENDAR_ALERT_ALARM_TIME = "alarmTime"
-CALENDAR_ALERT_CREATION_TIME = "creationTime"
-CALENDAR_ALERT_RECEIVED_TIME = "receivedTime"
-CALENDAR_ALERT_NOTIFY_TIME = "notifyTime"
-CALENDAR_ALERT_STATE = "state"
-CALENDAR_ALERT_MINUTES = "minutes"
-CALENDAR_ALERT_ACKNOWLEDGED = "acknowledged"
-CALENDAR_ALERT_DISMISSED = "dismissed"
-CALENDAR_ALERT_TYPE = "type"
-CALENDAR_ALERT_ORIGIN = "origin"
-
-# Calendar Cache
-CALENDAR_CACHE_KEY = "key"
-CALENDAR_CACHE_VALUE = "value"
-
-# Event status
-EVENT_STATUS_TENTATIVE = 0
-EVENT_STATUS_CONFIRMED = 1
-EVENT_STATUS_CANCELED = 2
-
-# Availability
-AVAILABILITY_BUSY = 0
-AVAILABILITY_FREE = 1
-AVAILABILITY_TENTATIVE = 2
-
-# Access level
-ACCESS_DEFAULT = 0
-ACCESS_CONFIDENTIAL = 1
-ACCESS_PRIVATE = 2
-ACCESS_PUBLIC = 3
-ACCESS_RESTRICTED = 4
-
-# Attendee relationship
-ATTENDEE_RELATIONSHIP_NONE = 0
-ATTENDEE_RELATIONSHIP_ORGANIZER = 1
-ATTENDEE_RELATIONSHIP_ATTENDEE = 2
-ATTENDEE_RELATIONSHIP_PERFORMER = 3
-ATTENDEE_RELATIONSHIP_SPEAKER = 4
-
-# Attendee type
-ATTENDEE_TYPE_NONE = 0
-ATTENDEE_TYPE_REQUIRED = 1
-ATTENDEE_TYPE_OPTIONAL = 2
-
-# Attendee status
-ATTENDEE_STATUS_NONE = 0
-ATTENDEE_STATUS_ACCEPTED = 1
-ATTENDEE_STATUS_DECLINED = 2
-ATTENDEE_STATUS_INVITED = 3
-ATTENDEE_STATUS_TENTATIVE = 4
-
-# Reminder method
-REMINDER_METHOD_DEFAULT = 0
-REMINDER_METHOD_ALERT = 1
-REMINDER_METHOD_EMAIL = 2
-REMINDER_METHOD_SMS = 3
-REMINDER_METHOD_ALARM = 4
-
-# Color type
-COLOR_TYPE_CALENDAR = 0
-COLOR_TYPE_EVENT = 1
-
-# Calendar alert state
-CALENDAR_ALERT_STATE_SCHEDULED = 0
-CALENDAR_ALERT_STATE_FIRED = 1
-CALENDAR_ALERT_STATE_DISMISSED = 2
-
-# Calendar alert type
-CALENDAR_ALERT_TYPE_ALARM = 0
-CALENDAR_ALERT_TYPE_REMINDER = 1
-
-# Calendar alert origin
-CALENDAR_ALERT_ORIGIN_SELF = 0
-CALENDAR_ALERT_ORIGIN_SYNC = 1
-
-# Calendar visibility
-CALENDAR_VISIBLE_TRUE = 1
-CALENDAR_VISIBLE_FALSE = 0
-
-# Calendar sync
-CALENDAR_SYNC_EVENTS_TRUE = 1
-CALENDAR_SYNC_EVENTS_FALSE = 0
-
-# Calendar primary
-CALENDAR_IS_PRIMARY_TRUE = 1
-CALENDAR_IS_PRIMARY_FALSE = 0
-
-# Calendar can modify time zone
-CALENDAR_CAN_MODIFY_TIME_ZONE_TRUE = 1
-CALENDAR_CAN_MODIFY_TIME_ZONE_FALSE = 0
-
-# Calendar can organizer respond
-CALENDAR_CAN_ORGANIZER_RESPOND_TRUE = 1
-CALENDAR_CAN_ORGANIZER_RESPOND_FALSE = 0
-
-# Sync columns
-CALENDAR_SYNC_ACCOUNT_NAME = "account_name"
-CALENDAR_SYNC_ACCOUNT_TYPE = "account_type"
-CALENDAR_SYNC_SOURCE_ID = "sync_id"
-CALENDAR_SYNC_VERSION = "sync_version"
-CALENDAR_SYNC_DIRTY = "sync_dirty"
-CALENDAR_SYNC_MARK = "sync_mark"
-CALENDAR_SYNC1 = "sync1"
-CALENDAR_SYNC2 = "sync2"
-CALENDAR_SYNC3 = "sync3"
-CALENDAR_SYNC4 = "sync4"
-CALENDAR_SYNC5 = "sync5"
-CALENDAR_SYNC6 = "sync6"
-CALENDAR_SYNC7 = "sync7"
-CALENDAR_SYNC8 = "sync8"
-CALENDAR_SYNC9 = "sync9"
-CALENDAR_SYNC10 = "sync10"
-
-# Calendar keys for CalendarCache
-CALENDAR_CACHE_KEY_TIMEZONE_TYPE = "timezoneType"
-CALENDAR_CACHE_KEY_TIMEZONE_INSTANCES = "timezoneInstances"
-CALENDAR_CACHE_KEY_TIMEZONE_INSTANCES_PREVIOUS = "timezoneInstancesPrevious"
-CALENDAR_CACHE_KEY_TIMEZONE_INSTANCES_NEXT = "timezoneInstancesNext"
-
-# Calendar notification
-CALENDAR_NOTIFICATION_ID = "_id"
-CALENDAR_NOTIFICATION_EVENT_ID = "event_id"
-CALENDAR_NOTIFICATION_ALARM_TIME = "alarmTime"
-CALENDAR_NOTIFICATION_BEGIN = "begin"
-CALENDAR_NOTIFICATION_END = "end"
-CALENDAR_NOTIFICATION_TITLE = "title"
-CALENDAR_NOTIFICATION_DESCRIPTION = "description"
-CALENDAR_NOTIFICATION_LOCATION = "location"
-CALENDAR_NOTIFICATION_STATE = "state"
-CALENDAR_NOTIFICATION_MINUTES = "minutes"
-CALENDAR_NOTIFICATION_VISIBILITY = "visibility"
-CALENDAR_NOTIFICATION_PRIORITY = "priority"
-CALENDAR_NOTIFICATION_GROUP_KEY = "groupKey"
-CALENDAR_NOTIFICATION_SORT_KEY = "sortKey"
-
-# URI constants
-CALENDAR_URI_CALENDARS = "content://com.android.calendar/calendars"
-CALENDAR_URI_EVENTS = "content://com.android.calendar/events"
-CALENDAR_URI_ATTENDEES = "content://com.android.calendar/attendees"
-CALENDAR_URI_REMINDERS = "content://com.android.calendar/reminders"
-CALENDAR_URI_INSTANCES = "content://com.android.calendar/instances/when"
-CALENDAR_URI_INSTANCES_GROUP_BY_DAY = "content://com.android.calendar/instances/groupbyday"
-CALENDAR_URI_COLORS = "content://com.android.calendar/colors"
-CALENDAR_URI_CALENDAR_ALERTS = "content://com.android.calendar/calendar_alerts"
-CALENDAR_URI_CALENDAR_CACHE = "content://com.android.calendar/calendar_cache"
-CALENDAR_URI_SYNC_STATE = "content://com.android.calendar/syncstate"
-CALENDAR_URI_CALENDAR_ENTITY = "content://com.android.calendar/calendar_entity"
-CALENDAR_URI_EVENT_ENTITY = "content://com.android.calendar/event_entity"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CalendarContract 命名空间容器
-# ═══════════════════════════════════════════════════════════════
-
-class CalendarContractBase(Stub):
- """CalendarContract — 日历合约基类"""
- pass
-
-
-class SyncColumns(Stub):
- """CalendarContract.SyncColumns — 同步列"""
- ACCOUNT_NAME = CALENDAR_SYNC_ACCOUNT_NAME
- ACCOUNT_TYPE = CALENDAR_SYNC_ACCOUNT_TYPE
- SOURCE_ID = CALENDAR_SYNC_SOURCE_ID
- VERSION = CALENDAR_SYNC_VERSION
- DIRTY = CALENDAR_SYNC_DIRTY
- SYNC1 = CALENDAR_SYNC1
- SYNC2 = CALENDAR_SYNC2
- SYNC3 = CALENDAR_SYNC3
- SYNC4 = CALENDAR_SYNC4
- SYNC5 = CALENDAR_SYNC5
- SYNC6 = CALENDAR_SYNC6
- SYNC7 = CALENDAR_SYNC7
- SYNC8 = CALENDAR_SYNC8
- SYNC9 = CALENDAR_SYNC9
- SYNC10 = CALENDAR_SYNC10
-
-
-class SyncState(Stub):
- """CalendarContract.SyncState — 同步状态表"""
- CONTENT_URI = CALENDAR_URI_SYNC_STATE
- _ID = "_id"
- ACCOUNT_NAME = "account_name"
- ACCOUNT_TYPE = "account_type"
- DATA = "data"
-
-
-class Calendars(Stub):
- """CalendarContract.Calendars — 日历表"""
- CONTENT_URI = CALENDAR_URI_CALENDARS
- _ID = "_id"
- CALENDAR_DISPLAY_NAME = "calendar_displayName"
- CALENDAR_ACCOUNT_NAME = "account_name"
- CALENDAR_ACCOUNT_TYPE = "account_type"
- CALENDAR_OWNER_ACCOUNT = "calendar_ownerAccount"
- CALENDAR_COLOR = "calendar_color"
- CALENDAR_COLOR_KEY = "calendar_color_key"
- CALENDAR_ACCESS_LEVEL = "calendar_access_level"
- CALENDAR_VISIBLE = "calendar_visible"
- CALENDAR_SYNC_EVENTS = "calendar_sync_events"
- CALENDAR_TIMEZONE = "calendar_timezone"
- CALENDAR_ALLOWED_REMINDERS = "calendar_allowedReminders"
- CALENDAR_ALLOWED_AVAILABILITY = "calendar_allowedAvailability"
- CALENDAR_ALLOWED_ATTENDEE_TYPES = "calendar_allowedAttendeeTypes"
- CALENDAR_IS_PRIMARY = "calendar_isPrimary"
- CALENDAR_MAX_REMINDERS = "calendar_maxReminders"
- CALENDAR_DTSTART = "calendar_dtstart"
- CALENDAR_CAN_ORGANIZER_RESPOND = "calendar_canOrganizerRespond"
- CALENDAR_CAN_MODIFY_TIME_ZONE = "calendar_canModifyTimeZone"
- CALENDAR_AVAILABLE_COLORS = "calendar_availableColors"
- CALENDAR_COLORS_RAW = "calendar_colorsRaw"
- CALENDAR_ALLOWED_REMINDERS = "calendar_allowedReminders"
- NAME = "calendar_displayName"
- SYNC_EVENTS = "calendar_sync_events"
-
- VISIBLE = 1
- SYNC_EVENTS_YES = 1
- SYNC_EVENTS_NO = 0
- NO_UNDO_UPDATE_DELETION = 1
-
- @staticmethod
- def query(context: Any, projection: List[str], selection: str = None,
- selection_args: List[str] = None, sort_order: str = None) -> List[Dict[str, Any]]:
- """Query the calendars table."""
- return []
-
- @staticmethod
- def queryWithFactory(context: Any, projection: List[str], selection: str = None,
- selection_args: List[str] = None, sort_order: str = None) -> Any:
- """Query calendars with factory."""
- return None
-
- @staticmethod
- def getCalendarColor(context: Any, calendar_id: int) -> int:
- """Get calendar color."""
- return 0xFF1976D2
-
-
-class Events(Stub):
- """CalendarContract.Events — 事件表"""
- CONTENT_URI = CALENDAR_URI_EVENTS
- _ID = "_id"
- TITLE = "title"
- DESCRIPTION = "description"
- EVENT_LOCATION = "eventLocation"
- DTSTART = "dtstart"
- DTEND = "dtend"
- DURATION = "duration"
- EVENT_TIMEZONE = "eventTimezone"
- ALL_DAY = "allDay"
- CALENDAR_ID = "calendar_id"
- ORGANIZER = "organizer"
- STATUS = "eventStatus"
- AVAILABILITY = "availability"
- ACCESS_LEVEL = "accessLevel"
- RRULE = "rrule"
- RDATE = "rdate"
- EXRULE = "exrule"
- EXDATE = "exdate"
- ORIGINAL_ID = "original_id"
- ORIGINAL_SYNC_ID = "original_sync_id"
- ORIGINAL_INSTANCE_TIME = "originalInstanceTime"
- ORIGINAL_ALL_DAY = "originalAllDay"
- LAST_DATE = "lastDate"
- HAS_ALARM = "hasAlarm"
- HAS_EXTENDED_PROPERTIES = "hasExtendedProperties"
- EVENT_COLOR = "eventColor"
- EVENT_COLOR_KEY = "eventColor_key"
- CUSTOM_APP_PACKAGE = "customAppPackage"
- CUSTOM_APP_URI = "customAppUri"
- ORGANIZER_CAN_RESPOND = "organizerCanRespond"
- SELF_ATTENDEE_STATUS = "selfAttendeeStatus"
- UID_2445 = "uid2445"
- IS_ORGANIZER = "isOrganizer"
- CAN_INVITE_OTHERS = "canInviteOthers"
- ALLOWED_REMINDERS = "allowedReminders"
-
- STATUS_TENTATIVE = 0
- STATUS_CONFIRMED = 1
- STATUS_CANCELED = 2
-
- @staticmethod
- def query(context: Any, projection: List[str], selection: str = None,
- selection_args: List[str] = None, sort_order: str = None) -> List[Dict[str, Any]]:
- """Query the events table."""
- return []
-
- @staticmethod
- def insert(context: Any, values: Dict[str, Any]) -> int:
- """Insert a new event. Returns the event ID."""
- return -1
-
- @staticmethod
- def update(context: Any, values: Dict[str, Any], selection: str = None,
- selection_args: List[str] = None) -> int:
- """Update events. Returns number of rows affected."""
- return 0
-
- @staticmethod
- def delete(context: Any, selection: str = None, selection_args: List[str] = None) -> int:
- """Delete events. Returns number of rows deleted."""
- return 0
-
- @staticmethod
- def queryEntity(context: Any, projection: List[str], selection: str = None,
- selection_args: List[str] = None, sort_order: str = None) -> List[Any]:
- """Query event entities."""
- return []
-
-
-class Attendees(Stub):
- """CalendarContract.Attendees — 参与者表"""
- CONTENT_URI = CALENDAR_URI_ATTENDEES
- _ID = "_id"
- EVENT_ID = "event_id"
- ATTENDEE_NAME = "attendeeName"
- ATTENDEE_EMAIL = "attendeeEmail"
- ATTENDEE_RELATIONSHIP = "attendeeRelationship"
- ATTENDEE_TYPE = "attendeeType"
- ATTENDEE_STATUS = "attendeeStatus"
- ATTENDEE_IDENTITY = "attendeeIdentity"
- ATTENDEE_ID_NAMESPACE = "attendeeIdNamespace"
-
- RELATIONSHIP_NONE = 0
- RELATIONSHIP_ORGANIZER = 1
- RELATIONSHIP_ATTENDEE = 2
- RELATIONSHIP_PERFORMER = 3
- RELATIONSHIP_SPEAKER = 4
-
- TYPE_NONE = 0
- TYPE_REQUIRED = 1
- TYPE_OPTIONAL = 2
-
- STATUS_NONE = 0
- STATUS_ACCEPTED = 1
- STATUS_DECLINED = 2
- STATUS_INVITED = 3
- STATUS_TENTATIVE = 4
-
- @staticmethod
- def query(context: Any, event_id: int, projection: List[str] = None) -> List[Dict[str, Any]]:
- """Query attendees for a specific event."""
- return []
-
-
-class Reminders(Stub):
- """CalendarContract.Reminders — 提醒表"""
- CONTENT_URI = CALENDAR_URI_REMINDERS
- _ID = "_id"
- EVENT_ID = "event_id"
- MINUTES = "minutes"
- METHOD = "method"
-
- METHOD_DEFAULT = 0
- METHOD_ALERT = 1
- METHOD_EMAIL = 2
- METHOD_SMS = 3
- METHOD_ALARM = 4
-
- @staticmethod
- def query(context: Any, event_id: int, projection: List[str] = None) -> List[Dict[str, Any]]:
- """Query reminders for a specific event."""
- return []
-
-
-class Instances(Stub):
- """CalendarContract.Instances — 实例表"""
- CONTENT_URI = CALENDAR_URI_INSTANCES
- CONTENT_BY_DAY_URI = CALENDAR_URI_INSTANCES_GROUP_BY_DAY
- _ID = "_id"
- EVENT_ID = "event_id"
- BEGIN = "begin"
- END = "end"
- TITLE = "title"
- DESCRIPTION = "description"
- EVENT_LOCATION = "eventLocation"
- ALL_DAY = "allDay"
- CALENDAR_ID = "calendar_id"
- RRULE = "rrule"
- ORIGINAL_ID = "original_id"
- ORIGINAL_INSTANCE_TIME = "originalInstanceTime"
- ORIGINAL_SYNC_ID = "original_sync_id"
- EVENT_TIMEZONE = "eventTimezone"
- DTSTART = "dtstart"
- DTEND = "dtend"
- DURATION = "duration"
- STATUS = "eventStatus"
- AVAILABILITY = "availability"
- ACCESS_LEVEL = "accessLevel"
- HAS_ALARM = "hasAlarm"
- HAS_EXTENDED_PROPERTIES = "hasExtendedProperties"
- EVENT_COLOR = "eventColor"
- SELF_ATTENDEE_STATUS = "selfAttendeeStatus"
- START_DAY = "startDay"
- END_DAY = "endDay"
- START_MINUTE = "startMinute"
- END_MINUTE = "endMinute"
-
- @staticmethod
- def query(context: Any, projection: List[str], begin_time: int, end_time: int,
- selection: str = None, selection_args: List[str] = None,
- sort_order: str = None) -> List[Dict[str, Any]]:
- """Query instances in a time range."""
- return []
-
-
-class Colors(Stub):
- """CalendarContract.Colors — 颜色表"""
- CONTENT_URI = CALENDAR_URI_COLORS
- _ID = "_id"
- COLOR_KEY = "color_key"
- COLOR = "color"
- COLOR_TYPE = "color_type"
-
- TYPE_CALENDAR = 0
- TYPE_EVENT = 1
-
- @staticmethod
- def query(context: Any, projection: List[str] = None) -> List[Dict[str, Any]]:
- """Query available colors."""
- return []
-
-
-class CalendarEntity(Stub):
- """CalendarContract.CalendarEntity — 日历实体"""
- CONTENT_URI = CALENDAR_URI_CALENDAR_ENTITY
- _ID = "_id"
- CALENDAR_DISPLAY_NAME = "calendar_displayName"
- CALENDAR_ACCOUNT_NAME = "account_name"
- CALENDAR_ACCOUNT_TYPE = "account_type"
- CALENDAR_OWNER_ACCOUNT = "calendar_ownerAccount"
- CALENDAR_COLOR = "calendar_color"
- CALENDAR_ACCESS_LEVEL = "calendar_access_level"
- CALENDAR_VISIBLE = "calendar_visible"
- CALENDAR_SYNC_EVENTS = "calendar_sync_events"
- CALENDAR_TIMEZONE = "calendar_timezone"
- CALENDAR_IS_PRIMARY = "calendar_isPrimary"
- CALENDAR_DTSTART = "calendar_dtstart"
- CALENDAR_CAN_ORGANIZER_RESPOND = "calendar_canOrganizerRespond"
- CALENDAR_CAN_MODIFY_TIME_ZONE = "calendar_canModifyTimeZone"
- CALENDAR_MAX_REMINDERS = "calendar_maxReminders"
- CALENDAR_ALLOWED_REMINDERS = "calendar_allowedReminders"
-
- @staticmethod
- def queryEntity(context: Any, projection: List[str], selection: str = None,
- selection_args: List[str] = None, sort_order: str = None) -> List[Any]:
- """Query calendar entities."""
- return []
-
-
-class EventEntity(Stub):
- """CalendarContract.EventEntity — 事件实体"""
- CONTENT_URI = CALENDAR_URI_EVENT_ENTITY
- _ID = "_id"
- TITLE = "title"
- DESCRIPTION = "description"
- EVENT_LOCATION = "eventLocation"
- DTSTART = "dtstart"
- DTEND = "dtend"
- DURATION = "duration"
- EVENT_TIMEZONE = "eventTimezone"
- ALL_DAY = "allDay"
- CALENDAR_ID = "calendar_id"
- ORGANIZER = "organizer"
- STATUS = "eventStatus"
- AVAILABILITY = "availability"
- ACCESS_LEVEL = "accessLevel"
- RRULE = "rrule"
- RDATE = "rdate"
- EXRULE = "exrule"
- EXDATE = "exdate"
- ORIGINAL_ID = "original_id"
- ORIGINAL_SYNC_ID = "original_sync_id"
- ORIGINAL_INSTANCE_TIME = "originalInstanceTime"
- ORIGINAL_ALL_DAY = "originalAllDay"
- LAST_DATE = "lastDate"
- HAS_ALARM = "hasAlarm"
- HAS_EXTENDED_PROPERTIES = "hasExtendedProperties"
- EVENT_COLOR = "eventColor"
- CUSTOM_APP_PACKAGE = "customAppPackage"
- CUSTOM_APP_URI = "customAppUri"
- ORGANIZER_CAN_RESPOND = "organizerCanRespond"
- SELF_ATTENDEE_STATUS = "selfAttendeeStatus"
- UID_2445 = "uid2445"
- IS_ORGANIZER = "isOrganizer"
- CAN_INVITE_OTHERS = "canInviteOthers"
- ALLOWED_REMINDERS = "allowedReminders"
-
- @staticmethod
- def queryEntity(context: Any, projection: List[str], selection: str = None,
- selection_args: List[str] = None, sort_order: str = None) -> List[Any]:
- """Query event entities."""
- return []
-
-
-class CalendarCache(Stub):
- """CalendarContract.CalendarCache — 日历缓存表"""
- CONTENT_URI = CALENDAR_URI_CALENDAR_CACHE
- KEY = "key"
- VALUE = "value"
-
- TIMEZONE_TYPE = "timezoneType"
- TIMEZONE_INSTANCES = "timezoneInstances"
- TIMEZONE_INSTANCES_PREVIOUS = "timezoneInstancesPrevious"
- TIMEZONE_INSTANCES_NEXT = "timezoneInstancesNext"
-
- TIMEZONE_TYPE_AUTO = "auto"
- TIMEZONE_TYPE_USER = "user"
-
- @staticmethod
- def getCacheKey(timezone_id: str, type_key: str) -> str:
- """Build a cache key for timezone data."""
- return f"{timezone_id}_{type_key}"
-
-
-class CalendarAlerts(Stub):
- """CalendarContract.CalendarAlerts — 日历提醒表"""
- CONTENT_URI = CALENDAR_URI_CALENDAR_ALERTS
- _ID = "_id"
- EVENT_ID = "event_id"
- BEGIN = "begin"
- END = "end"
- ALARM_TIME = "alarmTime"
- CREATION_TIME = "creationTime"
- RECEIVED_TIME = "receivedTime"
- NOTIFY_TIME = "notifyTime"
- STATE = "state"
- MINUTES = "minutes"
- ACKNOWLEDGED = "acknowledged"
- DISMISSED = "dismissed"
- TYPE = "type"
- ORIGIN = "origin"
-
- STATE_SCHEDULED = 0
- STATE_FIRED = 1
- STATE_DISMISSED = 2
-
- TYPE_ALARM = 0
- TYPE_REMINDER = 1
-
- ORIGIN_SELF = 0
- ORIGIN_SYNC = 1
-
- @staticmethod
- def query(context: Any, projection: List[str] = None) -> List[Dict[str, Any]]:
- """Query calendar alerts."""
- return []
-
- @staticmethod
- def insert(context: Any, values: Dict[str, Any]) -> int:
- """Insert a calendar alert. Returns the alert ID."""
- return -1
-
- @staticmethod
- def updateState(context: Any, alert_id: int, state: int):
- """Update the state of a calendar alert."""
- pass
-
-
-class CalendarNotification(Stub):
- """CalendarContract.CalendarNotification — 日历通知表"""
- CONTENT_URI = None # Virtual table, no direct content URI
- _ID = "_id"
- EVENT_ID = "event_id"
- ALARM_TIME = "alarmTime"
- BEGIN = "begin"
- END = "end"
- TITLE = "title"
- DESCRIPTION = "description"
- LOCATION = "location"
- STATE = "state"
- MINUTES = "minutes"
- VISIBILITY = "visibility"
- PRIORITY = "priority"
- GROUP_KEY = "groupKey"
- SORT_KEY = "sortKey"
-
- STATE_SHOWN = 0
- STATE_DISMISSED = 1
-
- VISIBILITY_PRIVATE = 0
- VISIBILITY_PUBLIC = 1
-
- PRIORITY_DEFAULT = 0
- PRIORITY_HIGH = 1
- PRIORITY_LOW = 2
-
- @staticmethod
- def notify(context: Any, event_id: int, alarm_time: int, begin: int, end: int):
- """Trigger notification for a calendar event."""
- pass
-
- @staticmethod
- def cancelNotification(context: Any, event_id: int):
- """Cancel notification for a calendar event."""
- pass
-
-
-class CalendarSyncColumns(SyncColumns):
- """CalendarContract.CalendarSyncColumns — 日历同步列"""
- CAL_SYNC1 = "cal_sync1"
- CAL_SYNC2 = "cal_sync2"
- CAL_SYNC3 = "cal_sync3"
- CAL_SYNC4 = "cal_sync4"
- CAL_SYNC5 = "cal_sync5"
- CAL_SYNC6 = "cal_sync6"
- CAL_SYNC7 = "cal_sync7"
- CAL_SYNC8 = "cal_sync8"
- CAL_SYNC9 = "cal_sync9"
- CAL_SYNC10 = "cal_sync10"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CalendarContract 根类
-# ═══════════════════════════════════════════════════════════════
-
-class CalendarContract(CalendarContractBase):
- """CalendarContract — 日历合约(扩展版)"""
-
- Calendars = Calendars
- Events = Events
- Attendees = Attendees
- Reminders = Reminders
- Instances = Instances
- Colors = Colors
- CalendarEntity = CalendarEntity
- EventEntity = EventEntity
- CalendarCache = CalendarCache
- CalendarAlerts = CalendarAlerts
- CalendarNotification = CalendarNotification
- CalendarSyncColumns = CalendarSyncColumns
- SyncState = SyncState
-
- # URI aliases
- CONTENT_URI_CALENDARS = CALENDAR_URI_CALENDARS
- CONTENT_URI_EVENTS = CALENDAR_URI_EVENTS
- CONTENT_URI_ATTENDEES = CALENDAR_URI_ATTENDEES
- CONTENT_URI_REMINDERS = CALENDAR_URI_REMINDERS
- CONTENT_URI_INSTANCES = CALENDAR_URI_INSTANCES
- CONTENT_URI_INSTANCES_GROUP_BY_DAY = CALENDAR_URI_INSTANCES_GROUP_BY_DAY
- CONTENT_URI_COLORS = CALENDAR_URI_COLORS
- CONTENT_URI_CALENDAR_ALERTS = CALENDAR_URI_CALENDAR_ALERTS
- CONTENT_URI_CALENDAR_CACHE = CALENDAR_URI_CALENDAR_CACHE
- CONTENT_URI_SYNC_STATE = CALENDAR_URI_SYNC_STATE
- CONTENT_URI_CALENDAR_ENTITY = CALENDAR_URI_CALENDAR_ENTITY
- CONTENT_URI_EVENT_ENTITY = CALENDAR_URI_EVENT_ENTITY
-
- @staticmethod
- def isValidEventType(context: Any, type_value: str) -> bool:
- """Check if a mime type is a valid event type."""
- return type_value in ("vnd.android.cursor.item/event", "vnd.android.cursor.dir/event")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CalendarContract 便捷类(扩展别名)
-# ═══════════════════════════════════════════════════════════════
-
-class CalendarContractCalendars(Calendars):
- """CalendarContract.Calendars 别名"""
- pass
-
-
-class CalendarContractEvents(Events):
- """CalendarContract.Events 别名"""
- pass
-
-
-class CalendarContractAttendees(Attendees):
- """CalendarContract.Attendees 别名"""
- pass
-
-
-class CalendarContractReminders(Reminders):
- """CalendarContract.Reminders 别名"""
- pass
-
-
-class CalendarContractInstances(Instances):
- """CalendarContract.Instances 别名"""
- pass
-
-
-class CalendarContractColors(Colors):
- """CalendarContract.Colors 别名"""
- pass
-
-
-class CalendarContractCalendarEntity(CalendarEntity):
- """CalendarContract.CalendarEntity 别名"""
- pass
-
-
-class CalendarContractEventEntity(EventEntity):
- """CalendarContract.EventEntity 别名"""
- pass
-
-
-class CalendarContractCalendarCache(CalendarCache):
- """CalendarContract.CalendarCache 别名"""
- pass
-
-
-class CalendarContractCalendarAlerts(CalendarAlerts):
- """CalendarContract.CalendarAlerts 别名"""
- pass
-
-
-class CalendarContractCalendarNotification(CalendarNotification):
- """CalendarContract.CalendarNotification 别名"""
- pass
-
-
-class CalendarContractCalendarSyncColumns(CalendarSyncColumns):
- """CalendarContract.CalendarSyncColumns 别名"""
- pass
-
-
-class CalendarContractSyncState(SyncState):
- """CalendarContract.SyncState 别名"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# CalendarEvent 辅助类
-# ═══════════════════════════════════════════════════════════════
-
-class CalendarEvent(Stub):
- """CalendarEvent — 事件对象封装"""
-
- def __init__(self, event_id: int = -1, title: str = "", description: str = "",
- location: str = "", dtstart: int = 0, dtend: int = 0,
- timezone: str = "UTC", all_day: bool = False,
- calendar_id: int = -1, organizer: str = "",
- status: int = EVENT_STATUS_CONFIRMED,
- availability: int = AVAILABILITY_BUSY,
- access_level: int = ACCESS_DEFAULT,
- rrule: str = "", duration: str = ""):
- super().__init__()
- self._id = event_id
- self._title = title
- self._description = description
- self._location = location
- self._dtstart = dtstart
- self._dtend = dtend
- self._timezone = timezone
- self._all_day = all_day
- self._calendar_id = calendar_id
- self._organizer = organizer
- self._status = status
- self._availability = availability
- self._access_level = access_level
- self._rrule = rrule
- self._duration = duration
- self._attendees: List[Dict[str, Any]] = []
- self._reminders: List[Dict[str, Any]] = []
- self._extended_properties: Dict[str, str] = {}
-
- def getId(self) -> int:
- return self._id
-
- def getTitle(self) -> str:
- return self._title
-
- def setTitle(self, title: str):
- self._title = title
-
- def getDescription(self) -> str:
- return self._description
-
- def setDescription(self, description: str):
- self._description = description
-
- def getLocation(self) -> str:
- return self._location
-
- def setLocation(self, location: str):
- self._location = location
-
- def getDtStart(self) -> int:
- return self._dtstart
-
- def setDtStart(self, dtstart: int):
- self._dtstart = dtstart
-
- def getDtEnd(self) -> int:
- return self._dtend
-
- def setDtEnd(self, dtend: int):
- self._dtend = dtend
-
- def getTimezone(self) -> str:
- return self._timezone
-
- def setTimezone(self, timezone: str):
- self._timezone = timezone
-
- def isAllDay(self) -> bool:
- return self._all_day
-
- def setAllDay(self, all_day: bool):
- self._all_day = all_day
-
- def getCalendarId(self) -> int:
- return self._calendar_id
-
- def setCalendarId(self, calendar_id: int):
- self._calendar_id = calendar_id
-
- def getOrganizer(self) -> str:
- return self._organizer
-
- def setOrganizer(self, organizer: str):
- self._organizer = organizer
-
- def getStatus(self) -> int:
- return self._status
-
- def setStatus(self, status: int):
- self._status = status
-
- def getAvailability(self) -> int:
- return self._availability
-
- def setAvailability(self, availability: int):
- self._availability = availability
-
- def getAccessLevel(self) -> int:
- return self._access_level
-
- def setAccessLevel(self, access_level: int):
- self._access_level = access_level
-
- def getRrule(self) -> str:
- return self._rrule
-
- def setRrule(self, rrule: str):
- self._rrule = rrule
-
- def getDuration(self) -> str:
- return self._duration
-
- def setDuration(self, duration: str):
- self._duration = duration
-
- def addAttendee(self, name: str, email: str, relationship: int = ATTENDEE_RELATIONSHIP_ATTENDEE,
- attendee_type: int = ATTENDEE_TYPE_REQUIRED,
- status: int = ATTENDEE_STATUS_NONE):
- """Add an attendee to this event."""
- self._attendees.append({
- "attendeeName": name,
- "attendeeEmail": email,
- "attendeeRelationship": relationship,
- "attendeeType": attendee_type,
- "attendeeStatus": status,
- })
-
- def getAttendees(self) -> List[Dict[str, Any]]:
- return list(self._attendees)
-
- def addReminder(self, minutes: int, method: int = REMINDER_METHOD_DEFAULT):
- """Add a reminder to this event."""
- self._reminders.append({
- "minutes": minutes,
- "method": method,
- })
-
- def getReminders(self) -> List[Dict[str, Any]]:
- return list(self._reminders)
-
- def putExtendedProperty(self, key: str, value: str):
- """Set an extended property."""
- self._extended_properties[key] = value
-
- def getExtendedProperty(self, key: str) -> Optional[str]:
- return self._extended_properties.get(key)
-
- def getExtendedProperties(self) -> Dict[str, str]:
- return dict(self._extended_properties)
-
- def toContentValues(self) -> Dict[str, Any]:
- """Convert event to content values dictionary."""
- values: Dict[str, Any] = {}
- if self._title:
- values["title"] = self._title
- if self._description:
- values["description"] = self._description
- if self._location:
- values["eventLocation"] = self._location
- if self._dtstart:
- values["dtstart"] = self._dtstart
- if self._dtend:
- values["dtend"] = self._dtend
- if self._timezone:
- values["eventTimezone"] = self._timezone
- values["allDay"] = 1 if self._all_day else 0
- if self._calendar_id >= 0:
- values["calendar_id"] = self._calendar_id
- if self._organizer:
- values["organizer"] = self._organizer
- values["eventStatus"] = self._status
- values["availability"] = self._availability
- values["accessLevel"] = self._access_level
- if self._rrule:
- values["rrule"] = self._rrule
- if self._duration:
- values["duration"] = self._duration
- return values
-
- @staticmethod
- def fromContentValues(values: Dict[str, Any]) -> "CalendarEvent":
- """Create an event from content values."""
- event = CalendarEvent()
- event._id = values.get("_id", -1)
- event._title = values.get("title", "")
- event._description = values.get("description", "")
- event._location = values.get("eventLocation", "")
- event._dtstart = values.get("dtstart", 0)
- event._dtend = values.get("dtend", 0)
- event._timezone = values.get("eventTimezone", "UTC")
- event._all_day = bool(values.get("allDay", 0))
- event._calendar_id = values.get("calendar_id", -1)
- event._organizer = values.get("organizer", "")
- event._status = values.get("eventStatus", EVENT_STATUS_CONFIRMED)
- event._availability = values.get("availability", AVAILABILITY_BUSY)
- event._access_level = values.get("accessLevel", ACCESS_DEFAULT)
- event._rrule = values.get("rrule", "")
- event._duration = values.get("duration", "")
- return event
-
- def toString(self) -> str:
- return f"CalendarEvent(id={self._id}, title='{self._title}')"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CalendarHelper 工具类
-# ═══════════════════════════════════════════════════════════════
-
-class CalendarHelper(Stub):
- """CalendarHelper — 日历操作辅助工具"""
-
- @staticmethod
- def createEvent(context: Any, calendar_id: int, title: str,
- dtstart: int, dtend: int, timezone: str = "UTC",
- description: str = "", location: str = "",
- all_day: bool = False) -> Optional[int]:
- """Create a calendar event. Returns event ID or None."""
- return None
-
- @staticmethod
- def updateEvent(context: Any, event_id: int, values: Dict[str, Any]) -> bool:
- """Update a calendar event."""
- return False
-
- @staticmethod
- def deleteEvent(context: Any, event_id: int) -> bool:
- """Delete a calendar event."""
- return False
-
- @staticmethod
- def getEvent(context: Any, event_id: int) -> Optional[CalendarEvent]:
- """Get a calendar event by ID."""
- return None
-
- @staticmethod
- def queryEvents(context: Any, calendar_id: Optional[int] = None,
- start_time: Optional[int] = None,
- end_time: Optional[int] = None) -> List[CalendarEvent]:
- """Query calendar events with optional filters."""
- return []
-
- @staticmethod
- def addReminder(context: Any, event_id: int, minutes: int,
- method: int = REMINDER_METHOD_DEFAULT) -> bool:
- """Add a reminder to an event."""
- return False
-
- @staticmethod
- def addAttendee(context: Any, event_id: int, email: str,
- name: str = "") -> bool:
- """Add an attendee to an event."""
- return False
-
- @staticmethod
- def getDefaultCalendarId(context: Any) -> int:
- """Get the default calendar ID."""
- return -1
-
- @staticmethod
- def queryCalendars(context: Any) -> List[Dict[str, Any]]:
- """Query all available calendars."""
- return []
-
- @staticmethod
- def getCalendars(context: Any) -> List[Dict[str, Any]]:
- """Get all calendars with sync enabled."""
- return []
-
- @staticmethod
- def createCalendar(context: Any, display_name: str,
- account_name: str, account_type: str,
- owner_account: str = "", timezone: str = "UTC") -> Optional[int]:
- """Create a new calendar."""
- return None
-
- @staticmethod
- def deleteCalendar(context: Any, calendar_id: int) -> bool:
- """Delete a calendar."""
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# CalendarTimezoneHelper 工具类
-# ═══════════════════════════════════════════════════════════════
-
-class CalendarTimezoneHelper(Stub):
- """CalendarTimezoneHelper — 时区辅助工具"""
-
- TIMEZONE_IDS = [
- "UTC", "GMT", "America/New_York", "America/Chicago",
- "America/Denver", "America/Los_Angeles", "America/Anchorage",
- "Pacific/Honolulu", "Europe/London", "Europe/Paris",
- "Europe/Berlin", "Europe/Moscow", "Europe/Istanbul",
- "Asia/Dubai", "Asia/Kolkata", "Asia/Bangkok",
- "Asia/Shanghai", "Asia/Tokyo", "Asia/Seoul",
- "Australia/Sydney", "Pacific/Auckland",
- ]
-
- @staticmethod
- def getAvailableTimezoneIds() -> List[str]:
- """Get list of available timezone IDs."""
- return list(CalendarTimezoneHelper.TIMEZONE_IDS)
-
- @staticmethod
- def toDisplayName(timezone_id: str, locale: Any = None) -> str:
- """Convert timezone ID to display name."""
- try:
- import zoneinfo
- tz = zoneinfo.ZoneInfo(timezone_id)
- now = datetime.datetime.now(tz)
- return f"{timezone_id} (UTC{now.strftime('%z')})"
- except Exception:
- return timezone_id
-
- @staticmethod
- def toMilliseconds(days: int = 0, hours: int = 0, minutes: int = 0,
- seconds: int = 0) -> int:
- """Convert time duration to milliseconds."""
- total_seconds = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds
- return total_seconds * 1000
-
- @staticmethod
- def fromMilliseconds(ms: int) -> Dict[str, int]:
- """Convert milliseconds to duration components."""
- total_seconds = ms // 1000
- days = total_seconds // 86400
- hours = (total_seconds % 86400) // 3600
- minutes = (total_seconds % 3600) // 60
- seconds = total_seconds % 60
- return {"days": days, "hours": hours, "minutes": minutes, "seconds": seconds}
-
-
-# ═══════════════════════════════════════════════════════════════
-# CalendarRecurrenceRule 工具类
-# ═══════════════════════════════════════════════════════════════
-
-class CalendarRecurrenceRule(Stub):
- """CalendarRecurrenceRule — 重复规则解析工具"""
-
- FREQ_DAILY = "DAILY"
- FREQ_WEEKLY = "WEEKLY"
- FREQ_MONTHLY = "MONTHLY"
- FREQ_YEARLY = "YEARLY"
-
- BY_DAY_SUNDAY = "SU"
- BY_DAY_MONDAY = "MO"
- BY_DAY_TUESDAY = "TU"
- BY_DAY_WEDNESDAY = "WE"
- BY_DAY_THURSDAY = "TH"
- BY_DAY_FRIDAY = "FR"
- BY_DAY_SATURDAY = "SA"
-
- def __init__(self, rrule: str = ""):
- super().__init__()
- self._freq: str = ""
- self._interval: int = 1
- self._count: Optional[int] = None
- self._until: Optional[int] = None
- self._by_day: List[str] = []
- self._by_month_day: List[int] = []
- self._by_month: List[int] = []
- self._by_year_day: List[int] = []
- self._week_start: str = "MO"
- self._raw = rrule
- if rrule:
- self._parse(rrule)
-
- def _parse(self, rrule: str):
- """Parse an RRULE string."""
- parts = rrule.split(";")
- for part in parts:
- if "=" not in part:
- continue
- key, value = part.split("=", 1)
- key = key.strip().upper()
- value = value.strip()
- if key == "FREQ":
- self._freq = value
- elif key == "INTERVAL":
- self._interval = int(value)
- elif key == "COUNT":
- self._count = int(value)
- elif key == "UNTIL":
- try:
- self._until = int(value)
- except ValueError:
- self._until = 0
- elif key == "BYDAY":
- self._by_day = value.split(",")
- elif key == "BYMONTHDAY":
- self._by_month_day = [int(x) for x in value.split(",")]
- elif key == "BYMONTH":
- self._by_month = [int(x) for x in value.split(",")]
- elif key == "BYYEARDAY":
- self._by_year_day = [int(x) for x in value.split(",")]
- elif key == "WKST":
- self._week_start = value
-
- def getFrequency(self) -> str:
- return self._freq
-
- def getInterval(self) -> int:
- return self._interval
-
- def getCount(self) -> Optional[int]:
- return self._count
-
- def getUntil(self) -> Optional[int]:
- return self._until
-
- def getByDay(self) -> List[str]:
- return list(self._by_day)
-
- def getByMonthDay(self) -> List[int]:
- return list(self._by_month_day)
-
- def getByMonth(self) -> List[int]:
- return list(self._by_month)
-
- def toString(self) -> str:
- return self._raw
-
- @staticmethod
- def createDaily(interval: int = 1, count: Optional[int] = None,
- until: Optional[int] = None) -> "CalendarRecurrenceRule":
- """Create a daily recurrence rule."""
- parts = [f"FREQ={CalendarRecurrenceRule.FREQ_DAILY}"]
- if interval > 1:
- parts.append(f"INTERVAL={interval}")
- if count is not None:
- parts.append(f"COUNT={count}")
- if until is not None:
- parts.append(f"UNTIL={until}")
- return CalendarRecurrenceRule(";".join(parts))
-
- @staticmethod
- def createWeekly(interval: int = 1, by_day: Optional[List[str]] = None,
- count: Optional[int] = None) -> "CalendarRecurrenceRule":
- """Create a weekly recurrence rule."""
- parts = [f"FREQ={CalendarRecurrenceRule.FREQ_WEEKLY}"]
- if interval > 1:
- parts.append(f"INTERVAL={interval}")
- if by_day:
- parts.append(f"BYDAY={','.join(by_day)}")
- if count is not None:
- parts.append(f"COUNT={count}")
- return CalendarRecurrenceRule(";".join(parts))
-
- @staticmethod
- def createMonthly(interval: int = 1, by_month_day: Optional[List[int]] = None,
- count: Optional[int] = None) -> "CalendarRecurrenceRule":
- """Create a monthly recurrence rule."""
- parts = [f"FREQ={CalendarRecurrenceRule.FREQ_MONTHLY}"]
- if interval > 1:
- parts.append(f"INTERVAL={interval}")
- if by_month_day:
- parts.append(f"BYMONTHDAY={','.join(str(d) for d in by_month_day)}")
- if count is not None:
- parts.append(f"COUNT={count}")
- return CalendarRecurrenceRule(";".join(parts))
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- # Constants
- "CALENDAR_DISPLAY_NAME", "CALENDAR_ACCOUNT_NAME", "CALENDAR_ACCOUNT_TYPE",
- "CALENDAR_OWNER_ACCOUNT", "CALENDAR_COLOR", "CALENDAR_COLOR_KEY",
- "CALENDAR_ACCESS_LEVEL", "CALENDAR_VISIBLE", "CALENDAR_SYNC_EVENTS",
- "CALENDAR_TIMEZONE", "CALENDAR_ALLOWED_REMINDERS", "CALENDAR_IS_PRIMARY",
- "CALENDAR_MAX_REMINDERS", "CALENDAR_DTSTART",
- "EVENT_ID", "EVENT_TITLE", "EVENT_DESCRIPTION", "EVENT_LOCATION",
- "EVENT_DTSTART", "EVENT_DTEND", "EVENT_DURATION", "EVENT_TIMEZONE",
- "EVENT_ALL_DAY", "EVENT_CALENDAR_ID", "EVENT_ORGANIZER",
- "EVENT_STATUS", "EVENT_AVAILABILITY", "EVENT_ACCESS_LEVEL",
- "EVENT_RRULE", "EVENT_RDATE", "EVENT_EXRULE", "EVENT_EXDATE",
- "ATTENDEE_ID", "ATTENDEE_EVENT_ID", "ATTENDEE_NAME", "ATTENDEE_EMAIL",
- "ATTENDEE_RELATIONSHIP", "ATTENDEE_TYPE", "ATTENDEE_STATUS",
- "REMINDER_ID", "REMINDER_EVENT_ID", "REMINDER_MINUTES", "REMINDER_METHOD",
- "INSTANCE_ID", "INSTANCE_BEGIN", "INSTANCE_END",
- "AVAILABILITY_BUSY", "AVAILABILITY_FREE", "AVAILABILITY_TENTATIVE",
- "ACCESS_DEFAULT", "ACCESS_CONFIDENTIAL", "ACCESS_PRIVATE",
- "ACCESS_PUBLIC", "ACCESS_RESTRICTED",
- "EVENT_STATUS_TENTATIVE", "EVENT_STATUS_CONFIRMED", "EVENT_STATUS_CANCELED",
- "ATTENDEE_RELATIONSHIP_NONE", "ATTENDEE_RELATIONSHIP_ORGANIZER",
- "ATTENDEE_RELATIONSHIP_ATTENDEE", "ATTENDEE_RELATIONSHIP_PERFORMER",
- "ATTENDEE_RELATIONSHIP_SPEAKER",
- "ATTENDEE_TYPE_NONE", "ATTENDEE_TYPE_REQUIRED", "ATTENDEE_TYPE_OPTIONAL",
- "ATTENDEE_STATUS_NONE", "ATTENDEE_STATUS_ACCEPTED", "ATTENDEE_STATUS_DECLINED",
- "ATTENDEE_STATUS_INVITED", "ATTENDEE_STATUS_TENTATIVE",
- "REMINDER_METHOD_DEFAULT", "REMINDER_METHOD_ALERT", "REMINDER_METHOD_EMAIL",
- "REMINDER_METHOD_SMS", "REMINDER_METHOD_ALARM",
- # Classes
- "CalendarContract", "Calendars", "Events", "Attendees", "Reminders",
- "Instances", "Colors", "CalendarEntity", "EventEntity", "CalendarCache",
- "CalendarAlerts", "CalendarNotification", "CalendarSyncColumns", "SyncState",
- "CalendarContractBase", "SyncColumns",
- "CalendarContractCalendars", "CalendarContractEvents",
- "CalendarContractAttendees", "CalendarContractReminders",
- "CalendarContractInstances", "CalendarContractColors",
- "CalendarContractCalendarEntity", "CalendarContractEventEntity",
- "CalendarContractCalendarCache", "CalendarContractCalendarAlerts",
- "CalendarContractCalendarNotification", "CalendarContractCalendarSyncColumns",
- "CalendarContractSyncState",
- # Helpers
- "CalendarEvent", "CalendarHelper", "CalendarTimezoneHelper",
- "CalendarRecurrenceRule",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/provider_contacts.py b/android_pyapi/android/provider_contacts.py
deleted file mode 100644
index b844d08..0000000
--- a/android_pyapi/android/provider_contacts.py
+++ /dev/null
@@ -1,776 +0,0 @@
-"""
-Android Provider ContactsContract 扩展组件
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import json
-import time
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# 联系人常量
-# ═══════════════════════════════════════════════════════════════
-
-TIMES_CONTACTED = "times_contacted"
-LAST_TIME_CONTACTED = "last_time_contacted"
-STARRED = "starred"
-CUSTOM_RINGTONE = "custom_ringtone"
-SEND_TO_VOICEMAIL = "send_to_voicemail"
-CONTACT_PRESENCE = "contact_presence"
-CONTACT_CHAT_CAPABILITY = "contact_chat_capability"
-CONTACT_STATUS = "contact_status"
-CONTACT_STATUS_TIMESTAMP = "contact_status_ts"
-CONTACT_STATUS_RES_PACKAGE = "contact_status_res_package"
-CONTACT_STATUS_LABEL = "contact_status_label"
-CONTACT_STATUS_ICON = "contact_status_icon"
-
-CONTACT_ID = "_id"
-CONTACT_LOOKUP_KEY = "lookup"
-CONTACT_DISPLAY_NAME = "display_name"
-CONTACT_PHOTO_ID = "photo_id"
-CONTACT_PHOTO_URI = "photo_uri"
-CONTACT_PHOTO_THUMBNAIL_URI = "photo_thumb_uri"
-CONTACT_LAST_TIME_CONTACTED = LAST_TIME_CONTACTED
-CONTACT_TIMES_CONTACTED = TIMES_CONTACTED
-CONTACT_STARRED = STARRED
-CONTACT_HAS_PHONE_NUMBER = "has_phone_number"
-CONTACT_IS_USER_PROFILE = "is_user_profile"
-CONTACT_IS_PRIVATE = "is_private"
-CONTACT_NAME_RAW_CONTACT_ID = "name_raw_contact_id"
-CONTACT_DISPLAY_NAME_SOURCE = "display_name_source"
-CONTACT_LOOKUP_KEY = CONTACT_LOOKUP_KEY
-CONTACT_SORT_KEY_PRIMARY = "sort_key"
-CONTACT_SORT_KEY_ALTERNATIVE = "sort_key_alt"
-
-LOOKUP_KEY = CONTACT_LOOKUP_KEY
-LOOKUP_ID = "_id"
-
-DATA_ID = "_id"
-DATA_CONTACT_ID = "contact_id"
-DATA_RAW_CONTACT_ID = "raw_contact_id"
-DATA_MIMETYPE = "mimetype"
-DATA_IS_PRIMARY = "is_primary"
-DATA_IS_SUPER_PRIMARY = "is_super_primary"
-DATA_DATA_VERSION = "data_version"
-DATA_DELETED = "deleted"
-DATA_SYNC1 = "data_sync1"
-DATA_SYNC2 = "data_sync2"
-DATA_SYNC3 = "data_sync3"
-DATA_SYNC4 = "data_sync4"
-DATA1 = "data1"
-DATA2 = "data2"
-DATA3 = "data3"
-DATA4 = "data4"
-DATA5 = "data5"
-DATA6 = "data6"
-DATA7 = "data7"
-DATA8 = "data8"
-DATA9 = "data9"
-DATA10 = "data10"
-DATA11 = "data11"
-DATA12 = "data12"
-DATA13 = "data13"
-DATA14 = "data14"
-DATA15 = "data15"
-
-RAW_CONTACT_ID = "_id"
-RAW_CONTACT_CONTACT_ID = "contact_id"
-RAW_CONTACT_ACCOUNT_NAME = "account_name"
-RAW_CONTACT_ACCOUNT_TYPE = "account_type"
-RAW_CONTACT_SOURCE_ID = "sourceid"
-RAW_CONTACT_VERSION = "version"
-RAW_CONTACT_DELETED = "deleted"
-RAW_CONTACT_AGGREGATION_MODE = "aggregation_mode"
-RAW_CONTACT_AGGREGATION_NEEDED = 0
-RAW_CONTACT_AGGREGATION_SUSPENDED = 1
-RAW_CONTACT_AGGREGATION_DEFAULT = 2
-RAW_CONTACT_SYNC1 = "sync1"
-RAW_CONTACT_SYNC2 = "sync2"
-RAW_CONTACT_SYNC3 = "sync3"
-RAW_CONTACT_SYNC4 = "sync4"
-RAW_CONTACT_METADATA = "metadata"
-
-# MIME 类型
-MIMETYPE_EMAIL = "vnd.android.cursor.item/email_v2"
-MIMETYPE_PHONE = "vnd.android.cursor.item/phone_v2"
-MIMETYPE_NAME = "vnd.android.cursor.item/name"
-MIMETYPE_POSTAL = "vnd.android.cursor.item/postal-address_v2"
-MIMETYPE_IM = "vnd.android.cursor.item/im"
-MIMETYPE_NOTE = "vnd.android.cursor.item/note"
-MIMETYPE_ORGANIZATION = "vnd.android.cursor.item/organization"
-MIMETYPE_PHOTO = "vnd.android.cursor.item/photo"
-MIMETYPE_WEBSITE = "vnd.android.cursor.item/website"
-MIMETYPE_SIP_ADDRESS = "vnd.android.cursor.item/sip_address"
-MIMETYPE_NICKNAME = "vnd.android.cursor.item/nickname"
-MIMETYPE_GROUP_MEMBERSHIP = "vnd.android.cursor.item/group_membership"
-MIMETYPE_EVENT = "vnd.android.cursor.item/contact_event"
-MIMETYPE_RELATION = "vnd.android.cursor.item/relation"
-
-FULL_NAME_STYLE_UNDEFINED = 0
-FULL_NAME_STYLE_WESTERN = 1
-FULL_NAME_STYLE_EASTERN = 2
-FULL_NAME_STYLE_CHINESE = 3
-FULL_NAME_STYLE_JAPANESE = 4
-FULL_NAME_STYLE_KOREAN = 5
-
-PHONETIC_NAME_STYLE_UNDEFINED = 0
-PHONETIC_NAME_STYLE_JAPANESE = 1
-PHONETIC_NAME_STYLE_KOREAN = 2
-PHONETIC_NAME_STYLE_PINYIN = 3
-PHONETIC_NAME_STYLE_ROMANJI = 4
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContactsContract 命名空间容器
-# ═══════════════════════════════════════════════════════════════
-
-class ContactsContractBase(Stub):
- """ContactsContract — 联系人合同基类"""
- pass
-
-
-class SyncColumns(Stub):
- """ContactsContract.SyncColumns — 同步列"""
- ACCOUNT_NAME = RAW_CONTACT_ACCOUNT_NAME
- ACCOUNT_TYPE = RAW_CONTACT_ACCOUNT_TYPE
- SOURCE_ID = RAW_CONTACT_SOURCE_ID
- VERSION = RAW_CONTACT_VERSION
- DIRTY = "dirty"
- SYNC1 = RAW_CONTACT_SYNC1
- SYNC2 = RAW_CONTACT_SYNC2
- SYNC3 = RAW_CONTACT_SYNC3
- SYNC4 = RAW_CONTACT_SYNC4
-
-
-class PresenceColumns(Stub):
- """ContactsContract.PresenceColumns — 在线状态列"""
- DATA_ID = "presence_data_id"
- PROTOCOL = "protocol"
- CUSTOM_PROTOCOL = "custom_protocol"
- IM_HANDLE = "im_handle"
- IM_ACCOUNT = "im_account"
- STATUS = "mode"
- STATUS_LABEL = "status_label"
- STATUS_RES_PACKAGE = "status_res_package"
- STATUS_ICON = "status_icon"
- STATUS_TIMESTAMP = "status_ts"
-
- AVAILABLE = 5
- AWAY = 2
- BUSY = 4
- DO_NOT_DISTURB = 4
- IDLE = 3
- INVISIBLE = 1
- OFFLINE = 0
-
-
-class Presence(PresenceColumns):
- """ContactsContract.Presence — 在线状态"""
- pass
-
-
-class FullNameStyle(Stub):
- """ContactsContract.FullNameStyle — 全名风格"""
- UNDEFINED = FULL_NAME_STYLE_UNDEFINED
- WESTERN = FULL_NAME_STYLE_WESTERN
- EASTERN = FULL_NAME_STYLE_EASTERN
- CHINESE = FULL_NAME_STYLE_CHINESE
- JAPANESE = FULL_NAME_STYLE_JAPANESE
- KOREAN = FULL_NAME_STYLE_KOREAN
-
-
-class PhoneticNameStyle(Stub):
- """ContactsContract.PhoneticNameStyle — 拼音名称风格"""
- UNDEFINED = PHONETIC_NAME_STYLE_UNDEFINED
- JAPANESE = PHONETIC_NAME_STYLE_JAPANESE
- KOREAN = PHONETIC_NAME_STYLE_KOREAN
- PINYIN = PHONETIC_NAME_STYLE_PINYIN
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContactsContract.Contacts
-# ═══════════════════════════════════════════════════════════════
-
-class ContactData(Stub):
- """内部联系人数据存储"""
- def __init__(self):
- self.id: int = 0
- self.lookup_key: str = ""
- self.display_name: str = ""
- self.photo_id: int = 0
- self.photo_uri: Optional[str] = None
- self.photo_thumb_uri: Optional[str] = None
- self.times_contacted: int = 0
- self.last_time_contacted: int = 0
- self.starred: bool = False
- self.custom_ringtone: Optional[str] = None
- self.send_to_voicemail: bool = False
- self.has_phone_number: bool = False
- self.is_user_profile: bool = False
- self.name_raw_contact_id: int = 0
- self.display_name_source: int = 0
- self.sort_key: str = ""
- self.sort_key_alt: str = ""
-
-
-class AggregationSuggestions(Stub):
- """ContactsContract.Contacts.AggregationSuggestions — 聚合建议"""
-
- class Builder(Stub):
- """聚合建议构建器"""
-
- def __init__(self):
- super().__init__()
- self._contact_id: int = 0
- self._limit: int = 0
- self._name: Optional[str] = None
-
- def setContactId(self, contact_id: int) -> "AggregationSuggestions.Builder":
- self._contact_id = contact_id
- return self
-
- def setLimit(self, limit: int) -> "AggregationSuggestions.Builder":
- self._limit = limit
- return self
-
- def addNameParameter(self, name: str) -> "AggregationSuggestions.Builder":
- self._name = name
- return self
-
- def build(self) -> str:
- return f"suggestions?contact_id={self._contact_id}&limit={self._limit}"
-
- CONTENT_DIRECTORY = "suggestions"
- PARAMETER_MATCH_NAME = "name"
-
-
-class Photo(Stub):
- """ContactsContract.Contacts.Photo — 联系人照片"""
- CONTENT_DIRECTORY = "photo"
- PHOTO = "data15"
- PHOTO_FILE_ID = "data14"
- DISPLAY_PHOTO = "display_photo"
-
-
-class Contacts(Stub):
- """ContactsContract.Contacts — 联系人表"""
-
- CONTENT_URI = "content://com.android.contacts/contacts"
- CONTENT_LOOKUP_URI = "content://com.android.contacts/contacts/lookup"
- CONTENT_FILTER_URI = "content://com.android.contacts/contacts/filter"
- CONTENT_STREQUENT_URI = "content://com.android.contacts/contacts/strequent"
- CONTENT_FREQUENT_URI = "content://com.android.contacts/contacts/frequent"
- CONTENT_STREQUENT_EMAIL_URI = "content://com.android.contacts/contacts/strequent/email"
- CONTENT_GROUP_URI = "content://com.android.contacts/contacts/group"
-
- AggregationSuggestions = AggregationSuggestions
- Photo = Photo
-
- # 列
- _ID = "_id"
- LOOKUP_KEY = "lookup"
- DISPLAY_NAME = "display_name"
- PHOTO_ID = "photo_id"
- PHOTO_URI = "photo_uri"
- PHOTO_THUMBNAIL_URI = "photo_thumb_uri"
- TIMES_CONTACTED = TIMES_CONTACTED
- LAST_TIME_CONTACTED = LAST_TIME_CONTACTED
- STARRED = STARRED
- CUSTOM_RINGTONE = CUSTOM_RINGTONE
- SEND_TO_VOICEMAIL = SEND_TO_VOICEMAIL
- HAS_PHONE_NUMBER = "has_phone_number"
- IS_USER_PROFILE = "is_user_profile"
- NAME_RAW_CONTACT_ID = "name_raw_contact_id"
- DISPLAY_NAME_SOURCE = "display_name_source"
- SORT_KEY_PRIMARY = "sort_key"
- SORT_KEY_ALTERNATIVE = "sort_key_alt"
- CONTACT_LAST_UPDATED_TIMESTAMP = "contact_last_updated_timestamp"
- CONTACT_PRESENCE = CONTACT_PRESENCE
- CONTACT_CHAT_CAPABILITY = CONTACT_CHAT_CAPABILITY
- CONTACT_STATUS = CONTACT_STATUS
- CONTACT_STATUS_TIMESTAMP = CONTACT_STATUS_TIMESTAMP
-
- @staticmethod
- def getLookupUri(contact_id: int, lookup_key: str) -> str:
- return f"{Contacts.CONTENT_LOOKUP_URI}/{lookup_key}/{contact_id}"
-
- @staticmethod
- def lookupContact(content_resolver: Any, lookup_uri: str) -> Optional[Dict[str, Any]]:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContactsContract.Data
-# ═══════════════════════════════════════════════════════════════
-
-class Data(Stub):
- """ContactsContract.Data — 数据表"""
-
- CONTENT_URI = "content://com.android.contacts/data"
-
- _ID = DATA_ID
- CONTACT_ID = DATA_CONTACT_ID
- RAW_CONTACT_ID = DATA_RAW_CONTACT_ID
- MIMETYPE = DATA_MIMETYPE
- IS_PRIMARY = DATA_IS_PRIMARY
- IS_SUPER_PRIMARY = DATA_IS_SUPER_PRIMARY
- DATA_VERSION = DATA_DATA_VERSION
- DELETED = DATA_DELETED
- SYNC1 = DATA_SYNC1
- SYNC2 = DATA_SYNC2
- SYNC3 = DATA_SYNC3
- SYNC4 = DATA_SYNC4
- DATA1 = DATA1
- DATA2 = DATA2
- DATA3 = DATA3
- DATA4 = DATA4
- DATA5 = DATA5
- DATA6 = DATA6
- DATA7 = DATA7
- DATA8 = DATA8
- DATA9 = DATA9
- DATA10 = DATA10
- DATA11 = DATA11
- DATA12 = DATA12
- DATA13 = DATA13
- DATA14 = DATA14
- DATA15 = DATA15
-
- # 偏好常量
- CONTACT_PREFERRED_ORDER = "contact_preferred_order"
- CONTACT_PREFERRED_PHONE = "contact_preferred_phone"
- CONTACT_PREFERRED_EMAIL = "contact_preferred_email"
- CONTACT_PREFERRED_PHONE_ORDER = "contact_preferred_phone_order"
- CONTACT_PREFERRED_EMAIL_ORDER = "contact_preferred_email_order"
-
- # 可见性
- VISIBILITY_VISIBLE = 0
- VISIBILITY_HIDDEN = 1
- VISIBILITY_DEFAULT = 0
- VISIBILITY = "visibility"
-
- @staticmethod
- def getContactPreferred(data_kind: str, data_set: List[Dict]) -> Optional[Dict]:
- if not data_set:
- return None
- primaries = [d for d in data_set if d.get("is_super_primary") or d.get("is_primary")]
- if primaries:
- return primaries[0]
- return data_set[0]
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContactsContract.CommonDataKinds
-# ═══════════════════════════════════════════════════════════════
-
-class CommonDataKinds(Stub):
- """ContactsContract.CommonDataKinds — 通用数据类型"""
-
- class Email(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_EMAIL
- TYPE_HOME = 1
- TYPE_WORK = 2
- TYPE_OTHER = 3
- TYPE_MOBILE = 4
- ADDRESS = DATA1
- DISPLAY_NAME = DATA4
- TYPE = DATA2
- LABEL = DATA3
-
- class Phone(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_PHONE
- TYPE_HOME = 1
- TYPE_MOBILE = 2
- TYPE_WORK = 3
- TYPE_FAX_WORK = 4
- TYPE_FAX_HOME = 5
- TYPE_PAGER = 6
- TYPE_OTHER = 7
- TYPE_CALLBACK = 8
- TYPE_CAR = 9
- TYPE_COMPANY_MAIN = 10
- TYPE_ISDN = 11
- TYPE_MAIN = 12
- TYPE_OTHER_FAX = 13
- TYPE_RADIO = 14
- TYPE_TELEX = 15
- TYPE_TTY_TDD = 16
- TYPE_WORK_MOBILE = 17
- TYPE_WORK_PAGER = 18
- TYPE_ASSISTANT = 19
- TYPE_MMS = 20
- NUMBER = DATA1
- NUMBER_KEY = "data4"
- TYPE = DATA2
- LABEL = DATA3
-
- class StructuredName(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_NAME
- DISPLAY_NAME = DATA1
- GIVEN_NAME = DATA2
- FAMILY_NAME = DATA3
- PREFIX = DATA4
- MIDDLE_NAME = DATA5
- SUFFIX = DATA6
- PHONETIC_GIVEN_NAME = DATA7
- PHONETIC_FAMILY_NAME = DATA8
- PHONETIC_MIDDLE_NAME = DATA9
- FULL_NAME_STYLE = DATA10
- PHONETIC_NAME_STYLE = DATA11
-
- class StructuredPostal(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_POSTAL
- FORMATTED_ADDRESS = DATA1
- STREET = DATA4
- POBOX = DATA5
- NEIGHBORHOOD = DATA6
- CITY = DATA7
- REGION = DATA8
- POSTCODE = DATA9
- COUNTRY = DATA10
- TYPE = DATA2
- LABEL = DATA3
- TYPE_HOME = 1
- TYPE_WORK = 2
- TYPE_OTHER = 3
-
- class Im(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_IM
- PROTOCOL = DATA5
- CUSTOM_PROTOCOL = DATA6
- DATA = DATA1
- TYPE = DATA2
-
- PROTOCOL_AIM = 0
- PROTOCOL_MSN = 1
- PROTOCOL_YAHOO = 2
- PROTOCOL_SKYPE = 3
- PROTOCOL_QQ = 4
- PROTOCOL_GTALK = 5
- PROTOCOL_ICQ = 6
- PROTOCOL_JABBER = 7
- PROTOCOL_CUSTOM = -1
-
- class Organization(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_ORGANIZATION
- COMPANY = DATA1
- TYPE = DATA2
- LABEL = DATA3
- TITLE = DATA4
- DEPARTMENT = DATA5
- JOB_DESCRIPTION = DATA6
- SYMBOL = DATA7
- PHONETIC_NAME = DATA8
- OFFICE_LOCATION = DATA9
- PHONETIC_NAME_STYLE = DATA10
- TYPE_WORK = 1
- TYPE_OTHER = 2
-
- class Photo(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_PHOTO
- PHOTO = DATA15
- PHOTO_FILE_ID = DATA14
-
- class Note(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_NOTE
- NOTE = DATA1
-
- class Website(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_WEBSITE
- URL = DATA1
- TYPE = DATA2
- TYPE_HOMEPAGE = 1
- TYPE_BLOG = 2
- TYPE_PROFILE = 3
- TYPE_HOME = 4
- TYPE_WORK = 5
- TYPE_FTP = 6
- TYPE_OTHER = 7
-
- class Event(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_EVENT
- START_DATE = DATA1
- TYPE = DATA2
- TYPE_ANNIVERSARY = 1
- TYPE_OTHER = 2
- TYPE_BIRTHDAY = 3
-
- class Relation(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_RELATION
- NAME = DATA1
- TYPE = DATA2
- TYPE_ASSISTANT = 1
- TYPE_BROTHER = 2
- TYPE_CHILD = 3
- TYPE_DOMESTIC_PARTNER = 4
- TYPE_FATHER = 5
- TYPE_FRIEND = 6
- TYPE_MANAGER = 7
- TYPE_MOTHER = 8
- TYPE_PARENT = 9
- TYPE_PARTNER = 10
- TYPE_REFERRED_BY = 11
- TYPE_RELATIVE = 12
- TYPE_SISTER = 13
- TYPE_SPOUSE = 14
-
- class Nickname(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_NICKNAME
- NAME = DATA1
- TYPE = DATA2
- TYPE_DEFAULT = 1
- TYPE_OTHER_NAME = 2
- TYPE_MAIDEN_NAME = 3
- TYPE_SHORT_NAME = 4
- TYPE_INITIALS = 5
-
- class SipAddress(Stub):
- CONTENT_ITEM_TYPE = MIMETYPE_SIP_ADDRESS
- SIP_ADDRESS = DATA1
- TYPE = DATA2
- TYPE_HOME = 1
- TYPE_WORK = 2
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContactsContract.RawContacts
-# ═══════════════════════════════════════════════════════════════
-
-class RawContacts(Stub):
- """ContactsContract.RawContacts — 原始联系人"""
-
- CONTENT_URI = "content://com.android.contacts/raw_contacts"
-
- _ID = RAW_CONTACT_ID
- CONTACT_ID = RAW_CONTACT_CONTACT_ID
- ACCOUNT_NAME = RAW_CONTACT_ACCOUNT_NAME
- ACCOUNT_TYPE = RAW_CONTACT_ACCOUNT_TYPE
- SOURCE_ID = RAW_CONTACT_SOURCE_ID
- VERSION = RAW_CONTACT_VERSION
- DELETED = RAW_CONTACT_DELETED
- AGGREGATION_MODE = RAW_CONTACT_AGGREGATION_MODE
- SYNC1 = RAW_CONTACT_SYNC1
- SYNC2 = RAW_CONTACT_SYNC2
- SYNC3 = RAW_CONTACT_SYNC3
- SYNC4 = RAW_CONTACT_SYNC4
- METADATA = RAW_CONTACT_METADATA
- RAW_CONTACT_IS_USER_PROFILE = "raw_contact_is_user_profile"
- RAW_CONTACT_IS_PRIVATE = "raw_contact_is_private"
- DISPLAY_NAME_SOURCE = "display_name_source"
- NAME_VERIFIED = "name_verified"
- GEOLOCATION = "geolocation"
-
- AGGREGATION_MODE_DEFAULT = 0
- AGGREGATION_MODE_IMMEDIATE = 1
- AGGREGATION_MODE_SUSPENDED = 2
- AGGREGATION_MODE_DISABLED = 3
-
- @staticmethod
- def getContactId(raw_contact_id: int) -> int:
- return 0
-
- @staticmethod
- def getLookupUri(raw_contact_id: int, lookup_key: str) -> str:
- return f"content://com.android.contacts/raw_contacts/{raw_contact_id}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContactsContract.StatusUpdates / Profile / Settings
-# ═══════════════════════════════════════════════════════════════
-
-class StatusUpdates(PresenceColumns):
- """ContactsContract.StatusUpdates — 状态更新"""
- CONTENT_URI = "content://com.android.contacts/status_updates"
-
-
-class Profile(Stub):
- """ContactsContract.Profile — 用户个人资料"""
- CONTENT_URI = "content://com.android.contacts/profile"
- CONTENT_VCARD_URI = "content://com.android.contacts/profile/vcard"
- CONTENT_RAW_CONTACTS_URI = "content://com.android.contacts/profile/raw_contacts"
- MIN_ID = 1000000000
- MAX_ID = 2000000000
-
-
-class Settings(Stub):
- """ContactsContract.Settings — 联系人设置"""
- CONTENT_URI = "content://com.android.contacts/settings"
- ACCOUNT_NAME = RAW_CONTACT_ACCOUNT_NAME
- ACCOUNT_TYPE = RAW_CONTACT_ACCOUNT_TYPE
- SHOULD_SYNC = "should_sync"
- UNGROUPED_VISIBLE = "ungrouped_visible"
- ANY_UNGROUPED = "any_ungrouped"
- UNGROUPED_COUNT = "ungrouped_count"
- UNGROUPED_WITH_PHONES = "ungrouped_with_phones"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContactsContract.PhoneLookup / DisplayPhoto / DataUsageFeedback
-# ═══════════════════════════════════════════════════════════════
-
-class PhoneLookup(Stub):
- """ContactsContract.PhoneLookup — 电话查找"""
- CONTENT_URI = "content://com.android.contacts/phone_lookup"
- CONTENT_FILTER_URI = "content://com.android.contacts/phone_lookup/filter"
- QUERY_PARAMETER_SIP_ADDRESS = "sip"
- NUMBER = "number"
- TYPE = "type"
- LABEL = "label"
- NORMALIZED_NUMBER = "normalized_number"
- CONTACT_ID = "contact_id"
- LOOKUP_KEY = "lookup"
- DISPLAY_NAME = "display_name"
- PHOTO_ID = "photo_id"
- PHOTO_URI = "photo_uri"
- PHOTO_THUMBNAIL_URI = "photo_thumb_uri"
-
-
-class DisplayPhoto(Stub):
- """ContactsContract.DisplayPhoto — 显示照片"""
- CONTENT_URI = "content://com.android.contacts/display_photo"
- DISPLAY_MAX_DIM = "display_max_dim"
- THUMBNAIL_MAX_DIM = "thumbnail_max_dim"
- CONTENT_DIRECTORY = "display_photo"
-
-
-class DataUsageFeedback(Stub):
- """ContactsContract.DataUsageFeedback — 数据使用反馈"""
- FEEDBACK_URI = "content://com.android.contacts/data/usagefeedback"
- USAGE_TYPE = "type"
- USAGE_TYPE_CALL = "call"
- USAGE_TYPE_TEXT = "text"
- USAGE_TYPE_EMAIL = "email"
- USAGE_TYPE_LONG_TEXT = "long_text"
- USAGE_TYPE_VIDEO_CALL = "video_call"
-
-
-class QuickContact(Stub):
- """ContactsContract.QuickContact — 快速联系人"""
-
- ACTION_QUICK_CONTACT = "android.provider.ContactsContract.QuickContact"
-
- MODE_SMALL = 0
- MODE_MEDIUM = 1
- MODE_LARGE = 2
-
- EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES"
- EXTRA_MODE = "android.provider.extra.MODE"
- EXTRA_PRIORITIZED_MIMETYPE = "android.provider.extra.PRIORITIZED_MIMETYPE"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContactsContract 控制器 — 模拟 ContentProvider 的数据存储
-# ═══════════════════════════════════════════════════════════════
-
-class ContactsContract(ContactsContractBase):
- """ContactsContract — 联系人合同"""
-
- Contacts = Contacts
- Data = Data
- CommonDataKinds = CommonDataKinds
- RawContacts = RawContacts
- StatusUpdates = StatusUpdates
- Profile = Profile
- Settings = Settings
- SyncColumns = SyncColumns
- Presence = Presence
- PhoneLookup = PhoneLookup
- DisplayPhoto = DisplayPhoto
- FullNameStyle = FullNameStyle
- PhoneticNameStyle = PhoneticNameStyle
- QuickContact = QuickContact
- DataUsageFeedback = DataUsageFeedback
-
- AUTHORITY = "com.android.contacts"
- CALLER_IS_SYNCADAPTER = "caller_is_syncadapter"
- DEFERRED_SNIPPETING = "deferred_snippeting"
- DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query"
- DIRECTORY_CONTENT_URI = "content://com.android.contacts/directories"
- LIMIT_PARAM_KEY = "limit"
- PRIMARY_ACCOUNT_NAME = "name_forPrimaryAccount"
- PRIMARY_ACCOUNT_TYPE = "type_forPrimaryAccount"
- PROVIDER_INTERFACE = "android.content.ContactsContract"
- REMOVE_DUPLICATE_ENTRIES = "remove_duplicate_entries"
- STREQUENT_PHONE_ONLY = "strequent_phone_only"
-
- _store: Dict[str, List[Dict[str, Any]]] = {
- "contacts": [],
- "raw_contacts": [],
- "data": [],
- }
- _lock = threading.Lock()
-
- @classmethod
- def addContact(cls, display_name: str = "",
- phone: str = "", email: str = "") -> int:
- with cls._lock:
- contact_id = len(cls._store["contacts"]) + 1
- contact = {
- "_id": contact_id,
- "display_name": display_name,
- "has_phone_number": bool(phone),
- "times_contacted": 0,
- "last_time_contacted": 0,
- "starred": False,
- }
- cls._store["contacts"].append(contact)
- raw_id = len(cls._store["raw_contacts"]) + 1
- raw = {
- "_id": raw_id,
- "contact_id": contact_id,
- "aggregation_mode": 0,
- "deleted": False,
- "account_name": "",
- "account_type": "",
- }
- cls._store["raw_contacts"].append(raw)
- if phone:
- cls._store["data"].append({
- "_id": len(cls._store["data"]) + 1,
- "raw_contact_id": raw_id,
- "mimetype": MIMETYPE_PHONE,
- "data1": phone,
- "data2": 2,
- "is_primary": True,
- })
- if email:
- cls._store["data"].append({
- "_id": len(cls._store["data"]) + 1,
- "raw_contact_id": raw_id,
- "mimetype": MIMETYPE_EMAIL,
- "data1": email,
- "data2": 1,
- "is_primary": True,
- })
- return contact_id
-
- @classmethod
- def query(cls, table: str, filters: Optional[Dict] = None) -> List[Dict[str, Any]]:
- with cls._lock:
- results = list(cls._store.get(table, []))
- if filters:
- filtered = []
- for item in results:
- match = True
- for k, v in filters.items():
- if item.get(k) != v:
- match = False
- break
- if match:
- filtered.append(item)
- return filtered
- return results
-
- @classmethod
- def toString(cls) -> str:
- return (f"ContactsContract(contacts={len(cls._store['contacts'])}, "
- f"raw={len(cls._store['raw_contacts'])}, "
- f"data={len(cls._store['data'])})")
\ No newline at end of file
diff --git a/android_pyapi/android/provider_settings.py b/android_pyapi/android/provider_settings.py
deleted file mode 100644
index 21ad0d2..0000000
--- a/android_pyapi/android/provider_settings.py
+++ /dev/null
@@ -1,1660 +0,0 @@
-"""
-Android Provider Settings 扩展组件
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import json
-import sys
-import time
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# Settings 基类 - 桌面实现
-# ═══════════════════════════════════════════════════════════════
-
-_SETTINGS_DATA_DIR = os.path.join(
- os.path.expanduser("~"), "Android-compat", "app-data", "shared_prefs"
-)
-
-
-class _SettingsBase(Stub):
- """Settings 基类 — 持久化存储到 JSON 文件"""
-
- _NAME = ""
- _cache: Dict[str, Dict[str, Any]] = {}
-
- @classmethod
- def _get_path(cls) -> str:
- os.makedirs(_SETTINGS_DATA_DIR, exist_ok=True)
- return os.path.join(_SETTINGS_DATA_DIR, f"{cls._NAME}.json")
-
- @classmethod
- def _load(cls) -> Dict[str, Any]:
- if cls._NAME in cls._cache:
- return cls._cache[cls._NAME]
- path = cls._get_path()
- if os.path.exists(path):
- try:
- with open(path, "r") as f:
- data = json.load(f)
- cls._cache[cls._NAME] = data
- return data
- except (json.JSONDecodeError, OSError):
- pass
- cls._cache[cls._NAME] = {}
- return cls._cache[cls._NAME]
-
- @classmethod
- def _save(cls):
- path = cls._get_path()
- try:
- with open(path, "w") as f:
- json.dump(cls._cache.get(cls._NAME, {}), f)
- except OSError:
- pass
-
- @classmethod
- def getString(cls, key: str, default_value: Optional[str] = None) -> Optional[str]:
- data = cls._load()
- return data.get(key, default_value)
-
- @classmethod
- def putString(cls, key: str, value: str) -> bool:
- data = cls._load()
- data[key] = value
- cls._save()
- return True
-
- @classmethod
- def getInt(cls, key: str, default_value: int = 0) -> int:
- data = cls._load()
- return data.get(key, default_value)
-
- @classmethod
- def putInt(cls, key: str, value: int) -> bool:
- data = cls._load()
- data[key] = value
- cls._save()
- return True
-
- @classmethod
- def getLong(cls, key: str, default_value: int = 0) -> int:
- return cls.getInt(key, default_value)
-
- @classmethod
- def putLong(cls, key: str, value: int) -> bool:
- return cls.putInt(key, value)
-
- @classmethod
- def getFloat(cls, key: str, default_value: float = 0.0) -> float:
- data = cls._load()
- return data.get(key, default_value)
-
- @classmethod
- def putFloat(cls, key: str, value: float) -> bool:
- data = cls._load()
- data[key] = value
- cls._save()
- return True
-
- @classmethod
- def hasKey(cls, key: str) -> bool:
- data = cls._load()
- return key in data
-
- @classmethod
- def getAll(cls) -> Dict[str, Any]:
- return dict(cls._load())
-
- @classmethod
- def clear(cls):
- cls._cache[cls._NAME] = {}
- cls._save()
-
- @classmethod
- def remove(cls, key: str):
- data = cls._load()
- data.pop(key, None)
- cls._save()
-
-
-# ═══════════════════════════════════════════════════════════════
-# Settings.System — 系统设置
-# ═══════════════════════════════════════════════════════════════
-
-SYSTEM_AIRPLANE_MODE_ON = "airplane_mode_on"
-SYSTEM_AIRPLANE_MODE_RADIOS = "airplane_mode_radios"
-SYSTEM_AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios"
-SYSTEM_ALARM_ALERT = "alarm_alert"
-SYSTEM_ALARM_ALERT_CACHE = "alarm_alert_cache"
-SYSTEM_ANDROID_ID = "android_id"
-SYSTEM_APPEND_FOR_LAST_AUDIBLE = "append_for_last_audible"
-SYSTEM_AUTO_TIME = "auto_time"
-SYSTEM_AUTO_TIME_ZONE = "auto_time_zone"
-SYSTEM_BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability"
-SYSTEM_BLUETOOTH_DISCOVERABILITY_TIMEOUT = "bluetooth_discoverability_timeout"
-SYSTEM_BLUETOOTH_ON = "bluetooth_on"
-SYSTEM_CAR_DOCK_SOUND = "car_dock_sound"
-SYSTEM_CAR_UNDOCK_SOUND = "car_undock_sound"
-SYSTEM_DESK_DOCK_SOUND = "desk_dock_sound"
-SYSTEM_DESK_UNDOCK_SOUND = "desk_undock_sound"
-SYSTEM_DOCK_SOUNDS_ENABLED = "dock_sounds_enabled"
-SYSTEM_DTMF_TONE_WHEN_DIALING = "dtmf_tone"
-SYSTEM_EGG_MODE = "egg_mode"
-SYSTEM_END_BUTTON_BEHAVIOR = "end_button_behavior"
-SYSTEM_FONT_SCALE = "font_scale"
-SYSTEM_HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled"
-SYSTEM_HEARING_AID = "hearing_aid"
-SYSTEM_HOME_SOUND = "home_sound"
-SYSTEM_HOME_UNDOCK_SOUND = "home_undock_sound"
-SYSTEM_HTTP_PROXY = "http_proxy"
-SYSTEM_LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled"
-SYSTEM_LOCKSCREEN_DISABLED = "lock_screen_lock_after_timeout"
-SYSTEM_LOCK_TO_APP_ENABLED = "lock_to_app_enabled"
-SYSTEM_MODE_RINGER = "mode_ringer"
-SYSTEM_MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected"
-SYSTEM_MUTE_STREAMS_AFFECTED = "mute_streams_affected"
-SYSTEM_NEXT_ALARM_FORMATTED = "next_alarm_formatted"
-SYSTEM_NOTIFICATION_SOUND = "notification_sound"
-SYSTEM_NOTIFICATION_SOUND_CACHE = "notification_sound_cache"
-SYSTEM_POWER_SOUNDS_ENABLED = "power_sounds_enabled"
-SYSTEM_RINGTONE = "ringtone"
-SYSTEM_RINGTONE_CACHE = "ringtone_cache"
-SYSTEM_SCREEN_BRIGHTNESS = "screen_brightness"
-SYSTEM_SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode"
-SYSTEM_SCREEN_BRIGHTNESS_MODE_MANUAL = 0
-SYSTEM_SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1
-SYSTEM_SCREEN_OFF_TIMEOUT = "screen_off_timeout"
-SYSTEM_SETTINGS_CLASSNAME = "settings_classname"
-SYSTEM_SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run"
-SYSTEM_SHOW_GTALK_SERVICE_STATUS = "show_gtalk_service_status"
-SYSTEM_SHOW_PROCESSES = "show_processes"
-SYSTEM_SHOW_WEB_SUGGESTIONS = "show_web_suggestions"
-SYSTEM_SIP_RECEIVE_CALLS = "sip_receive_calls"
-SYSTEM_SIP_CALL_OPTIONS = "sip_call_options"
-SYSTEM_SOUND_EFFECTS_ENABLED = "sound_effects_enabled"
-SYSTEM_STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in"
-SYSTEM_TTY_MODE = "tty_mode"
-SYSTEM_UNLOCK_SOUND = "unlock_sound"
-SYSTEM_USER_ROTATION = "user_rotation"
-SYSTEM_VIBRATE_ON = "vibrate_on"
-SYSTEM_VOLUME_ALARM = "volume_alarm"
-SYSTEM_VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco"
-SYSTEM_VOLUME_DTMF = "volume_dtmf"
-SYSTEM_VOLUME_MUSIC = "volume_music"
-SYSTEM_VOLUME_NOTIFICATION = "volume_notification"
-SYSTEM_VOLUME_RING = "volume_ring"
-SYSTEM_VOLUME_SYSTEM = "volume_system"
-SYSTEM_VOLUME_VOICE = "volume_voice"
-SYSTEM_VOLUME_MASTER = "volume_master"
-SYSTEM_VOLUME_MASTER_MUTE = "volume_master_mute"
-SYSTEM_VOLUME_MICROPHONE_MUTE = "volume_microphone_mute"
-SYSTEM_VOLUME_RING_MUTED = "volume_ring_muted"
-SYSTEM_VOLUME_MUSIC_MUTED = "volume_music_muted"
-SYSTEM_VOLUME_NOTIFICATION_MUTED = "volume_notification_muted"
-SYSTEM_VOLUME_ALARM_MUTED = "volume_alarm_muted"
-SYSTEM_VOLUME_SYSTEM_MUTED = "volume_system_muted"
-SYSTEM_VOLUME_VOICE_MUTED = "volume_voice_muted"
-SYSTEM_VOLUME_BLUETOOTH_SCO_MUTED = "volume_bluetooth_sco_muted"
-SYSTEM_WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"
-SYSTEM_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms"
-SYSTEM_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on"
-SYSTEM_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay"
-SYSTEM_WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept"
-SYSTEM_WIFI_ON = "wifi_on"
-SYSTEM_WIFI_SLEEP_POLICY = "wifi_sleep_policy"
-SYSTEM_WIFI_SLEEP_POLICY_DEFAULT = 0
-SYSTEM_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1
-SYSTEM_WIFI_SLEEP_POLICY_NEVER = 2
-SYSTEM_WIFI_STATIC_DHCP_HOSTNAME = "wifi_static_dhcp_hostname"
-SYSTEM_WIFI_STATIC_IP = "wifi_static_ip"
-SYSTEM_WIFI_STATIC_GATEWAY = "wifi_static_gateway"
-SYSTEM_WIFI_STATIC_NETMASK = "wifi_static_netmask"
-SYSTEM_WIFI_STATIC_DNS1 = "wifi_static_dns1"
-SYSTEM_WIFI_STATIC_DNS2 = "wifi_static_dns2"
-SYSTEM_WIFI_WATCHDOG_ON = "wifi_watchdog_on"
-SYSTEM_WINDOW_ANIMATION_SCALE = "window_animation_scale"
-SYSTEM_TRANSITION_ANIMATION_SCALE = "transition_animation_scale"
-SYSTEM_ANIMATOR_DURATION_SCALE = "animator_duration_scale"
-SYSTEM_ACCELEROMETER_ROTATION = "accelerometer_rotation"
-SYSTEM_SCREEN_BRIGHTNESS_MODE = SYSTEM_SCREEN_BRIGHTNESS_MODE
-SYSTEM_HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY = "hide_rotation_lock_toggle_for_accessibility"
-SYSTEM_VIBRATE_INPUT_DEVICES = "vibrate_input_devices"
-SYSTEM_VOLUME_ADJUST_SOUNDS_ENABLED = "volume_adjust_sounds_enabled"
-SYSTEM_MASTER_MONO = "master_mono"
-SYSTEM_MASTER_BALANCE = "master_balance"
-SYSTEM_NOTIFICATION_LIGHT_PULSE = "notification_light_pulse"
-SYSTEM_NOTIFICATION_LIGHT_COLOR = "notification_light_color"
-SYSTEM_NOTIFICATION_LIGHT_ON_TIME = "notification_light_on_time"
-SYSTEM_NOTIFICATION_LIGHT_OFF_TIME = "notification_light_off_time"
-SYSTEM_SWIPE_TO_SCREENSHOT_ENABLED = "swipe_to_screenshot_enabled"
-SYSTEM_BATTERY_LIGHT_ENABLED = "battery_light_enabled"
-SYSTEM_BATTERY_LIGHT_COLOR = "battery_light_color"
-SYSTEM_BATTERY_LIGHT_ON_TIME = "battery_light_on_time"
-SYSTEM_BATTERY_LIGHT_OFF_TIME = "battery_light_off_time"
-SYSTEM_SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj"
-SYSTEM_SCREEN_BRIGHTNESS_FLOAT = "screen_brightness_float"
-SYSTEM_VOLUME_HUSH_GESTURE = "volume_hush_gesture"
-
-
-class SettingsSystem(_SettingsBase):
- """Settings.System — 系统设置表"""
-
- _NAME = "settings_system"
-
- # Airplane mode
- AIRPLANE_MODE_ON = SYSTEM_AIRPLANE_MODE_ON
- AIRPLANE_MODE_RADIOS = SYSTEM_AIRPLANE_MODE_RADIOS
- AIRPLANE_MODE_TOGGLEABLE_RADIOS = SYSTEM_AIRPLANE_MODE_TOGGLEABLE_RADIOS
-
- # Volume
- VOLUME_ALARM = SYSTEM_VOLUME_ALARM
- VOLUME_BLUETOOTH_SCO = SYSTEM_VOLUME_BLUETOOTH_SCO
- VOLUME_DTMF = SYSTEM_VOLUME_DTMF
- VOLUME_MUSIC = SYSTEM_VOLUME_MUSIC
- VOLUME_NOTIFICATION = SYSTEM_VOLUME_NOTIFICATION
- VOLUME_RING = SYSTEM_VOLUME_RING
- VOLUME_SYSTEM = SYSTEM_VOLUME_SYSTEM
- VOLUME_VOICE = SYSTEM_VOLUME_VOICE
- VOLUME_MASTER = SYSTEM_VOLUME_MASTER
- VOLUME_MASTER_MUTE = SYSTEM_VOLUME_MASTER_MUTE
- VOLUME_MICROPHONE_MUTE = SYSTEM_VOLUME_MICROPHONE_MUTE
-
- # Screen
- SCREEN_BRIGHTNESS = SYSTEM_SCREEN_BRIGHTNESS
- SCREEN_BRIGHTNESS_MODE = SYSTEM_SCREEN_BRIGHTNESS_MODE
- SCREEN_BRIGHTNESS_MODE_MANUAL = SYSTEM_SCREEN_BRIGHTNESS_MODE_MANUAL
- SCREEN_BRIGHTNESS_MODE_AUTOMATIC = SYSTEM_SCREEN_BRIGHTNESS_MODE_AUTOMATIC
- SCREEN_OFF_TIMEOUT = SYSTEM_SCREEN_OFF_TIMEOUT
- SCREEN_AUTO_BRIGHTNESS_ADJ = SYSTEM_SCREEN_AUTO_BRIGHTNESS_ADJ
- ACCELEROMETER_ROTATION = SYSTEM_ACCELEROMETER_ROTATION
- USER_ROTATION = SYSTEM_USER_ROTATION
- HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY = SYSTEM_HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY
-
- # Sound
- ALARM_ALERT = SYSTEM_ALARM_ALERT
- NOTIFICATION_SOUND = SYSTEM_NOTIFICATION_SOUND
- RINGTONE = SYSTEM_RINGTONE
- DTMF_TONE_WHEN_DIALING = SYSTEM_DTMF_TONE_WHEN_DIALING
- SOUND_EFFECTS_ENABLED = SYSTEM_SOUND_EFFECTS_ENABLED
- HAPTIC_FEEDBACK_ENABLED = SYSTEM_HAPTIC_FEEDBACK_ENABLED
- VIBRATE_ON = SYSTEM_VIBRATE_ON
- MODE_RINGER = SYSTEM_MODE_RINGER
- MODE_RINGER_STREAMS_AFFECTED = SYSTEM_MODE_RINGER_STREAMS_AFFECTED
- MUTE_STREAMS_AFFECTED = SYSTEM_MUTE_STREAMS_AFFECTED
- VIBRATE_INPUT_DEVICES = SYSTEM_VIBRATE_INPUT_DEVICES
- VOLUME_ADJUST_SOUNDS_ENABLED = SYSTEM_VOLUME_ADJUST_SOUNDS_ENABLED
-
- # Dock
- DOCK_SOUNDS_ENABLED = SYSTEM_DOCK_SOUNDS_ENABLED
- CAR_DOCK_SOUND = SYSTEM_CAR_DOCK_SOUND
- CAR_UNDOCK_SOUND = SYSTEM_CAR_UNDOCK_SOUND
- DESK_DOCK_SOUND = SYSTEM_DESK_DOCK_SOUND
- DESK_UNDOCK_SOUND = SYSTEM_DESK_UNDOCK_SOUND
- POWER_SOUNDS_ENABLED = SYSTEM_POWER_SOUNDS_ENABLED
- LOCKSCREEN_SOUNDS_ENABLED = SYSTEM_LOCKSCREEN_SOUNDS_ENABLED
- UNLOCK_SOUND = SYSTEM_UNLOCK_SOUND
- HOME_SOUND = SYSTEM_HOME_SOUND
- HOME_UNDOCK_SOUND = SYSTEM_HOME_UNDOCK_SOUND
-
- # Time
- AUTO_TIME = SYSTEM_AUTO_TIME
- AUTO_TIME_ZONE = SYSTEM_AUTO_TIME_ZONE
- NEXT_ALARM_FORMATTED = SYSTEM_NEXT_ALARM_FORMATTED
-
- # Bluetooth
- BLUETOOTH_ON = SYSTEM_BLUETOOTH_ON
- BLUETOOTH_DISCOVERABILITY = SYSTEM_BLUETOOTH_DISCOVERABILITY
- BLUETOOTH_DISCOVERABILITY_TIMEOUT = SYSTEM_BLUETOOTH_DISCOVERABILITY_TIMEOUT
-
- # Wi-Fi
- WIFI_ON = SYSTEM_WIFI_ON
- WIFI_SLEEP_POLICY = SYSTEM_WIFI_SLEEP_POLICY
- WIFI_SLEEP_POLICY_DEFAULT = SYSTEM_WIFI_SLEEP_POLICY_DEFAULT
- WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = SYSTEM_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED
- WIFI_SLEEP_POLICY_NEVER = SYSTEM_WIFI_SLEEP_POLICY_NEVER
- WIFI_MAX_DHCP_RETRY_COUNT = SYSTEM_WIFI_MAX_DHCP_RETRY_COUNT
- WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = SYSTEM_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS
- WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = SYSTEM_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON
- WIFI_NUM_OPEN_NETWORKS_KEPT = SYSTEM_WIFI_NUM_OPEN_NETWORKS_KEPT
- WIFI_STATIC_DHCP_HOSTNAME = SYSTEM_WIFI_STATIC_DHCP_HOSTNAME
- WIFI_STATIC_IP = SYSTEM_WIFI_STATIC_IP
- WIFI_STATIC_GATEWAY = SYSTEM_WIFI_STATIC_GATEWAY
- WIFI_STATIC_NETMASK = SYSTEM_WIFI_STATIC_NETMASK
- WIFI_STATIC_DNS1 = SYSTEM_WIFI_STATIC_DNS1
- WIFI_STATIC_DNS2 = SYSTEM_WIFI_STATIC_DNS2
-
- # Animation
- WINDOW_ANIMATION_SCALE = SYSTEM_WINDOW_ANIMATION_SCALE
- TRANSITION_ANIMATION_SCALE = SYSTEM_TRANSITION_ANIMATION_SCALE
- ANIMATOR_DURATION_SCALE = SYSTEM_ANIMATOR_DURATION_SCALE
-
- # Text
- FONT_SCALE = SYSTEM_FONT_SCALE
- SHOW_WEB_SUGGESTIONS = SYSTEM_SHOW_WEB_SUGGESTIONS
-
- # Other
- ANDROID_ID = SYSTEM_ANDROID_ID
- EGG_MODE = SYSTEM_EGG_MODE
- END_BUTTON_BEHAVIOR = SYSTEM_END_BUTTON_BEHAVIOR
- HTTP_PROXY = SYSTEM_HTTP_PROXY
- SETUP_WIZARD_HAS_RUN = SYSTEM_SETUP_WIZARD_HAS_RUN
- SHOW_GTALK_SERVICE_STATUS = SYSTEM_SHOW_GTALK_SERVICE_STATUS
- SHOW_PROCESSES = SYSTEM_SHOW_PROCESSES
- STAY_ON_WHILE_PLUGGED_IN = SYSTEM_STAY_ON_WHILE_PLUGGED_IN
- TTY_MODE = SYSTEM_TTY_MODE
- SIP_RECEIVE_CALLS = SYSTEM_SIP_RECEIVE_CALLS
- SIP_CALL_OPTIONS = SYSTEM_SIP_CALL_OPTIONS
- HEARING_AID = SYSTEM_HEARING_AID
- SETTINGS_CLASSNAME = SYSTEM_SETTINGS_CLASSNAME
- LOCKSCREEN_DISABLED = SYSTEM_LOCKSCREEN_DISABLED
- LOCK_TO_APP_ENABLED = SYSTEM_LOCK_TO_APP_ENABLED
- ACCESSIBILITY_ENABLED = "accessibility_enabled"
- MASTER_MONO = SYSTEM_MASTER_MONO
- MASTER_BALANCE = SYSTEM_MASTER_BALANCE
- NOTIFICATION_LIGHT_PULSE = SYSTEM_NOTIFICATION_LIGHT_PULSE
- NOTIFICATION_LIGHT_COLOR = SYSTEM_NOTIFICATION_LIGHT_COLOR
- NOTIFICATION_LIGHT_ON_TIME = SYSTEM_NOTIFICATION_LIGHT_ON_TIME
- NOTIFICATION_LIGHT_OFF_TIME = SYSTEM_NOTIFICATION_LIGHT_OFF_TIME
- SWIPE_TO_SCREENSHOT_ENABLED = SYSTEM_SWIPE_TO_SCREENSHOT_ENABLED
- BATTERY_LIGHT_ENABLED = SYSTEM_BATTERY_LIGHT_ENABLED
- BATTERY_LIGHT_COLOR = SYSTEM_BATTERY_LIGHT_COLOR
- BATTERY_LIGHT_ON_TIME = SYSTEM_BATTERY_LIGHT_ON_TIME
- BATTERY_LIGHT_OFF_TIME = SYSTEM_BATTERY_LIGHT_OFF_TIME
- VOLUME_HUSH_GESTURE = SYSTEM_VOLUME_HUSH_GESTURE
-
- # Device provisioning
- DEVICE_PROVISIONED = "device_provisioned"
-
- @classmethod
- def getString(cls, key: str, default_value: Optional[str] = None) -> Optional[str]:
- return super().getString(key, default_value)
-
- @classmethod
- def putString(cls, key: str, value: str) -> bool:
- return super().putString(key, value)
-
- @classmethod
- def getInt(cls, key: str, default_value: int = 0) -> int:
- return super().getInt(key, default_value)
-
- @classmethod
- def putInt(cls, key: str, value: int) -> bool:
- return super().putInt(key, value)
-
- @classmethod
- def getFloat(cls, key: str, default_value: float = 0.0) -> float:
- return super().getFloat(key, default_value)
-
- @classmethod
- def putFloat(cls, key: str, value: float) -> bool:
- return super().putFloat(key, value)
-
- @classmethod
- def getLong(cls, key: str, default_value: int = 0) -> int:
- return super().getLong(key, default_value)
-
- @classmethod
- def putLong(cls, key: str, value: int) -> bool:
- return super().putLong(key, value)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Settings.Secure — 安全设置
-# ═══════════════════════════════════════════════════════════════
-
-SECURE_ADB_ENABLED = "adb_enabled"
-SECURE_ALLOW_MOCK_LOCATION = "mock_location"
-SECURE_ALLOW_MOCK_LOCATION = "mock_location"
-SECURE_ANDROID_ID = "android_id"
-SECURE_BACKGROUND_PROCESS_LIMIT = "background_process_limit"
-SECURE_BLUETOOTH_HCI_LOG = "bluetooth_hci_log"
-SECURE_BLUETOOTH_ON = "bluetooth_on"
-SECURE_CAMERA_GESTURE_DISABLED = "camera_gesture_disabled"
-SECURE_CAMERA_GESTURE_SOUND_ENABLED = "camera_gesture_sound_enabled"
-SECURE_CAPTIVE_PORTAL_DETECTION_ENABLED = "captive_portal_detection_enabled"
-SECURE_CAPTIVE_PORTAL_SERVER = "captive_portal_server"
-SECURE_DEVELOPER_TOOLS_ENABLED = "developer_tools_enabled"
-SECURE_DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled"
-SECURE_DEVICE_PROVISIONED = "device_provisioned"
-SECURE_DOZE_ENABLED = "doze_enabled"
-SECURE_DOZE_PULSE_ON_PICK = "doze_pulse_on_pick"
-SECURE_DOZE_PULSE_ON_LONG_PRESS = "doze_pulse_on_long_press"
-SECURE_DOZE_PULSE_ON_TAP = "doze_pulse_on_tap"
-SECURE_ENHANCED_VOICE_PRIVACY_ENABLED = "enhanced_voice_privacy_enabled"
-SECURE_FACTORY_RESET = "factory_reset"
-SECURE_GPS = "gps"
-SECURE_GUEST_USER_ENABLED = "guest_user_enabled"
-SECURE_HDCP_CHECKING = "hdcp_checking"
-SECURE_HTTP_PROXY = "http_proxy"
-SECURE_IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations"
-SECURE_INSTALL_NON_MARKET_APPS = "install_non_market_apps"
-SECURE_INSTANT_APPS_ENABLED = "instant_apps_enabled"
-SECURE_KEYGUARD_DISABLE_LAYOUT = "keyguard_disable_layout"
-SECURE_KEYGUARD_SLIDE_ENABLED = "keyguard_slide_enabled"
-SECURE_LOCATION_MODE = "location_mode"
-SECURE_LOCATION_MODE_HIGH_ACCURACY = 3
-SECURE_LOCATION_MODE_SENSORS_ONLY = 1
-SECURE_LOCATION_MODE_BATTERY_SAVING = 2
-SECURE_LOCATION_MODE_OFF = 0
-SECURE_LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed"
-SECURE_LOCK_BIOMETRIC_WEAK_FALLBACK = "lock_biometric_weak_fallback"
-SECURE_LOCK_PATTERN_ENABLED = "lock_pattern_autolock"
-SECURE_LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern"
-SECURE_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled"
-SECURE_LOCK_PIN_ENABLED = "lock_pin_enabled"
-SECURE_LOCK_PASSWORD_ENABLED = "lock_password_enabled"
-SECURE_LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications"
-SECURE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = "lock_screen_allow_remote_input"
-SECURE_LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications"
-SECURE_LOCK_SCREEN_LOCK_AFTER_TIMEOUT = "lock_screen_lock_after_timeout"
-SECURE_LOCK_SCREEN_OWNER_INFO = "lock_screen_owner_info"
-SECURE_LOCK_SCREEN_OWNER_INFO_ENABLED = "lock_screen_owner_info_enabled"
-SECURE_LOCK_SCREEN_WHEN_LOCKED = "lock_screen_when_locked"
-SECURE_LOCK_TO_APP_EXIT_LOCKED = "lock_to_app_exit_locked"
-SECURE_MANAGED_PROFILE_CONTACT_REMOTE_SEARCH = "managed_profile_contact_remote_search"
-SECURE_MOUNT_FILESYSTEM = "mount_filesystem"
-SECURE_MULTI_SIM_DATA_SUBSCRIPTION = "multi_sim_data_subscription"
-SECURE_MULTI_SIM_SMS_SUBSCRIPTION = "multi_sim_sms_subscription"
-SECURE_MULTI_SIM_VOICE_SUBSCRIPTION = "multi_sim_voice_subscription"
-SECURE_NOTIFICATION_BADGING = "notification_badging"
-SECURE_NOTIFICATION_BUBBLES = "notification_bubbles"
-SECURE_NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners"
-SECURE_NOTIFICATION_SHOW_MEDIA_PLAYER = "notification_show_media_player"
-SECURE_NFC_ON = "nfc_on"
-SECURE_NIGHT_DISPLAY_ACTIVATED = "night_display_activated"
-SECURE_NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode"
-SECURE_NIGHT_DISPLAY_COLOR_TEMPERATURE = "night_display_color_temperature"
-SECURE_NIGHT_DISPLAY_CUSTOM_START_TIME = "night_display_custom_start_time"
-SECURE_NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time"
-SECURE_PACKAGE_VERIFIER_ENABLE = "package_verifier_enable"
-SECURE_PACKAGE_VERIFIER_INCLUDE_ADB = "package_verifier_include_adb"
-SECURE_PACKAGE_VERIFIER_TIMEOUT = "package_verifier_timeout"
-SECURE_PARENTAL_CONTROL_ENABLED = "parental_control_enabled"
-SECURE_PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update"
-SECURE_PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url"
-SECURE_RTT_ENABLED = "rtt_enabled"
-SECURE_SCREENSAVER_COMPONENTS = "screensaver_components"
-SECURE_SCREENSAVER_DEFAULTS = "screensaver_defaults"
-SECURE_SCREENSAVER_ACTIVATE_ON_SLEEP = "screensaver_activate_on_sleep"
-SECURE_SCREENSAVER_ACTIVATE_ON_DOCK = "screensaver_activate_on_dock"
-SECURE_SCREENSAVER_ENABLED = "screensaver_enabled"
-SECURE_SKIP_FIRST_USE_HINTS = "skip_first_use_hints"
-SECURE_SLEEP_TIMEOUT = "sleep_timeout"
-SECURE_SMS_DEFAULT_APPLICATION = "sms_default_application"
-SECURE_THEME_MODE = "theme_mode"
-SECURE_TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled"
-SECURE_UI_NIGHT_MODE = "ui_night_mode"
-SECURE_USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"
-SECURE_USER_SETUP_COMPLETE = "user_setup_complete"
-SECURE_VERIFY_APPS = "verify_apps"
-SECURE_VERIFY_APPS = "verify_apps"
-SECURE_VOLUME_CONTROLLER_AS_MEDIA = "volume_controller_as_media"
-SECURE_VR_DEVELOPER_MODE_ENABLED = "vr_developer_mode_enabled"
-SECURE_VR_DISPLAY_MODE = "vr_display_mode"
-SECURE_VR_LAUNCH_POLICY = "vr_launch_policy"
-SECURE_WAKE_GESTURE_ENABLED = "wake_gesture_enabled"
-SECURE_WIFI_AP_INTERNET_AVAILABLE = "wifi_ap_internet_available"
-SECURE_WIFI_AUTO_CONNECT_TYPE = "wifi_auto_connect_type"
-SCRUBBER_WIFI_IDLE_MS = "wifi_idle_ms"
-SECURE_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on"
-SECURE_WIFI_WATCHDOG_ON = "wifi_watchdog_on"
-SECURE_WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED = "wifi_watchdog_poor_network_test_enabled"
-SECURE_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = "wifi_watchdog_acceptable_packet_loss_percentage"
-SECURE_WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count"
-SECURE_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = "wifi_watchdog_background_check_delay_ms"
-SECURE_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = "wifi_watchdog_background_check_enabled"
-SECURE_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = "wifi_watchdog_background_check_timeout_ms"
-SECURE_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = "wifi_watchdog_initial_ignored_ping_count"
-SECURE_WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count"
-SECURE_WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms"
-SECURE_WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms"
-SECURE_WIFI_WATCHDOG_WATCH_LIST = "wifi_watchdog_watch_list"
-SECURE_WIFI_WATCHDOG_DNS_CHECK_COUNT = "wifi_watchdog_dns_check_count"
-SECURE_WIFI_WATCHDOG_DNS_CHECK_TIMEOUT_MS = "wifi_watchdog_dns_check_timeout_ms"
-SECURE_WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks"
-SECURE_WIFI_WATCHDOG_TEST_SIZE_BYTES = "wifi_watchdog_test_size_bytes"
-SECURE_WIFI_WATCHDOG_TRIGGER_DELAY_MS = "wifi_watchdog_trigger_delay_ms"
-SECURE_WIFI_AUTO_CONNECT_TYPE = SECURE_WIFI_AUTO_CONNECT_TYPE
-
-
-class SettingsSecure(_SettingsBase):
- """Settings.Secure — 安全设置表"""
-
- _NAME = "settings_secure"
-
- # Development
- ADB_ENABLED = SECURE_ADB_ENABLED
- ALLOW_MOCK_LOCATION = SECURE_ALLOW_MOCK_LOCATION
- DEVELOPMENT_SETTINGS_ENABLED = SECURE_DEVELOPMENT_SETTINGS_ENABLED
- DEVELOPMENT_TOOLS_ENABLED = SECURE_DEVELOPER_TOOLS_ENABLED
- BACKGROUND_PROCESS_LIMIT = SECURE_BACKGROUND_PROCESS_LIMIT
- BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu"
- FULL_BUGREPORT_ENABLED = "full_bugreport_enabled"
- OEM_UNLOCK_ENABLED = "oem_unlock_enabled"
- PROCESS_STATS_ENABLED = "process_stats_enabled"
- STRICT_MODE_ENABLED = "strict_mode_enabled"
-
- # Security
- INSTALL_NON_MARKET_APPS = SECURE_INSTALL_NON_MARKET_APPS
- VERIFY_APPS = SECURE_VERIFY_APPS
- PACKAGE_VERIFIER_ENABLE = SECURE_PACKAGE_VERIFIER_ENABLE
- PACKAGE_VERIFIER_INCLUDE_ADB = SECURE_PACKAGE_VERIFIER_INCLUDE_ADB
- PACKAGE_VERIFIER_TIMEOUT = SECURE_PACKAGE_VERIFIER_TIMEOUT
- LOCK_PATTERN_ENABLED = SECURE_LOCK_PATTERN_ENABLED
- LOCK_PATTERN_VISIBLE = SECURE_LOCK_PATTERN_VISIBLE
- LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = SECURE_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
- LOCK_PIN_ENABLED = SECURE_LOCK_PIN_ENABLED
- LOCK_PASSWORD_ENABLED = SECURE_LOCK_PASSWORD_ENABLED
- LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = SECURE_LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
- LOCK_SCREEN_ALLOW_REMOTE_INPUT = SECURE_LOCK_SCREEN_ALLOW_REMOTE_INPUT
- LOCK_SCREEN_SHOW_NOTIFICATIONS = SECURE_LOCK_SCREEN_SHOW_NOTIFICATIONS
- LOCK_SCREEN_LOCK_AFTER_TIMEOUT = SECURE_LOCK_SCREEN_LOCK_AFTER_TIMEOUT
- LOCK_SCREEN_OWNER_INFO = SECURE_LOCK_SCREEN_OWNER_INFO
- LOCK_SCREEN_OWNER_INFO_ENABLED = SECURE_LOCK_SCREEN_OWNER_INFO_ENABLED
- LOCK_SCREEN_WHEN_LOCKED = SECURE_LOCK_SCREEN_WHEN_LOCKED
- LOCK_TO_APP_EXIT_LOCKED = SECURE_LOCK_TO_APP_EXIT_LOCKED
- KEYGUARD_DISABLE_LAYOUT = SECURE_KEYGUARD_DISABLE_LAYOUT
- KEYGUARD_SLIDE_ENABLED = SECURE_KEYGUARD_SLIDE_ENABLED
- LOCK_BIOMETRIC_WEAK_FALLBACK = SECURE_LOCK_BIOMETRIC_WEAK_FALLBACK
- PARENTAL_CONTROL_ENABLED = SECURE_PARENTAL_CONTROL_ENABLED
- PARENTAL_CONTROL_LAST_UPDATE = SECURE_PARENTAL_CONTROL_LAST_UPDATE
- PARENTAL_CONTROL_REDIRECT_URL = SECURE_PARENTAL_CONTROL_REDIRECT_URL
-
- # Location
- LOCATION_MODE = SECURE_LOCATION_MODE
- LOCATION_MODE_HIGH_ACCURACY = SECURE_LOCATION_MODE_HIGH_ACCURACY
- LOCATION_MODE_SENSORS_ONLY = SECURE_LOCATION_MODE_SENSORS_ONLY
- LOCATION_MODE_BATTERY_SAVING = SECURE_LOCATION_MODE_BATTERY_SAVING
- LOCATION_MODE_OFF = SECURE_LOCATION_MODE_OFF
- LOCATION_PROVIDERS_ALLOWED = SECURE_LOCATION_PROVIDERS_ALLOWED
- GPS = SECURE_GPS
-
- # Wi-Fi watchdog
- WIFI_WATCHDOG_ON = SECURE_WIFI_WATCHDOG_ON
- WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED = SECURE_WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED
- WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = SECURE_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE
- WIFI_WATCHDOG_AP_COUNT = SECURE_WIFI_WATCHDOG_AP_COUNT
- WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = SECURE_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS
- WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = SECURE_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED
- WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = SECURE_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS
- WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = SECURE_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT
- WIFI_WATCHDOG_PING_COUNT = SECURE_WIFI_WATCHDOG_PING_COUNT
- WIFI_WATCHDOG_PING_DELAY_MS = SECURE_WIFI_WATCHDOG_PING_DELAY_MS
- WIFI_WATCHDOG_PING_TIMEOUT_MS = SECURE_WIFI_WATCHDOG_PING_TIMEOUT_MS
- WIFI_WATCHDOG_WATCH_LIST = SECURE_WIFI_WATCHDOG_WATCH_LIST
- WIFI_AUTO_CONNECT_TYPE = SECURE_WIFI_AUTO_CONNECT_TYPE
- WIFI_IDLE_MS = SCRUBBER_WIFI_IDLE_MS
- WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = SECURE_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON
- WIFI_AP_INTERNET_AVAILABLE = SECURE_WIFI_AP_INTERNET_AVAILABLE
-
- # USB
- USB_MASS_STORAGE_ENABLED = SECURE_USB_MASS_STORAGE_ENABLED
-
- # Accessibility
- ACCESSIBILITY_ENABLED = "accessibility_enabled"
- TOUCH_EXPLORATION_ENABLED = SECURE_TOUCH_EXPLORATION_ENABLED
- ENHANCED_VOICE_PRIVACY_ENABLED = SECURE_ENHANCED_VOICE_PRIVACY_ENABLED
- ACCESSIBILITY_SCRIPT_INJECTION = "accessibility_script_injection"
- ACCESSIBILITY_SPEAK_PASSWORD = "accessibility_speak_password"
- ACCESSIBILITY_WEB_CONTENT_KEY = "accessibility_web_content_key"
- TOUCH_EXPLORATION_ENABLED = SECURE_TOUCH_EXPLORATION_ENABLED
- NOTIFICATION_ENABLED_LISTENERS = SECURE_NOTIFICATION_ENABLED_LISTENERS
- NOTIFICATION_BADGING = SECURE_NOTIFICATION_BADGING
- NOTIFICATION_BUBBLES = SECURE_NOTIFICATION_BUBBLES
- NOTIFICATION_SHOW_MEDIA_PLAYER = SECURE_NOTIFICATION_SHOW_MEDIA_PLAYER
-
- # Display
- DOZE_ENABLED = SECURE_DOZE_ENABLED
- DOZE_PULSE_ON_PICK = SECURE_DOZE_PULSE_ON_PICK
- DOZE_PULSE_ON_LONG_PRESS = SECURE_DOZE_PULSE_ON_LONG_PRESS
- DOZE_PULSE_ON_TAP = SECURE_DOZE_PULSE_ON_TAP
- WAKE_GESTURE_ENABLED = SECURE_WAKE_GESTURE_ENABLED
- CAMERA_GESTURE_DISABLED = SECURE_CAMERA_GESTURE_DISABLED
- CAMERA_GESTURE_SOUND_ENABLED = SECURE_CAMERA_GESTURE_SOUND_ENABLED
- NIGHT_DISPLAY_ACTIVATED = SECURE_NIGHT_DISPLAY_ACTIVATED
- NIGHT_DISPLAY_AUTO_MODE = SECURE_NIGHT_DISPLAY_AUTO_MODE
- NIGHT_DISPLAY_COLOR_TEMPERATURE = SECURE_NIGHT_DISPLAY_COLOR_TEMPERATURE
- NIGHT_DISPLAY_CUSTOM_START_TIME = SECURE_NIGHT_DISPLAY_CUSTOM_START_TIME
- NIGHT_DISPLAY_CUSTOM_END_TIME = SECURE_NIGHT_DISPLAY_CUSTOM_END_TIME
- THEME_MODE = SECURE_THEME_MODE
- UI_NIGHT_MODE = SECURE_UI_NIGHT_MODE
- SCREENSAVER_ENABLED = SECURE_SCREENSAVER_ENABLED
- SCREENSAVER_COMPONENTS = SECURE_SCREENSAVER_COMPONENTS
- SCREENSAVER_DEFAULTS = SECURE_SCREENSAVER_DEFAULTS
- SCREENSAVER_ACTIVATE_ON_SLEEP = SECURE_SCREENSAVER_ACTIVATE_ON_SLEEP
- SCREENSAVER_ACTIVATE_ON_DOCK = SECURE_SCREENSAVER_ACTIVATE_ON_DOCK
- SLEEP_TIMEOUT = SECURE_SLEEP_TIMEOUT
- IMMERSIVE_MODE_CONFIRMATIONS = SECURE_IMMERSIVE_MODE_CONFIRMATIONS
-
- # Network
- CAPTIVE_PORTAL_DETECTION_ENABLED = SECURE_CAPTIVE_PORTAL_DETECTION_ENABLED
- CAPTIVE_PORTAL_SERVER = SECURE_CAPTIVE_PORTAL_SERVER
- HTTP_PROXY = SECURE_HTTP_PROXY
- RTT_ENABLED = SECURE_RTT_ENABLED
- NFC_ON = SECURE_NFC_ON
- BLUETOOTH_ON = SECURE_BLUETOOTH_ON
- BLUETOOTH_HCI_LOG = SECURE_BLUETOOTH_HCI_LOG
- MULTI_SIM_DATA_SUBSCRIPTION = SECURE_MULTI_SIM_DATA_SUBSCRIPTION
- MULTI_SIM_SMS_SUBSCRIPTION = SECURE_MULTI_SIM_SMS_SUBSCRIPTION
- MULTI_SIM_VOICE_SUBSCRIPTION = SECURE_MULTI_SIM_VOICE_SUBSCRIPTION
- SMS_DEFAULT_APPLICATION = SECURE_SMS_DEFAULT_APPLICATION
-
- # Device
- DEVICE_PROVISIONED = SECURE_DEVICE_PROVISIONED
- ANDROID_ID = SECURE_ANDROID_ID
- FACTORY_RESET = SECURE_FACTORY_RESET
- USER_SETUP_COMPLETE = SECURE_USER_SETUP_COMPLETE
- SKIP_FIRST_USE_HINTS = SECURE_SKIP_FIRST_USE_HINTS
- GUEST_USER_ENABLED = SECURE_GUEST_USER_ENABLED
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH = SECURE_MANAGED_PROFILE_CONTACT_REMOTE_SEARCH
- MOUNT_FILESYSTEM = SECURE_MOUNT_FILESYSTEM
- HDCP_CHECKING = SECURE_HDCP_CHECKING
- INSTANT_APPS_ENABLED = SECURE_INSTANT_APPS_ENABLED
-
- # Volume
- VOLUME_CONTROLLER_AS_MEDIA = SECURE_VOLUME_CONTROLLER_AS_MEDIA
-
- # VR
- VR_DEVELOPER_MODE_ENABLED = SECURE_VR_DEVELOPER_MODE_ENABLED
- VR_DISPLAY_MODE = SECURE_VR_DISPLAY_MODE
- VR_LAUNCH_POLICY = SECURE_VR_LAUNCH_POLICY
-
- @classmethod
- def getString(cls, key: str, default_value: Optional[str] = None) -> Optional[str]:
- return super().getString(key, default_value)
-
- @classmethod
- def putString(cls, key: str, value: str) -> bool:
- return super().putString(key, value)
-
- @classmethod
- def getInt(cls, key: str, default_value: int = 0) -> int:
- return super().getInt(key, default_value)
-
- @classmethod
- def putInt(cls, key: str, value: int) -> bool:
- return super().putInt(key, value)
-
- @classmethod
- def getFloat(cls, key: str, default_value: float = 0.0) -> float:
- return super().getFloat(key, default_value)
-
- @classmethod
- def putFloat(cls, key: str, value: float) -> bool:
- return super().putFloat(key, value)
-
- @classmethod
- def getLong(cls, key: str, default_value: int = 0) -> int:
- return super().getLong(key, default_value)
-
- @classmethod
- def putLong(cls, key: str, value: int) -> bool:
- return super().putLong(key, value)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Settings.Global — 全局设置
-# ═══════════════════════════════════════════════════════════════
-
-GLOBAL_AIRPLANE_MODE_ON = "airplane_mode_on"
-GLOBAL_AIRPLANE_MODE_RADIOS = "airplane_mode_radios"
-GLOBAL_AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios"
-GLOBAL_ALARM_ALERT = "alarm_alert"
-GLOBAL_ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED = "allow_user_switching_when_system_user_locked"
-GLOBAL_ALWAYS_ON_DISPLAY_BRIGHTNESS = "always_on_display_brightness"
-GLOBAL_ALWAYS_ON_DISPLAY_CONSTANT_BRIGHTNESS = "always_on_display_constant_brightness"
-GLOBAL_ALWAYS_FINISH_ACTIVITIES = "always_finish_activities"
-GLOBAL_ANIMATOR_DURATION_SCALE = "animator_duration_scale"
-GLOBAL_APP_STANDBY_ENABLED = "app_standby_enabled"
-GLOBAL_AUTO_TIME = "auto_time"
-GLOBAL_AUTO_TIME_ZONE = "auto_time_zone"
-GLOBAL_BATTERY_DISCHARGE_DURATION_THRESHOLD = "battery_discharge_duration_threshold"
-GLOBAL_BATTERY_DISCHARGE_THRESHOLD = "battery_discharge_threshold"
-GLOBAL_BLUETOOTH_CLASS_OF_DEVICE = "bluetooth_class_of_device"
-GLOBAL_BLUETOOTH_DISABLED_PROFILES = "bluetooth_disabled_profiles"
-GLOBAL_BLUETOOTH_INTEROPERABILITY_LIST = "bluetooth_interoperability_list"
-GLOBAL_BLUETOOTH_ON = "bluetooth_on"
-GLOBAL_BOOT_COUNT = "boot_count"
-GLOBAL_BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu"
-GLOBAL_CACHED_APPS_FREEZER_ENABLED = "cached_apps_freezer_enabled"
-GLOBAL_CAPTIVE_PORTAL_DETECTION_ENABLED = "captive_portal_detection_enabled"
-GLOBAL_CAPTIVE_PORTAL_SERVER = "captive_portal_server"
-GLOBAL_CARRIER_APP_NAMES = "carrier_app_names"
-GLOBAL_CARRIER_APP_WHITELIST = "carrier_app_whitelist"
-GLOBAL_CDMA_CELL_BROADCAST_SMS = "cdma_cell_broadcast_sms"
-GLOBAL_CDMA_ROAMING_MODE = "cdma_roaming_mode"
-GLOBAL_CDMA_SUBSCRIPTION = "cdma_subscription"
-GLOBAL_CELL_ON = "cell_on"
-GLOBAL_COMPATIBILITY_MODE = "compatibility_mode"
-GLOBAL_CONNECTIVITY_MANAGER_INITIALIZED = "connectivity_manager_initialized"
-GLOBAL_CONTACTS_ACCOUNT_TYPE = "contacts_account_type"
-GLOBAL_CONTACTS_DATABASE_UPDATE = "contacts_database_update"
-GLOBAL_DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile"
-GLOBAL_DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi"
-GLOBAL_DATA_ROAMING = "data_roaming"
-GLOBAL_DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS = "data_stall_alarm_non_aggressive_delay_in_ms"
-GLOBAL_DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS = "data_stall_alarm_aggressive_delay_in_ms"
-GLOBAL_DEBUG_APP = "debug_app"
-GLOBAL_DEBUG_VIEW_ATTRIBUTES = "debug_view_attributes"
-GLOBAL_DEFAULT_INSTALL_LOCATION = "default_install_location"
-GLOBAL_DEFAULT_SIM_SETTINGS = "default_sim_settings"
-GLOBAL_DEFAULT_WIFI_INTERFACE = "default_wifi_interface"
-GLOBAL_DEVICE_DEMO_MODE = "device_demo_mode"
-GLOBAL_DEVICE_IDLE_CONSTANTS = "device_idle_constants"
-GLOBAL_DEVICE_NAME = "device_name"
-GLOBAL_DEVICE_PROVISIONED = "device_provisioned"
-GLOBAL_DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data_enabled"
-GLOBAL_DEVELOPMENT_ENABLE_FREEFORM_WINDOW_SUPPORT = "development_enable_freeform_window_support"
-GLOBAL_DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES = "development_force_resizable_activities"
-GLOBAL_DEVELOPMENT_FORCE_RTL = "development_force_rtl"
-GLOBAL_DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled"
-GLOBAL_DISK_FREE_CHANGE_REPORTING_MINIMUM = "disk_free_change_reporting_minimum"
-GLOBAL_DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled"
-GLOBAL_DOCK_EVENT = "dock_event"
-GLOBAL_DOWNLOAD_MAX_BYTES_OVER_MOBILE = "download_max_bytes_over_mobile"
-GLOBAL_DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE = "download_recommended_max_bytes_over_mobile"
-GLOBAL_DROPBOX_AGE_SECONDS = "dropbox_age_seconds"
-GLOBAL_DROPBOX_MAX_FILES = "dropbox_max_files"
-GLOBAL_DROPBOX_QUOTA_KB = "dropbox_quota_kb"
-GLOBAL_DROPBOX_QUOTA_PERCENT = "dropbox_quota_percent"
-GLOBAL_DROPBOX_RESERVE_PERCENT = "dropbox_reserve_percent"
-GLOBAL_DROPBOX_TAG_PREFIX = "dropbox:"
-GLOBAL_EMERGENCY_TONE = "emergency_tone"
-GLOBAL_ENABLE_ACCESSIBILITY = "enable_accessibility"
-GLOBAL_ENABLE_CELLULAR_ON_BOOT = "enable_cellular_on_boot"
-GLOBAL_ENABLE_GPU_DEBUG_LAYERS = "enable_gpu_debug_layers"
-GLOBAL_ENABLE_NETWORK_ACTIVITY = "enable_network_activity"
-GLOBAL_ENCODED_SURROUND_OUTPUT = "encoded_surround_output"
-GLOBAL_ENCODED_SURROUND_OUTPUT_ENABLED = "encoded_surround_output_enabled"
-GLOBAL_EPHEMERAL_COOKIE_DURATION_SECONDS = "ephemeral_cookie_duration_seconds"
-GLOBAL_FANCY_IME_ANIMATIONS = "fancy_ime_animations"
-GLOBAL_FORCE_ALLOW_SCREEN_ON = "force_allow_screen_on"
-GLOBAL_FORCE_ALLOW_SYSTEM_USER_ONLY = "force_allow_system_user_only"
-GLOBAL_FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled"
-GLOBAL_FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED = "forced_app_standby_for_small_battery_enabled"
-GLOBAL_FORCED_APP_STANDBY_SMALL_BATTERY_THRESHOLD_MILLIS = "forced_app_standby_small_battery_threshold_millis"
-GLOBAL_FSTRIM_MANDATORY_INTERVAL = "fstrim_mandatory_interval"
-GLOBAL_GLOBAL_HTTP_PROXY_EXCLUSION_LIST = "global_http_proxy_exclusion_list"
-GLOBAL_GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host"
-GLOBAL_GLOBAL_HTTP_PROXY_PAC = "global_http_proxy_pac"
-GLOBAL_GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port"
-GLOBAL_GPRS_REGISTER_CHECK_PERIOD_MS = "gprs_register_check_period_ms"
-GLOBAL_GUEST_USER_ENABLED = "guest_user_enabled"
-GLOBAL_HDCP_CHECKING = "hdcp_checking"
-GLOBAL_HEADS_UP_NOTIFICATIONS_ENABLED = "heads_up_notifications_enabled"
-GLOBAL_HISTORY_DAYS = "history_days"
-GLOBAL_HOTSPOT_APN = "hotspot_apn"
-GLOBAL_HOTSPOT_APN_TYPE = "hotspot_apn_type"
-GLOBAL_HOTSPOT_APN_AUTH_TYPE = "hotspot_apn_auth_type"
-GLOBAL_HOTSPOT_APN_PROTOCOL = "hotspot_apn_protocol"
-GLOBAL_HOTSPOT_APN_ROAMING_PROTOCOL = "hotspot_apn_roaming_protocol"
-GLOBAL_HOTSPOT_APN_USER = "hotspot_apn_user"
-GLOBAL_HOTSPOT_APN_PASS = "hotspot_apn_pass"
-GLOBAL_HOTSPOT_CARRIER_ENABLED = "hotspot_carrier_enabled"
-GLOBAL_HOTSPOT_ENABLED = "hotspot_enabled"
-GLOBAL_HOTSPOT_SSID = "hotspot_ssid"
-GLOBAL_HOTSPOT_SECURITY_TYPE = "hotspot_security_type"
-GLOBAL_INET_CONDITION = "inet_condition"
-GLOBAL_INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD = "installed_instant_app_min_cache_period"
-GLOBAL_INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD = "installed_instant_app_max_cache_period"
-GLOBAL_INSTANT_APP_DEXOPT_ENABLED = "instant_app_dexopt_enabled"
-GLOBAL_INTENT_FIREWALL_MAIN_INTERACTION_FILTER = "intent_firewall_main_interaction_filter"
-GLOBAL_INTENT_FIREWALL_COMPONENT_FILTER = "intent_firewall_component_filter"
-GLOBAL_INTENT_FIREWALL_PACKAGE_FILTER = "intent_firewall_package_filter"
-GLOBAL_INTENT_FIREWALL_CATEGORY_FILTER = "intent_firewall_category_filter"
-GLOBAL_INTENT_FIREWALL_ACTION_FILTER = "intent_firewall_action_filter"
-GLOBAL_INTENT_FIREWALL_TYPE = "intent_firewall_type"
-GLOBAL_JOB_SCHEDULER_CONSTANTS = "job_scheduler_constants"
-GLOBAL_KEEP_PROFILE_IN_BACKGROUND = "keep_profile_in_background"
-GLOBAL_LID_BEHAVIOR = "lid_behavior"
-GLOBAL_LOCK_SCREEN_WHEN_LOCKED = "lock_screen_when_locked"
-GLOBAL_LOW_BATTERY_SOUND = "low_battery_sound"
-GLOBAL_LOW_BATTERY_SOUND_TIMEOUT = "low_battery_sound_timeout"
-GLOBAL_LOW_POWER_MODE = "low_power_mode"
-GLOBAL_LOW_POWER_MODE_STICKY = "low_power_mode_sticky"
-GLOBAL_LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_mode_trigger_level"
-GLOBAL_MACHINE_UID = "machine_uid"
-GLOBAL_MAX_NOTIFICATION_ENQUEUE_RATE = "max_notification_enqueue_rate"
-GLOBAL_MEDIA_SCANNER_ON_BOOT = "media_scanner_on_boot"
-GLOBAL_MOBILE_DATA = "mobile_data"
-GLOBAL_MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on"
-GLOBAL_MODE_RINGER = "mode_ringer"
-GLOBAL_MULTI_SIM_DATA_CALL_SUBSCRIPTION = "multi_sim_data_call_subscription"
-GLOBAL_NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration"
-GLOBAL_NETSTATS_DEV_DELETE_AGE = "netstats_dev_delete_age"
-GLOBAL_NETSTATS_DEV_PERSIST_BYTES = "netstats_dev_persist_bytes"
-GLOBAL_NETSTATS_DEV_ROTATE_AGE = "netstats_dev_rotate_age"
-GLOBAL_NETSTATS_ENABLED = "netstats_enabled"
-GLOBAL_NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes"
-GLOBAL_NETSTATS_POLL_INTERVAL = "netstats_poll_interval"
-GLOBAL_NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled"
-GLOBAL_NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age"
-GLOBAL_NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration"
-GLOBAL_NETSTATS_UID_DELETE_AGE = "netstats_uid_delete_age"
-GLOBAL_NETSTATS_UID_PERSIST_BYTES = "netstats_uid_persist_bytes"
-GLOBAL_NETSTATS_UID_ROTATE_AGE = "netstats_uid_rotate_age"
-GLOBAL_NETSTATS_UID_TAG_BUCKET_DURATION = "netstats_uid_tag_bucket_duration"
-GLOBAL_NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age"
-GLOBAL_NETSTATS_UID_TAG_PERSIST_BYTES = "netstats_uid_tag_persist_bytes"
-GLOBAL_NETSTATS_UID_TAG_ROTATE_AGE = "netstats_uid_tag_rotate_age"
-GLOBAL_NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi"
-GLOBAL_NETWORK_METERED_MULTIPATH_PREFERENCE = "network_metered_multipath_preference"
-GLOBAL_NETWORK_PREFERENCE = "network_preference"
-GLOBAL_NETWORK_RECOMMENDATIONS_ENABLED = "network_recommendations_enabled"
-GLOBAL_NETWORK_RECOMMENDATIONS_PACKAGE = "network_recommendations_package"
-GLOBAL_NETWORK_SCORER_APP = "network_scorer_app"
-GLOBAL_NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT = "network_switch_notification_daily_limit"
-GLOBAL_NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS = "network_switch_notification_rate_limit_millis"
-GLOBAL_NETWORK_WATCHLIST_ENABLED = "network_watchlist_enabled"
-GLOBAL_NFC_ON = "nfc_on"
-GLOBAL_NITZ_UPDATE_DIFF = "nitz_update_diff"
-GLOBAL_NITZ_UPDATE_SPACING = "nitz_update_spacing"
-GLOBAL_NOTIFICATION_BACKGROUNDING = "notification_backgrounding"
-GLOBAL_NOTIFICATION_CHANNEL_BACKGROUNDING = "notification_channel_backgrounding"
-GLOBAL_NOTIFICATION_MAX_CHANNEL_GROUPS = "notification_max_channel_groups"
-GLOBAL_NOTIFICATION_MAX_CHANNELS = "notification_max_channels"
-GLOBAL_NOTIFICATION_SNOOZE_MIN_TIME_SECONDS = "notification_snooze_min_time_seconds"
-GLOBAL_NOTIFICATION_SNOOZE_MAX_TIME_SECONDS = "notification_snooze_max_time_seconds"
-GLOBAL_NOTIFICATION_SNOOZE_OPTIONS = "notification_snooze_options"
-GLOBAL_NOTIFICATION_TIMEOUT_IN_SECONDS = "notification_timeout_in_seconds"
-GLOBAL_NR_NSA_NR_5G_ENABLED = "nr_nsa_nr_5g_enabled"
-GLOBAL_NR_NSA_SUB6_5G_ENABLED = "nr_nsa_sub6_5g_enabled"
-GLOBAL_NR_NSA_MMWAVE_5G_ENABLED = "nr_nsa_mmwave_5g_enabled"
-GLOBAL_NR_NSA_SA_MODE = "nr_nsa_sa_mode"
-GLOBAL_NR_SA_5G_ENABLED = "nr_sa_5g_enabled"
-GLOBAL_NSD_ON = "nsd_on"
-GLOBAL_NUM_SIM_EVENTS = "num_sim_events"
-GLOBAL_OVERLAY_DISPLAY_DEVICES = "overlay_display_devices"
-GLOBAL_PACKAGE_VERIFIER_DEFAULT_RESPONSE = "package_verifier_default_response"
-GLOBAL_PACKAGE_VERIFIER_ENABLE = "package_verifier_enable"
-GLOBAL_PACKAGE_VERIFIER_INCLUDE_ADB = "package_verifier_include_adb"
-GLOBAL_PACKAGE_VERIFIER_SETTING = "package_verifier_setting"
-GLOBAL_PACKAGE_VERIFIER_TIMEOUT = "package_verifier_timeout"
-GLOBAL_PDP_WATCHDOG_ERROR_POLL_COUNT = "pdp_watchdog_error_poll_count"
-GLOBAL_PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS = "pdp_watchdog_error_poll_interval_ms"
-GLOBAL_PDP_WATCHDOG_LONG_POLL_INTERVAL_MS = "pdp_watchdog_long_poll_interval_ms"
-GLOBAL_PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT = "pdp_watchdog_max_pdp_reset_fail_count"
-GLOBAL_PDP_WATCHDOG_POLL_INTERVAL_MS = "pdp_watchdog_poll_interval_ms"
-GLOBAL_PDP_WATCHDOG_TRIGGER_PACKET_COUNT = "pdp_watchdog_trigger_packet_count"
-GLOBAL_POWER_MANAGER_CONSTANTS = "power_manager_constants"
-GLOBAL_PREFERRED_NETWORK_MODE = "preferred_network_mode"
-GLOBAL_PREPEND_APN = "prepend_apn"
-GLOBAL_PREVIOUS_BOOT_COUNT = "previous_boot_count"
-GLOBAL_PRIVATE_DNS_MODE = "private_dns_mode"
-GLOBAL_PRIVATE_DNS_SPECIFIER = "private_dns_specifier"
-GLOBAL_PROBLEM_DETECTED = "problem_detected"
-GLOBAL_PROTECTED_NETWORKS = "protected_networks"
-GLOBAL_RADIO_SCREEN_TIMEOUT = "radio_screen_timeout"
-GLOBAL_RAM_SIZE = "ram_size"
-GLOBAL_RECOVERY_UPDATE = "recovery_update"
-GLOBAL_REMOTE_BUGREPORT_NOTIFICATION_ENABLED = "remote_bugreport_notification_enabled"
-GLOBAL_REQUIRE_DEVICE_UNLOCK = "require_device_unlock"
-GLOBAL_RESTART_BROADCAST_INTERVAL = "restart_broadcast_interval"
-GLOBAL_ROAMING_SETTINGS = "roaming_settings"
-GLOBAL_SAFE_BOOT_DISALLOWED = "safe_boot_disallowed"
-GLOBAL_SAMPLING_PROFILER_MS = "sampling_profiler_ms"
-GLOBAL_SCREEN_BRIGHTNESS = "screen_brightness"
-GLOBAL_SCREEN_BRIGHTNESS_FLOAT = "screen_brightness_float"
-GLOBAL_SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode"
-GLOBAL_SCREEN_OFF_TIMEOUT = "screen_off_timeout"
-GLOBAL_SCREEN_ON_POWER_BUTTON = "screen_on_power_button"
-GLOBAL_SDCARD_BLACKLISTED_DEFAULT_SYNCABLE_TYPES = "sdcard_blacklisted_default_syncable_types"
-GLOBAL_SELINUX_STATUS = "selinux_status"
-GLOBAL_SELINUX_UPDATE = "selinux_update"
-GLOBAL_SEND_ACTION_APP_ERROR = "send_action_app_error"
-GLOBAL_SENSOR_PRIVACY = "sensor_privacy"
-GLOBAL_SERVICE_AUTO_RESTART_DURATION = "service_auto_restart_duration"
-GLOBAL_SERVICE_RESTART_DURATION = "service_restart_duration"
-GLOBAL_SERVICE_RESTART_DURATION_LIMIT = "service_restart_duration_limit"
-GLOBAL_SET_INSTALL_LOCATION = "set_install_location"
-GLOBAL_SHARED_SYSTEM_USER_WHITELIST = "shared_system_user_whitelist"
-GLOBAL_SHORTCUT_MANAGER_CONSTANTS = "shortcut_manager_constants"
-GLOBAL_SHOW_HIDDEN_LAUNCHER_ICON_APPS = "show_hidden_launcher_icon_apps"
-GLOBAL_SHOW_MEDIA_OUTPUT_SWITCHER = "show_media_output_switcher"
-GLOBAL_SHOW_NOTIFICATION_CHANNEL_WARNINGS = "show_notification_channel_warnings"
-GLOBAL_SHOW_PASSWORD = "show_password"
-GLOBAL_SHOW_TEMPERATURE_WARNING = "show_temperature_warning"
-GLOBAL_SHOW_ZEN_UPGRADE_NOTIFICATION = "show_zen_upgrade_notification"
-GLOBAL_SIM_INSERTED_STATUS = "sim_inserted_status"
-GLOBAL_SIM_OPERATOR_NUMERIC = "sim_operator_numeric"
-GLOBAL_SKIP_RESTORE_AFTER_FACTORY_RESET = "skip_restore_after_factory_reset"
-GLOBAL_SKIP_USER_SUGGESTION = "skip_user_suggestion"
-GLOBAL_SLEEP = "sleep"
-GLOBAL_SMART_USER_AUTO_LOCK = "smart_user_auto_lock"
-GLOBAL_SMS_OUTGOING_CHECK_INTERVAL_MS = "sms_outgoing_check_interval_ms"
-GLOBAL_SMS_OUTGOING_CHECK_MAX_COUNT = "sms_outgoing_check_max_count"
-GLOBAL_SMS_SHORT_CODES = "sms_short_codes"
-GLOBAL_SMS_SHORT_CODES_UPDATE_MODE = "sms_short_codes_update_mode"
-GLOBAL_SS_SYSTEM_UID = "ss_system_uid"
-GLOBAL_SS_USER_UID = "ss_user_uid"
-GLOBAL_STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in"
-GLOBAL_STORAGE_BENCHMARK_INTERVAL = "storage_benchmark_interval"
-GLOBAL_STORAGE_SETTINGS_CLOBBER_THRESHOLD = "storage_settings_clobber_threshold"
-GLOBAL_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED = "swipe_bottom_to_notification_enabled"
-GLOBAL_SWITCH_HAS_BEEN_USED = "switch_has_been_used"
-GLOBAL_SYNC_MANAGER_CONSTANTS = "sync_manager_constants"
-GLOBAL_SYSTEM_MAX_ERRORS = "system_max_errors"
-GLOBAL_SYSTEM_USER_HOME_URI = "system_user_home_uri"
-GLOBAL_TCP_DEFAULT_INIT_RWND = "tcp_default_init_rwnd"
-GLOBAL_TCP_OPTIMIZATION = "tcp_optimization"
-GLOBAL_TCP_TIMEOUT = "tcp_timeout"
-GLOBAL_TETHER_DUN_APN = "tether_dun_apn"
-GLOBAL_TETHER_DUN_REQUIRED = "tether_dun_required"
-GLOBAL_TETHER_OFFLOAD_DISABLED = "tether_offload_disabled"
-GLOBAL_TETHER_SUPPORTED = "tether_supported"
-GLOBAL_THEATER_MODE = "theater_mode"
-GLOBAL_TIME_ONLINE = "time_online"
-GLOBAL_TIMEOUT_TO_FORCE_SLEEP_MS = "timeout_to_force_sleep_ms"
-GLOBAL_TITLE = "title"
-GLOBAL_TPRONES = "tprones"
-GLOBAL_TRANSITION_ANIMATION_SCALE = "transition_animation_scale"
-GLOBAL_TRUSTED_SOUND = "trusted_sound"
-GLOBAL_TTY_MODE = "tty_mode"
-GLOBAL_TZINFO_UPDATE_CONTENT_URL = "tzinfo_update_content_url"
-GLOBAL_TZINFO_UPDATE_METADATA_URL = "tzinfo_update_metadata_url"
-GLOBAL_UART_ON_BOOT = "uart_on_boot"
-GLOBAL_UBIFS = "ubifs"
-GLOBAL_UID_CPUSET = "uid_cpuset"
-GLOBAL_UNKNOWN_SOURCES_DEFAULT_REVERSED = "unknown_sources_default_reversed"
-GLOBAL_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_DURATION = "unused_static_shared_lib_min_cache_duration"
-GLOBAL_UPDATABLE_DRIVER_ALL_APPS = "updatable_driver_all_apps"
-GLOBAL_UPDATABLE_DRIVER_PRODUCTION_OPT_IN = "updatable_driver_production_opt_in"
-GLOBAL_UPDATABLE_DRIVER_PRODUCTION_DENYLIST = "updatable_driver_production_denylist"
-GLOBAL_UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST = "updatable_driver_production_allowlist"
-GLOBAL_UPDATABLE_DRIVER_PRERELEASE_OPT_IN = "updatable_driver_prerelease_opt_in"
-GLOBAL_UPDATABLE_DRIVER_PROCESS_PACKAGES = "updatable_driver_process_packages"
-GLOBAL_UPDATABLE_DRIVER_DENYLIST = "updatable_driver_denylist"
-GLOBAL_USB_AUDIO_AUTOROUTING_DISABLED = "usb_audio_autorouting_disabled"
-GLOBAL_USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"
-GLOBAL_USE_GOOGLE_MAIL = "use_google_mail"
-GLOBAL_USER_SWITCHER = "user_switcher"
-GLOBAL_VERIFY_APPS = "verify_apps"
-GLOBAL_VOLUME_VIBRATE = "volume_vibrate"
-GLOBAL_VOLUME_HUSH_GESTURE = "volume_hush_gesture"
-GLOBAL_VR_DEVELOPER_MODE_ENABLED = "vr_developer_mode_enabled"
-GLOBAL_VR_DISPLAY_MODE = "vr_display_mode"
-GLOBAL_VR_LAUNCH_POLICY = "vr_launch_policy"
-GLOBAL_WAIT_FOR_DEBUGGER = "wait_for_debugger"
-GLOBAL_WALLPAPER_COMPONENT = "wallpaper_component"
-GLOBAL_WIFI_BANDWIDTH_TEST_INTERVAL = "wifi_bandwidth_test_interval"
-GLOBAL_WIFI_BANDWIDTH_TEST_TIMEOUT = "wifi_bandwidth_test_timeout"
-GLOBAL_WIFI_BOUNCE_ACTIVITY_DELAY_MS = "wifi_bounce_activity_delay_ms"
-GLOBAL_WIFI_COUNTRY_CODE = "wifi_country_code"
-GLOBAL_WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN = "wifi_device_owner_configs_lockdown"
-GLOBAL_WIFI_DISPLAY_CERTIFICATION_ON = "wifi_display_certification_on"
-GLOBAL_WIFI_DISPLAY_ON = "wifi_display_on"
-GLOBAL_WIFI_DISPLAY_WPS_CONFIG = "wifi_display_wps_config"
-GLOBAL_WIFI_DRIVER_INTERFACE = "wifi_driver_interface"
-GLOBAL_WIFI_DRIVER_OPERATION_MODE = "wifi_driver_operation_mode"
-GLOBAL_WIFI_ENHANCED_AUTO_JOIN = "wifi_enhanced_auto_join"
-GLOBAL_WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS = "wifi_ephemeral_out_of_range_timeout_ms"
-GLOBAL_WIFI_FRAMEWORK_LOGGING_INTERVAL_SECONDS = "wifi_framework_logging_interval_seconds"
-GLOBAL_WIFI_FRAMEWORK_SCAN_INTERVAL_MS = "wifi_framework_scan_interval_ms"
-GLOBAL_WIFI_FRAMEWORK_SCAN_INTERVAL_MIN_MS = "wifi_framework_scan_interval_min_ms"
-GLOBAL_WIFI_FRAMEWORK_SCAN_INTERVAL_MAX_MS = "wifi_framework_scan_interval_max_ms"
-GLOBAL_WIFI_FRAMEWORK_ACTIVE_SCAN_INTERVAL_MS = "wifi_framework_active_scan_interval_ms"
-GLOBAL_WIFI_FRAMEWORK_P2P_SCAN_INTERVAL_MS = "wifi_framework_p2p_scan_interval_ms"
-GLOBAL_WIFI_FREQUENCY_BAND = "wifi_frequency_band"
-GLOBAL_WIFI_HOTSPOT2_ENABLED = "wifi_hotspot2_enabled"
-GLOBAL_WIFI_IDLE_MS = "wifi_idle_ms"
-GLOBAL_WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"
-GLOBAL_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms"
-GLOBAL_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on"
-GLOBAL_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay"
-GLOBAL_WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept"
-GLOBAL_WIFI_ON = "wifi_on"
-GLOBAL_WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name"
-GLOBAL_WIFI_SAVED_STATE = "wifi_saved_state"
-GLOBAL_WIFI_SCAN_ALWAYS_AVAILABLE = "wifi_scan_always_available"
-GLOBAL_WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS = "wifi_scan_interval_when_p2p_connected_ms"
-GLOBAL_WIFI_SLEEP_POLICY = "wifi_sleep_policy"
-GLOBAL_WIFI_SLEEP_POLICY_DEFAULT = 0
-GLOBAL_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1
-GLOBAL_WIFI_SLEEP_POLICY_NEVER = 2
-GLOBAL_WIFI_SUPPLICANT_SCAN_INTERVAL_MS = "wifi_supplicant_scan_interval_ms"
-GLOBAL_WIFI_SUSPEND_OPTIMIZATIONS_ENABLED = "wifi_suspend_optimizations_enabled"
-GLOBAL_WIFI_VERBOSE_LOGGING_ENABLED = "wifi_verbose_logging_enabled"
-GLOBAL_WIFI_WATCHDOG_ON = "wifi_watchdog_on"
-GLOBAL_WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED = "wifi_watchdog_poor_network_test_enabled"
-GLOBAL_WIMAX_ON = "wimax_on"
-GLOBAL_WINDOW_ANIMATION_SCALE = "window_animation_scale"
-GLOBAL_WINDOW_ORIENTATION_LISTENER_LOG = "window_orientation_listener_log"
-GLOBAL_WIFI_ENHANCED_AUTO_JOIN = GLOBAL_WIFI_ENHANCED_AUTO_JOIN
-GLOBAL_WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS = GLOBAL_WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS
-GLOBAL_WIFI_FRAMEWORK_LOGGING_INTERVAL_SECONDS = GLOBAL_WIFI_FRAMEWORK_LOGGING_INTERVAL_SECONDS
-GLOBAL_WIFI_FRAMEWORK_SCAN_INTERVAL_MS = GLOBAL_WIFI_FRAMEWORK_SCAN_INTERVAL_MS
-GLOBAL_WIFI_FRAMEWORK_SCAN_INTERVAL_MIN_MS = GLOBAL_WIFI_FRAMEWORK_SCAN_INTERVAL_MIN_MS
-GLOBAL_WIFI_FRAMEWORK_SCAN_INTERVAL_MAX_MS = GLOBAL_WIFI_FRAMEWORK_SCAN_INTERVAL_MAX_MS
-GLOBAL_WIFI_FRAMEWORK_ACTIVE_SCAN_INTERVAL_MS = GLOBAL_WIFI_FRAMEWORK_ACTIVE_SCAN_INTERVAL_MS
-GLOBAL_WIFI_FRAMEWORK_P2P_SCAN_INTERVAL_MS = GLOBAL_WIFI_FRAMEWORK_P2P_SCAN_INTERVAL_MS
-GLOBAL_WIFI_FREQUENCY_BAND = GLOBAL_WIFI_FREQUENCY_BAND
-GLOBAL_WIFI_HOTSPOT2_ENABLED = GLOBAL_WIFI_HOTSPOT2_ENABLED
-GLOBAL_WIFI_IDLE_MS = GLOBAL_WIFI_IDLE_MS
-GLOBAL_WIFI_MAX_DHCP_RETRY_COUNT = GLOBAL_WIFI_MAX_DHCP_RETRY_COUNT
-GLOBAL_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = GLOBAL_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS
-GLOBAL_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = GLOBAL_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON
-GLOBAL_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = GLOBAL_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY
-GLOBAL_WIFI_NUM_OPEN_NETWORKS_KEPT = GLOBAL_WIFI_NUM_OPEN_NETWORKS_KEPT
-GLOBAL_WIFI_ON = GLOBAL_WIFI_ON
-GLOBAL_WIFI_P2P_DEVICE_NAME = GLOBAL_WIFI_P2P_DEVICE_NAME
-GLOBAL_WIFI_SAVED_STATE = GLOBAL_WIFI_SAVED_STATE
-GLOBAL_WIFI_SCAN_ALWAYS_AVAILABLE = GLOBAL_WIFI_SCAN_ALWAYS_AVAILABLE
-GLOBAL_WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS = GLOBAL_WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS
-GLOBAL_WIFI_SLEEP_POLICY = GLOBAL_WIFI_SLEEP_POLICY
-GLOBAL_WIFI_SLEEP_POLICY_DEFAULT = GLOBAL_WIFI_SLEEP_POLICY_DEFAULT
-GLOBAL_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = GLOBAL_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED
-GLOBAL_WIFI_SLEEP_POLICY_NEVER = GLOBAL_WIFI_SLEEP_POLICY_NEVER
-GLOBAL_WIFI_SUPPLICANT_SCAN_INTERVAL_MS = GLOBAL_WIFI_SUPPLICANT_SCAN_INTERVAL_MS
-GLOBAL_WIFI_SUSPEND_OPTIMIZATIONS_ENABLED = GLOBAL_WIFI_SUSPEND_OPTIMIZATIONS_ENABLED
-GLOBAL_WIFI_VERBOSE_LOGGING_ENABLED = GLOBAL_WIFI_VERBOSE_LOGGING_ENABLED
-GLOBAL_WIFI_WATCHDOG_ON = GLOBAL_WIFI_WATCHDOG_ON
-GLOBAL_WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED = GLOBAL_WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED
-GLOBAL_WIMAX_ON = GLOBAL_WIMAX_ON
-GLOBAL_WINDOW_ANIMATION_SCALE = GLOBAL_WINDOW_ANIMATION_SCALE
-GLOBAL_WINDOW_ORIENTATION_LISTENER_LOG = GLOBAL_WINDOW_ORIENTATION_LISTENER_LOG
-GLOBAL_WIRELESS_CHARGING_STARTED_SOUND = "wireless_charging_started_sound"
-GLOBAL_WOW_DISABLE = "wow_disable"
-GLOBAL_WTF_IS_THIS = "wtf_is_this"
-GLOBAL_ZEN_MODE = "zen_mode"
-GLOBAL_ZEN_MODE_CONFIG_ETAG = "zen_mode_config_etag"
-GLOBAL_ZEN_MODE_RINGER_LEVEL = "zen_mode_ringer_level"
-GLOBAL_ZEN_MODE_DURATION = "zen_mode_duration"
-
-
-class SettingsGlobal(_SettingsBase):
- """Settings.Global — 全局设置表"""
-
- _NAME = "settings_global"
-
- # Airplane mode
- AIRPLANE_MODE_ON = GLOBAL_AIRPLANE_MODE_ON
- AIRPLANE_MODE_RADIOS = GLOBAL_AIRPLANE_MODE_RADIOS
- AIRPLANE_MODE_TOGGLEABLE_RADIOS = GLOBAL_AIRPLANE_MODE_TOGGLEABLE_RADIOS
-
- # Wi-Fi
- WIFI_ON = GLOBAL_WIFI_ON
- WIFI_SLEEP_POLICY = GLOBAL_WIFI_SLEEP_POLICY
- WIFI_SLEEP_POLICY_DEFAULT = GLOBAL_WIFI_SLEEP_POLICY_DEFAULT
- WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = GLOBAL_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED
- WIFI_SLEEP_POLICY_NEVER = GLOBAL_WIFI_SLEEP_POLICY_NEVER
- WIFI_MAX_DHCP_RETRY_COUNT = GLOBAL_WIFI_MAX_DHCP_RETRY_COUNT
- WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = GLOBAL_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON
- WIFI_NUM_OPEN_NETWORKS_KEPT = GLOBAL_WIFI_NUM_OPEN_NETWORKS_KEPT
- WIFI_SCAN_ALWAYS_AVAILABLE = GLOBAL_WIFI_SCAN_ALWAYS_AVAILABLE
- WIFI_COUNTRY_CODE = GLOBAL_WIFI_COUNTRY_CODE
- WIFI_FREQUENCY_BAND = GLOBAL_WIFI_FREQUENCY_BAND
- WIFI_ENHANCED_AUTO_JOIN = GLOBAL_WIFI_ENHANCED_AUTO_JOIN
- WIFI_HOTSPOT2_ENABLED = GLOBAL_WIFI_HOTSPOT2_ENABLED
- WIFI_VERBOSE_LOGGING_ENABLED = GLOBAL_WIFI_VERBOSE_LOGGING_ENABLED
- WIFI_SUSPEND_OPTIMIZATIONS_ENABLED = GLOBAL_WIFI_SUSPEND_OPTIMIZATIONS_ENABLED
- WIFI_WATCHDOG_ON = GLOBAL_WIFI_WATCHDOG_ON
- WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS = GLOBAL_WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS
-
- # Bluetooth
- BLUETOOTH_ON = GLOBAL_BLUETOOTH_ON
- BLUETOOTH_CLASS_OF_DEVICE = GLOBAL_BLUETOOTH_CLASS_OF_DEVICE
- BLUETOOTH_DISABLED_PROFILES = GLOBAL_BLUETOOTH_DISABLED_PROFILES
- BLUETOOTH_INTEROPERABILITY_LIST = GLOBAL_BLUETOOTH_INTEROPERABILITY_LIST
-
- # Cellular / Mobile
- MOBILE_DATA = GLOBAL_MOBILE_DATA
- MOBILE_DATA_ALWAYS_ON = GLOBAL_MOBILE_DATA_ALWAYS_ON
- DATA_ROAMING = GLOBAL_DATA_ROAMING
- CELL_ON = GLOBAL_CELL_ON
- PREFERRED_NETWORK_MODE = GLOBAL_PREFERRED_NETWORK_MODE
- CDMA_ROAMING_MODE = GLOBAL_CDMA_ROAMING_MODE
- CDMA_SUBSCRIPTION = GLOBAL_CDMA_SUBSCRIPTION
- LTE_SERVICE_FORCED = "lte_service_forced"
- NR_NSA_NR_5G_ENABLED = GLOBAL_NR_NSA_NR_5G_ENABLED
- NR_NSA_SUB6_5G_ENABLED = GLOBAL_NR_NSA_SUB6_5G_ENABLED
- NR_NSA_MMWAVE_5G_ENABLED = GLOBAL_NR_NSA_MMWAVE_5G_ENABLED
-
- # Hotspot
- HOTSPOT_ENABLED = GLOBAL_HOTSPOT_ENABLED
- HOTSPOT_SSID = GLOBAL_HOTSPOT_SSID
- HOTSPOT_SECURITY_TYPE = GLOBAL_HOTSPOT_SECURITY_TYPE
- HOTSPOT_APN = GLOBAL_HOTSPOT_APN
- TETHER_SUPPORTED = GLOBAL_TETHER_SUPPORTED
- TETHER_DUN_REQUIRED = GLOBAL_TETHER_DUN_REQUIRED
- TETHER_DUN_APN = GLOBAL_TETHER_DUN_APN
-
- # Development
- DEVELOPMENT_SETTINGS_ENABLED = GLOBAL_DEVELOPMENT_SETTINGS_ENABLED
- DEVELOPMENT_ENABLE_FREEFORM_WINDOW_SUPPORT = GLOBAL_DEVELOPMENT_ENABLE_FREEFORM_WINDOW_SUPPORT
- DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES = GLOBAL_DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES
- DEVELOPMENT_FORCE_RTL = GLOBAL_DEVELOPMENT_FORCE_RTL
- DEBUG_APP = GLOBAL_DEBUG_APP
- DEBUG_VIEW_ATTRIBUTES = GLOBAL_DEBUG_VIEW_ATTRIBUTES
- WAIT_FOR_DEBUGGER = GLOBAL_WAIT_FOR_DEBUGGER
- ALWAYS_FINISH_ACTIVITIES = GLOBAL_ALWAYS_FINISH_ACTIVITIES
- WINDOW_ANIMATION_SCALE = GLOBAL_WINDOW_ANIMATION_SCALE
- TRANSITION_ANIMATION_SCALE = GLOBAL_TRANSITION_ANIMATION_SCALE
- ANIMATOR_DURATION_SCALE = GLOBAL_ANIMATOR_DURATION_SCALE
- SHOW_PASSWORD = GLOBAL_SHOW_PASSWORD
- BUGREPORT_IN_POWER_MENU = GLOBAL_BUGREPORT_IN_POWER_MENU
- STAY_ON_WHILE_PLUGGED_IN = GLOBAL_STAY_ON_WHILE_PLUGGED_IN
- USB_MASS_STORAGE_ENABLED = GLOBAL_USB_MASS_STORAGE_ENABLED
- ACCESSIBILITY_ENABLED = "accessibility_enabled"
- SENSOR_PRIVACY = GLOBAL_SENSOR_PRIVACY
-
- # Display
- SCREEN_BRIGHTNESS = GLOBAL_SCREEN_BRIGHTNESS
- SCREEN_BRIGHTNESS_FLOAT = GLOBAL_SCREEN_BRIGHTNESS_FLOAT
- SCREEN_BRIGHTNESS_MODE = GLOBAL_SCREEN_BRIGHTNESS_MODE
- SCREEN_OFF_TIMEOUT = GLOBAL_SCREEN_OFF_TIMEOUT
- THEATER_MODE = GLOBAL_THEATER_MODE
- LOW_POWER_MODE = GLOBAL_LOW_POWER_MODE
- LOW_POWER_MODE_STICKY = GLOBAL_LOW_POWER_MODE_STICKY
- LOW_POWER_MODE_TRIGGER_LEVEL = GLOBAL_LOW_POWER_MODE_TRIGGER_LEVEL
- DOZE_ENABLED = "doze_enabled"
- DEVICE_DEMO_MODE = GLOBAL_DEVICE_DEMO_MODE
- DEVICE_NAME = GLOBAL_DEVICE_NAME
- ALWAYS_ON_DISPLAY_BRIGHTNESS = GLOBAL_ALWAYS_ON_DISPLAY_BRIGHTNESS
- ALWAYS_ON_DISPLAY_CONSTANT_BRIGHTNESS = GLOBAL_ALWAYS_ON_DISPLAY_CONSTANT_BRIGHTNESS
-
- # Network
- NETWORK_PREFERENCE = GLOBAL_NETWORK_PREFERENCE
- NETWORK_SCORER_APP = GLOBAL_NETWORK_SCORER_APP
- NETWORK_AVOID_BAD_WIFI = GLOBAL_NETWORK_AVOID_BAD_WIFI
- NETWORK_METERED_MULTIPATH_PREFERENCE = GLOBAL_NETWORK_METERED_MULTIPATH_PREFERENCE
- CAPTIVE_PORTAL_DETECTION_ENABLED = GLOBAL_CAPTIVE_PORTAL_DETECTION_ENABLED
- CAPTIVE_PORTAL_SERVER = GLOBAL_CAPTIVE_PORTAL_SERVER
- PRIVATE_DNS_MODE = GLOBAL_PRIVATE_DNS_MODE
- PRIVATE_DNS_SPECIFIER = GLOBAL_PRIVATE_DNS_SPECIFIER
- GLOBAL_HTTP_PROXY_HOST = GLOBAL_GLOBAL_HTTP_PROXY_HOST
- GLOBAL_HTTP_PROXY_PORT = GLOBAL_GLOBAL_HTTP_PROXY_PORT
- GLOBAL_HTTP_PROXY_PAC = GLOBAL_GLOBAL_HTTP_PROXY_PAC
- GLOBAL_HTTP_PROXY_EXCLUSION_LIST = GLOBAL_GLOBAL_HTTP_PROXY_EXCLUSION_LIST
- NFC_ON = GLOBAL_NFC_ON
- NSD_ON = GLOBAL_NSD_ON
-
- # Device
- DEVICE_PROVISIONED = GLOBAL_DEVICE_PROVISIONED
- BOOT_COUNT = GLOBAL_BOOT_COUNT
- DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = GLOBAL_DEVICE_PROVISIONING_MOBILE_DATA_ENABLED
- RAM_SIZE = GLOBAL_RAM_SIZE
- MACHINE_UID = GLOBAL_MACHINE_UID
- SELINUX_STATUS = GLOBAL_SELINUX_STATUS
-
- # Time
- AUTO_TIME = GLOBAL_AUTO_TIME
- AUTO_TIME_ZONE = GLOBAL_AUTO_TIME_ZONE
- NITZ_UPDATE_DIFF = GLOBAL_NITZ_UPDATE_DIFF
- NITZ_UPDATE_SPACING = GLOBAL_NITZ_UPDATE_SPACING
- TIME_ONLINE = GLOBAL_TIME_ONLINE
-
- # Do not disturb / Zen
- ZEN_MODE = GLOBAL_ZEN_MODE
- ZEN_MODE_CONFIG_ETAG = GLOBAL_ZEN_MODE_CONFIG_ETAG
- ZEN_MODE_RINGER_LEVEL = GLOBAL_ZEN_MODE_RINGER_LEVEL
- ZEN_MODE_DURATION = GLOBAL_ZEN_MODE_DURATION
-
- # Audio
- MODE_RINGER = GLOBAL_MODE_RINGER
- ENCODED_SURROUND_OUTPUT = GLOBAL_ENCODED_SURROUND_OUTPUT
- ENCODED_SURROUND_OUTPUT_ENABLED = GLOBAL_ENCODED_SURROUND_OUTPUT_ENABLED
- DOCK_AUDIO_MEDIA_ENABLED = GLOBAL_DOCK_AUDIO_MEDIA_ENABLED
- VOLUME_HUSH_GESTURE = GLOBAL_VOLUME_HUSH_GESTURE
-
- # Storage
- DEFAULT_INSTALL_LOCATION = GLOBAL_DEFAULT_INSTALL_LOCATION
- SET_INSTALL_LOCATION = GLOBAL_SET_INSTALL_LOCATION
- STORAGE_BENCHMARK_INTERVAL = GLOBAL_STORAGE_BENCHMARK_INTERVAL
-
- # Package verifier
- PACKAGE_VERIFIER_ENABLE = GLOBAL_PACKAGE_VERIFIER_ENABLE
- PACKAGE_VERIFIER_INCLUDE_ADB = GLOBAL_PACKAGE_VERIFIER_INCLUDE_ADB
- PACKAGE_VERIFIER_TIMEOUT = GLOBAL_PACKAGE_VERIFIER_TIMEOUT
- PACKAGE_VERIFIER_DEFAULT_RESPONSE = GLOBAL_PACKAGE_VERIFIER_DEFAULT_RESPONSE
-
- # User
- GUEST_USER_ENABLED = GLOBAL_GUEST_USER_ENABLED
- USER_SWITCHER = GLOBAL_USER_SWITCHER
- ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED = GLOBAL_ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED
- KEEP_PROFILE_IN_BACKGROUND = GLOBAL_KEEP_PROFILE_IN_BACKGROUND
- SKIP_USER_SUGGESTION = GLOBAL_SKIP_USER_SUGGESTION
-
- # Notifications
- HEADS_UP_NOTIFICATIONS_ENABLED = GLOBAL_HEADS_UP_NOTIFICATIONS_ENABLED
- MAX_NOTIFICATION_ENQUEUE_RATE = GLOBAL_MAX_NOTIFICATION_ENQUEUE_RATE
- NOTIFICATION_SNOOZE_MIN_TIME_SECONDS = GLOBAL_NOTIFICATION_SNOOZE_MIN_TIME_SECONDS
- NOTIFICATION_SNOOZE_MAX_TIME_SECONDS = GLOBAL_NOTIFICATION_SNOOZE_MAX_TIME_SECONDS
- NOTIFICATION_TIMEOUT_IN_SECONDS = GLOBAL_NOTIFICATION_TIMEOUT_IN_SECONDS
- SHOW_NOTIFICATION_CHANNEL_WARNINGS = GLOBAL_SHOW_NOTIFICATION_CHANNEL_WARNINGS
- SHOW_MEDIA_OUTPUT_SWITCHER = GLOBAL_SHOW_MEDIA_OUTPUT_SWITCHER
- NOTIFICATION_BACKGROUNDING = GLOBAL_NOTIFICATION_BACKGROUNDING
-
- # Wired/Wireless charging
- WIRELESS_CHARGING_STARTED_SOUND = GLOBAL_WIRELESS_CHARGING_STARTED_SOUND
- LOW_BATTERY_SOUND = GLOBAL_LOW_BATTERY_SOUND
- LOW_BATTERY_SOUND_TIMEOUT = GLOBAL_LOW_BATTERY_SOUND_TIMEOUT
-
- # VR
- VR_DEVELOPER_MODE_ENABLED = GLOBAL_VR_DEVELOPER_MODE_ENABLED
- VR_DISPLAY_MODE = GLOBAL_VR_DISPLAY_MODE
- VR_LAUNCH_POLICY = GLOBAL_VR_LAUNCH_POLICY
-
- @classmethod
- def getString(cls, key: str, default_value: Optional[str] = None) -> Optional[str]:
- return super().getString(key, default_value)
-
- @classmethod
- def putString(cls, key: str, value: str) -> bool:
- return super().putString(key, value)
-
- @classmethod
- def getInt(cls, key: str, default_value: int = 0) -> int:
- return super().getInt(key, default_value)
-
- @classmethod
- def putInt(cls, key: str, value: int) -> bool:
- return super().putInt(key, value)
-
- @classmethod
- def getFloat(cls, key: str, default_value: float = 0.0) -> float:
- return super().getFloat(key, default_value)
-
- @classmethod
- def putFloat(cls, key: str, value: float) -> bool:
- return super().putFloat(key, value)
-
- @classmethod
- def getLong(cls, key: str, default_value: int = 0) -> int:
- return super().getLong(key, default_value)
-
- @classmethod
- def putLong(cls, key: str, value: int) -> bool:
- return super().putLong(key, value)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Settings.NameValueTable — 名称值表接口
-# ═══════════════════════════════════════════════════════════════
-
-class NameValueTable(Stub):
- """Settings.NameValueTable — 名称-值表接口"""
-
- NAME = "name"
- VALUE = "value"
-
- @staticmethod
- def getUri(uri: Any) -> Any:
- """Get the content URI for the name-value table."""
- return uri
-
- @staticmethod
- def getString(resolver: Any, uri: Any, name: str) -> Optional[str]:
- """Get a string from the name-value table."""
- return None
-
- @staticmethod
- def putString(resolver: Any, uri: Any, name: str, value: str) -> bool:
- """Put a string into the name-value table."""
- return False
-
- @staticmethod
- def getInt(resolver: Any, uri: Any, name: str, default_value: int = 0) -> int:
- """Get an integer from the name-value table."""
- return default_value
-
- @staticmethod
- def putInt(resolver: Any, uri: Any, name: str, value: int) -> bool:
- """Put an integer into the name-value table."""
- return False
-
- @staticmethod
- def getFloat(resolver: Any, uri: Any, name: str, default_value: float = 0.0) -> float:
- """Get a float from the name-value table."""
- return default_value
-
- @staticmethod
- def putFloat(resolver: Any, uri: Any, name: str, value: float) -> bool:
- """Put a float into the name-value table."""
- return False
-
- @staticmethod
- def getLong(resolver: Any, uri: Any, name: str, default_value: int = 0) -> int:
- """Get a long from the name-value table."""
- return default_value
-
- @staticmethod
- def putLong(resolver: Any, uri: Any, name: str, value: int) -> bool:
- """Put a long into the name-value table."""
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Settings 根类
-# ═══════════════════════════════════════════════════════════════
-
-class Settings(Stub):
- """Settings — 系统设置(扩展版)"""
-
- System = SettingsSystem
- Secure = SettingsSecure
- Global = SettingsGlobal
- NameValueTable = NameValueTable
-
- # Action constants
- ACTION_SETTINGS = "android.settings.SETTINGS"
- ACTION_APN_SETTINGS = "android.settings.APN_SETTINGS"
- ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS"
- ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS"
- ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS"
- ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS"
- ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS"
- ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS"
- ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS"
- ACTION_CONDITION_PROVIDER_SETTINGS = "android.settings.CONDITION_PROVIDER_SETTINGS"
- ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS"
- ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS"
- ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS"
- ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS"
- ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"
- ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS"
- ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS"
- ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS"
- ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"
- ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS"
- ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS"
- ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS"
- ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS"
- ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS"
- ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS"
- ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS"
- ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS"
- ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.MANAGE_OVERLAY_PERMISSION"
- ACTION_MANAGE_UNKNOWN_APP_SOURCES = "android.settings.MANAGE_UNKNOWN_APP_SOURCES"
- ACTION_MANAGE_WRITE_SETTINGS = "android.settings.MANAGE_WRITE_SETTINGS"
- ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS"
- ACTION_NETWORK_OPERATOR_SETTINGS = "android.settings.NETWORK_OPERATOR_SETTINGS"
- ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS"
- ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS"
- ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS"
- ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.NOTIFICATION_LISTENER_SETTINGS"
- ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS"
- ACTION_PRINT_SETTINGS = "android.settings.PRINT_SETTINGS"
- ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS"
- ACTION_QUICK_ACCESS_WALLET_SETTINGS = "android.settings.QUICK_ACCESS_WALLET_SETTINGS"
- ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS"
- ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
- ACTION_REQUEST_MANAGE_MEDIA = "android.settings.REQUEST_MANAGE_MEDIA"
- ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE"
- ACTION_REQUEST_SCHEDULE_EXACT_ALARM = "android.settings.REQUEST_SCHEDULE_EXACT_ALARM"
- ACTION_SEARCH_SETTINGS = "android.settings.SEARCH_SETTINGS"
- ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"
- ACTION_SETTINGS = ACTION_SETTINGS
- ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS"
- ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO"
- ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS"
- ACTION_STORAGE_MANAGER_SETTINGS = "android.settings.STORAGE_MANAGER_SETTINGS"
- ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS"
- ACTION_SYSTEM_UPDATE_SETTINGS = "android.settings.SYSTEM_UPDATE_SETTINGS"
- ACTION_TETHER_PROVISIONING = "android.settings.TETHER_PROVISIONING"
- ACTION_TRUSTED_CREDENTIALS_USER = "android.settings.TRUSTED_CREDENTIALS_USER"
- ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS"
- ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS"
- ACTION_VIDEO_ACCESSIBILITY_SETTINGS = "android.settings.VIDEO_ACCESSIBILITY_SETTINGS"
- ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE"
- ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE"
- ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE"
- ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS"
- ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS"
- ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS"
- ACTION_WEBVIEW_SETTINGS = "android.settings.WEBVIEW_SETTINGS"
- ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS"
- ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS"
- ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS"
- ACTION_ZWITE_MIGRATE_SETTINGS = "android.settings.ZWITE_MIGRATE_SETTINGS"
-
- # Extra constants
- EXTRA_ACCOUNT_TYPES = "account_types"
- EXTRA_AUTHORITIES = "authorities"
- EXTRA_BATTERY_SAVER_MODE_ENABLED = "extra_battery_saver_mode_enabled"
- EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "extra_do_not_disturb_mode_enabled"
- EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "extra_do_not_disturb_mode_minutes"
- EXTRA_INPUT_METHOD_ID = "input_method_id"
- EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGH_LIGHT = "extra_settings_embedded_deep_link_high_light"
- EXTRA_SETTINGS_EMBEDDED_DEEP_LINK = "extra_settings_embedded_deep_link"
-
- # Intent constant for Settings
- EXTRA_APP_PACKAGE = "android.intent.extra.PACKAGE_NAME"
-
- @staticmethod
- def canDrawOverlays(context: Any) -> bool:
- """Check if the app can draw overlays."""
- return True
-
- @staticmethod
- def canWriteSettings(context: Any) -> bool:
- """Check if the app can write system settings."""
- return True
-
- @staticmethod
- def checkAndWriteSettings(context: Any, settings_key: str, value: Any) -> bool:
- """Check and write a settings value if permitted."""
- return False
-
- @staticmethod
- def getDefaultSettingsPackageName(context: Any) -> str:
- """Get the default settings package name."""
- return "com.android.settings"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Settings Extras — 额外工具类
-# ═══════════════════════════════════════════════════════════════
-
-class SettingsExtras:
- """SettingsExtras — 设置辅助工具"""
-
- @staticmethod
- def isAirplaneModeOn(context: Any) -> bool:
- """Check if airplane mode is on."""
- return SettingsSystem.getInt(SettingsSystem.AIRPLANE_MODE_ON, 0) == 1
-
- @staticmethod
- def setAirplaneMode(context: Any, on: bool) -> bool:
- """Set airplane mode on or off."""
- return SettingsSystem.putInt(SettingsSystem.AIRPLANE_MODE_ON, 1 if on else 0)
-
- @staticmethod
- def isWifiOn(context: Any) -> bool:
- """Check if Wi-Fi is on."""
- return SettingsSystem.getInt(SettingsSystem.WIFI_ON, 0) == 1
-
- @staticmethod
- def isBluetoothOn(context: Any) -> bool:
- """Check if Bluetooth is on."""
- return SettingsSystem.getInt(SettingsSystem.BLUETOOTH_ON, 0) == 1
-
- @staticmethod
- def isAdbEnabled(context: Any) -> bool:
- """Check if ADB is enabled."""
- return SettingsSecure.getInt(SettingsSecure.ADB_ENABLED, 0) == 1
-
- @staticmethod
- def isInstallNonMarketAppsAllowed(context: Any) -> bool:
- """Check if installing apps from unknown sources is allowed."""
- return SettingsSecure.getInt(SettingsSecure.INSTALL_NON_MARKET_APPS, 0) == 1
-
- @staticmethod
- def getScreenBrightness(context: Any, default: int = 255) -> int:
- """Get screen brightness value (0-255)."""
- return SettingsSystem.getInt(SettingsSystem.SCREEN_BRIGHTNESS, default)
-
- @staticmethod
- def setScreenBrightness(context: Any, value: int) -> bool:
- """Set screen brightness (0-255)."""
- return SettingsSystem.putInt(SettingsSystem.SCREEN_BRIGHTNESS, max(0, min(255, value)))
-
- @staticmethod
- def getScreenOffTimeout(context: Any, default: int = 30000) -> int:
- """Get screen off timeout in milliseconds."""
- return SettingsSystem.getInt(SettingsSystem.SCREEN_OFF_TIMEOUT, default)
-
- @staticmethod
- def setScreenOffTimeout(context: Any, timeout_ms: int) -> bool:
- """Set screen off timeout in milliseconds."""
- return SettingsSystem.putInt(SettingsSystem.SCREEN_OFF_TIMEOUT, timeout_ms)
-
- @staticmethod
- def isDevelopmentSettingsEnabled(context: Any) -> bool:
- """Check if development settings are enabled."""
- return SettingsSecure.getInt(SettingsSecure.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1
-
- @staticmethod
- def isMockLocationAllowed(context: Any) -> bool:
- """Check if mock location is allowed."""
- return SettingsSecure.getInt(SettingsSecure.ALLOW_MOCK_LOCATION, 0) == 1
-
- @staticmethod
- def getDeviceName(context: Any, default: str = "") -> str:
- """Get the device name."""
- value = SettingsGlobal.getString(SettingsGlobal.DEVICE_NAME)
- return value if value is not None else default
-
- @staticmethod
- def setDeviceName(context: Any, name: str) -> bool:
- """Set the device name."""
- return SettingsGlobal.putString(SettingsGlobal.DEVICE_NAME, name)
-
- @staticmethod
- def getZenMode(context: Any, default: int = 0) -> int:
- """Get the current Zen/Do Not Disturb mode."""
- return SettingsGlobal.getInt(SettingsGlobal.ZEN_MODE, default)
-
- @staticmethod
- def isDataRoamingEnabled(context: Any) -> bool:
- """Check if data roaming is enabled."""
- return SettingsGlobal.getInt(SettingsGlobal.DATA_ROAMING, 0) == 1
-
- @staticmethod
- def isMobileDataEnabled(context: Any) -> bool:
- """Check if mobile data is enabled."""
- return SettingsGlobal.getInt(SettingsGlobal.MOBILE_DATA, 1) == 1
-
- @staticmethod
- def getScreenBrightnessMode(context: Any) -> int:
- """Get screen brightness mode (manual=0, auto=1)."""
- return SettingsSystem.getInt(SettingsSystem.SCREEN_BRIGHTNESS_MODE, 0)
-
- @staticmethod
- def setScreenBrightnessMode(context: Any, mode: int) -> bool:
- """Set screen brightness mode (manual=0, auto=1)."""
- return SettingsSystem.putInt(SettingsSystem.SCREEN_BRIGHTNESS_MODE, mode)
-
- @staticmethod
- def getHttpProxy(context: Any) -> Optional[str]:
- """Get the HTTP proxy setting."""
- return SettingsSystem.getString(SettingsSystem.HTTP_PROXY)
-
- @staticmethod
- def setHttpProxy(context: Any, proxy: str) -> bool:
- """Set the HTTP proxy."""
- return SettingsSystem.putString(SettingsSystem.HTTP_PROXY, proxy)
-
- @staticmethod
- def getGlobalHttpProxy(context: Any) -> Dict[str, Any]:
- """Get the global HTTP proxy settings."""
- return {
- "host": SettingsGlobal.getString(SettingsGlobal.GLOBAL_HTTP_PROXY_HOST),
- "port": SettingsGlobal.getInt(SettingsGlobal.GLOBAL_HTTP_PROXY_PORT, 0),
- "pac": SettingsGlobal.getString(SettingsGlobal.GLOBAL_HTTP_PROXY_PAC),
- "exclusion_list": SettingsGlobal.getString(SettingsGlobal.GLOBAL_HTTP_PROXY_EXCLUSION_LIST),
- }
-
- @staticmethod
- def isDeviceProvisioned(context: Any) -> bool:
- """Check if the device has been provisioned."""
- return SettingsGlobal.getInt(SettingsGlobal.DEVICE_PROVISIONED, 0) == 1
-
- @staticmethod
- def getBootCount(context: Any) -> int:
- """Get the number of times the device has been booted."""
- return SettingsGlobal.getInt(SettingsGlobal.BOOT_COUNT, 0)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SettingsProvider 辅助类
-# ═══════════════════════════════════════════════════════════════
-
-class SettingsProvider(Stub):
- """SettingsProvider — 设置提供者辅助类"""
-
- @staticmethod
- def getStringForUser(resolver: Any, name: str, user_handle: Any,
- default_value: Optional[str] = None) -> Optional[str]:
- """Get a string setting for a specific user."""
- return default_value
-
- @staticmethod
- def putStringForUser(resolver: Any, name: str, value: str,
- user_handle: Any) -> bool:
- """Put a string setting for a specific user."""
- return True
-
- @staticmethod
- def getIntForUser(resolver: Any, name: str, user_handle: Any,
- default_value: int = 0) -> int:
- """Get an integer setting for a specific user."""
- return default_value
-
- @staticmethod
- def putIntForUser(resolver: Any, name: str, value: int,
- user_handle: Any) -> bool:
- """Put an integer setting for a specific user."""
- return True
-
- @staticmethod
- def getUriFor(name: str) -> str:
- """Get the content URI for a named setting."""
- return f"content://settings/{name}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- # Base
- "_SettingsBase",
- # System
- "SettingsSystem",
- "SYSTEM_AIRPLANE_MODE_ON", "SYSTEM_WIFI_ON", "SYSTEM_BLUETOOTH_ON",
- "SYSTEM_SCREEN_BRIGHTNESS", "SYSTEM_SCREEN_OFF_TIMEOUT",
- "SYSTEM_VOLUME_ALARM", "SYSTEM_VOLUME_MUSIC", "SYSTEM_VOLUME_RING",
- "SYSTEM_VOLUME_NOTIFICATION", "SYSTEM_VOLUME_SYSTEM",
- "SYSTEM_FONT_SCALE", "SYSTEM_HAPTIC_FEEDBACK_ENABLED",
- "SYSTEM_SOUND_EFFECTS_ENABLED", "SYSTEM_DTMF_TONE_WHEN_DIALING",
- "SYSTEM_ACCELEROMETER_ROTATION", "SYSTEM_USER_ROTATION",
- "SYSTEM_WINDOW_ANIMATION_SCALE", "SYSTEM_TRANSITION_ANIMATION_SCALE",
- "SYSTEM_ANIMATOR_DURATION_SCALE",
- # Secure
- "SettingsSecure",
- "SECURE_ADB_ENABLED", "SECURE_ALLOW_MOCK_LOCATION",
- "SECURE_INSTALL_NON_MARKET_APPS", "SECURE_ANDROID_ID",
- "SECURE_DEVICE_PROVISIONED", "SECURE_LOCATION_MODE",
- "SECURE_LOCK_PATTERN_ENABLED", "SECURE_USB_MASS_STORAGE_ENABLED",
- # Global
- "SettingsGlobal",
- "GLOBAL_AIRPLANE_MODE_ON", "GLOBAL_WIFI_ON", "GLOBAL_BLUETOOTH_ON",
- "GLOBAL_MOBILE_DATA", "GLOBAL_DATA_ROAMING", "GLOBAL_BOOT_COUNT",
- "GLOBAL_DEVICE_PROVISIONED", "GLOBAL_DEVICE_NAME",
- "GLOBAL_WINDOW_ANIMATION_SCALE", "GLOBAL_TRANSITION_ANIMATION_SCALE",
- "GLOBAL_ANIMATOR_DURATION_SCALE", "GLOBAL_WIFI_SCAN_ALWAYS_AVAILABLE",
- "GLOBAL_ZEN_MODE", "GLOBAL_STAY_ON_WHILE_PLUGGED_IN",
- "GLOBAL_LOW_POWER_MODE", "GLOBAL_AUTO_TIME", "GLOBAL_AUTO_TIME_ZONE",
- # Main
- "Settings", "NameValueTable",
- # Helpers
- "SettingsExtras", "SettingsProvider",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/renderscript.py b/android_pyapi/android/renderscript.py
deleted file mode 100644
index c86457b..0000000
--- a/android_pyapi/android/renderscript.py
+++ /dev/null
@@ -1,903 +0,0 @@
-from __future__ import annotations
-
-"""
-Android RenderScript 组件 — RenderScript, Allocation, Element, Type, Script 等
-方法签名完全对齐 Android SDK (android.renderscript 包)
-"""
-
-import math
-from typing import Any, Callable, Dict, List, Optional, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# RenderScript
-# ═══════════════════════════════════════════════════════════════
-
-class RenderScript(Stub):
- """RenderScript — RenderScript 运行时上下文 (桌面仅存根)"""
-
- # 优先级
- Priority_LOW = 0
- Priority_NORMAL = 1
- Priority_HIGH = 2
-
- # 上下文类型
- ContextType_NORMAL = 0
- ContextType_DEBUG = 1
- ContextType_PROFILE = 2
-
- def __init__(self):
- super().__init__()
- self._context_type = RenderScript.ContextType_NORMAL
- self._error_handler: Optional[Callable] = None
- self._message_handler: Optional[Callable] = None
- self._priority = RenderScript.Priority_NORMAL
- self._initialized = False
-
- @staticmethod
- def create(context: Any = None) -> "RenderScript":
- """创建 RenderScript 上下文"""
- rs = RenderScript()
- rs._initialized = True
- return rs
-
- @staticmethod
- def createMultiContext(context: Any = None,
- context_type: int = ContextType_NORMAL,
- flags: int = 0,
- api_version: int = 0) -> "RenderScript":
- """创建多上下文 RenderScript"""
- rs = RenderScript()
- rs._context_type = context_type
- rs._initialized = True
- return rs
-
- def setPriority(self, priority: int):
- """设置优先级"""
- self._priority = priority
-
- def getPriority(self) -> int:
- return self._priority
-
- def setErrorHandler(self, handler: Callable):
- """设置错误处理器"""
- self._error_handler = handler
-
- def setMessageHandler(self, handler: Callable):
- """设置消息处理器"""
- self._message_handler = handler
-
- def finish(self):
- """等待所有挂起渲染完成"""
- pass
-
- def destroy(self):
- """销毁 RenderScript 上下文"""
- self._initialized = False
-
- def getApplicationContext(self) -> Any:
- return None
-
- def getErrorHandler(self) -> Optional[Callable]:
- return self._error_handler
-
- def getMessageHandler(self) -> Optional[Callable]:
- return self._message_handler
-
- def isDestroyed(self) -> bool:
- return not self._initialized
-
- def nvLoadAll(self):
- pass
-
- def nvLoadFont(self, name: str) -> int:
- return 0
-
- def nvLoadProp(self, name: str) -> int:
- return 0
-
- def toString(self) -> str:
- return f"RenderScript(priority={self._priority}, initialized={self._initialized})"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# Element
-# ═══════════════════════════════════════════════════════════════
-
-class Element(Stub):
- """Element — RenderScript 数据类型元素"""
-
- # 预定义数据类型
- F32: "Element" = None
- F64: "Element" = None
- I8: "Element" = None
- I16: "Element" = None
- I32: "Element" = None
- I64: "Element" = None
- U8: "Element" = None
- U16: "Element" = None
- U32: "Element" = None
- U64: "Element" = None
- BOOLEAN: "Element" = None
- ALLOCATION: "Element" = None
- A_8: "Element" = None
- RGB_565: "Element" = None
- RGBA_4444: "Element" = None
- RGBA_8888: "Element" = None
- F32_2: "Element" = None
- F32_3: "Element" = None
- F32_4: "Element" = None
- F64_2: "Element" = None
- F64_3: "Element" = None
- F64_4: "Element" = None
- I8_2: "Element" = None
- I8_3: "Element" = None
- I8_4: "Element" = None
- I16_2: "Element" = None
- I16_3: "Element" = None
- I16_4: "Element" = None
- I32_2: "Element" = None
- I32_3: "Element" = None
- I32_4: "Element" = None
- I64_2: "Element" = None
- I64_3: "Element" = None
- I64_4: "Element" = None
- U8_2: "Element" = None
- U8_3: "Element" = None
- U8_4: "Element" = None
- U16_2: "Element" = None
- U16_3: "Element" = None
- U16_4: "Element" = None
- U32_2: "Element" = None
- U32_3: "Element" = None
- U32_4: "Element" = None
- U64_2: "Element" = None
- U64_3: "Element" = None
- U64_4: "Element" = None
-
- # 数据类型
- DataType = type("DataType", (), {
- "NONE": 0, "FLOAT_32": 1, "FLOAT_64": 2,
- "SIGNED_8": 3, "SIGNED_16": 4, "SIGNED_32": 5, "SIGNED_64": 6,
- "UNSIGNED_8": 7, "UNSIGNED_16": 8, "UNSIGNED_32": 9, "UNSIGNED_64": 10,
- "BOOLEAN": 11, "UNSIGNED_5_6_5": 12, "UNSIGNED_5_5_5_1": 13,
- "UNSIGNED_4_4_4_4": 14, "MATRIX_4X4": 15, "MATRIX_3X3": 16,
- "UNSIGNED_2_10_10_10": 17, "RS_ELEMENT": 18,
- })
-
- # 数据类型大小
- DataType = DataType()
-
- def __init__(self, rs: Optional[RenderScript] = None, data_type: int = 0,
- vector_size: int = 1):
- super().__init__()
- self._rs = rs
- self._data_type = data_type
- self._vector_size = vector_size
- self._element_size = self._compute_size()
-
- def _compute_size(self) -> int:
- base_sizes = {
- Element.DataType.FLOAT_32: 4, Element.DataType.FLOAT_64: 8,
- Element.DataType.SIGNED_8: 1, Element.DataType.SIGNED_16: 2,
- Element.DataType.SIGNED_32: 4, Element.DataType.SIGNED_64: 8,
- Element.DataType.UNSIGNED_8: 1, Element.DataType.UNSIGNED_16: 2,
- Element.DataType.UNSIGNED_32: 4, Element.DataType.UNSIGNED_64: 8,
- Element.DataType.BOOLEAN: 1,
- Element.DataType.UNSIGNED_5_6_5: 2,
- Element.DataType.UNSIGNED_5_5_5_1: 2,
- Element.DataType.UNSIGNED_4_4_4_4: 2,
- Element.DataType.MATRIX_4X4: 64,
- Element.DataType.MATRIX_3X3: 36,
- Element.DataType.RS_ELEMENT: 4,
- }
- return base_sizes.get(self._data_type, 4) * self._vector_size
-
- def getBytesSize(self) -> int:
- return self._element_size
-
- def getVectorSize(self) -> int:
- return self._vector_size
-
- def getDataType(self) -> int:
- return self._data_type
-
- def isCompatible(self, e: "Element") -> bool:
- return self._data_type == e._data_type and self._vector_size == e._vector_size
-
- def getSubElement(self, index: int) -> Optional["Element"]:
- return None
-
- def getSubElementCount(self) -> int:
- return 0
-
- def getSubElementArraySize(self, index: int) -> int:
- return 0
-
- def getSubElementOffsetBytes(self, index: int) -> int:
- return 0
-
- def toString(self) -> str:
- return f"Element(dataType={self._data_type}, vectorSize={self._vector_size})"
-
- def hashCode(self) -> int:
- return hash((self._data_type, self._vector_size)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Element):
- return False
- return self._data_type == other._data_type and self._vector_size == other._vector_size
-
- @staticmethod
- def BOOL(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.BOOLEAN, 1)
-
- @staticmethod
- def U8(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.UNSIGNED_8, 1)
-
- @staticmethod
- def I8(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.SIGNED_8, 1)
-
- @staticmethod
- def U16(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.UNSIGNED_16, 1)
-
- @staticmethod
- def I16(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.SIGNED_16, 1)
-
- @staticmethod
- def U32(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.UNSIGNED_32, 1)
-
- @staticmethod
- def I32(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.SIGNED_32, 1)
-
- @staticmethod
- def U64(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.UNSIGNED_64, 1)
-
- @staticmethod
- def I64(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.SIGNED_64, 1)
-
- @staticmethod
- def F32(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.FLOAT_32, 1)
-
- @staticmethod
- def F64(rs: RenderScript) -> "Element":
- return Element(rs, Element.DataType.FLOAT_64, 1)
-
- @staticmethod
- def createVector(rs: RenderScript, data_type: int, size: int) -> "Element":
- return Element(rs, data_type, size)
-
- @staticmethod
- def createPixel(rs: RenderScript, data_type: int, pixel_type: int) -> "Element":
- return Element(rs, data_type, 4)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Type
-# ═══════════════════════════════════════════════════════════════
-
-class Type(Stub):
- """Type — RenderScript 内存分配类型"""
-
- CubemapFace = type("CubemapFace", (), {
- "POSITIVE_X": 0, "NEGATIVE_X": 1,
- "POSITIVE_Y": 2, "NEGATIVE_Y": 3,
- "POSITIVE_Z": 4, "NEGATIVE_Z": 5,
- })
-
- def __init__(self, rs: Optional[RenderScript] = None,
- element: Optional[Element] = None,
- dim_x: int = 0, dim_y: int = 0, dim_z: int = 0,
- mipmaps: bool = False, faces: bool = False):
- super().__init__()
- self._rs = rs
- self._element = element
- self._dim_x = dim_x
- self._dim_y = dim_y
- self._dim_z = dim_z
- self._mipmaps = mipmaps
- self._faces = faces
- self._yuv_format = 0
-
- def getElement(self) -> Optional[Element]:
- return self._element
-
- def getX(self) -> int:
- return self._dim_x
-
- def getY(self) -> int:
- return self._dim_y
-
- def getZ(self) -> int:
- return self._dim_z
-
- def getCount(self) -> int:
- return self._dim_x * max(self._dim_y, 1) * max(self._dim_z, 1)
-
- def hasMipmaps(self) -> bool:
- return self._mipmaps
-
- def hasFaces(self) -> bool:
- return self._faces
-
- def getYuvFormat(self) -> int:
- return self._yuv_format
-
- def setYuvFormat(self, yuv_format: int):
- self._yuv_format = yuv_format
-
- def toString(self) -> str:
- return (f"Type(element={self._element}, dims={self._dim_x}x{self._dim_y}"
- f"x{self._dim_z}, mipmaps={self._mipmaps})")
-
- def hashCode(self) -> int:
- return hash((self._dim_x, self._dim_y, self._dim_z)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Type):
- return False
- return (self._dim_x == other._dim_x and self._dim_y == other._dim_y
- and self._dim_z == other._dim_z)
-
- # ── Builder ──
-
- class Builder(Stub):
- """Builder — Type 构建器"""
-
- def __init__(self, rs: RenderScript, element: Element):
- super().__init__()
- self._rs = rs
- self._element = element
- self._dim_x = 0
- self._dim_y = 0
- self._dim_z = 0
- self._mipmaps = False
- self._faces = False
- self._yuv_format = 0
-
- def setX(self, value: int) -> "Type.Builder":
- self._dim_x = value
- return self
-
- def setY(self, value: int) -> "Type.Builder":
- self._dim_y = value
- return self
-
- def setZ(self, value: int) -> "Type.Builder":
- self._dim_z = value
- return self
-
- def setMipmaps(self, enable: bool) -> "Type.Builder":
- self._mipmaps = enable
- return self
-
- def setFaces(self, enable: bool) -> "Type.Builder":
- self._faces = enable
- return self
-
- def setYuvFormat(self, yuv_format: int) -> "Type.Builder":
- self._yuv_format = yuv_format
- return self
-
- def create(self) -> Type:
- t = Type(self._rs, self._element, self._dim_x, self._dim_y,
- self._dim_z, self._mipmaps, self._faces)
- t._yuv_format = self._yuv_format
- return t
-
-
-# ═══════════════════════════════════════════════════════════════
-# Allocation
-# ═══════════════════════════════════════════════════════════════
-
-class Allocation(Stub):
- """Allocation — RenderScript 内存分配"""
-
- # 使用类型
- USAGE_SCRIPT = 0x0001
- USAGE_GRAPHICS_TEXTURE = 0x0002
- USAGE_GRAPHICS_VERTEX = 0x0004
- USAGE_GRAPHICS_CONSTANTS = 0x0008
- USAGE_GRAPHICS_RENDER_TARGET = 0x0010
- USAGE_IO_INPUT = 0x0020
- USAGE_IO_OUTPUT = 0x0040
- USAGE_SHARED = 0x0080
-
- # Mipmap 控制
- MIPMAP_FULL = 0
- MIPMAP_ON_SYNC_TO_TEXTURE = 1
-
- def __init__(self, rs: Optional[RenderScript] = None,
- type_: Optional[Type] = None,
- usage: int = USAGE_SCRIPT):
- super().__init__()
- self._rs = rs
- self._type = type_
- self._usage = usage
- self._data: Any = None
- self._element_size = type_.getElement().getBytesSize() if type_ and type_.getElement() else 0
-
- @staticmethod
- def createTyped(rs: RenderScript, type_: Type,
- usage: int = USAGE_SCRIPT) -> "Allocation":
- """创建分配"""
- alloc = Allocation(rs, type_, usage)
- total_size = type_.getCount() * type_.getElement().getBytesSize() if type_.getElement() else 0
- alloc._data = bytearray(total_size)
- return alloc
-
- @staticmethod
- def createFromBitmap(rs: RenderScript, bitmap: Any,
- usage: int = USAGE_SCRIPT) -> "Allocation":
- """从位图创建分配"""
- # 尝试获取位图尺寸
- width, height = 0, 0
- try:
- width = bitmap.getWidth() if hasattr(bitmap, 'getWidth') else 0
- height = bitmap.getHeight() if hasattr(bitmap, 'getHeight') else 0
- except Exception:
- pass
- element = Element(rs, Element.DataType.UNSIGNED_8, 4)
- type_ = Type(rs, element, width, height)
- alloc = Allocation(rs, type_, usage)
- alloc._data = bytearray(width * height * 4)
- return alloc
-
- @staticmethod
- def createFromBitmapBoxed(rs: RenderScript, bitmap: Any,
- usage: int = USAGE_SCRIPT) -> "Allocation":
- return Allocation.createFromBitmap(rs, bitmap, usage)
-
- def copyFrom(self, data: Any):
- """从数组或位图复制数据"""
- if isinstance(data, (bytes, bytearray)):
- self._data = bytearray(data)
- elif hasattr(data, '__iter__'):
- import struct
- try:
- self._data = bytearray(struct.pack(f'<{len(list(data))}f',
- *[float(v) for v in data]))
- except Exception:
- self._data = bytearray(len(list(data)) * 4)
- else:
- self._data = bytearray(1024)
-
- def copyTo(self, data: Any):
- """将数据复制到目标"""
- if isinstance(data, bytearray) and self._data:
- data[:] = self._data
- elif isinstance(data, list):
- data.clear()
- if self._data:
- for i in range(0, len(self._data), 4):
- data.append(int.from_bytes(self._data[i:i+4], 'little'))
-
- def resize(self, dim_x: int):
- """重新调整分配大小"""
- if self._type:
- self._type._dim_x = dim_x
- self._data = bytearray(self._type.getCount() * self._element_size)
-
- def getType(self) -> Optional[Type]:
- return self._type
-
- def getUsage(self) -> int:
- return self._usage
-
- def getElement(self) -> Optional[Element]:
- return self._type.getElement() if self._type else None
-
- def syncAll(self, src_location: int):
- pass
-
- def destroy(self):
- self._data = None
-
- def toString(self) -> str:
- return (f"Allocation(type={self._type}, usage={self._usage}, "
- f"data_size={len(self._data) if self._data else 0})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# Matrix4f
-# ═══════════════════════════════════════════════════════════════
-
-class Matrix4f(Stub):
- """Matrix4f — 4x4 浮点矩阵"""
-
- def __init__(self):
- super().__init__()
- self._matrix = [0.0] * 16
- self._matrix[0] = 1.0 # 单位矩阵
- self._matrix[5] = 1.0
- self._matrix[10] = 1.0
- self._matrix[15] = 1.0
-
- def getArray(self) -> List[float]:
- return list(self._matrix)
-
- def setArray(self, array: List[float]):
- if len(array) >= 16:
- self._matrix = list(array[:16])
-
- def loadIdentity(self):
- self._matrix = [0.0] * 16
- self._matrix[0] = 1.0
- self._matrix[5] = 1.0
- self._matrix[10] = 1.0
- self._matrix[15] = 1.0
-
- def load(self, src: "Matrix4f"):
- self._matrix = list(src._matrix)
-
- def loadRotate(self, rot: float, x: float, y: float, z: float):
- angle_rad = math.radians(rot)
- c = math.cos(angle_rad)
- s = math.sin(angle_rad)
- self.loadIdentity()
- if x == 1 and y == 0 and z == 0:
- self._matrix[5] = c
- self._matrix[6] = -s
- self._matrix[9] = s
- self._matrix[10] = c
- elif x == 0 and y == 1 and z == 0:
- self._matrix[0] = c
- self._matrix[2] = s
- self._matrix[8] = -s
- self._matrix[10] = c
- elif x == 0 and y == 0 and z == 1:
- self._matrix[0] = c
- self._matrix[1] = -s
- self._matrix[4] = s
- self._matrix[5] = c
-
- def loadScale(self, x: float, y: float, z: float):
- self.loadIdentity()
- self._matrix[0] = x
- self._matrix[5] = y
- self._matrix[10] = z
-
- def loadTranslate(self, x: float, y: float, z: float):
- self.loadIdentity()
- self._matrix[12] = x
- self._matrix[13] = y
- self._matrix[14] = z
-
- def loadMultiply(self, lhs: "Matrix4f", rhs: "Matrix4f"):
- for i in range(4):
- for j in range(4):
- self._matrix[i * 4 + j] = sum(
- lhs._matrix[i * 4 + k] * rhs._matrix[k * 4 + j]
- for k in range(4)
- )
-
- def multiply(self, rhs: "Matrix4f"):
- result = [0.0] * 16
- for i in range(4):
- for j in range(4):
- result[i * 4 + j] = sum(
- self._matrix[i * 4 + k] * rhs._matrix[k * 4 + j]
- for k in range(4)
- )
- self._matrix = result
-
- def transpose(self):
- for i in range(4):
- for j in range(i + 1, 4):
- self._matrix[i * 4 + j], self._matrix[j * 4 + i] = \
- self._matrix[j * 4 + i], self._matrix[i * 4 + j]
-
- def toString(self) -> str:
- rows = []
- for i in range(4):
- row = self._matrix[i*4:(i+1)*4]
- rows.append(f"[{', '.join(f'{v:.4f}' for v in row)}]")
- return f"Matrix4f({', '.join(rows)})"
-
- def hashCode(self) -> int:
- return hash(tuple(self._matrix)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Matrix4f):
- return False
- return self._matrix == other._matrix
-
-
-# ═══════════════════════════════════════════════════════════════
-# Matrix3f
-# ═══════════════════════════════════════════════════════════════
-
-class Matrix3f(Stub):
- """Matrix3f — 3x3 浮点矩阵"""
-
- def __init__(self):
- super().__init__()
- self._matrix = [0.0] * 9
- self._matrix[0] = 1.0
- self._matrix[4] = 1.0
- self._matrix[8] = 1.0
-
- def getArray(self) -> List[float]:
- return list(self._matrix)
-
- def setArray(self, array: List[float]):
- if len(array) >= 9:
- self._matrix = list(array[:9])
-
- def loadIdentity(self):
- self._matrix = [0.0] * 9
- self._matrix[0] = 1.0
- self._matrix[4] = 1.0
- self._matrix[8] = 1.0
-
- def load(self, src: "Matrix3f"):
- self._matrix = list(src._matrix)
-
- def loadMultiply(self, lhs: "Matrix3f", rhs: "Matrix3f"):
- for i in range(3):
- for j in range(3):
- self._matrix[i * 3 + j] = sum(
- lhs._matrix[i * 3 + k] * rhs._matrix[k * 3 + j]
- for k in range(3)
- )
-
- def multiply(self, rhs: "Matrix3f"):
- result = [0.0] * 9
- for i in range(3):
- for j in range(3):
- result[i * 3 + j] = sum(
- self._matrix[i * 3 + k] * rhs._matrix[k * 3 + j]
- for k in range(3)
- )
- self._matrix = result
-
- def transpose(self):
- for i in range(3):
- for j in range(i + 1, 3):
- self._matrix[i * 3 + j], self._matrix[j * 3 + i] = \
- self._matrix[j * 3 + i], self._matrix[i * 3 + j]
-
- def toString(self) -> str:
- rows = []
- for i in range(3):
- row = self._matrix[i*3:(i+1)*3]
- rows.append(f"[{', '.join(f'{v:.4f}' for v in row)}]")
- return f"Matrix3f({', '.join(rows)})"
-
- def hashCode(self) -> int:
- return hash(tuple(self._matrix)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Matrix3f):
- return False
- return self._matrix == other._matrix
-
-
-# ═══════════════════════════════════════════════════════════════
-# Script (base)
-# ═══════════════════════════════════════════════════════════════
-
-class Script(Stub):
- """Script — RenderScript 脚本基类"""
-
- def __init__(self, rs: Optional[RenderScript] = None):
- super().__init__()
- self._rs = rs
- self._kernel_groups: List[Any] = []
-
- def setVar(self, index: int, value: Any):
- """设置脚本变量"""
- pass
-
- def getVar(self, index: int) -> Any:
- return None
-
- def setTimeZone(self, timezone: str):
- pass
-
- def forEach(self, slot: int, ains: List[Allocation],
- aout: Allocation, vdata: Any = None):
- """执行 forEach 内核"""
- raise AndroidOnlyError("Script.forEach() 仅在 Android (RenderScript) 设备上可用")
-
- def invoke(self, slot: int):
- """调用可调用函数"""
- pass
-
- def bindAllocation(self, va: Allocation, slot: int):
- """绑定分配"""
- pass
-
- def destroy(self):
- pass
-
- def toString(self) -> str:
- return f"Script@{hex(id(self))}"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScriptC
-# ═══════════════════════════════════════════════════════════════
-
-class ScriptC(Script):
- """ScriptC — 编译的 RenderScript 内核脚本"""
-
- def __init__(self, rs: RenderScript, resource_id: int = 0):
- super().__init__(rs)
- self._resource_id = resource_id
-
- def toString(self) -> str:
- return f"ScriptC(resourceId={self._resource_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScriptIntrinsicBlur
-# ═══════════════════════════════════════════════════════════════
-
-class ScriptIntrinsicBlur(Script):
- """ScriptIntrinsicBlur — 高斯模糊内在函数"""
-
- def __init__(self, rs: RenderScript):
- super().__init__(rs)
- self._radius: float = 5.0
- self._input: Optional[Allocation] = None
-
- @staticmethod
- def create(rs: RenderScript, e: Element) -> "ScriptIntrinsicBlur":
- """创建模糊内在函数"""
- return ScriptIntrinsicBlur(rs)
-
- def setRadius(self, radius: float):
- """设置模糊半径"""
- self._radius = max(0.0, min(radius, 25.0))
-
- def setInput(self, alloc: Allocation):
- """设置输入分配"""
- self._input = alloc
-
- def forEach(self, aout: Allocation):
- """执行模糊"""
- if self._input and aout:
- pass # 在桌面环境不执行实际模糊
-
- def toString(self) -> str:
- return f"ScriptIntrinsicBlur(radius={self._radius})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScriptIntrinsicConvolve3x3
-# ═══════════════════════════════════════════════════════════════
-
-class ScriptIntrinsicConvolve3x3(Script):
- """ScriptIntrinsicConvolve3x3 — 3x3 卷积内在函数"""
-
- def __init__(self, rs: RenderScript):
- super().__init__(rs)
- self._coefficients: List[float] = [0.0] * 9
- self._input: Optional[Allocation] = None
-
- @staticmethod
- def create(rs: RenderScript, e: Element) -> "ScriptIntrinsicConvolve3x3":
- """创建卷积内在函数"""
- return ScriptIntrinsicConvolve3x3(rs)
-
- def setCoefficients(self, coeffs: List[float]):
- """设置卷积系数"""
- for i in range(min(len(coeffs), 9)):
- self._coefficients[i] = coeffs[i]
-
- def setInput(self, alloc: Allocation):
- """设置输入分配"""
- self._input = alloc
-
- def forEach(self, aout: Allocation):
- """执行卷积"""
- pass
-
- def toString(self) -> str:
- return f"ScriptIntrinsicConvolve3x3(coefficients={self._coefficients})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# 初始化 Element 静态实例
-# ═══════════════════════════════════════════════════════════════
-
-def _init_elements():
- """初始化 Element 预定义实例(在模块导入时调用)"""
- rs = RenderScript.create()
- Element.F32 = Element.F32(rs)
- Element.F64 = Element.F64(rs)
- Element.I8 = Element.I8(rs)
- Element.I16 = Element.I16(rs)
- Element.I32 = Element.I32(rs)
- Element.I64 = Element.I64(rs)
- Element.U8 = Element.U8(rs)
- Element.U16 = Element.U16(rs)
- Element.U32 = Element.U32(rs)
- Element.U64 = Element.U64(rs)
- Element.BOOLEAN = Element.BOOL(rs)
- Element.ALLOCATION = Element(rs, Element.DataType.RS_ELEMENT, 1)
- Element.A_8 = Element.createPixel(rs, Element.DataType.UNSIGNED_8, 1)
- Element.RGB_565 = Element.createPixel(rs, Element.DataType.UNSIGNED_5_6_5, 3)
- Element.RGBA_4444 = Element.createPixel(rs, Element.DataType.UNSIGNED_4_4_4_4, 4)
- Element.RGBA_8888 = Element.createPixel(rs, Element.DataType.UNSIGNED_8, 4)
- Element.F32_2 = Element.createVector(rs, Element.DataType.FLOAT_32, 2)
- Element.F32_3 = Element.createVector(rs, Element.DataType.FLOAT_32, 3)
- Element.F32_4 = Element.createVector(rs, Element.DataType.FLOAT_32, 4)
- Element.F64_2 = Element.createVector(rs, Element.DataType.FLOAT_64, 2)
- Element.F64_3 = Element.createVector(rs, Element.DataType.FLOAT_64, 3)
- Element.F64_4 = Element.createVector(rs, Element.DataType.FLOAT_64, 4)
- Element.I8_2 = Element.createVector(rs, Element.DataType.SIGNED_8, 2)
- Element.I8_3 = Element.createVector(rs, Element.DataType.SIGNED_8, 3)
- Element.I8_4 = Element.createVector(rs, Element.DataType.SIGNED_8, 4)
- Element.I16_2 = Element.createVector(rs, Element.DataType.SIGNED_16, 2)
- Element.I16_3 = Element.createVector(rs, Element.DataType.SIGNED_16, 3)
- Element.I16_4 = Element.createVector(rs, Element.DataType.SIGNED_16, 4)
- Element.I32_2 = Element.createVector(rs, Element.DataType.SIGNED_32, 2)
- Element.I32_3 = Element.createVector(rs, Element.DataType.SIGNED_32, 3)
- Element.I32_4 = Element.createVector(rs, Element.DataType.SIGNED_32, 4)
- Element.I64_2 = Element.createVector(rs, Element.DataType.SIGNED_64, 2)
- Element.I64_3 = Element.createVector(rs, Element.DataType.SIGNED_64, 3)
- Element.I64_4 = Element.createVector(rs, Element.DataType.SIGNED_64, 4)
- Element.U8_2 = Element.createVector(rs, Element.DataType.UNSIGNED_8, 2)
- Element.U8_3 = Element.createVector(rs, Element.DataType.UNSIGNED_8, 3)
- Element.U8_4 = Element.createVector(rs, Element.DataType.UNSIGNED_8, 4)
- Element.U16_2 = Element.createVector(rs, Element.DataType.UNSIGNED_16, 2)
- Element.U16_3 = Element.createVector(rs, Element.DataType.UNSIGNED_16, 3)
- Element.U16_4 = Element.createVector(rs, Element.DataType.UNSIGNED_16, 4)
- Element.U32_2 = Element.createVector(rs, Element.DataType.UNSIGNED_32, 2)
- Element.U32_3 = Element.createVector(rs, Element.DataType.UNSIGNED_32, 3)
- Element.U32_4 = Element.createVector(rs, Element.DataType.UNSIGNED_32, 4)
- Element.U64_2 = Element.createVector(rs, Element.DataType.UNSIGNED_64, 2)
- Element.U64_3 = Element.createVector(rs, Element.DataType.UNSIGNED_64, 3)
- Element.U64_4 = Element.createVector(rs, Element.DataType.UNSIGNED_64, 4)
-
-
-_init_elements()
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "RenderScript",
- "Allocation",
- "Element",
- "Type",
- "Script",
- "ScriptIntrinsicBlur",
- "ScriptIntrinsicConvolve3x3",
- "ScriptC",
- "Matrix4f",
- "Matrix3f",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/se.py b/android_pyapi/android/se.py
deleted file mode 100644
index 00d9366..0000000
--- a/android_pyapi/android/se.py
+++ /dev/null
@@ -1,175 +0,0 @@
-"""
-Android se 组件 — SecureElement, Session, Channel, Reader, OmapiConnection 等
-方法签名完全对齐 Android SDK (SecureElement API)
-"""
-
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# SecureElement
-# ═══════════════════════════════════════════════════════════════
-
-class SecureElement(Stub):
- """SecureElement — 安全元件"""
-
- SERVICE_INTERFACE = "android.se.SECURE_ELEMENT_SERVICE"
- EXTRA_READER = "android.se.extra.READER"
- EXTRA_READER_NAME = "android.se.extra.READER_NAME"
- EXTRA_SLOT_ID = "android.se.extra.SLOT_ID"
- EXTRA_CONNECT_RESPONSE = "android.se.extra.CONNECT_RESPONSE"
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# Reader
-# ═══════════════════════════════════════════════════════════════
-
-class Reader(Stub):
- """Reader — 安全元件读取器"""
-
- def __init__(self, name: str = "eSE"):
- super().__init__()
- self._name = name
- self._sessions: List[Session] = []
-
- def getName(self) -> str:
- return self._name
-
- def openSession(self) -> "Session":
- session = Session(self)
- self._sessions.append(session)
- return session
-
- def closeSessions(self):
- for s in self._sessions:
- s.close()
- self._sessions.clear()
-
- def isSecureElementPresent(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"Reader(name={self._name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Session
-# ═══════════════════════════════════════════════════════════════
-
-class Session(Stub):
- """Session — 安全元件会话"""
-
- def __init__(self, reader: Optional[Reader] = None):
- super().__init__()
- self._reader = reader
- self._channels: List[Channel] = []
- self._closed = False
-
- def openLogicalChannel(self, aid: bytes) -> Optional["Channel"]:
- if self._closed:
- return None
- channel = Channel(self, logical=True)
- self._channels.append(channel)
- channel._select_response = bytes([0x90, 0x00]) # SW_OK
- return channel
-
- def openBasicChannel(self, aid: bytes) -> Optional["Channel"]:
- if self._closed:
- return None
- channel = Channel(self, logical=False)
- self._channels.append(channel)
- channel._select_response = bytes([0x90, 0x00]) # SW_OK
- return channel
-
- def close(self):
- for c in self._channels:
- c.close()
- self._channels.clear()
- self._closed = True
-
- def getSessions(self) -> List["Session"]:
- return [self]
-
- def getChannels(self) -> List["Channel"]:
- return list(self._channels)
-
- def toString(self) -> str:
- return f"Session(reader={self._reader}, channels={len(self._channels)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Channel
-# ═══════════════════════════════════════════════════════════════
-
-class Channel(Stub):
- """Channel — 安全元件通道"""
-
- def __init__(self, session: Session, logical: bool = True):
- super().__init__()
- self._session = session
- self._logical = logical
- self._closed = False
- self._select_response: Optional[bytes] = None
-
- def close(self):
- self._closed = True
-
- def sendData(self, command: bytes) -> bytes:
- if self._closed:
- return bytes([0x6F, 0x00]) # No such EF
- # Simulate successful APDU response
- return bytes([0x90, 0x00])
-
- def getSelectResponse(self) -> Optional[bytes]:
- return self._select_response
-
- def getSession(self) -> Session:
- return self._session
-
- def isBasicChannel(self) -> bool:
- return not self._logical
-
- def isClosed(self) -> bool:
- return self._closed
-
- def toString(self) -> str:
- return f"Channel(logical={self._logical}, closed={self._closed})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# OmapiConnection
-# ═══════════════════════════════════════════════════════════════
-
-class OmapiConnection(Stub):
- """OmapiConnection — OMAPI 连接入口"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance(context: Any = None) -> "OmapiConnection":
- return OmapiConnection()
-
- def getReaders(self) -> List[Reader]:
- return [Reader("eSE")]
-
- def getReader(self, name: str) -> Optional[Reader]:
- return Reader(name)
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "SecureElement",
- "Reader",
- "Session",
- "Channel",
- "OmapiConnection",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/security.py b/android_pyapi/android/security.py
deleted file mode 100644
index f4a6431..0000000
--- a/android_pyapi/android/security.py
+++ /dev/null
@@ -1,182 +0,0 @@
-"""
-Android Security 组件 — KeyChain, NetworkSecurityPolicy, AppUriAuthenticationPolicy 等
-方法签名完全对齐 Android SDK (android.security 包)
-"""
-
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# KeyChain
-# ═══════════════════════════════════════════════════════════════
-
-class KeyChain(Stub):
- """KeyChain — 系统级密钥链访问 (桌面环境不可用)"""
-
- ACTION_KEYCHAIN_CHANGED = "android.security.action.KEYCHAIN_CHANGED"
- ACTION_KEY_ACCESS_CHANGED = "android.security.action.KEY_ACCESS_CHANGED"
- EXTRA_KEY_ACCESSIBLE = "android.security.extra.KEY_ACCESSIBLE"
- EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS"
- EXTRA_RESULT = "android.security.extra.RESULT"
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def createInstallIntent() -> Any:
- """创建安装证书的 Intent (Android-only)"""
- raise AndroidOnlyError("KeyChain.createInstallIntent() 仅在 Android 设备上可用")
-
- @staticmethod
- def choosePrivateKeyAlias(activity: Any, response: Any,
- keyTypes: Optional[List[str]] = None,
- issuers: Optional[List[Any]] = None,
- host: Optional[str] = None,
- port: int = -1,
- alias: Optional[str] = None):
- """选择私钥别名 (Android-only)"""
- raise AndroidOnlyError("KeyChain.choosePrivateKeyAlias() 仅在 Android 设备上可用")
-
- @staticmethod
- def isKeyAlgorithmSupported(algorithm: str) -> bool:
- """检查密钥算法是否支持"""
- supported = {"RSA", "EC", "DSA", "AES", "HmacSHA256", "HmacSHA1"}
- return algorithm in supported
-
- @staticmethod
- def isBoundKeyAlgorithm(algorithm: str) -> bool:
- """检查是否是绑定到硬件的密钥算法 (桌面环境不支持)"""
- return False
-
- @staticmethod
- def getPrivateKey(context: Any, alias: str) -> Any:
- """获取私钥 (Android-only)"""
- raise AndroidOnlyError("KeyChain.getPrivateKey() 仅在 Android 设备上可用")
-
- @staticmethod
- def getCertificateChain(context: Any, alias: str) -> Optional[List[Any]]:
- """获取证书链 (Android-only)"""
- raise AndroidOnlyError("KeyChain.getCertificateChain() 仅在 Android 设备上可用")
-
- def toString(self) -> str:
- return "KeyChain(desktop-stub)"
-
- def hashCode(self) -> int:
- return hash("android.security.KeyChain") & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return isinstance(other, KeyChain)
-
-
-# ═══════════════════════════════════════════════════════════════
-# AppUriAuthenticationPolicy
-# ═══════════════════════════════════════════════════════════════
-
-class AppUriAuthenticationPolicy(Stub):
- """AppUriAuthenticationPolicy — URI 认证策略 (Android 11+)"""
-
- def __init__(self):
- super().__init__()
- self._rules: Dict[str, List[str]] = {}
-
- def addAppAndUriMapping(self, app: Any, uri: Any, alias: str):
- """添加应用与 URI 映射"""
- app_pkg = str(app) if app else ""
- uri_str = str(uri) if uri else ""
- if app_pkg not in self._rules:
- self._rules[app_pkg] = []
- self._rules[app_pkg].append(uri_str)
-
- def getAppAndUriMappings(self) -> Dict[str, List[str]]:
- """获取所有规则映射"""
- return dict(self._rules)
-
- def toString(self) -> str:
- return f"AppUriAuthenticationPolicy(rules={self._rules})"
-
- def hashCode(self) -> int:
- return hash(str(self._rules)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, AppUriAuthenticationPolicy):
- return False
- return self._rules == other._rules
-
-
-# ═══════════════════════════════════════════════════════════════
-# KeyChainAliasResponse
-# ═══════════════════════════════════════════════════════════════
-
-class KeyChainAliasResponse(Stub):
- """KeyChainAliasResponse — 密钥别名选择响应"""
-
- def __init__(self, alias: Optional[str] = None):
- super().__init__()
- self._alias = alias
-
- def getAlias(self) -> Optional[str]:
- """获取选定的密钥别名"""
- return self._alias
-
- def toString(self) -> str:
- return f"KeyChainAliasResponse(alias={self._alias})"
-
- def hashCode(self) -> int:
- return hash(self._alias) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, KeyChainAliasResponse):
- return False
- return self._alias == other._alias
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkSecurityPolicy
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkSecurityPolicy(Stub):
- """NetworkSecurityPolicy — 网络安全策略"""
-
- _instance: Optional["NetworkSecurityPolicy"] = None
-
- def __init__(self):
- super().__init__()
- self._cleartext_permitted = True
-
- @staticmethod
- def getInstance() -> "NetworkSecurityPolicy":
- """获取全局 NetworkSecurityPolicy 实例"""
- if NetworkSecurityPolicy._instance is None:
- NetworkSecurityPolicy._instance = NetworkSecurityPolicy()
- return NetworkSecurityPolicy._instance
-
- def isCleartextTrafficPermitted(self, host: Optional[str] = None) -> bool:
- """检查是否允许明文流量 (桌面默认允许)"""
- return self._cleartext_permitted
-
- def setCleartextTrafficPermitted(self, permitted: bool):
- """设置是否允许明文流量"""
- self._cleartext_permitted = permitted
-
- def toString(self) -> str:
- return f"NetworkSecurityPolicy(cleartextPermitted={self._cleartext_permitted})"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "KeyChain",
- "AppUriAuthenticationPolicy",
- "KeyChainAliasResponse",
- "NetworkSecurityPolicy",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/service_autofill.py b/android_pyapi/android/service_autofill.py
deleted file mode 100644
index 393a1f5..0000000
--- a/android_pyapi/android/service_autofill.py
+++ /dev/null
@@ -1,423 +0,0 @@
-from __future__ import annotations
-
-"""
-Android Service Autofill 组件 — AutofillService, FillRequest, FillResponse,
-SaveRequest, SaveInfo, Dataset, AutofillFieldClassificationService 等
-方法签名完全对齐 Android SDK (android.service.autofill 包)
-"""
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# FillRequest
-# ═══════════════════════════════════════════════════════════════
-
-class FillRequest(Stub):
- """FillRequest — 自动填充请求"""
-
- # 请求标志
- FLAG_MANUAL_REQUEST = 0x0001
- FLAG_COMPATIBILITY_MODE_REQUEST = 0x0002
-
- def __init__(self, request_id: int = 0, flags: int = 0,
- fill_contexts: Optional[List[Any]] = None):
- super().__init__()
- self._request_id = request_id
- self._flags = flags
- self._fill_contexts = fill_contexts or []
- self._client_state: Optional[Any] = None
-
- def getId(self) -> int:
- """获取请求 ID"""
- return self._request_id
-
- def getFlags(self) -> int:
- """获取标志"""
- return self._flags
-
- def getFillContexts(self) -> List[Any]:
- """获取填充上下文"""
- return list(self._fill_contexts)
-
- def getClientState(self) -> Optional[Any]:
- return self._client_state
-
- def setClientState(self, state: Any):
- self._client_state = state
-
- def toString(self) -> str:
- return (f"FillRequest(id={self._request_id}, "
- f"flags={self._flags}, contexts={len(self._fill_contexts)})")
-
- def hashCode(self) -> int:
- return self._request_id & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, FillRequest):
- return False
- return self._request_id == other._request_id
-
-
-# ═══════════════════════════════════════════════════════════════
-# Dataset
-# ═══════════════════════════════════════════════════════════════
-
-class Dataset(Stub):
- """Dataset — 自动填充数据集"""
-
- def __init__(self):
- super().__init__()
- self._field_values: Dict[Any, Any] = {}
- self._id: Optional[Any] = None
- self._authentication: Optional[Any] = None
-
- def getFieldValues(self) -> Dict[Any, Any]:
- return dict(self._field_values)
-
- def getId(self) -> Optional[Any]:
- return self._id
-
- def setId(self, id: Any):
- self._id = id
-
- def toString(self) -> str:
- return f"Dataset(fields={len(self._field_values)}, id={self._id})"
-
- def hashCode(self) -> int:
- return hash(str(self._id)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Dataset):
- return False
- return self._id == other._id
-
- # ── Builder ──
-
- class Builder(Stub):
- """Builder — Dataset 构建器"""
-
- def __init__(self):
- super().__init__()
- self._dataset = Dataset()
-
- def setId(self, id: Any) -> "Dataset.Builder":
- self._dataset._id = id
- return self
-
- def setValue(self, id: Any, value: Any) -> "Dataset.Builder":
- self._dataset._field_values[id] = value
- return self
-
- def setAuthentication(self, authentication: Any) -> "Dataset.Builder":
- self._dataset._authentication = authentication
- return self
-
- def build(self) -> Dataset:
- return self._dataset
-
-
-# ═══════════════════════════════════════════════════════════════
-# SaveInfo
-# ═══════════════════════════════════════════════════════════════
-
-class SaveInfo(Stub):
- """SaveInfo — 保存信息"""
-
- # 保存类型
- SAVE_DATA_TYPE_EMAIL = 0x0001
- SAVE_DATA_TYPE_PASSWORD = 0x0002
- SAVE_DATA_TYPE_USERNAME = 0x0004
- SAVE_DATA_TYPE_CREDIT_CARD = 0x0008
- SAVE_DATA_TYPE_ADDRESS = 0x0010
- SAVE_DATA_TYPE_GENERIC = 0x0020
- SAVE_DATA_TYPE_PASSWORD_V2 = 0x0040
- SAVE_DATA_TYPE_SMS_2FA = 0x0080
- SAVE_DATA_TYPE_BIRTH_DATE = 0x0100
- SAVE_DATA_TYPE_EMAIL_ADDRESS = 0x0200
- SAVE_DATA_TYPE_PHONE = 0x0400
- SAVE_DATA_TYPE_USERNAME_V2 = 0x0800
- SAVE_DATA_TYPE_CARD_NUMBER = 0x1000
- SAVE_DATA_TYPE_CARD_EXPIRATION_DATE = 0x2000
- SAVE_DATA_TYPE_CARD_SECURITY_CODE = 0x4000
- SAVE_DATA_TYPE_FI_ACCOUNT_NUMBER = 0x8000
- SAVE_DATA_TYPE_FI_ROUTING_NUMBER = 0x10000
- SAVE_DATA_TYPE_PASSPORT = 0x20000
- SAVE_DATA_TYPE_DRIVERS_LICENSE = 0x40000
- SAVE_DATA_TYPE_SSN = 0x80000
-
- # 标志
- FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 0x0001
-
- def __init__(self):
- super().__init__()
- self._type: int = SaveInfo.SAVE_DATA_TYPE_GENERIC
- self._required_ids: List[Any] = []
- self._optional_ids: List[Any] = []
- self._description: Optional[Any] = None
- self._flags: int = 0
- self._trigger_ids: List[Any] = []
- self._validator: Optional[Any] = None
-
- def getType(self) -> int:
- return self._type
-
- def getRequiredIds(self) -> List[Any]:
- return list(self._required_ids)
-
- def getOptionalIds(self) -> List[Any]:
- return list(self._optional_ids)
-
- def getDescription(self) -> Optional[Any]:
- return self._description
-
- def getFlags(self) -> int:
- return self._flags
-
- def toString(self) -> str:
- return (f"SaveInfo(type={self._type}, required={len(self._required_ids)}, "
- f"optional={len(self._optional_ids)})")
-
- def hashCode(self) -> int:
- return hash((self._type, tuple(self._required_ids))) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, SaveInfo):
- return False
- return self._type == other._type
-
- # ── Builder ──
-
- class Builder(Stub):
- """Builder — SaveInfo 构建器"""
-
- def __init__(self, type_: int, required_ids: List[Any]):
- super().__init__()
- self._save_info = SaveInfo()
- self._save_info._type = type_
- self._save_info._required_ids = list(required_ids)
-
- def setOptionalIds(self, optional_ids: List[Any]) -> "SaveInfo.Builder":
- self._save_info._optional_ids = list(optional_ids)
- return self
-
- def setDescription(self, description: Any) -> "SaveInfo.Builder":
- self._save_info._description = description
- return self
-
- def setFlags(self, flags: int) -> "SaveInfo.Builder":
- self._save_info._flags = flags
- return self
-
- def setTriggerIds(self, trigger_ids: List[Any]) -> "SaveInfo.Builder":
- self._save_info._trigger_ids = list(trigger_ids)
- return self
-
- def setValidator(self, validator: Any) -> "SaveInfo.Builder":
- self._save_info._validator = validator
- return self
-
- def build(self) -> SaveInfo:
- return self._save_info
-
-
-# ═══════════════════════════════════════════════════════════════
-# FillResponse
-# ═══════════════════════════════════════════════════════════════
-
-class FillResponse(Stub):
- """FillResponse — 自动填充响应"""
-
- def __init__(self):
- super().__init__()
- self._datasets: List[Dataset] = []
- self._save_info: Optional[SaveInfo] = None
- self._client_state: Optional[Any] = None
- self._authentication_result: Optional[Any] = None
-
- def getDatasets(self) -> List[Dataset]:
- return list(self._datasets)
-
- def getSaveInfo(self) -> Optional[SaveInfo]:
- return self._save_info
-
- def getClientState(self) -> Optional[Any]:
- return self._client_state
-
- def toString(self) -> str:
- return (f"FillResponse(datasets={len(self._datasets)}, "
- f"saveInfo={'set' if self._save_info else 'none'})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
- # ── Builder ──
-
- class Builder(Stub):
- """Builder — FillResponse 构建器"""
-
- def __init__(self):
- super().__init__()
- self._response = FillResponse()
-
- def addDataset(self, dataset: Dataset) -> "FillResponse.Builder":
- self._response._datasets.append(dataset)
- return self
-
- def setDatasets(self, datasets: List[Dataset]) -> "FillResponse.Builder":
- self._response._datasets = list(datasets)
- return self
-
- def setSaveInfo(self, save_info: SaveInfo) -> "FillResponse.Builder":
- self._response._save_info = save_info
- return self
-
- def setClientState(self, client_state: Any) -> "FillResponse.Builder":
- self._response._client_state = client_state
- return self
-
- def setAuthenticationResult(self, result: Any) -> "FillResponse.Builder":
- self._response._authentication_result = result
- return self
-
- def build(self) -> FillResponse:
- return self._response
-
-
-# ═══════════════════════════════════════════════════════════════
-# SaveRequest
-# ═══════════════════════════════════════════════════════════════
-
-class SaveRequest(Stub):
- """SaveRequest — 保存请求"""
-
- def __init__(self, request_id: int = 0,
- client_state: Optional[Any] = None,
- fill_contexts: Optional[List[Any]] = None):
- super().__init__()
- self._request_id = request_id
- self._client_state = client_state
- self._fill_contexts = fill_contexts or []
-
- def getId(self) -> int:
- return self._request_id
-
- def getClientState(self) -> Optional[Any]:
- return self._client_state
-
- def getFillContexts(self) -> List[Any]:
- return list(self._fill_contexts)
-
- def toString(self) -> str:
- return (f"SaveRequest(id={self._request_id}, "
- f"contexts={len(self._fill_contexts)})")
-
- def hashCode(self) -> int:
- return self._request_id & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, SaveRequest):
- return False
- return self._request_id == other._request_id
-
-
-# ═══════════════════════════════════════════════════════════════
-# AutofillService
-# ═══════════════════════════════════════════════════════════════
-
-class AutofillService(Stub):
- """AutofillService — 自动填充服务"""
-
- SERVICE_INTERFACE = "android.service.autofill.AutofillService"
- SERVICE_META_DATA = "android.autofill"
-
- def __init__(self):
- super().__init__()
-
- def onFillRequest(self, request: FillRequest,
- cancellation_signal: Any,
- callback: Any):
- """填充请求回调"""
- response = FillResponse()
- if callback and hasattr(callback, 'onSuccess'):
- callback.onSuccess(response)
-
- def onSaveRequest(self, request: SaveRequest, callback: Any):
- """保存请求回调"""
- if callback and hasattr(callback, 'onSuccess'):
- callback.onSuccess()
-
- def onConnected(self):
- """服务已连接"""
- pass
-
- def onDisconnected(self):
- """服务已断开"""
- pass
-
- def onUnbind(self, intent: Any) -> bool:
- return False
-
- def toString(self) -> str:
- return f"AutofillService@{hex(id(self))}"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# AutofillFieldClassificationService
-# ═══════════════════════════════════════════════════════════════
-
-class AutofillFieldClassificationService(Stub):
- """AutofillFieldClassificationService — 自动填充字段分类服务"""
-
- SERVICE_INTERFACE = (
- "android.service.autofill.AutofillFieldClassificationService"
- )
-
- def __init__(self):
- super().__init__()
-
- def onConnected(self):
- pass
-
- def onDisconnected(self):
- pass
-
- def onClassificationRequest(self, request: Any, callback: Any):
- if callback and hasattr(callback, 'onSuccess'):
- callback.onSuccess(None)
-
- def toString(self) -> str:
- return f"AutofillFieldClassificationService@{hex(id(self))}"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "AutofillService",
- "FillRequest",
- "FillResponse",
- "SaveRequest",
- "SaveInfo",
- "Dataset",
- "AutofillFieldClassificationService",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/service_controls.py b/android_pyapi/android/service_controls.py
deleted file mode 100644
index 8a1e45c..0000000
--- a/android_pyapi/android/service_controls.py
+++ /dev/null
@@ -1,350 +0,0 @@
-"""
-Android Service Controls 组件 — ControlsProviderService, Control, DeviceTypes,
-StatefulControl, StatelessControl 等
-方法签名完全对齐 Android SDK (android.service.controls 包)
-"""
-
-from typing import Any, Callable, Dict, List, Optional, Set
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# DeviceTypes
-# ═══════════════════════════════════════════════════════════════
-
-class DeviceTypes(Stub):
- """DeviceTypes — 设备类型常量"""
-
- TYPE_AC_HEATER = "AC_HEATER"
- TYPE_AC_UNIT = "AC_UNIT"
- TYPE_AIR_FRESHENER = "AIR_FRESHENER"
- TYPE_AIR_PURIFIER = "AIR_PURIFIER"
- TYPE_BLINDS = "BLINDS"
- TYPE_CAMERA = "CAMERA"
- TYPE_CLOSET = "CLOSET"
- TYPE_COFFEE_MAKER = "COFFEE_MAKER"
- TYPE_CURTAIN = "CURTAIN"
- TYPE_DEHUMIDIFIER = "DEHUMIDIFIER"
- TYPE_DISHWASHER = "DISHWASHER"
- TYPE_DISPLAY = "DISPLAY"
- TYPE_DOOR = "DOOR"
- TYPE_DOORBELL = "DOORBELL"
- TYPE_DRAWER = "DRAWER"
- TYPE_DRYER = "DRYER"
- TYPE_FAN = "FAN"
- TYPE_GARAGE = "GARAGE"
- TYPE_GATE = "GATE"
- TYPE_HEATER = "HEATER"
- TYPE_HOOD = "HOOD"
- TYPE_HUMIDIFIER = "HUMIDIFIER"
- TYPE_KETTLE = "KETTLE"
- TYPE_LIGHT = "LIGHT"
- TYPE_LIGHTBULB = "LIGHTBULB"
- TYPE_LOCK = "LOCK"
- TYPE_MICROWAVE = "MICROWAVE"
- TYPE_MOP = "MOP"
- TYPE_MOWER = "MOWER"
- TYPE_MULTICOOKER = "MULTICOOKER"
- TYPE_OUTLET = "OUTLET"
- TYPE_OVEN = "OVEN"
- TYPE_PERGOLLA = "PERGOLLA"
- TYPE_RADIATOR = "RADIATOR"
- TYPE_REFRIGERATOR = "REFRIGERATOR"
- TYPE_REMOTE_STAND = "REMOTE_STAND"
- TYPE_RICE_COOKER = "RICE_COOKER"
- TYPE_ROUTINE = "ROUTINE"
- TYPE_SCENE = "SCENE"
- TYPE_SECURITY_SYSTEM = "SECURITY_SYSTEM"
- TYPE_SET_TOP = "SET_TOP"
- TYPE_SHOWER = "SHOWER"
- TYPE_SHUTTER = "SHUTTER"
- TYPE_SMOKE_DETECTOR = "SMOKE_DETECTOR"
- TYPE_SOUNDBAR = "SOUNDBAR"
- TYPE_SPRINKLER = "SPRINKLER"
- TYPE_STANDMIXER = "STANDMIXER"
- TYPE_THERMOSTAT = "THERMOSTAT"
- TYPE_TV = "TV"
- TYPE_VACUUM = "VACUUM"
- TYPE_VALVE = "VALVE"
- TYPE_WASHER = "WASHER"
- TYPE_WATER_HEATER = "WATER_HEATER"
- TYPE_WINDOW = "WINDOW"
- TYPE_WINE_COOLER = "WINE_COOLER"
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# Control
-# ═══════════════════════════════════════════════════════════════
-
-class Control(Stub):
- """Control — 设备控件基类"""
-
- # 状态
- STATUS_UNKNOWN = 0
- STATUS_OK = 1
- STATUS_NOT_RESPONDING = 2
- STATUS_ERROR = 3
- STATUS_FIRMWARE_UPDATE = 4
-
- def __init__(self, control_id: str, title: str,
- subtitle: str, device_type: str):
- super().__init__()
- self._control_id = control_id
- self._title = title
- self._subtitle = subtitle
- self._device_type = device_type
- self._status = Control.STATUS_OK
- self._status_text: str = ""
- self._custom_icon: Optional[Any] = None
- self._custom_color: int = 0
- self._is_auth_required: bool = False
- self._structure: str = ""
- self._zone: str = ""
- self._is_favorite: bool = False
- self._device_types_list: List[str] = [device_type]
- self._parent_id: Optional[str] = None
-
- def getControlId(self) -> str:
- """获取控件 ID"""
- return self._control_id
-
- def getTitle(self) -> str:
- """获取标题"""
- return self._title
-
- def getSubtitle(self) -> str:
- """获取副标题"""
- return self._subtitle
-
- def getDeviceType(self) -> str:
- """获取设备类型"""
- return self._device_type
-
- def getStatus(self) -> int:
- return self._status
-
- def setStatus(self, status: int):
- self._status = status
-
- def getStatusText(self) -> str:
- return self._status_text
-
- def setStatusText(self, status_text: str):
- self._status_text = status_text
-
- def getStructure(self) -> str:
- return self._structure
-
- def setStructure(self, structure: str):
- self._structure = structure
-
- def getZone(self) -> str:
- return self._zone
-
- def setZone(self, zone: str):
- self._zone = zone
-
- def isFavorite(self) -> bool:
- return self._is_favorite
-
- def setFavorite(self, favorite: bool):
- self._is_favorite = favorite
-
- def toString(self) -> str:
- return (f"Control(id={self._control_id}, title={self._title}, "
- f"type={self._device_type}, status={self._status})")
-
- def hashCode(self) -> int:
- return hash(self._control_id) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Control):
- return False
- return self._control_id == other._control_id
-
-
-# ═══════════════════════════════════════════════════════════════
-# StatefulControl
-# ═══════════════════════════════════════════════════════════════
-
-class StatefulControl(Control):
- """StatefulControl — 有状态控件"""
-
- def __init__(self, control_id: str, title: str,
- subtitle: str, device_type: str):
- super().__init__(control_id, title, subtitle, device_type)
- self._current_value: Any = None
- self._min_value: Optional[float] = None
- self._max_value: Optional[float] = None
- self._step: Optional[float] = None
- self._unit: Optional[str] = None
- self._is_on: bool = False
- self._mode: str = ""
-
- def setStatus(self, status: int) -> "StatefulControl":
- """设置状态"""
- self._status = status
- return self
-
- def setStatusText(self, status_text: str) -> "StatefulControl":
- """设置状态文本"""
- self._status_text = status_text
- return self
-
- def getCurrentValue(self) -> Any:
- return self._current_value
-
- def setCurrentValue(self, value: Any) -> "StatefulControl":
- self._current_value = value
- return self
-
- def getMinValue(self) -> Optional[float]:
- return self._min_value
-
- def setMinValue(self, min_value: float) -> "StatefulControl":
- self._min_value = min_value
- return self
-
- def getMaxValue(self) -> Optional[float]:
- return self._max_value
-
- def setMaxValue(self, max_value: float) -> "StatefulControl":
- self._max_value = max_value
- return self
-
- def getStep(self) -> Optional[float]:
- return self._step
-
- def setStep(self, step: float) -> "StatefulControl":
- self._step = step
- return self
-
- def isOn(self) -> bool:
- return self._is_on
-
- def setOn(self, is_on: bool) -> "StatefulControl":
- self._is_on = is_on
- return self
-
- def getMode(self) -> str:
- return self._mode
-
- def setMode(self, mode: str) -> "StatefulControl":
- self._mode = mode
- return self
-
- def toString(self) -> str:
- return (f"StatefulControl(id={self._control_id}, title={self._title}, "
- f"type={self._device_type}, on={self._is_on}, "
- f"value={self._current_value})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# StatelessControl
-# ═══════════════════════════════════════════════════════════════
-
-class StatelessControl(Control):
- """StatelessControl — 无状态控件"""
-
- def __init__(self, control_id: str, title: str,
- subtitle: str, device_type: str):
- super().__init__(control_id, title, subtitle, device_type)
- self._action_text: str = ""
-
- def getActionText(self) -> str:
- return self._action_text
-
- def setActionText(self, action_text: str) -> "StatelessControl":
- self._action_text = action_text
- return self
-
- def toString(self) -> str:
- return (f"StatelessControl(id={self._control_id}, "
- f"title={self._title}, type={self._device_type})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ControlsProviderService
-# ═══════════════════════════════════════════════════════════════
-
-class ControlsProviderService(Stub):
- """ControlsProviderService — 控件提供者服务"""
-
- SERVICE_INTERFACE = "android.service.controls.ControlsProviderService"
-
- # 控件类型
- CONTROL_TYPE_TOGGLE = 1
- CONTROL_TYPE_RANGE = 2
- CONTROL_TYPE_STATELESS = 3
- CONTROL_TYPE_BUTTON = 4
-
- def __init__(self):
- super().__init__()
- self._controls: Dict[str, Control] = {}
- self._publishers: Dict[str, Any] = {}
- self._subscribers: Dict[str, Any] = {}
-
- def onCreatePublisherFor(self, control_ids: List[str]) -> Any:
- """为指定控件创建发布者"""
- publisher = type("Publisher", (), {
- "onUnsubscribe": lambda: None,
- "onRequest": lambda cid: None,
- })()
- for cid in control_ids:
- self._publishers[cid] = publisher
- return publisher
-
- def onGetSubscriberFor(self, control_ids: List[str]) -> Any:
- """获取控件订阅者"""
- subscriber = type("Subscriber", (), {
- "onSubscribe": lambda cid: None,
- "onUnsubscribe": lambda cid: None,
- })()
- for cid in control_ids:
- self._subscribers[cid] = subscriber
- return subscriber
-
- def publishControls(self, control_ids: List[str], controls: List[Control]):
- """发布控件状态"""
- for control in controls:
- self._controls[control.getControlId()] = control
-
- def addControl(self, control: Control):
- """添加控件"""
- self._controls[control.getControlId()] = control
-
- def removeControl(self, control_id: str):
- """移除控件"""
- self._controls.pop(control_id, None)
-
- def getControl(self, control_id: str) -> Optional[Control]:
- return self._controls.get(control_id)
-
- def getControls(self) -> List[Control]:
- return list(self._controls.values())
-
- def toString(self) -> str:
- return f"ControlsProviderService(controls={len(self._controls)})"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "ControlsProviderService",
- "Control",
- "DeviceTypes",
- "StatefulControl",
- "StatelessControl",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/service_dreams.py b/android_pyapi/android/service_dreams.py
deleted file mode 100644
index 0248fa2..0000000
--- a/android_pyapi/android/service_dreams.py
+++ /dev/null
@@ -1,140 +0,0 @@
-"""
-Android Service Dreams 组件 — DreamService 等
-方法签名完全对齐 Android SDK (android.service.dreams 包)
-"""
-
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# DreamService
-# ═══════════════════════════════════════════════════════════════
-
-class DreamService(Stub):
- """DreamService — 屏保服务基类"""
-
- # 服务接口
- SERVICE_INTERFACE = "android.service.dreams.DreamService"
- SERVICE_META_DATA = "android.service.dream"
-
- # 退出原因
- EXIT_CAUSE_UNKNOWN = 0
- EXIT_CAUSE_TIMEOUT = 1
- EXIT_CAUSE_USER = 2
- EXIT_CAUSE_DREAM_FINISHED = 3
-
- def __init__(self):
- super().__init__()
- self._fullscreen: bool = False
- self._interactive: bool = False
- self._dreaming: bool = False
- self._window: Optional[Any] = None
- self._content_view: Optional[Any] = None
- self._exit_cause: int = DreamService.EXIT_CAUSE_UNKNOWN
- self._created: bool = False
- self._screen_bright: bool = True
- self._doze_component: Optional[Any] = None
- self._doze_mode: bool = False
- self._debug: bool = False
-
- def setContentView(self, view: Any):
- """设置内容视图"""
- self._content_view = view
-
- def getContentView(self) -> Optional[Any]:
- return self._content_view
-
- def setFullscreen(self, fullscreen: bool):
- """设置全屏模式"""
- self._fullscreen = fullscreen
-
- def isFullscreen(self) -> bool:
- """检查是否全屏"""
- return self._fullscreen
-
- def isInteractive(self) -> bool:
- """检查是否可交互"""
- return self._interactive
-
- def setInteractive(self, interactive: bool):
- """设置可交互"""
- self._interactive = interactive
-
- def getWindow(self) -> Optional[Any]:
- """获取窗口"""
- return self._window
-
- def startDream(self):
- """开始屏保"""
- self._dreaming = True
-
- def awaken(self):
- """唤醒/结束屏保"""
- self._dreaming = False
-
- def onDreamingStarted(self):
- """屏保开始时回调"""
- self._dreaming = True
-
- def onDreamingStopped(self):
- """屏保停止时回调"""
- self._dreaming = False
-
- def onCreate(self):
- """创建时回调"""
- self._created = True
-
- def onDestroy(self):
- """销毁时回调"""
- self._created = False
- self._dreaming = False
-
- def onAttachedToWindow(self):
- """附加到窗口时回调"""
- pass
-
- def onDetachedFromWindow(self):
- """从窗口分离时回调"""
- pass
-
- def isDreaming(self) -> bool:
- """检查是否正在运行屏保"""
- return self._dreaming
-
- def getExitCause(self) -> int:
- return self._exit_cause
-
- def setExitCause(self, cause: int):
- self._exit_cause = cause
-
- def onWakeUp(self):
- """唤醒回调"""
- self.awaken()
-
- def canDoze(self) -> bool:
- return self._doze_mode
-
- def setDozeComponent(self, component: Any):
- self._doze_component = component
-
- def toString(self) -> str:
- return (f"DreamService(dreaming={self._dreaming}, "
- f"fullscreen={self._fullscreen}, "
- f"interactive={self._interactive})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "DreamService",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/service_media.py b/android_pyapi/android/service_media.py
deleted file mode 100644
index a974e71..0000000
--- a/android_pyapi/android/service_media.py
+++ /dev/null
@@ -1,812 +0,0 @@
-"""
-Android Media Service 组件 — MediaBrowserService, MediaSessionService, BrowserRoot, Result 等
-方法签名完全对齐 Android SDK (android.service.media 包)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# Result
-# ═══════════════════════════════════════════════════════════════
-
-class Result(Stub):
- """Result — 异步操作结果"""
-
- FLAG_OPTION_NOT_KNOWN = 0
- FLAG_OPTION_FOUND = 1
- FLAG_OPTION_NOT_FOUND = 2
- FLAG_OPTION_ERROR = 4
-
- def __init__(self, result_type: Any = None):
- super().__init__()
- self._result_type = result_type
- self._result: Any = None
- self._flags: int = Result.FLAG_OPTION_NOT_KNOWN
- self._is_done: bool = False
- self._is_sent: bool = False
- self._error: Optional[str] = None
-
- def getResult(self) -> Any:
- return self._result
-
- def setResult(self, result: Any):
- self._result = result
-
- def getFlags(self) -> int:
- return self._flags
-
- def setFlags(self, flags: int):
- self._flags = flags
-
- def isDone(self) -> bool:
- return self._is_done
-
- def isSent(self) -> bool:
- return self._is_sent
-
- def getError(self) -> Optional[str]:
- return self._error
-
- def sendResult(self, result: Any):
- """发送结果"""
- self._result = result
- self._is_done = True
- self._is_sent = True
-
- def sendError(self, error: str):
- """发送错误"""
- self._error = error
- self._is_done = True
- self._is_sent = True
- self._flags = Result.FLAG_OPTION_ERROR
-
- def onResultSent(self, result: Any, flags: int = 0):
- """结果已发送回调"""
- self._result = result
- self._flags = flags
- self._is_done = True
-
- def toString(self) -> str:
- return f"Result(done={self._is_done}, sent={self._is_sent})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# BrowserRoot
-# ═══════════════════════════════════════════════════════════════
-
-class BrowserRoot(Stub):
- """BrowserRoot — 媒体浏览根节点"""
-
- EXTRA_RECENT = "android.service.media.extra.RECENT"
- EXTRA_OFFLINE = "android.service.media.extra.OFFLINE"
- EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED"
- EXTRA_EMPTY_ROOT_ALLOWED = "android.service.media.extra.EMPTY_ROOT_ALLOWED"
- EXTRA_RECYCLERVIEW = "android.service.media.extra.RECYCLERVIEW"
-
- def __init__(self, root_id: str = "", extras: Any = None):
- super().__init__()
- self._root_id = root_id
- self._extras = extras
- self._title: str = ""
- self._is_visible: bool = True
- self._is_playable: bool = False
- self._is_browsable: bool = True
- self._children: List[MediaBrowserService.BrowserRoot] = []
- self._icon_uri: str = ""
- self._subtitle: str = ""
- self._description: str = ""
-
- def getRootId(self) -> str:
- return self._root_id
-
- def setRootId(self, root_id: str):
- self._root_id = root_id
-
- def getExtras(self) -> Any:
- return self._extras
-
- def setExtras(self, extras: Any):
- self._extras = extras
-
- def getTitle(self) -> str:
- return self._title
-
- def setTitle(self, title: str):
- self._title = title
-
- def isVisible(self) -> bool:
- return self._is_visible
-
- def setVisible(self, visible: bool):
- self._is_visible = visible
-
- def isPlayable(self) -> bool:
- return self._is_playable
-
- def setPlayable(self, playable: bool):
- self._is_playable = playable
-
- def isBrowsable(self) -> bool:
- return self._is_browsable
-
- def setBrowsable(self, browsable: bool):
- self._is_browsable = browsable
-
- def getIconUri(self) -> str:
- return self._icon_uri
-
- def setIconUri(self, uri: str):
- self._icon_uri = uri
-
- def getSubtitle(self) -> str:
- return self._subtitle
-
- def setSubtitle(self, subtitle: str):
- self._subtitle = subtitle
-
- def getDescription(self) -> str:
- return self._description
-
- def setDescription(self, desc: str):
- self._description = desc
-
- def toString(self) -> str:
- return f"BrowserRoot(rootId={self._root_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaBrowserService
-# ═══════════════════════════════════════════════════════════════
-
-class MediaBrowserService(Stub):
- """MediaBrowserService — 媒体浏览服务"""
-
- SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"
- SERVICE_META_DATA = "android.media.browse"
-
- KEY_MEDIA_ITEM = "media_item"
- KEY_SEARCH_RESULTS = "search_results"
- KEY_ERROR = "error"
- KEY_MEDIA_ROOT = "media_root"
- KEY_RECENT = "recent"
- KEY_OFFLINE = "offline"
- KEY_SUGGESTED = "suggested"
- KEY_EMPTY_ROOT_ALLOWED = "empty_root_allowed"
- KEY_PAGE = "page"
- KEY_PAGE_SIZE = "page_size"
-
- # ═══════════════════════════════════════════════════════
- # BrowserRoot (inner class)
- # ═══════════════════════════════════════════════════════
-
- class BrowserRoot(Stub):
- """MediaBrowserService.BrowserRoot — 浏览根节点"""
-
- EXTRA_RECENT = "android.service.media.extra.RECENT"
- EXTRA_OFFLINE = "android.service.media.extra.OFFLINE"
- EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED"
- EXTRA_EMPTY_ROOT_ALLOWED = "android.service.media.extra.EMPTY_ROOT_ALLOWED"
-
- def __init__(self, root_id: str = "", extras: Any = None):
- super().__init__()
- self._root_id = root_id
- self._extras = extras
-
- def getRootId(self) -> str:
- return self._root_id
-
- def getExtras(self) -> Any:
- return self._extras
-
- # ═══════════════════════════════════════════════════════
- # Result (inner class)
- # ═══════════════════════════════════════════════════════
-
- class Result(Stub):
- """MediaBrowserService.Result — 服务结果"""
-
- FLAG_OPTION_NOT_KNOWN = 0
- FLAG_OPTION_FOUND = 1
- FLAG_OPTION_NOT_FOUND = 2
- FLAG_OPTION_ERROR = 4
-
- def __init__(self):
- super().__init__()
- self._result: Any = None
- self._flags: int = MediaBrowserService.Result.FLAG_OPTION_NOT_KNOWN
- self._is_done: bool = False
- self._error: Optional[str] = None
-
- def getResult(self) -> Any:
- return self._result
-
- def getFlags(self) -> int:
- return self._flags
-
- def isDone(self) -> bool:
- return self._is_done
-
- def sendResult(self, result: Any, flags: int = 0):
- self._result = result
- self._flags = flags
- self._is_done = True
-
- def sendError(self, error: str):
- self._error = error
- self._flags = MediaBrowserService.Result.FLAG_OPTION_ERROR
- self._is_done = True
-
- def onResultSent(self, result: Any, flags: int = 0):
- self._result = result
- self._flags = flags
- self._is_done = True
-
- def __init__(self):
- super().__init__()
- self._root: Optional[MediaBrowserService.BrowserRoot] = None
- self._session: Optional[MediaSessionService.MediaSession] = None
- self._is_connected: bool = False
- self._media_items: Dict[str, Any] = {}
- self._children_cache: Dict[str, List[Any]] = {}
- self._search_results: Dict[str, List[Any]] = {}
- self._package_name: str = ""
- self._on_load_children_callbacks: Dict[str, Callable] = {}
- self._on_load_item_callbacks: Dict[str, Callable] = {}
-
- def onGetRoot(self, client_package_name: str, client_uid: int,
- root_hints: Any = None) -> Optional[BrowserRoot]:
- """获取根节点回调"""
- return self._root
-
- def onLoadChildren(self, parent_id: str, result: Result):
- """加载子节点回调"""
- children = self._children_cache.get(parent_id, [])
- result.sendResult(children)
-
- def onLoadChildrenWithOptions(self, parent_id: str, result: Result,
- options: Any = None):
- """加载子节点 (带选项) 回调"""
- self.onLoadChildren(parent_id, result)
-
- def onLoadItem(self, item_id: str, result: Result):
- """加载媒体项回调"""
- item = self._media_items.get(item_id)
- if item:
- result.sendResult(item)
- else:
- result.sendError(f"Item not found: {item_id}")
-
- def onSearch(self, query: str, extras: Any, result: Result):
- """搜索回调"""
- results = self._search_results.get(query, [])
- result.sendResult(results)
-
- def onCustomAction(self, action: str, extras: Any, result: Result):
- """自定义动作回调"""
- result.sendResult(None)
-
- def setRoot(self, root: BrowserRoot):
- self._root = root
-
- def getRoot(self) -> Optional[BrowserRoot]:
- return self._root
-
- def setSession(self, session: MediaSessionService.MediaSession):
- self._session = session
-
- def getSession(self) -> Optional[MediaSessionService.MediaSession]:
- return self._session
-
- def setMediaItems(self, items: Dict[str, Any]):
- self._media_items = dict(items)
-
- def addMediaItem(self, item_id: str, item: Any):
- self._media_items[item_id] = item
-
- def setChildren(self, parent_id: str, children: List[Any]):
- self._children_cache[parent_id] = list(children)
-
- def addChild(self, parent_id: str, child: Any):
- if parent_id not in self._children_cache:
- self._children_cache[parent_id] = []
- self._children_cache[parent_id].append(child)
-
- def setSearchResults(self, query: str, results: List[Any]):
- self._search_results[query] = list(results)
-
- def isConnected(self) -> bool:
- return self._is_connected
-
- def setConnected(self, connected: bool):
- self._is_connected = connected
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def setPackageName(self, pkg: str):
- self._package_name = pkg
-
- def notifyChildrenChanged(self, parent_id: str):
- """通知子节点已变更"""
- pass
-
- def notifyChildrenChangedWithOptions(self, parent_id: str, options: Any = None):
- """通知子节点已变更 (带选项)"""
- pass
-
- def toString(self) -> str:
- return f"MediaBrowserService(root={self._root})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaSessionService
-# ═══════════════════════════════════════════════════════════════
-
-class MediaSessionService(Stub):
- """MediaSessionService — 媒体会话服务"""
-
- SERVICE_INTERFACE = "android.media.session.MediaSessionService"
- SERVICE_META_DATA = "android.media.session"
-
- KEY_MEDIA_SESSION = "media_session"
- KEY_MEDIA_SESSION_TOKEN = "media_session_token"
- KEY_MEDIA_CONTROLLER = "media_controller"
- KEY_PLAYBACK_STATE = "playback_state"
- KEY_METADATA = "metadata"
- KEY_QUEUE = "queue"
- KEY_QUEUE_TITLE = "queue_title"
- KEY_ACTIONS = "actions"
- KEY_ERROR = "error"
- KEY_EXTRAS = "extras"
- KEY_RATING = "rating"
- KEY_REPEAT_MODE = "repeat_mode"
- KEY_SHUFFLE_MODE = "shuffle_mode"
-
- # ═══════════════════════════════════════════════════════
- # MediaSession
- # ═══════════════════════════════════════════════════════
-
- class MediaSession(Stub):
- """MediaSessionService.MediaSession — 媒体会话"""
-
- FLAG_HANDLES_MEDIA_BUTTONS = 1
- FLAG_HANDLES_TRANSPORT_CONTROLS = 2
- FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 4
-
- PLAYBACK_STATE_NONE = 0
- PLAYBACK_STATE_STOPPED = 1
- PLAYBACK_STATE_PAUSED = 2
- PLAYBACK_STATE_PLAYING = 3
- PLAYBACK_STATE_FAST_FORWARDING = 4
- PLAYBACK_STATE_REWINDING = 5
- PLAYBACK_STATE_BUFFERING = 6
- PLAYBACK_STATE_ERROR = 7
- PLAYBACK_STATE_SKIPPING_TO_PREVIOUS = 8
- PLAYBACK_STATE_SKIPPING_TO_NEXT = 9
- PLAYBACK_STATE_SKIPPING_TO_QUEUE_ITEM = 10
- PLAYBACK_STATE_CONNECTING = 11
-
- REPEAT_MODE_NONE = 0
- REPEAT_MODE_ONE = 1
- REPEAT_MODE_ALL = 2
- REPEAT_MODE_GROUP = 3
-
- SHUFFLE_MODE_NONE = 0
- SHUFFLE_MODE_ALL = 1
- SHUFFLE_MODE_GROUP = 2
-
- ACTION_PLAY = 1
- ACTION_PAUSE = 2
- ACTION_PLAY_PAUSE = 4
- ACTION_STOP = 8
- ACTION_SEEK_TO = 16
- ACTION_FAST_FORWARD = 32
- ACTION_REWIND = 64
- ACTION_SKIP_TO_NEXT = 128
- ACTION_SKIP_TO_PREVIOUS = 256
- ACTION_SKIP_TO_QUEUE_ITEM = 512
- ACTION_SET_RATING = 1024
- ACTION_SET_REPEAT_MODE = 2048
- ACTION_SET_SHUFFLE_MODE = 4096
- ACTION_SET_CAPTIONING_ENABLED = 8192
- ACTION_PLAY_FROM_MEDIA_ID = 16384
- ACTION_PLAY_FROM_SEARCH = 32768
- ACTION_PLAY_FROM_URI = 65536
- ACTION_PREPARE = 131072
- ACTION_PREPARE_FROM_MEDIA_ID = 262144
- ACTION_PREPARE_FROM_SEARCH = 524288
- ACTION_PREPARE_FROM_URI = 1048576
-
- class Callback(Stub):
- """MediaSessionService.MediaSession.Callback — 会话回调"""
-
- def onPlay(self):
- pass
-
- def onPause(self):
- pass
-
- def onStop(self):
- pass
-
- def onSeekTo(self, pos: int):
- pass
-
- def onFastForward(self):
- pass
-
- def onRewind(self):
- pass
-
- def onSkipToNext(self):
- pass
-
- def onSkipToPrevious(self):
- pass
-
- def onSkipToQueueItem(self, id: int):
- pass
-
- def onSetRating(self, rating: Any):
- pass
-
- def onSetRepeatMode(self, repeat_mode: int):
- pass
-
- def onSetShuffleMode(self, shuffle_mode: int):
- pass
-
- def onPlayFromMediaId(self, media_id: str, extras: Any):
- pass
-
- def onPlayFromSearch(self, query: str, extras: Any):
- pass
-
- def onPlayFromUri(self, uri: str, extras: Any):
- pass
-
- def onPrepare(self):
- pass
-
- def onPrepareFromMediaId(self, media_id: str, extras: Any):
- pass
-
- def onPrepareFromSearch(self, query: str, extras: Any):
- pass
-
- def onPrepareFromUri(self, uri: str, extras: Any):
- pass
-
- def onCommand(self, command: str, extras: Any, cb: Any):
- pass
-
- def onCustomAction(self, action: str, extras: Any):
- pass
-
- def onMediaButtonEvent(self, intent: Any) -> bool:
- return False
-
- def __init__(self, tag: str = ""):
- super().__init__()
- self._tag = tag
- self._callback: Optional[MediaSessionService.MediaSession.Callback] = None
- self._playback_state: int = MediaSessionService.MediaSession.PLAYBACK_STATE_NONE
- self._metadata: Any = None
- self._queue: List[Any] = []
- self._queue_title: str = ""
- self._actions: int = 0
- self._repeat_mode: int = MediaSessionService.MediaSession.REPEAT_MODE_NONE
- self._shuffle_mode: int = MediaSessionService.MediaSession.SHUFFLE_MODE_NONE
- self._active: bool = False
- self._flags: int = 0
- self._position: int = 0
- self._duration: int = 0
- self._error: Optional[str] = None
- self._extras: Dict[str, Any] = {}
-
- def setCallback(self, callback: Callback):
- self._callback = callback
-
- def getCallback(self) -> Optional[Callback]:
- return self._callback
-
- def setActive(self, active: bool):
- self._active = active
-
- def isActive(self) -> bool:
- return self._active
-
- def setFlags(self, flags: int):
- self._flags = flags
-
- def getFlags(self) -> int:
- return self._flags
-
- def setPlaybackState(self, state: int):
- self._playback_state = state
-
- def getPlaybackState(self) -> int:
- return self._playback_state
-
- def setMetadata(self, metadata: Any):
- self._metadata = metadata
-
- def getMetadata(self) -> Any:
- return self._metadata
-
- def setQueue(self, queue: List[Any]):
- self._queue = list(queue)
-
- def getQueue(self) -> List[Any]:
- return list(self._queue)
-
- def setQueueTitle(self, title: str):
- self._queue_title = title
-
- def getQueueTitle(self) -> str:
- return self._queue_title
-
- def setActions(self, actions: int):
- self._actions = actions
-
- def getActions(self) -> int:
- return self._actions
-
- def setRepeatMode(self, mode: int):
- self._repeat_mode = mode
-
- def getRepeatMode(self) -> int:
- return self._repeat_mode
-
- def setShuffleMode(self, mode: int):
- self._shuffle_mode = mode
-
- def getShuffleMode(self) -> int:
- return self._shuffle_mode
-
- def getTag(self) -> str:
- return self._tag
-
- def setPosition(self, pos: int):
- self._position = pos
-
- def getPosition(self) -> int:
- return self._position
-
- def setDuration(self, duration: int):
- self._duration = duration
-
- def getDuration(self) -> int:
- return self._duration
-
- def setError(self, error: str):
- self._error = error
-
- def getError(self) -> Optional[str]:
- return self._error
-
- def getExtras(self) -> Dict[str, Any]:
- return dict(self._extras)
-
- def setExtras(self, extras: Dict[str, Any]):
- self._extras = dict(extras)
-
- def isPlaying(self) -> bool:
- return self._playback_state == MediaSessionService.MediaSession.PLAYBACK_STATE_PLAYING
-
- def toString(self) -> str:
- return f"MediaSession(tag={self._tag}, state={self._playback_state})"
-
- def __init__(self):
- super().__init__()
- self._sessions: Dict[str, MediaSessionService.MediaSession] = {}
- self._browser_service: Optional[MediaBrowserService] = None
- self._is_running: bool = False
-
- def onCreate(self):
- """创建服务"""
- self._is_running = True
-
- def onDestroy(self):
- """销毁服务"""
- self._is_running = False
- for session in self._sessions.values():
- session.setActive(False)
- self._sessions.clear()
-
- def onGetSession(self, controller_info: Any) -> Optional[MediaSession]:
- """获取会话回调"""
- if self._sessions:
- return next(iter(self._sessions.values()))
- return None
-
- def getSessions(self) -> List[MediaSession]:
- return list(self._sessions.values())
-
- def addSession(self, tag: str, session: MediaSession):
- self._sessions[tag] = session
-
- def removeSession(self, tag: str):
- self._sessions.pop(tag, None)
-
- def getSession(self, tag: str) -> Optional[MediaSession]:
- return self._sessions.get(tag)
-
- def setBrowserService(self, service: MediaBrowserService):
- self._browser_service = service
-
- def getBrowserService(self) -> Optional[MediaBrowserService]:
- return self._browser_service
-
- def isRunning(self) -> bool:
- return self._is_running
-
- def toString(self) -> str:
- return f"MediaSessionService(sessions={len(self._sessions)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaSessionServiceCallback
-# ═══════════════════════════════════════════════════════════════
-
-class MediaSessionServiceCallback(Stub):
- """MediaSessionServiceCallback — 媒体会话服务回调"""
-
- def onSessionCreated(self, session: MediaSessionService.MediaSession):
- pass
-
- def onSessionDestroyed(self, session: MediaSessionService.MediaSession):
- pass
-
- def onSessionActive(self, session: MediaSessionService.MediaSession):
- pass
-
- def onSessionInactive(self, session: MediaSessionService.MediaSession):
- pass
-
- def onPlaybackStateChanged(self, session: MediaSessionService.MediaSession, state: int):
- pass
-
- def onMetadataChanged(self, session: MediaSessionService.MediaSession, metadata: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaSessionUtils
-# ═══════════════════════════════════════════════════════════════
-
-class MediaSessionUtils(Stub):
- """MediaSessionUtils — 媒体会话工具类"""
-
- @staticmethod
- def createMediaSession(tag: str) -> MediaSessionService.MediaSession:
- return MediaSessionService.MediaSession(tag)
-
- @staticmethod
- def createBrowserRoot(root_id: str, extras: Any = None) -> BrowserRoot:
- return BrowserRoot(root_id, extras)
-
- @staticmethod
- def createServiceResult() -> MediaBrowserService.Result:
- return MediaBrowserService.Result()
-
- @staticmethod
- def getPlaybackStateName(state: int) -> str:
- names = {
- MediaSessionService.MediaSession.PLAYBACK_STATE_NONE: "NONE",
- MediaSessionService.MediaSession.PLAYBACK_STATE_STOPPED: "STOPPED",
- MediaSessionService.MediaSession.PLAYBACK_STATE_PAUSED: "PAUSED",
- MediaSessionService.MediaSession.PLAYBACK_STATE_PLAYING: "PLAYING",
- MediaSessionService.MediaSession.PLAYBACK_STATE_FAST_FORWARDING: "FAST_FORWARDING",
- MediaSessionService.MediaSession.PLAYBACK_STATE_REWINDING: "REWINDING",
- MediaSessionService.MediaSession.PLAYBACK_STATE_BUFFERING: "BUFFERING",
- MediaSessionService.MediaSession.PLAYBACK_STATE_ERROR: "ERROR",
- }
- return names.get(state, f"UNKNOWN({state})")
-
- @staticmethod
- def isActiveSession(session: MediaSessionService.MediaSession) -> bool:
- return session is not None and session.isActive()
-
- @staticmethod
- def getSupportedActions(session: MediaSessionService.MediaSession) -> int:
- return session.getActions() if session else 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaSessionServiceConfig
-# ═══════════════════════════════════════════════════════════════
-
-class MediaSessionServiceConfig(Stub):
- """MediaSessionServiceConfig — 媒体会话服务配置"""
-
- def __init__(self):
- super().__init__()
- self._max_sessions: int = 10
- self._allow_multiple_sessions: bool = True
- self._notification_enabled: bool = True
- self._auto_play_on_start: bool = False
- self._enable_media_buttons: bool = True
- self._enable_queue: bool = True
-
- def getMaxSessions(self) -> int:
- return self._max_sessions
-
- def setMaxSessions(self, max_sessions: int):
- self._max_sessions = max_sessions
-
- def isAllowMultipleSessions(self) -> bool:
- return self._allow_multiple_sessions
-
- def setAllowMultipleSessions(self, allow: bool):
- self._allow_multiple_sessions = allow
-
- def isNotificationEnabled(self) -> bool:
- return self._notification_enabled
-
- def setNotificationEnabled(self, enabled: bool):
- self._notification_enabled = enabled
-
- def isAutoPlayOnStart(self) -> bool:
- return self._auto_play_on_start
-
- def setAutoPlayOnStart(self, auto_play: bool):
- self._auto_play_on_start = auto_play
-
- def isMediaButtonsEnabled(self) -> bool:
- return self._enable_media_buttons
-
- def setMediaButtonsEnabled(self, enabled: bool):
- self._enable_media_buttons = enabled
-
- def isQueueEnabled(self) -> bool:
- return self._enable_queue
-
- def setQueueEnabled(self, enabled: bool):
- self._enable_queue = enabled
-
- def toString(self) -> str:
- return f"MediaSessionServiceConfig(maxSessions={self._max_sessions})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MediaSessionServiceHelper
-# ═══════════════════════════════════════════════════════════════
-
-class MediaSessionServiceHelper(Stub):
- """MediaSessionServiceHelper — 媒体会话服务辅助类"""
-
- @staticmethod
- def requestMediaSessionService(context: Any, service: MediaSessionService):
- """请求媒体会话服务"""
- service.onCreate()
-
- @staticmethod
- def releaseMediaSessionService(service: MediaSessionService):
- """释放媒体会话服务"""
- service.onDestroy()
-
- @staticmethod
- def sendMediaButton(context: Any, session: MediaSessionService.MediaSession,
- key_code: int):
- """发送媒体按键"""
- cb = session.getCallback()
- if cb:
- cb.onMediaButtonEvent(None)
-
- @staticmethod
- def createDefaultSession(tag: str = "default") -> MediaSessionService.MediaSession:
- session = MediaSessionService.MediaSession(tag)
- session.setCallback(MediaSessionService.MediaSession.Callback())
- return session
-
- @staticmethod
- def playbackStateToString(state: int) -> str:
- return MediaSessionUtils.getPlaybackStateName(state)
\ No newline at end of file
diff --git a/android_pyapi/android/service_notification.py b/android_pyapi/android/service_notification.py
deleted file mode 100644
index f397be8..0000000
--- a/android_pyapi/android/service_notification.py
+++ /dev/null
@@ -1,378 +0,0 @@
-"""
-Android Service Notification 组件 — NotificationListenerService, StatusBarNotification, RankingMap 等
-方法签名完全对齐 Android SDK (android.service.notification 包)
-"""
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# StatusBarNotification
-# ═══════════════════════════════════════════════════════════════
-
-class StatusBarNotification(Stub):
- """StatusBarNotification — 状态栏通知"""
-
- def __init__(self, pkg: str = "", op_pkg: str = "",
- id: int = 0, tag: Optional[str] = None,
- uid: int = 10001, pid: int = 1000,
- user: Any = None, notification: Any = None,
- post_time: int = 0):
- super().__init__()
- self._pkg = pkg
- self._op_pkg = op_pkg or pkg
- self._id = id
- self._tag = tag
- self._uid = uid
- self._pid = pid
- self._user = user
- self._notification = notification
- self._post_time = post_time or int(time.time() * 1000)
- self._is_clearable = True
- self._is_ongoing = False
- self._key = f"{pkg}|{id}|{tag or ''}"
- self._override_group_key: Optional[str] = None
- self._override_public = False
- self._initial_source_id = 0
- self._initial_source_uid = uid
- self._initial_source_pkg = pkg
-
- def getPackageName(self) -> str:
- """获取通知所属包名"""
- return self._pkg
-
- def getOpPkg(self) -> str:
- return self._op_pkg
-
- def getNotification(self) -> Any:
- """获取 Notification 对象"""
- return self._notification
-
- def getId(self) -> int:
- """获取通知 ID"""
- return self._id
-
- def getTag(self) -> Optional[str]:
- """获取通知标签"""
- return self._tag
-
- def getPostTime(self) -> int:
- """获取发送时间 (毫秒)"""
- return self._post_time
-
- def getUid(self) -> int:
- return self._uid
-
- def getPid(self) -> int:
- return self._pid
-
- def getUser(self) -> Any:
- return self._user
-
- def getKey(self) -> str:
- return self._key
-
- def isClearable(self) -> bool:
- """是否可以清除"""
- return self._is_clearable
-
- def isOngoing(self) -> bool:
- """是否是持续通知"""
- return self._is_ongoing
-
- def setClearable(self, clearable: bool):
- self._is_clearable = clearable
-
- def setOngoing(self, ongoing: bool):
- self._is_ongoing = ongoing
-
- def getOverrideGroupKey(self) -> Optional[str]:
- return self._override_group_key
-
- def setOverrideGroupKey(self, override_group_key: Optional[str]):
- self._override_group_key = override_group_key
-
- def isGroup(self) -> bool:
- return self._override_group_key is not None
-
- def clone(self) -> "StatusBarNotification":
- """克隆通知"""
- clone = StatusBarNotification(
- pkg=self._pkg, op_pkg=self._op_pkg, id=self._id,
- tag=self._tag, uid=self._uid, pid=self._pid,
- user=self._user, notification=self._notification,
- post_time=self._post_time,
- )
- clone._is_clearable = self._is_clearable
- clone._is_ongoing = self._is_ongoing
- clone._key = self._key
- clone._override_group_key = self._override_group_key
- return clone
-
- def toString(self) -> str:
- return (f"StatusBarNotification(pkg={self._pkg}, id={self._id}, "
- f"tag={self._tag}, postTime={self._post_time})")
-
- def hashCode(self) -> int:
- return hash(self._key) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, StatusBarNotification):
- return False
- return self._key == other._key
-
-
-# ═══════════════════════════════════════════════════════════════
-# NotificationListenerService
-# ═══════════════════════════════════════════════════════════════
-
-class NotificationListenerService(Stub):
- """NotificationListenerService — 通知监听服务"""
-
- # 取消原因
- REASON_LISTENER_CANCEL = 1
- REASON_CLICK = 2
- REASON_CANCEL = 3
- REASON_DELETE = 4
- REASON_PACKAGE_CHANGED = 5
- REASON_USER_STOPPED = 6
- REASON_PACKACE_BANNED = 7
- REASON_APP_CANCEL = 8
- REASON_APP_CANCEL_ALL = 9
- REASON_CHANNEL_BANNED = 10
- REASON_SNOOZED = 11
- REASON_TIMEOUT = 12
- REASON_ERROR = 13
- REASON_GROUP_SUMMARY_CANCELED = 14
- REASON_ASSISTANT_CANCEL = 15
-
- # 中断过滤器
- INTERRUPTION_FILTER_NONE = 0
- INTERRUPTION_FILTER_PRIORITY = 1
- INTERRUPTION_FILTER_ALARMS = 2
- INTERRUPTION_FILTER_ALL = 3
- INTERRUPTION_FILTER_UNKNOWN = 4
-
- # 提示
- HINT_HOST_DISABLE_CALL_EFFECTS = 1
- HINT_HOST_DISABLE_EFFECTS = 2
- HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 3
-
- # SUW 组件
- TRAMPOLINE_ACTIVITY_CLASS = (
- "com.android.settings.Settings$NotificationAppListActivity"
- )
-
- def __init__(self):
- super().__init__()
- self._active_notifications: Dict[str, StatusBarNotification] = {}
- self._keys_list: List[str] = []
- self._interruption_filter: int = (
- NotificationListenerService.INTERRUPTION_FILTER_ALL
- )
- self._ranking_map: Optional["NotificationListenerService.RankingMap"] = None
- self._is_listener_bound = False
-
- @staticmethod
- def requestRebind(component_name: Any):
- """请求重新绑定通知监听器"""
- pass
-
- @staticmethod
- def requestUnbind(component_name: Any):
- """请求解绑通知监听器"""
- pass
-
- def onNotificationPosted(self, sbn: StatusBarNotification,
- ranking_map: Optional["RankingMap"] = None):
- """通知被发送时回调"""
- if sbn:
- self._active_notifications[sbn.getKey()] = sbn
- self._keys_list = list(self._active_notifications.keys())
- if ranking_map:
- self._ranking_map = ranking_map
-
- def onNotificationRemoved(self, sbn: StatusBarNotification,
- ranking_map: Optional["RankingMap"] = None,
- reason: int = REASON_LISTENER_CANCEL):
- """通知被移除时回调"""
- if sbn:
- key = sbn.getKey()
- self._active_notifications.pop(key, None)
- if key in self._keys_list:
- self._keys_list.remove(key)
-
- def onListenerConnected(self):
- """监听器已连接"""
- self._is_listener_bound = True
-
- def onListenerDisconnected(self):
- """监听器已断开"""
- self._is_listener_bound = False
-
- def onNotificationRemovedReason(self, sbn: StatusBarNotification,
- ranking_map: "RankingMap",
- reason: int):
- """通知被移除 (带原因)"""
- self.onNotificationRemoved(sbn, ranking_map, reason)
-
- def onNotificationPostedWithRankingMap(self, sbn: StatusBarNotification,
- ranking_map: "RankingMap"):
- """通知被发送 (带排名映射)"""
- self.onNotificationPosted(sbn, ranking_map)
-
- def getActiveNotifications(self) -> List[StatusBarNotification]:
- """获取活动通知列表"""
- return list(self._active_notifications.values())
-
- def getActiveNotificationsWithRankingMap(self) -> Tuple[
- List[StatusBarNotification],
- Optional["RankingMap"]]:
- """获取活动通知及排名映射"""
- return list(self._active_notifications.values()), self._ranking_map
-
- def getCurrentInterruptionFilter(self) -> int:
- """获取当前中断过滤器"""
- return self._interruption_filter
-
- def setInterruptionFilter(self, interruption_filter: int):
- """设置中断过滤器"""
- self._interruption_filter = interruption_filter
-
- def cancelNotification(self, key: str):
- """取消指定通知"""
- self._active_notifications.pop(key, None)
- if key in self._keys_list:
- self._keys_list.remove(key)
-
- def cancelAllNotifications(self):
- """取消所有通知"""
- self._active_notifications.clear()
- self._keys_list.clear()
-
- def requestRebind(self, component_name: Any):
- """请求重新绑定"""
- pass
-
- def requestUnbind(self):
- """请求解绑"""
- pass
-
- def registerAsSystemService(self, context: Any, component_name: Any,
- user: int):
- pass
-
- def unregisterAsSystemService(self):
- pass
-
- def isBound(self) -> bool:
- return self._is_listener_bound
-
- def toString(self) -> str:
- return (f"NotificationListenerService("
- f"notifications={len(self._active_notifications)}, "
- f"filter={self._interruption_filter})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
- # ── RankingMap ──
-
- class RankingMap(Stub):
- """RankingMap — 通知排名映射"""
-
- def __init__(self):
- super().__init__()
- self._rankings: Dict[str, "NotificationListenerService.Ranking"] = {}
-
- def getOrderedKeys(self) -> List[str]:
- """获取有序键列表"""
- return list(self._rankings.keys())
-
- def getRanking(self, key: str) -> Optional["NotificationListenerService.Ranking"]:
- """获取指定通知的排名信息"""
- return self._rankings.get(key)
-
- def getRawRanking(self, key: str) -> Optional[Any]:
- return self._rankings.get(key)
-
- def toString(self) -> str:
- return f"RankingMap(keys={len(self._rankings)})"
-
- def hashCode(self) -> int:
- return hash(tuple(self._rankings.keys())) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, NotificationListenerService.RankingMap):
- return False
- return self._rankings == other._rankings
-
- class Ranking(Stub):
- """Ranking — 通知排名"""
-
- def __init__(self):
- super().__init__()
- self._key: str = ""
- self._rank: int = 0
- self._is_ambient: bool = False
- self._matches_interruption_filter: bool = True
- self._suppressed_visual_effects: int = 0
- self._importance: int = 3 # IMPORTANCE_DEFAULT
- self._importance_explanation: Optional[str] = None
- self._group_key: Optional[str] = None
- self._override_group_key: Optional[str] = None
- self._channel: Optional[Any] = None
- self._is_suspended: bool = False
-
- def getKey(self) -> str:
- return self._key
-
- def getRank(self) -> int:
- return self._rank
-
- def isAmbient(self) -> bool:
- return self._is_ambient
-
- def matchesInterruptionFilter(self) -> bool:
- return self._matches_interruption_filter
-
- def getSuppressedVisualEffects(self) -> int:
- return self._suppressed_visual_effects
-
- def getImportance(self) -> int:
- return self._importance
-
- def getImportanceExplanation(self) -> Optional[str]:
- return self._importance_explanation
-
- def getGroupKey(self) -> Optional[str]:
- return self._group_key
-
- def getOverrideGroupKey(self) -> Optional[str]:
- return self._override_group_key
-
- def getChannel(self) -> Optional[Any]:
- return self._channel
-
- def isSuspended(self) -> bool:
- return self._is_suspended
-
- def toString(self) -> str:
- return (f"Ranking(key={self._key}, rank={self._rank}, "
- f"importance={self._importance})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "NotificationListenerService",
- "StatusBarNotification",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/service_quicksettings.py b/android_pyapi/android/service_quicksettings.py
deleted file mode 100644
index eeccab8..0000000
--- a/android_pyapi/android/service_quicksettings.py
+++ /dev/null
@@ -1,214 +0,0 @@
-"""
-Android Service QuickSettings 组件 — TileService, Tile 等
-方法签名完全对齐 Android SDK (android.service.quicksettings 包)
-"""
-
-import time
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# Tile
-# ═══════════════════════════════════════════════════════════════
-
-class Tile(Stub):
- """Tile — 快捷设置磁贴"""
-
- # 状态常量
- STATE_ACTIVE = 1
- STATE_INACTIVE = 2
- STATE_UNAVAILABLE = 0
-
- def __init__(self):
- super().__init__()
- self._state: int = Tile.STATE_INACTIVE
- self._label: str = ""
- self._subtitle: str = ""
- self._content_description: str = ""
- self._icon: Optional[Any] = None
- self._icon_res_id: int = 0
- self._meta_data: Optional[Dict[str, Any]] = None
- self._last_updated: int = 0
-
- def getState(self) -> int:
- """获取磁贴状态"""
- return self._state
-
- def setState(self, state: int):
- """设置磁贴状态"""
- self._state = state
- self._last_updated = int(time.time() * 1000)
-
- def getLabel(self) -> str:
- """获取标签"""
- return self._label
-
- def setLabel(self, label: str):
- """设置标签"""
- self._label = label
- self._last_updated = int(time.time() * 1000)
-
- def getSubtitle(self) -> str:
- """获取副标题"""
- return self._subtitle
-
- def setSubtitle(self, subtitle: str):
- """设置副标题"""
- self._subtitle = subtitle
- self._last_updated = int(time.time() * 1000)
-
- def getContentDescription(self) -> str:
- """获取内容描述"""
- return self._content_description
-
- def setContentDescription(self, content_description: str):
- """设置内容描述"""
- self._content_description = content_description
-
- def getIcon(self) -> Optional[Any]:
- """获取图标"""
- return self._icon
-
- def setIcon(self, icon: Any):
- """设置图标"""
- self._icon = icon
- self._last_updated = int(time.time() * 1000)
-
- def updateTile(self):
- """更新磁贴 (通知系统刷新)"""
- self._last_updated = int(time.time() * 1000)
-
- def getMetaData(self) -> Optional[Dict[str, Any]]:
- return self._meta_data
-
- def setMetaData(self, meta_data: Dict[str, Any]):
- self._meta_data = meta_data
-
- def toString(self) -> str:
- state_names = {
- Tile.STATE_ACTIVE: "ACTIVE",
- Tile.STATE_INACTIVE: "INACTIVE",
- Tile.STATE_UNAVAILABLE: "UNAVAILABLE",
- }
- return (f"Tile(label={self._label}, state="
- f"{state_names.get(self._state, self._state)})")
-
- def hashCode(self) -> int:
- return hash((self._label, self._state)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Tile):
- return False
- return (self._label == other._label and self._state == other._state)
-
-
-# ═══════════════════════════════════════════════════════════════
-# TileService
-# ═══════════════════════════════════════════════════════════════
-
-class TileService(Stub):
- """TileService — 快捷设置磁贴服务"""
-
- # 动作
- ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE"
- ACTION_REQUEST_LISTENING = (
- "android.service.quicksettings.action.REQUEST_LISTENING"
- )
- META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE"
-
- def __init__(self):
- super().__init__()
- self._qs_tile: Optional[Tile] = None
- self._locked: bool = False
- self._secure: bool = False
- self._listening: bool = False
- self._tile_added: bool = False
- self._tile_removed: bool = False
-
- @staticmethod
- def requestListeningState(context: Any, component: Any):
- """请求监听状态 (Android-only)"""
- pass
-
- def isLocked(self) -> bool:
- """检查设备是否锁定"""
- return self._locked
-
- def isSecure(self) -> bool:
- """检查设备是否安全锁定"""
- return self._secure
-
- def startActivity(self, intent: Any):
- """启动 Activity (Android-only)"""
- raise AndroidOnlyError(
- "TileService.startActivity() 仅在 Android 设备上可用"
- )
-
- def showDialog(self, dialog: Any):
- """显示对话框"""
- pass
-
- def getQsTile(self) -> Optional[Tile]:
- """获取快速设置磁贴"""
- return self._qs_tile
-
- def setQsTile(self, tile: Tile):
- self._qs_tile = tile
-
- def unlockAndRun(self, runnable: Callable):
- """解锁并运行"""
- runnable()
-
- def onTileAdded(self):
- """磁贴被添加时回调"""
- self._tile_added = True
-
- def onTileRemoved(self):
- """磁贴被移除时回调"""
- self._tile_removed = True
-
- def onStartListening(self):
- """开始监听时回调"""
- self._listening = True
-
- def onStopListening(self):
- """停止监听时回调"""
- self._listening = False
-
- def onClick(self):
- """被点击时回调"""
- if self._qs_tile:
- current_state = self._qs_tile.getState()
- if current_state == Tile.STATE_ACTIVE:
- self._qs_tile.setState(Tile.STATE_INACTIVE)
- elif current_state == Tile.STATE_INACTIVE:
- self._qs_tile.setState(Tile.STATE_ACTIVE)
-
- def onDestroy(self):
- """销毁时回调"""
- pass
-
- def isListening(self) -> bool:
- return self._listening
-
- def toString(self) -> str:
- return (f"TileService(locked={self._locked}, secure={self._secure}, "
- f"listening={self._listening})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "TileService",
- "Tile",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/service_voice.py b/android_pyapi/android/service_voice.py
deleted file mode 100644
index d6d2cc3..0000000
--- a/android_pyapi/android/service_voice.py
+++ /dev/null
@@ -1,869 +0,0 @@
-"""
-Android Service Voice 组件 — VoiceInteractionService, VoiceInteractionSession, VoiceInteractor 等
-方法签名完全对齐 Android SDK (android.service.voice 包)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量定义
-# ═══════════════════════════════════════════════════════════════
-
-KEY_ACTION = "action"
-KEY_ACTION_ARG = "action_arg"
-KEY_ARGUMENTS = "arguments"
-KEY_CONFIDENCE_SCORE = "confidence_score"
-KEY_ERROR = "error"
-KEY_FEATURE_ID = "feature_id"
-KEY_ID = "id"
-KEY_LANGUAGE = "language"
-KEY_LOCALE = "locale"
-KEY_MESSAGE = "message"
-KEY_PACKAGE_NAME = "package_name"
-KEY_POWER_SOURCE = "power_source"
-KEY_PROMPT = "prompt"
-KEY_RESULT = "result"
-KEY_SESSION_ID = "session_id"
-KEY_STATUS = "status"
-KEY_TIMEOUT_MS = "timeout_ms"
-KEY_VOLUME = "volume"
-KEY_WAKE_WORD = "wake_word"
-KEY_IS_DEMO = "is_demo"
-KEY_IS_TRUSTED = "is_trusted"
-KEY_IS_VALID = "is_valid"
-KEY_RECOGNITION_RESULT = "recognition_result"
-
-SHOW_SOURCE_FULL_SCREEN = 0
-SHOW_SOURCE_DOCKED = 1
-SHOW_SOURCE_PEEK = 2
-SHOW_SOURCE_ASSISTANT = 3
-SHOW_SOURCE_VOICE_SEARCH = 4
-SHOW_SOURCE_SHORTCUT = 5
-SHOW_SOURCE_NOTIFICATION = 6
-SHOW_SOURCE_WIDGET = 7
-
-VOICE_INTERACTION_ACTION = "android.service.voice.action.VOICE_INTERACTION"
-VOICE_INTERACTION_META_DATA = "android.service.voice.voice_interaction"
-VOICE_INTERACTION_SERVICE = "android.service.voice.VoiceInteractionService"
-
-SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService"
-SESSION_SERVICE_INTERFACE = "android.service.voice.VoiceInteractionSessionService"
-
-FLAG_SHOW_WITH_SCREEN_ON = 1
-FLAG_SHOW_WITH_SCREEN_OFF = 2
-FLAG_SHOW_WHEN_LOCKED = 4
-FLAG_SHOW_AS_SYSTEM_OVERLAY = 8
-FLAG_EXCLUSIVE = 16
-
-VOICE_ACTIVITY_STATE_UNKNOWN = 0
-VOICE_ACTIVITY_STATE_LISTENING = 1
-VOICE_ACTIVITY_STATE_PROCESSING = 2
-VOICE_ACTIVITY_STATE_RESPONDING = 3
-VOICE_ACTIVITY_STATE_INACTIVE = 4
-VOICE_ACTIVITY_STATE_ERROR = 5
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractionService
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractionService(Stub):
- """VoiceInteractionService — 语音交互服务"""
-
- def __init__(self):
- super().__init__()
- self._is_connected: bool = False
- self._session: Optional[VoiceInteractionSession] = None
- self._available_voice_actions: List[str] = []
- self._supported_languages: List[str] = []
- self._active_session: bool = False
- self._disabled_until: int = 0
- self._feature_id: str = ""
- self._package_name: str = ""
-
- def onReady(self):
- """服务就绪回调"""
- self._is_connected = True
-
- def onConnected(self):
- """已连接回调"""
- self._is_connected = True
-
- def onDisconnected(self):
- """断开连接回调"""
- self._is_connected = False
-
- def onShutdown(self):
- """关闭回调"""
- self._is_connected = False
- self._session = None
-
- def setAvailableVoiceActions(self, actions: List[str]):
- """设置可用语音动作"""
- self._available_voice_actions = list(actions)
-
- def getAvailableVoiceActions(self) -> List[str]:
- return list(self._available_voice_actions)
-
- def setSupportedLanguages(self, languages: List[str]):
- self._supported_languages = list(languages)
-
- def getSupportedLanguages(self) -> List[str]:
- return list(self._supported_languages)
-
- def isConnected(self) -> bool:
- return self._is_connected
-
- def getActiveSession(self) -> Optional[VoiceInteractionSession]:
- return self._session
-
- def setActiveSession(self, session: Optional[VoiceInteractionSession]):
- self._session = session
- self._active_session = session is not None
-
- def isActiveSession(self) -> bool:
- return self._active_session
-
- def showSession(self, args: Dict[str, Any] = None, flags: int = 0):
- """显示语音会话"""
- if self._session:
- self._session.show(args or {}, flags)
-
- def finish(self):
- """结束服务"""
- self._is_connected = False
- if self._session:
- self._session.finish()
- self._session = None
-
- def createSession(self, service_context: Any = None,
- session_id: int = 0) -> VoiceInteractionSession:
- """创建语音交互会话"""
- session = VoiceInteractionSession(service_context)
- session.setSessionId(session_id)
- self._session = session
- return session
-
- def getFeatureId(self) -> str:
- return self._feature_id
-
- def setFeatureId(self, feature_id: str):
- self._feature_id = feature_id
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def setPackageName(self, pkg: str):
- self._package_name = pkg
-
- def isDisabled(self) -> bool:
- return self._disabled_until > int(time.time() * 1000)
-
- def toString(self) -> str:
- return f"VoiceInteractionService(connected={self._is_connected})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractionSession
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractionSession(Stub):
- """VoiceInteractionSession — 语音交互会话"""
-
- STATE_UNKNOWN = 0
- STATE_LISTENING = 1
- STATE_PROCESSING = 2
- STATE_RESPONDING = 3
- STATE_INACTIVE = 4
- STATE_ERROR = 5
- STATE_FINISHED = 6
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._session_id: int = 0
- self._state: int = VoiceInteractionSession.STATE_UNKNOWN
- self._interactor: Optional[VoiceInteractor] = None
- self._current_arguments: Dict[str, Any] = {}
- self._is_active: bool = False
- self._is_finished: bool = False
- self._prompt: str = ""
- self._confidence_score: float = 0.0
- self._recognition_result: Any = None
- self._current_action: str = ""
-
- def setSessionId(self, session_id: int):
- self._session_id = session_id
-
- def getSessionId(self) -> int:
- return self._session_id
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getInteractor(self) -> Optional[VoiceInteractor]:
- return self._interactor
-
- def setInteractor(self, interactor: VoiceInteractor):
- self._interactor = interactor
-
- def show(self, args: Dict[str, Any], flags: int):
- """显示会话"""
- self._current_arguments = args
- self._is_active = True
- self._state = VoiceInteractionSession.STATE_LISTENING
- self.onShow(args, flags)
-
- def hide(self):
- """隐藏会话"""
- self._is_active = False
- self._state = VoiceInteractionSession.STATE_INACTIVE
- self.onHide()
-
- def finish(self):
- """结束会话"""
- self._is_finished = True
- self._state = VoiceInteractionSession.STATE_FINISHED
- self._is_active = False
- self.onFinish()
-
- def setPrompt(self, prompt: str):
- self._prompt = prompt
-
- def getPrompt(self) -> str:
- return self._prompt
-
- def setConfidenceScore(self, score: float):
- self._confidence_score = score
-
- def getConfidenceScore(self) -> float:
- return self._confidence_score
-
- def setRecognitionResult(self, result: Any):
- self._recognition_result = result
-
- def getRecognitionResult(self) -> Any:
- return self._recognition_result
-
- def setCurrentAction(self, action: str):
- self._current_action = action
-
- def getCurrentAction(self) -> str:
- return self._current_action
-
- def isActive(self) -> bool:
- return self._is_active
-
- def isFinished(self) -> bool:
- return self._is_finished
-
- def startListening(self, prompt: str = ""):
- """开始监听"""
- self._state = VoiceInteractionSession.STATE_LISTENING
- self._prompt = prompt
-
- def stopListening(self):
- """停止监听"""
- if self._state == VoiceInteractionSession.STATE_LISTENING:
- self._state = VoiceInteractionSession.STATE_PROCESSING
-
- def processVoiceInput(self, input_data: Any):
- """处理语音输入"""
- self._state = VoiceInteractionSession.STATE_PROCESSING
- self._recognition_result = input_data
-
- def respond(self, response: Any):
- """响应"""
- self._state = VoiceInteractionSession.STATE_RESPONDING
-
- def onShow(self, args: Dict[str, Any], flags: int):
- """会话显示回调"""
- pass
-
- def onHide(self):
- """会话隐藏回调"""
- pass
-
- def onFinish(self):
- """会话结束回调"""
- pass
-
- def onListeningStarted(self, prompt: str):
- """开始监听回调"""
- pass
-
- def onListeningFinished(self):
- """监听结束回调"""
- pass
-
- def onRecognitionResult(self, result: Any):
- """识别结果回调"""
- pass
-
- def onConfidenceScoreChanged(self, score: float):
- """置信度变化回调"""
- pass
-
- def onRequestConfirmation(self, prompt: Any):
- """请求确认回调"""
- if self._interactor:
- self._interactor.onRequestConfirmation(prompt)
-
- def onRequestSelect(self, prompt: Any, options: List[Any]):
- """请求选择回调"""
- if self._interactor:
- self._interactor.onRequestSelect(prompt, options)
-
- def onRequestComplete(self, result: Any):
- """请求完成回调"""
- if self._interactor:
- self._interactor.onRequestComplete(result)
-
- def onRequestError(self, error: Any):
- """请求错误回调"""
- if self._interactor:
- self._interactor.onRequestError(error)
-
- def toString(self) -> str:
- return f"VoiceInteractionSession(id={self._session_id}, state={self._state})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractionManager
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractionManager(Stub):
- """VoiceInteractionManager — 语音交互管理器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._active_service: Optional[VoiceInteractionService] = None
- self._supported_actions: List[str] = []
- self._is_available: bool = True
-
- @staticmethod
- def getInstance(context: Any) -> Optional[VoiceInteractionManager]:
- return VoiceInteractionManager(context)
-
- def getActiveService(self) -> Optional[VoiceInteractionService]:
- return self._active_service
-
- def setActiveService(self, service: VoiceInteractionService):
- self._active_service = service
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def setAvailable(self, available: bool):
- self._is_available = available
-
- def getSupportedActions(self) -> List[str]:
- return list(self._supported_actions)
-
- def setSupportedActions(self, actions: List[str]):
- self._supported_actions = list(actions)
-
- def startVoiceActivity(self, voice_session: VoiceInteractionSession):
- """启动语音活动"""
- voice_session.setState(VoiceInteractionSession.STATE_LISTENING)
-
- def setVoiceActivityState(self, state: int):
- """设置语音活动状态"""
- pass
-
- def showSession(self, service: VoiceInteractionService, args: Dict[str, Any],
- flags: int):
- """显示会话"""
- service.showSession(args, flags)
-
- def hideSession(self, service: VoiceInteractionService):
- """隐藏会话"""
- session = service.getActiveSession()
- if session:
- session.hide()
-
- def finishSession(self, service: VoiceInteractionService):
- """结束会话"""
- session = service.getActiveSession()
- if session:
- session.finish()
-
- def getSessionToken(self) -> Any:
- return None
-
- def toString(self) -> str:
- return f"VoiceInteractionManager(available={self._is_available})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractor
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractor(Stub):
- """VoiceInteractor — 语音交互器"""
-
- REQUEST_CONFIRMATION = "confirmation"
- REQUEST_SELECT = "select"
- REQUEST_COMPLETE = "complete"
- REQUEST_ERROR = "error"
- REQUEST_ABORT = "abort"
- REQUEST_COMMAND = "command"
-
- def __init__(self):
- super().__init__()
- self._requests: List[VoiceInteractor.Request] = []
- self._active_request: Optional[VoiceInteractor.Request] = None
- self._is_available: bool = True
-
- def submitRequest(self, request: VoiceInteractor.Request):
- """提交请求"""
- self._requests.append(request)
- self._active_request = request
-
- def cancelRequest(self, request: VoiceInteractor.Request):
- """取消请求"""
- self._requests = [r for r in self._requests if r is not request]
- if self._active_request is request:
- self._active_request = None
-
- def getActiveRequest(self) -> Optional[VoiceInteractor.Request]:
- return self._active_request
-
- def getPendingRequests(self) -> List[VoiceInteractor.Request]:
- return list(self._requests)
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def setAvailable(self, available: bool):
- self._is_available = available
-
- def onRequestConfirmation(self, prompt: Any):
- """确认请求回调"""
- request = VoiceInteractor.ConfirmationRequest(prompt)
- self.submitRequest(request)
-
- def onRequestSelect(self, prompt: Any, options: List[Any]):
- """选择请求回调"""
- request = VoiceInteractor.SelectRequest(prompt, options)
- self.submitRequest(request)
-
- def onRequestComplete(self, result: Any):
- """完成请求回调"""
- request = VoiceInteractor.CompleteRequest(result)
- self.submitRequest(request)
-
- def onRequestError(self, error: Any):
- """错误请求回调"""
- request = VoiceInteractor.ErrorRequest(error)
- self.submitRequest(request)
-
- def destroy(self):
- """销毁"""
- self._requests.clear()
- self._active_request = None
-
- def toString(self) -> str:
- return f"VoiceInteractor(requests={len(self._requests)})"
-
- # ═══════════════════════════════════════════════════════
- # VoiceInteractor.Request 基类
- # ═══════════════════════════════════════════════════════
-
- class Request(Stub):
- """VoiceInteractor.Request — 请求基类"""
-
- def __init__(self, request_type: str = ""):
- super().__init__()
- self._request_type = request_type
- self._is_active: bool = True
- self._timeout_ms: int = 30000
- self._created_at: int = int(time.time() * 1000)
- self._result: Any = None
-
- def getRequestType(self) -> str:
- return self._request_type
-
- def isActive(self) -> bool:
- return self._is_active
-
- def setActive(self, active: bool):
- self._is_active = active
-
- def getTimeoutMs(self) -> int:
- return self._timeout_ms
-
- def setTimeoutMs(self, timeout: int):
- self._timeout_ms = timeout
-
- def getCreatedAt(self) -> int:
- return self._created_at
-
- def getResult(self) -> Any:
- return self._result
-
- def setResult(self, result: Any):
- self._result = result
-
- def isExpired(self) -> bool:
- return (int(time.time() * 1000) - self._created_at) > self._timeout_ms
-
- def onCancelled(self):
- self._is_active = False
-
- # ═══════════════════════════════════════════════════════
- # ConfirmationRequest
- # ═══════════════════════════════════════════════════════
-
- class ConfirmationRequest(Request):
- """VoiceInteractor.ConfirmationRequest — 确认请求"""
-
- def __init__(self, prompt: Any = None, args: Dict[str, Any] = None):
- super().__init__(VoiceInteractor.REQUEST_CONFIRMATION)
- self._prompt = prompt
- self._args = args or {}
-
- def getPrompt(self) -> Any:
- return self._prompt
-
- def getArgs(self) -> Dict[str, Any]:
- return dict(self._args)
-
- def onConfirmationResult(self, confirmed: bool, result: Any = None):
- """确认结果回调"""
- self.setResult({"confirmed": confirmed, "data": result})
-
- # ═══════════════════════════════════════════════════════
- # SelectRequest
- # ═══════════════════════════════════════════════════════
-
- class SelectRequest(Request):
- """VoiceInteractor.SelectRequest — 选择请求"""
-
- def __init__(self, prompt: Any = None, options: List[Any] = None):
- super().__init__(VoiceInteractor.REQUEST_SELECT)
- self._prompt = prompt
- self._options = options or []
- self._selected_index: int = -1
-
- def getPrompt(self) -> Any:
- return self._prompt
-
- def getOptions(self) -> List[Any]:
- return list(self._options)
-
- def getSelectedIndex(self) -> int:
- return self._selected_index
-
- def onSelectResult(self, index: int, result: Any = None):
- """选择结果回调"""
- self._selected_index = index
- self.setResult({"index": index, "data": result})
-
- # ═══════════════════════════════════════════════════════
- # CompleteRequest
- # ═══════════════════════════════════════════════════════
-
- class CompleteRequest(Request):
- """VoiceInteractor.CompleteRequest — 完成请求"""
-
- def __init__(self, result: Any = None):
- super().__init__(VoiceInteractor.REQUEST_COMPLETE)
- self.setResult(result)
-
- def onCompleteResult(self, result: Any = None):
- """完成结果回调"""
- self.setResult(result)
-
- # ═══════════════════════════════════════════════════════
- # ErrorRequest
- # ═══════════════════════════════════════════════════════
-
- class ErrorRequest(Request):
- """VoiceInteractor.ErrorRequest — 错误请求"""
-
- def __init__(self, error: Any = None):
- super().__init__(VoiceInteractor.REQUEST_ERROR)
- self._error = error
-
- def getError(self) -> Any:
- return self._error
-
- def onErrorResult(self, error: Any = None):
- """错误结果回调"""
- self.setResult({"error": error or self._error})
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractionSessionService
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractionSessionService(Stub):
- """VoiceInteractionSessionService — 语音交互会话服务"""
-
- SERVICE_INTERFACE = "android.service.voice.VoiceInteractionSessionService"
- SERVICE_META_DATA = "android.voice_interaction"
-
- def __init__(self):
- super().__init__()
- self._service: Optional[VoiceInteractionService] = None
- self._current_session: Optional[VoiceInteractionSession] = None
- self._session_count: int = 0
- self._is_running: bool = False
-
- def onNewSession(self, args: Dict[str, Any]) -> VoiceInteractionSession:
- """创建新会话"""
- self._session_count += 1
- session = VoiceInteractionSession()
- session.setSessionId(self._session_count)
- session.show(args, 0)
- self._current_session = session
- return session
-
- def onSessionFinished(self, session: VoiceInteractionSession):
- """会话结束回调"""
- if self._current_session is session:
- self._current_session = None
- session.finish()
-
- def setVoiceInteractionService(self, service: VoiceInteractionService):
- self._service = service
-
- def getVoiceInteractionService(self) -> Optional[VoiceInteractionService]:
- return self._service
-
- def getCurrentSession(self) -> Optional[VoiceInteractionSession]:
- return self._current_session
-
- def isRunning(self) -> bool:
- return self._is_running
-
- def setRunning(self, running: bool):
- self._is_running = running
-
- def onDestroy(self):
- """销毁"""
- if self._current_session:
- self._current_session.finish()
- self._current_session = None
- self._is_running = False
-
- def toString(self) -> str:
- return f"VoiceInteractionSessionService(running={self._is_running})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractionSessionCallback
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractionSessionCallback(Stub):
- """VoiceInteractionSessionCallback — 语音交互会话回调"""
-
- def onSessionStarted(self, session: VoiceInteractionSession):
- pass
-
- def onSessionFinished(self, session: VoiceInteractionSession):
- pass
-
- def onSessionHidden(self, session: VoiceInteractionSession):
- pass
-
- def onSessionShown(self, session: VoiceInteractionSession):
- pass
-
- def onResultChanged(self, session: VoiceInteractionSession, result: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractionUtils
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractionUtils(Stub):
- """VoiceInteractionUtils — 语音交互工具类"""
-
- @staticmethod
- def isVoiceInteractionAvailable(context: Any) -> bool:
- return True
-
- @staticmethod
- def getActiveServiceComponentName(context: Any) -> Any:
- return None
-
- @staticmethod
- def getSupportedVoiceActions(context: Any) -> List[str]:
- return []
-
- @staticmethod
- def setVoiceActionEnabled(context: Any, action: str, enabled: bool):
- pass
-
- @staticmethod
- def requestVoiceInteractionService(context: Any, service: VoiceInteractionService):
- pass
-
- @staticmethod
- def createVoiceInteractor(context: Any) -> VoiceInteractor:
- return VoiceInteractor()
-
- @staticmethod
- def getVoiceInteractionServiceInfo(context: Any) -> Any:
- return None
-
- @staticmethod
- def isVoiceInteractionService(context: Any, pkg: str) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# Keyphrase (hotword detection helpers)
-# ═══════════════════════════════════════════════════════════════
-
-class Keyphrase(Stub):
- """Keyphrase — 唤醒词/关键词"""
-
- def __init__(self, phrase: str = "", id: int = 0):
- super().__init__()
- self._phrase = phrase
- self._id = id
- self._locale: str = ""
- self._confidence_level: float = 0.0
- self._is_enabled: bool = True
-
- def getPhrase(self) -> str:
- return self._phrase
-
- def setPhrase(self, phrase: str):
- self._phrase = phrase
-
- def getId(self) -> int:
- return self._id
-
- def setId(self, id: int):
- self._id = id
-
- def getLocale(self) -> str:
- return self._locale
-
- def setLocale(self, locale: str):
- self._locale = locale
-
- def getConfidenceLevel(self) -> float:
- return self._confidence_level
-
- def setConfidenceLevel(self, level: float):
- self._confidence_level = level
-
- def isEnabled(self) -> bool:
- return self._is_enabled
-
- def setEnabled(self, enabled: bool):
- self._is_enabled = enabled
-
- def toString(self) -> str:
- return f"Keyphrase(phrase={self._phrase})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# VoiceInteractionSessionActivity (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class VoiceInteractionSessionActivity(Stub):
- """VoiceInteractionSessionActivity — 语音交互会话活动"""
-
- def __init__(self):
- super().__init__()
- self._session: Optional[VoiceInteractionSession] = None
- self._activity_state: int = 0
-
- def setSession(self, session: VoiceInteractionSession):
- self._session = session
-
- def getSession(self) -> Optional[VoiceInteractionSession]:
- return self._session
-
- def getActivityState(self) -> int:
- return self._activity_state
-
- def setActivityState(self, state: int):
- self._activity_state = state
-
- def finishActivity(self):
- self._activity_state = VoiceInteractionSession.STATE_FINISHED
-
- def toString(self) -> str:
- return f"VoiceInteractionSessionActivity(state={self._activity_state})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AlwaysOnHotwordDetector (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class AlwaysOnHotwordDetector(Stub):
- """AlwaysOnHotwordDetector — 始终开启的唤醒词检测器"""
-
- STATE_NOT_READY = 0
- STATE_READY = 1
- STATE_DETECTING = 2
- STATE_PAUSED = 3
- STATE_ERROR = 4
- STATE_DISABLED = 5
-
- RECOGNITION_FLAG_NONE = 0
- RECOGNITION_FLAG_ALLOW_MULTIPLE = 1
- RECOGNITION_FLAG_CAPTURE_TRIGGER = 2
- RECOGNITION_FLAG_TRIGGER_AFTER_PREVIOUS = 4
-
- def __init__(self):
- super().__init__()
- self._state: int = AlwaysOnHotwordDetector.STATE_NOT_READY
- self._keyphrases: List[Keyphrase] = []
- self._is_detecting: bool = False
- self._detection_callback: Optional[Callable] = None
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getKeyphrases(self) -> List[Keyphrase]:
- return list(self._keyphrases)
-
- def addKeyphrase(self, keyphrase: Keyphrase):
- self._keyphrases.append(keyphrase)
-
- def startRecognition(self, recognition_flags: int = 0):
- """开始识别"""
- self._is_detecting = True
- self._state = AlwaysOnHotwordDetector.STATE_DETECTING
-
- def stopRecognition(self):
- """停止识别"""
- self._is_detecting = False
- self._state = AlwaysOnHotwordDetector.STATE_READY
-
- def isDetecting(self) -> bool:
- return self._is_detecting
-
- def setDetectionCallback(self, callback: Callable):
- self._detection_callback = callback
-
- def destroy(self):
- self._is_detecting = False
- self._state = AlwaysOnHotwordDetector.STATE_NOT_READY
- self._keyphrases.clear()
-
- def toString(self) -> str:
- return f"AlwaysOnHotwordDetector(state={self._state})"
\ No newline at end of file
diff --git a/android_pyapi/android/service_vr.py b/android_pyapi/android/service_vr.py
deleted file mode 100644
index 23c6e1e..0000000
--- a/android_pyapi/android/service_vr.py
+++ /dev/null
@@ -1,62 +0,0 @@
-"""
-Android Service VR 组件 — VrListenerService 等
-方法签名完全对齐 Android SDK (android.service.vr 包)
-"""
-
-from typing import Any, Callable, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# VrListenerService
-# ═══════════════════════════════════════════════════════════════
-
-class VrListenerService(Stub):
- """VrListenerService — VR 监听服务 (已弃用, 仅存根)"""
-
- SERVICE_INTERFACE = "android.service.vr.VrListenerService"
-
- def __init__(self):
- super().__init__()
- self._current_vr_activity: Optional[str] = None
- self._is_listening: bool = False
-
- def onCurrentVrActivityChanged(self, component: Any):
- """当前 VR Activity 变化时回调"""
- if component:
- self._current_vr_activity = str(component)
-
- def getCurrentVrActivity(self) -> Optional[str]:
- """获取当前 VR Activity"""
- return self._current_vr_activity
-
- def onConnected(self):
- """服务连接回调"""
- self._is_listening = True
-
- def onDisconnected(self):
- """服务断开回调"""
- self._is_listening = False
-
- def isListening(self) -> bool:
- return self._is_listening
-
- def toString(self) -> str:
- return (f"VrListenerService("
- f"activity={self._current_vr_activity})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "VrListenerService",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/service_wallpaper.py b/android_pyapi/android/service_wallpaper.py
deleted file mode 100644
index 4908029..0000000
--- a/android_pyapi/android/service_wallpaper.py
+++ /dev/null
@@ -1,264 +0,0 @@
-"""
-Android Service Wallpaper 组件 — WallpaperService, Engine, SurfaceHolder 等
-方法签名完全对齐 Android SDK (android.service.wallpaper 包)
-"""
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurfaceHolder
-# ═══════════════════════════════════════════════════════════════
-
-class SurfaceHolder(Stub):
- """SurfaceHolder — 表面持有者 (桌面存根)"""
-
- # 表面类型
- SURFACE_TYPE_NORMAL = 0
- SURFACE_TYPE_HARDWARE = 1
- SURFACE_TYPE_GPU = 2
- SURFACE_TYPE_PUSH_BUFFERS = 3
-
- def __init__(self):
- super().__init__()
- self._surface: Optional[Any] = None
- self._surface_frame: Optional[Any] = None
- self._surface_type: int = SurfaceHolder.SURFACE_TYPE_NORMAL
- self._fixed_size: Optional[Tuple[int, int]] = None
- self._format: int = 0 # PixelFormat.UNKNOWN
- self._callbacks: List[Any] = []
-
- def getSurface(self) -> Any:
- """获取 Surface"""
- return self._surface
-
- def getSurfaceFrame(self) -> Any:
- return self._surface_frame
-
- def isCreating(self) -> bool:
- return False
-
- def setType(self, surface_type: int):
- self._surface_type = surface_type
-
- def getType(self) -> int:
- return self._surface_type
-
- def setFormat(self, format: int):
- self._format = format
-
- def getFormat(self) -> int:
- return self._format
-
- def setFixedSize(self, width: int, height: int):
- self._fixed_size = (width, height)
-
- def setSizeFromLayout(self):
- pass
-
- def addCallback(self, callback: Any):
- if callback not in self._callbacks:
- self._callbacks.append(callback)
-
- def removeCallback(self, callback: Any):
- if callback in self._callbacks:
- self._callbacks.remove(callback)
-
- def notifySurfaceCreated(self):
- for cb in self._callbacks:
- if hasattr(cb, 'surfaceCreated'):
- cb.surfaceCreated(self)
-
- def notifySurfaceChanged(self, format: int, width: int, height: int):
- for cb in self._callbacks:
- if hasattr(cb, 'surfaceChanged'):
- cb.surfaceChanged(self, format, width, height)
-
- def notifySurfaceDestroyed(self):
- for cb in self._callbacks:
- if hasattr(cb, 'surfaceDestroyed'):
- cb.surfaceDestroyed(self)
-
- def lockCanvas(self) -> Any:
- """锁定画布"""
- return None
-
- def lockCanvas(self, dirty: Any) -> Any:
- """锁定画布 (指定脏区域)"""
- return None
-
- def unlockCanvasAndPost(self, canvas: Any):
- """解锁并提交画布"""
- pass
-
- def toString(self) -> str:
- size_str = (f"{self._fixed_size[0]}x{self._fixed_size[1]}"
- if self._fixed_size else "dynamic")
- return f"SurfaceHolder(size={size_str}, callbacks={len(self._callbacks)})"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# WallpaperService
-# ═══════════════════════════════════════════════════════════════
-
-class WallpaperService(Stub):
- """WallpaperService — 动态壁纸服务基类"""
-
- # 服务接口
- SERVICE_INTERFACE = "android.service.wallpaper.WallpaperService"
- ACTION_LIVE_WALLPAPER_CHOOSER = (
- "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER"
- )
-
- # 元数据
- META_DATA_WALLPAPER = "android.service.wallpaper"
-
- def __init__(self):
- super().__init__()
-
- def onCreate(self):
- """创建壁纸服务"""
- pass
-
- def onCreateEngine(self) -> "WallpaperService.Engine":
- """创建壁纸引擎"""
- return WallpaperService.Engine(self)
-
- def onDestroy(self):
- """销毁壁纸服务"""
- pass
-
- def toString(self) -> str:
- return f"WallpaperService@{hex(id(self))}"
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
- # ── Engine ──
-
- class Engine(Stub):
- """Engine — 壁纸引擎"""
-
- def __init__(self, service: "WallpaperService" = None):
- super().__init__()
- self._service = service
- self._is_visible: bool = True
- self._is_created: bool = False
- self._surface_holder = SurfaceHolder()
- self._surface_holder.addCallback(self)
- self._offset: Tuple[float, float, float, float, float] = (0, 0, 0, 0, 0)
- self._x_ppw: float = 1.0
- self._y_ppw: float = 1.0
- self._desired_width: int = 0
- self._desired_height: int = 0
- self._touch_events_enabled: bool = False
- self._offset_notifications_enabled: bool = False
- self._draw_count: int = 0
-
- def onCreate(self, surface_holder: SurfaceHolder):
- """创建引擎"""
- self._is_created = True
-
- def onSurfaceCreated(self, holder: SurfaceHolder):
- """表面创建时回调"""
- pass
-
- def onSurfaceDestroyed(self, holder: SurfaceHolder):
- """表面销毁时回调"""
- pass
-
- def onSurfaceChanged(self, holder: SurfaceHolder,
- format: int, width: int, height: int):
- """表面尺寸变化时回调"""
- pass
-
- def onDraw(self, canvas: Any):
- """绘制壁纸"""
- self._draw_count += 1
-
- def onOffsetsChanged(self, x_offset: float, y_offset: float,
- x_step: float, y_step: float,
- x_pixel_offset: int, y_pixel_offset: int):
- """偏移量变化回调"""
- self._offset = (x_offset, y_offset, x_step, y_step)
-
- def onTouchEvent(self, motion_event: Any):
- """触摸事件回调"""
- pass
-
- def onVisibilityChanged(self, visible: bool):
- """可见性变化回调"""
- self._is_visible = visible
-
- def setOffsetNotifications(self, x_ppw: float, y_ppw: float):
- """设置偏移通知"""
- self._x_ppw = x_ppw
- self._y_ppw = y_ppw
- self._offset_notifications_enabled = True
-
- def getSurfaceHolder(self) -> SurfaceHolder:
- """获取表面持有者"""
- return self._surface_holder
-
- def getDesiredMinimumWidth(self) -> int:
- return self._desired_width
-
- def getDesiredMinimumHeight(self) -> int:
- return self._desired_height
-
- def isVisible(self) -> bool:
- return self._is_visible
-
- def isPreview(self) -> bool:
- return False
-
- def setTouchEventsEnabled(self, enabled: bool):
- self._touch_events_enabled = enabled
-
- def setCreateSurfaceFromSurfaceControlResult(self, result: Any):
- pass
-
- def surfaceCreated(self, holder: SurfaceHolder):
- """SurfaceHolder.Callback — 表面创建"""
- self.onSurfaceCreated(holder)
-
- def surfaceChanged(self, holder: SurfaceHolder,
- format: int, width: int, height: int):
- """SurfaceHolder.Callback — 表面变化"""
- self.onSurfaceChanged(holder, format, width, height)
-
- def surfaceDestroyed(self, holder: SurfaceHolder):
- """SurfaceHolder.Callback — 表面销毁"""
- self.onSurfaceDestroyed(holder)
-
- def toString(self) -> str:
- return (f"Engine(visible={self._is_visible}, "
- f"draws={self._draw_count})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "WallpaperService",
- "SurfaceHolder",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/sip.py b/android_pyapi/android/sip.py
deleted file mode 100644
index 275d4f0..0000000
--- a/android_pyapi/android/sip.py
+++ /dev/null
@@ -1,519 +0,0 @@
-"""
-Android SIP API — SipManager, SipProfile, SipSession, SipAudioCall
-(已废弃但存在于 SDK 中)
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "SipManager",
- "SipProfile",
- "SipSession",
- "SipAudioCall",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipManager
-# ═══════════════════════════════════════════════════════════════
-
-class SipManager(Stub):
- """SipManager — SIP 会话管理器 (桌面存根, 已废弃)"""
-
- EXTRA_CALL_ID = "android.sip.extra.CALL_ID"
- EXTRA_OFFER_SD = "android.sip.extra.OFFER_SD"
- EXTRA_PEER_PROFILE = "android.sip.extra.PEER_PROFILE"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._opened = False
- self._registered = False
- self._session: Optional["SipSession"] = None
- self._listener: Optional[Callable] = None
-
- @staticmethod
- def isSipWifiOnly(context: Any) -> bool:
- """检查 SIP 是否仅限 WiFi"""
- return False
-
- @staticmethod
- def isVoipSupported(context: Any) -> bool:
- """检查是否支持 VoIP"""
- return True
-
- @staticmethod
- def isApiSupported(context: Any) -> bool:
- """检查 SIP API 是否支持"""
- return True
-
- @staticmethod
- def newInstance(context: Any) -> "SipManager":
- """创建新实例"""
- return SipManager(context)
-
- def open(self, localProfile: "SipProfile") -> "SipSession":
- """打开 SIP 会话"""
- self._opened = True
- self._session = SipSession(localProfile)
- return self._session
-
- def setRegistrationListener(
- self, localProfileUri: str, listener: "SipSession.Listener"
- ):
- """设置注册监听器"""
- if self._session:
- self._session.setListener(listener)
-
- def close(self, localProfileUri: str):
- """关闭 SIP 会话"""
- self._opened = False
- self._registered = False
- self._session = None
-
- def getSessionFor(self, intent: Any) -> Optional["SipSession"]:
- """获取 Intent 对应的 SIP 会话"""
- return self._session
-
- def register(
- self, localProfile: "SipProfile", expiryTime: int, listener: "SipSession.Listener"
- ):
- """注册 SIP"""
- raise AndroidOnlyError("SipManager.register() 仅在 Android 设备上可用")
-
- def unregister(
- self, localProfile: "SipProfile", listener: "SipSession.Listener"
- ):
- """注销 SIP"""
- raise AndroidOnlyError("SipManager.unregister() 仅在 Android 设备上可用")
-
- def isOpened(self, localProfileUri: str) -> bool:
- """检查是否已打开"""
- return self._opened
-
- def isRegistered(self, localProfileUri: str) -> bool:
- """检查是否已注册"""
- return self._registered
-
- def createSipSessionIfNeeded(self, localProfile: "SipProfile") -> "SipSession":
- """如有必要则创建 SIP 会话"""
- if self._session is None:
- self._session = SipSession(localProfile)
- return self._session
-
- def createSipProfile(self, intent: Any) -> Optional["SipProfile"]:
- """从 Intent 创建 SIP 配置文件"""
- return None
-
- def toString(self) -> str:
- return f"SipManager(opened={self._opened}, registered={self._registered})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipProfile
-# ═══════════════════════════════════════════════════════════════
-
-class SipProfile(Stub):
- """SipProfile — SIP 配置文件"""
-
- # --- Protocol constants ---
- PROTOCOL_UDP = "UDP"
- PROTOCOL_TCP = "TCP"
- PROTOCOL_TLS = "TLS"
-
- class Builder(Stub):
- """SipProfile.Builder — SIP 配置文件构建器"""
-
- def __init__(self, uri: str = ""):
- super().__init__()
- self._profile = SipProfile()
- self._profile._uri = uri
-
- def setProfileName(self, name: str) -> "SipProfile.Builder":
- self._profile._profile_name = name
- return self
-
- def setUserName(self, userName: str) -> "SipProfile.Builder":
- self._profile._user_name = userName
- return self
-
- def setDomain(self, domain: str) -> "SipProfile.Builder":
- self._profile._domain = domain
- return self
-
- def setPassword(self, password: str) -> "SipProfile.Builder":
- self._profile._password = password
- return self
-
- def setPort(self, port: int) -> "SipProfile.Builder":
- self._profile._port = port
- return self
-
- def setProtocol(self, protocol: str) -> "SipProfile.Builder":
- self._profile._protocol = protocol
- return self
-
- def setSendKeepAlive(self, enabled: bool) -> "SipProfile.Builder":
- self._profile._send_keep_alive = enabled
- return self
-
- def setAutoRegistration(self, enabled: bool) -> "SipProfile.Builder":
- self._profile._auto_registration = enabled
- return self
-
- def setDisplayName(self, displayName: str) -> "SipProfile.Builder":
- self._profile._display_name = displayName
- return self
-
- def setAuthUserName(self, authUserName: str) -> "SipProfile.Builder":
- self._profile._auth_user_name = authUserName
- return self
-
- def build(self) -> "SipProfile":
- return self._profile
-
- def toString(self) -> str:
- return f"SipProfile.Builder(name={self._profile._profile_name})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self):
- super().__init__()
- self._uri = ""
- self._profile_name = ""
- self._user_name = ""
- self._domain = ""
- self._display_name = ""
- self._password = ""
- self._protocol = self.PROTOCOL_UDP
- self._port = 5060
- self._send_keep_alive = False
- self._auto_registration = True
- self._auth_user_name = ""
-
- def getProfileName(self) -> str:
- return self._profile_name
-
- def getUserName(self) -> str:
- return self._user_name
-
- def getDomain(self) -> str:
- return self._domain
-
- def getDisplayName(self) -> str:
- return self._display_name
-
- def getPassword(self) -> str:
- return self._password
-
- def getProtocol(self) -> str:
- return self._protocol
-
- def getPort(self) -> int:
- return self._port
-
- def getSendKeepAlive(self) -> bool:
- return self._send_keep_alive
-
- def isAutoRegistration(self) -> bool:
- return self._auto_registration
-
- def getUri(self) -> str:
- return self._uri
-
- def toString(self) -> str:
- return (f"SipProfile(name={self._profile_name}, "
- f"user={self._user_name}@{self._domain})")
-
- def equals(self, other) -> bool:
- if not isinstance(other, SipProfile):
- return False
- return self._uri == other._uri
-
- def hashCode(self) -> int:
- return hash(self._uri) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipSession
-# ═══════════════════════════════════════════════════════════════
-
-class SipSession(Stub):
- """SipSession — SIP 会话"""
-
- # --- State constants ---
- STATE_READY_TO_CALL = 0
- STATE_INCOMING_CALL = 1
- STATE_INCOMING_CALL_ANSWERING = 2
- STATE_IN_CALL = 3
- STATE_OUTGOING_CALL = 4
- STATE_OUTGOING_CALL_RINGING = 5
- STATE_OUTGOING_CALL_CANCELING = 6
- STATE_PINGING = 7
- STATE_DEREGISTERING = 8
- STATE_CLOSED = 9
-
- def __init__(self, profile: "SipProfile" = None):
- super().__init__()
- self._profile = profile
- self._listener: Optional["SipSession.Listener"] = None
- self._state = self.STATE_CLOSED
- self._call_id = ""
- self._peer_profile: Optional[SipProfile] = None
- self._in_call = False
-
- def setListener(self, listener: "SipSession.Listener"):
- """设置会话监听器"""
- self._listener = listener
-
- def register(self, duration: int):
- """注册 SIP"""
- raise AndroidOnlyError("SipSession.register() 仅在 Android 设备上可用")
-
- def unregister(self):
- """注销 SIP"""
- raise AndroidOnlyError("SipSession.unregister() 仅在 Android 设备上可用")
-
- def makeAudioCall(
- self, localProfile: "SipProfile", peerProfile: "SipProfile"
- ):
- """发起音频呼叫"""
- raise AndroidOnlyError("SipSession.makeAudioCall() 仅在 Android 设备上可用")
-
- def answerCall(self, callId: str, sessionDescription: int):
- """接听呼叫"""
- raise AndroidOnlyError("SipSession.answerCall() 仅在 Android 设备上可用")
-
- def endCall(self):
- """结束呼叫"""
- raise AndroidOnlyError("SipSession.endCall() 仅在 Android 设备上可用")
-
- def changeCall(self, callId: str, sessionDescription: int):
- """更改呼叫"""
- raise AndroidOnlyError("SipSession.changeCall() 仅在 Android 设备上可用")
-
- def getCallId(self) -> str:
- return self._call_id
-
- def getPeerProfile(self) -> Optional["SipProfile"]:
- return self._peer_profile
-
- def getState(self) -> int:
- return self._state
-
- def isInCall(self) -> bool:
- return self._in_call
-
- def getLocalProfile(self) -> Optional["SipProfile"]:
- return self._profile
-
- # ═══════════════════════════════════════════════════════════
- # Listener
- # ═══════════════════════════════════════════════════════════
-
- class Listener(Stub):
- """SipSession.Listener — SIP 会话监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onCalling(self, session: "SipSession"):
- """呼叫中回调"""
- pass
-
- def onRinging(self, session: "SipSession", caller: "SipProfile"):
- """响铃回调"""
- pass
-
- def onCallEstablished(self, session: "SipSession", sessionDescription: str):
- """呼叫建立回调"""
- pass
-
- def onCallEnded(self, session: "SipSession"):
- """呼叫结束回调"""
- pass
-
- def onCallBusy(self, session: "SipSession"):
- """呼叫忙碌回调"""
- pass
-
- def onError(self, session: "SipSession", errorCode: int, errorMessage: str):
- """错误回调"""
- pass
-
- def onCallChangeFailed(self, session: "SipSession", errorCode: int, errorMessage: str):
- """呼叫变更失败回调"""
- pass
-
- def onRegistrationDone(self, session: "SipSession", duration: int):
- """注册成功回调"""
- pass
-
- def onRegistrationFailed(
- self, session: "SipSession", errorCode: int, errorMessage: str
- ):
- """注册失败回调"""
- pass
-
- def onRegistrationTimeout(self, session: "SipSession"):
- """注册超时回调"""
- pass
-
- def toString(self) -> str:
- return f"SipSession.Listener@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"SipSession(state={self._state})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SipAudioCall
-# ═══════════════════════════════════════════════════════════════
-
-class SipAudioCall(Stub):
- """SipAudioCall — SIP 音频呼叫"""
-
- def __init__(self, context: Any = None, localProfile: "SipProfile" = None):
- super().__init__()
- self._context = context
- self._local_profile = localProfile
- self._listener: Optional["SipAudioCall.Listener"] = None
- self._muted = False
- self._holding = False
- self._in_call = False
-
- def setListener(self, listener: "SipAudioCall.Listener"):
- """设置音频呼叫监听器"""
- self._listener = listener
-
- def startAudio(self):
- """开始音频"""
- raise AndroidOnlyError("SipAudioCall.startAudio() 仅在 Android 设备上可用")
-
- def stopAudio(self):
- """停止音频"""
- raise AndroidOnlyError("SipAudioCall.stopAudio() 仅在 Android 设备上可用")
-
- def close(self):
- """关闭音频呼叫"""
- self._in_call = False
- self._holding = False
-
- def isMuted(self) -> bool:
- return self._muted
-
- def toggleMute(self):
- """切换静音"""
- self._muted = not self._muted
-
- def hold(self, hold: int):
- """保持呼叫"""
- self._holding = (hold != 0)
-
- def continueCall(self, sessionDescription: int):
- """继续呼叫"""
- raise AndroidOnlyError("SipAudioCall.continueCall() 仅在 Android 设备上可用")
-
- def makeCall(
- self, localProfile: "SipProfile", peerProfile: "SipProfile", timeout: int
- ):
- """发起呼叫"""
- raise AndroidOnlyError("SipAudioCall.makeCall() 仅在 Android 设备上可用")
-
- def answerCall(self, sessionDescription: int):
- """接听呼叫"""
- raise AndroidOnlyError("SipAudioCall.answerCall() 仅在 Android 设备上可用")
-
- def sendDtmf(self, code: int):
- """发送 DTMF"""
- pass
-
- # ═══════════════════════════════════════════════════════════
- # Listener
- # ═══════════════════════════════════════════════════════════
-
- class Listener(Stub):
- """SipAudioCall.Listener — 音频呼叫监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onReadyToCall(self, call: "SipAudioCall"):
- """准备呼叫回调"""
- pass
-
- def onCallEstablished(self, call: "SipAudioCall", sessionDescription: str):
- """呼叫建立回调"""
- pass
-
- def onCallEnded(self, call: "SipAudioCall"):
- """呼叫结束回调"""
- pass
-
- def onCallHeld(self, call: "SipAudioCall"):
- """呼叫保持回调"""
- pass
-
- def onCallChanged(self, call: "SipAudioCall"):
- """呼叫变更回调"""
- pass
-
- def onError(self, call: "SipAudioCall", errorCode: int, errorMessage: str):
- """错误回调"""
- pass
-
- def onRingingBack(self, call: "SipAudioCall"):
- """回铃回调"""
- pass
-
- def onRinging(self, call: "SipAudioCall", caller: "SipProfile"):
- """响铃回调"""
- pass
-
- def toString(self) -> str:
- return f"SipAudioCall.Listener@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"SipAudioCall(inCall={self._in_call})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/speech.py b/android_pyapi/android/speech.py
deleted file mode 100644
index 1429ae5..0000000
--- a/android_pyapi/android/speech.py
+++ /dev/null
@@ -1,370 +0,0 @@
-"""
-Android Speech API — SpeechRecognizer, RecognitionListener, RecognitionService, RecognizerIntent
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-import threading
-import time
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "SpeechRecognizer",
- "RecognitionListener",
- "RecognitionService",
- "RecognizerIntent",
- "RecognizerResultsIntent",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# SpeechRecognizer
-# ═══════════════════════════════════════════════════════════════
-
-class SpeechRecognizer(Stub):
- """SpeechRecognizer — 语音识别器 (桌面麦克风模拟)"""
-
- RESULTS_RECOGNITION = "results_recognition"
- CONFIDENCE_SCORES = "confidence_scores"
-
- ERROR_NETWORK_TIMEOUT = 1
- ERROR_NETWORK = 2
- ERROR_AUDIO = 3
- ERROR_SERVER = 4
- ERROR_CLIENT = 5
- ERROR_SPEECH_TIMEOUT = 6
- ERROR_NO_MATCH = 7
- ERROR_RECOGNIZER_BUSY = 8
- ERROR_INSUFFICIENT_PERMISSIONS = 9
- ERROR_TOO_MANY_REQUESTS = 10
- ERROR_LANGUAGE_NOT_SUPPORTED = 11
- ERROR_LANGUAGE_UNAVAILABLE = 12
- ERROR_SERVER_DISCONNECTED = 13
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._listener: Optional["RecognitionListener"] = None
- self._is_listening = False
- self._destroyed = False
- self._simulate_timer: Optional[threading.Timer] = None
-
- @staticmethod
- def createSpeechRecognizer(context: Any) -> "SpeechRecognizer":
- """创建语音识别器"""
- return SpeechRecognizer(context)
-
- @staticmethod
- def isRecognitionAvailable(context: Any) -> bool:
- """检查语音识别是否可用"""
- try:
- import speech_recognition as sr
- return True
- except ImportError:
- try:
- import whisper # noqa: F401
- return True
- except ImportError:
- pass
- return False
-
- def setRecognitionListener(self, listener: "RecognitionListener"):
- """设置识别监听器"""
- self._listener = listener
-
- def startListening(self, intent: Any):
- """开始语音识别"""
- if self._destroyed:
- return
-
- self._is_listening = True
-
- # 使用简单识别模拟
- if self._listener:
- self._listener.onReadyForSpeech(None)
- self._listener.onBeginningOfSpeech()
-
- # 模拟麦克风音量变化
- for i in range(3):
- self._listener.onRmsChanged(5.0 + i * 2.0)
- time.sleep(0.05)
-
- self._listener.onBufferReceived(bytearray(1024))
- self._listener.onEndOfSpeech()
-
- # 模拟识别结果
- results = {self.RESULTS_RECOGNITION: ["hello world"], self.CONFIDENCE_SCORES: [0.95]}
- self._listener.onResults(results)
-
- def stopListening(self):
- """停止语音识别"""
- self._is_listening = False
- if self._simulate_timer:
- self._simulate_timer.cancel()
- self._simulate_timer = None
-
- def cancel(self):
- """取消语音识别"""
- self._is_listening = False
- if self._simulate_timer:
- self._simulate_timer.cancel()
- self._simulate_timer = None
- if self._listener:
- self._listener.onError(self.ERROR_NO_MATCH)
-
- def destroy(self):
- """销毁语音识别器"""
- self._destroyed = True
- self._is_listening = False
- if self._simulate_timer:
- self._simulate_timer.cancel()
- self._simulate_timer = None
- self._listener = None
-
- def toString(self) -> str:
- return f"SpeechRecognizer(listening={self._is_listening})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RecognitionListener
-# ═══════════════════════════════════════════════════════════════
-
-class RecognitionListener(Stub):
- """RecognitionListener — 语音识别监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onReadyForSpeech(self, params: Any):
- """准备开始语音识别回调"""
- pass
-
- def onBeginningOfSpeech(self):
- """开始说话回调"""
- pass
-
- def onRmsChanged(self, rmsdB: float):
- """音量变化回调"""
- pass
-
- def onBufferReceived(self, buffer: bytearray):
- """接收音频缓冲区回调"""
- pass
-
- def onEndOfSpeech(self):
- """说话结束回调"""
- pass
-
- def onError(self, error: int):
- """错误回调"""
- pass
-
- def onResults(self, results: Dict[str, Any]):
- """识别结果回调"""
- pass
-
- def onPartialResults(self, partialResults: Dict[str, Any]):
- """部分识别结果回调"""
- pass
-
- def onSegmentResults(self, segmentResults: Dict[str, Any]):
- """分段结果回调"""
- pass
-
- def onEndOfSegmentedSession(self, sessionId: int):
- """分段会话结束回调"""
- pass
-
- def onLanguageDetection(self, language: str):
- """语言检测回调"""
- pass
-
- def onEvent(self, eventType: int, params: Any):
- """事件回调"""
- pass
-
- def toString(self) -> str:
- return f"RecognitionListener@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RecognitionService
-# ═══════════════════════════════════════════════════════════════
-
-class RecognitionService(Stub):
- """RecognitionService — 语音识别服务"""
-
- SERVICE_INTERFACE = "android.speech.RecognitionService"
- SERVICE_META_DATA = "android.speech"
-
- def __init__(self):
- super().__init__()
- self._callback: Optional["RecognitionService.Callback"] = None
-
- def onStartListening(self, intent: Any, listener: "RecognitionService.Callback"):
- """开始监听回调"""
- pass
-
- def onCancel(self, listener: "RecognitionService.Callback"):
- """取消回调"""
- pass
-
- def onStopListening(self, listener: "RecognitionService.Callback"):
- """停止监听回调"""
- pass
-
- def onDestroy(self):
- """销毁回调"""
- pass
-
- def oneShotListening(self, intent: Any, listener: "RecognitionService.Callback"):
- """一次性监听"""
- if listener:
- listener.readyForSpeech(None)
- listener.beginningOfSpeech()
- listener.endOfSpeech()
- results = {SpeechRecognizer.RESULTS_RECOGNITION: ["hello"]}
- listener.results(results)
-
- def getCurrentCallback(self) -> Optional["RecognitionService.Callback"]:
- return self._callback
-
- # ═══════════════════════════════════════════════════════════
- # Callback
- # ═══════════════════════════════════════════════════════════
-
- class Callback(Stub):
- """RecognitionService.Callback — 识别服务回调"""
-
- def __init__(self):
- super().__init__()
-
- def results(self, results: Dict[str, Any]):
- """返回识别结果"""
- pass
-
- def partialResults(self, partialResults: Dict[str, Any]):
- """返回部分结果"""
- pass
-
- def error(self, error: int):
- """返回错误"""
- pass
-
- def beginningOfSpeech(self):
- """开始说话回调"""
- pass
-
- def bufferReceived(self, buffer: bytearray):
- """接收音频缓冲区回调"""
- pass
-
- def endOfSpeech(self):
- """说话结束回调"""
- pass
-
- def readyForSpeech(self, params: Any):
- """准备开始语音识别"""
- pass
-
- def rmsChanged(self, rmsdB: float):
- """音量变化回调"""
- pass
-
- def toString(self) -> str:
- return f"RecognitionService.Callback@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"RecognitionService@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RecognizerIntent
-# ═══════════════════════════════════════════════════════════════
-
-class RecognizerIntent(Stub):
- """RecognizerIntent — 识别器 Intent 常量"""
-
- ACTION_RECOGNIZE_SPEECH = "android.speech.action.RECOGNIZE_SPEECH"
- ACTION_WEB_SEARCH = "android.speech.action.WEB_SEARCH"
- ACTION_VOICE_SEARCH_HANDS_FREE = "android.speech.action.VOICE_SEARCH_HANDS_FREE"
- ACTION_GET_LANGUAGE_DETAILS = "android.speech.action.GET_LANGUAGE_DETAILS"
-
- EXTRA_LANGUAGE_MODEL = "android.speech.extra.LANGUAGE_MODEL"
- EXTRA_LANGUAGE = "android.speech.extra.LANGUAGE"
- EXTRA_MAX_RESULTS = "android.speech.extra.MAX_RESULTS"
- EXTRA_PARTIAL_RESULTS = "android.speech.extra.PARTIAL_RESULTS"
- EXTRA_CALLING_PACKAGE = "android.speech.extra.CALLING_PACKAGE"
- EXTRA_PROMPT = "android.speech.extra.PROMPT"
- EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS = "android.speech.extra.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS"
- EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extra.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS"
- EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extra.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS"
- EXTRA_CONFIDENCE_SCORES = "android.speech.extra.CONFIDENCE_SCORES"
- EXTRA_RESULTS = "android.speech.extra.RESULTS"
- EXTRA_SECURE = "android.speech.extra.SECURE"
- EXTRA_SUPPORTED_LANGUAGES = "android.speech.extra.SUPPORTED_LANGUAGES"
- EXTRA_LANGUAGE_PREFERENCE = "android.speech.extra.LANGUAGE_PREFERENCE"
- EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE"
- EXTRA_LANGUAGE_DETAILS = "android.speech.extra.LANGUAGE_DETAILS"
-
- LANGUAGE_MODEL_FREE_FORM = "free_form"
- LANGUAGE_MODEL_WEB_SEARCH = "web_search"
-
- RESULT_AUDIO_ERROR = 1
- RESULT_CLIENT_ERROR = 2
- RESULT_NETWORK_ERROR = 3
- RESULT_SERVER_ERROR = 4
- RESULT_NO_MATCH = 5
-
- DETAIL_META_DATA = "android.speech.DETAIL_META_DATA"
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# RecognizerResultsIntent
-# ═══════════════════════════════════════════════════════════════
-
-class RecognizerResultsIntent(Stub):
- """RecognizerResultsIntent — 识别结果 Intent 常量"""
-
- ACTION_VOICE_SEARCH_RESULTS = "android.speech.action.VOICE_SEARCH_RESULTS"
- EXTRA_VOICE_SEARCH_RESULT_STRINGS = "android.speech.extra.VOICE_SEARCH_RESULT_STRINGS"
- EXTRA_VOICE_SEARCH_RESULT_URLS = "android.speech.extra.VOICE_SEARCH_RESULT_URLS"
- EXTRA_VOICE_SEARCH_RESULT_HTML = "android.speech.extra.VOICE_SEARCH_RESULT_HTML"
- EXTRA_VOICE_SEARCH_RESULT_HTML_BASE_URLS = "android.speech.extra.VOICE_SEARCH_RESULT_HTML_BASE_URLS"
- URI_SCHEME_INLINE = "inline"
-
- def __init__(self):
- super().__init__()
\ No newline at end of file
diff --git a/android_pyapi/android/speech_tts.py b/android_pyapi/android/speech_tts.py
deleted file mode 100644
index 60c8dcd..0000000
--- a/android_pyapi/android/speech_tts.py
+++ /dev/null
@@ -1,401 +0,0 @@
-"""
-Android Speech/TTS 组件 — TextToSpeech, Voice, SynthesisCallback 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-import locale as _locale
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextToSpeech.OnInitListener
-# ═══════════════════════════════════════════════════════════════
-
-class TextToSpeechOnInitListener(Stub):
- """OnInitListener — 初始化监听器"""
-
- def onInit(self, status: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# UtteranceProgressListener
-# ═══════════════════════════════════════════════════════════════
-
-class UtteranceProgressListener(Stub):
- """UtteranceProgressListener — 发音进度监听器"""
-
- def onStart(self, utterance_id: str):
- pass
-
- def onDone(self, utterance_id: str):
- pass
-
- def onError(self, utterance_id: str, error_code: int = -1):
- pass
-
- def onStop(self, utterance_id: str, interrupted: bool = False):
- pass
-
- def onBeginSynthesis(self, utterance_id: str, sample_rate_in_hz: int,
- audio_format: int, channel_count: int):
- pass
-
- def onRangeStart(self, utterance_id: str, start: int, end: int, frame: int):
- pass
-
-
-class TextToSpeechOnUtteranceCompletedListener(Stub):
- """OnUtteranceCompletedListener — 旧版发音完成监听器"""
-
- def onUtteranceCompleted(self, utterance_id: str):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# SynthesisRequest
-# ═══════════════════════════════════════════════════════════════
-
-class SynthesisRequest(Stub):
- """SynthesisRequest — 合成请求"""
-
- def __init__(self):
- super().__init__()
- self._text: str = ""
- self._speech_rate: float = 1.0
- self._voice: Optional["Voice"] = None
- self._calling_uid: int = 0
- self._country: str = ""
- self._language: str = ""
- self._variant: str = ""
- self._params: Dict[str, str] = {}
-
- def getText(self) -> str:
- return self._text
-
- def getSpeechRate(self) -> float:
- return self._speech_rate
-
- def getVoice(self) -> Optional["Voice"]:
- return self._voice
-
- def getCallingUid(self) -> int:
- return self._calling_uid
-
- def getCountry(self) -> str:
- return self._country
-
- def getLanguage(self) -> str:
- return self._language
-
- def getVariant(self) -> str:
- return self._variant
-
- def getParams(self) -> Dict[str, str]:
- return dict(self._params)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SynthesisCallback
-# ═══════════════════════════════════════════════════════════════
-
-class SynthesisCallback(Stub):
- """SynthesisCallback — 合成回调"""
-
- def start(self, sample_rate_in_hz: int, audio_format: int, channel_count: int) -> int:
- return 0
-
- def getMaxBufferSize(self) -> int:
- return 8192
-
- def getChannelCount(self) -> int:
- return 1
-
- def getAudioFormat(self) -> int:
- return 1
-
- def getSampleRate(self) -> int:
- return 22050
-
- def availableBuffer(self, buffer_size: int) -> int:
- return buffer_size
-
- def audioAvailable(self, audio: bytes) -> int:
- return len(audio)
-
- def done(self) -> int:
- return 0
-
- def error(self) -> int:
- return -1
-
- def hasStarted(self) -> bool:
- return False
-
- def hasFinished(self) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Voice
-# ═══════════════════════════════════════════════════════════════
-
-class Voice(Stub):
- """Voice — 语音"""
-
- QUALITY_DEFAULT = -1
- QUALITY_VERY_LOW = 100
- QUALITY_LOW = 200
- QUALITY_NORMAL = 300
- QUALITY_HIGH = 400
- QUALITY_VERY_HIGH = 500
-
- LATENCY_DEFAULT = -1
- LATENCY_VERY_LOW = 100
- LATENCY_LOW = 200
- LATENCY_NORMAL = 300
- LATENCY_HIGH = 400
- LATENCY_VERY_HIGH = 500
-
- def __init__(self, name: str = "", locale: Any = None,
- quality: int = QUALITY_NORMAL, latency: int = LATENCY_NORMAL,
- requires_network: bool = False,
- features: Optional[List[str]] = None):
- super().__init__()
- self._name = name
- self._locale = locale or _locale.getdefaultlocale()[0]
- self._quality = quality
- self._latency = latency
- self._requires_network = requires_network
- self._features = features or []
-
- def getName(self) -> str:
- return self._name
-
- def getLocale(self) -> Any:
- return self._locale
-
- def getQuality(self) -> int:
- return self._quality
-
- def getLatency(self) -> int:
- return self._latency
-
- def isNetworkConnectionRequired(self) -> bool:
- return self._requires_network
-
- def getFeatures(self) -> List[str]:
- return list(self._features)
-
- def toString(self) -> str:
- return f"Voice(name={self._name}, locale={self._locale})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextToSpeech.Engine
-# ═══════════════════════════════════════════════════════════════
-
-class TextToSpeechEngine(Stub):
- """TextToSpeech.Engine — TTS 引擎元数据"""
-
- ACTION_CHECK_TTS_DATA = "android.speech.tts.engine.CHECK_TTS_DATA"
- ACTION_INSTALL_TTS_DATA = "android.speech.tts.engine.INSTALL_TTS_DATA"
- ACTION_GET_SAMPLE_TEXT = "android.speech.tts.engine.GET_SAMPLE_TEXT"
-
- KEY_PARAM_STREAM = "streamType"
- KEY_PARAM_VOLUME = "volume"
- KEY_PARAM_PAN = "pan"
- KEY_PARAM_UTTERANCE_ID = "utteranceId"
- KEY_PARAM_SESSION_ID = "sessionId"
-
- KEY_FEATURE_NETWORK_SYNTHESIS = "networkSynthesis"
- KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedSynthesis"
- KEY_FEATURE_NOT_INSTALLED = "notInstalled"
-
- DEFAULT_STREAM = 3
- DEFAULT_LANG = "eng"
- DEFAULT_COUNTRY = "USA"
- DEFAULT_VARIANT = ""
-
- @staticmethod
- def getLocaleLang(lang: str) -> str:
- return lang[:3] if len(lang) >= 3 else lang
-
- @staticmethod
- def getLocaleCountry(lang: str) -> str:
- return lang[3:6] if len(lang) >= 6 else ""
-
- @staticmethod
- def getLocaleVariant(lang: str) -> str:
- return lang[6:] if len(lang) > 6 else ""
-
-
-Engine = TextToSpeechEngine
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextToSpeech
-# ═══════════════════════════════════════════════════════════════
-
-class TextToSpeech(Stub):
- """TextToSpeech — 文字转语音"""
-
- SUCCESS = 0
- ERROR = -1
- STOPPED = -2
-
- QUEUE_FLUSH = 0
- QUEUE_ADD = 1
-
- LANG_COUNTRY_AVAILABLE = 1
- LANG_AVAILABLE = 0
- LANG_COUNTRY_VAR_AVAILABLE = 2
- LANG_MISSING_DATA = -1
- LANG_NOT_SUPPORTED = -2
-
- Engine = TextToSpeechEngine
-
- def __init__(self, context: Any = None, listener: Optional[TextToSpeechOnInitListener] = None):
- super().__init__()
- self._context = context
- self._listener = listener
- self._utterance_progress_listener: Optional[UtteranceProgressListener] = None
- self._language: str = ""
- self._country: str = ""
- self._pitch: float = 1.0
- self._speech_rate: float = 1.0
- self._voice: Optional[Voice] = None
- self._voices: List[Voice] = [
- Voice("en-us-1", "en_US", Voice.QUALITY_HIGH, Voice.LATENCY_NORMAL),
- Voice("en-gb-1", "en_GB", Voice.QUALITY_NORMAL, Voice.LATENCY_NORMAL),
- Voice("zh-cn-1", "zh_CN", Voice.QUALITY_HIGH, Voice.LATENCY_NORMAL),
- ]
- self._engine_package: str = ""
- self._initialized = False
- if listener:
- try:
- listener.onInit(self.SUCCESS)
- except Exception:
- pass
- self._initialized = True
-
- def speak(self, text: str, queue_mode: int = QUEUE_FLUSH,
- params: Any = None, utterance_id: str = "") -> int:
- return self.SUCCESS
-
- def stop(self) -> int:
- return self.SUCCESS
-
- def shutdown(self):
- self._initialized = False
-
- def setLanguage(self, language: str, country: str = "", variant: str = "") -> int:
- self._language = language
- self._country = country
- return self.LANG_AVAILABLE
-
- def getLanguage(self) -> Tuple[str, str, str]:
- return (self._language, self._country, "")
-
- def isLanguageAvailable(self, language: str, country: str = "",
- variant: str = "") -> int:
- return self.LANG_AVAILABLE
-
- def setOnUtteranceProgressListener(self, listener: UtteranceProgressListener):
- self._utterance_progress_listener = listener
-
- def setOnUtteranceCompletedListener(self, listener: TextToSpeechOnUtteranceCompletedListener):
- pass
-
- def setPitch(self, pitch: float) -> int:
- self._pitch = pitch
- return self.SUCCESS
-
- def setSpeechRate(self, rate: float) -> int:
- self._speech_rate = rate
- return self.SUCCESS
-
- def getVoice(self) -> Optional[Voice]:
- return self._voice
-
- def setVoice(self, voice: Voice) -> int:
- self._voice = voice
- return self.SUCCESS
-
- def getVoices(self) -> Set[Voice]:
- return set(self._voices)
-
- def addSpeech(self, text: str, filename: str) -> int:
- return self.SUCCESS
-
- def addEyes(self, text: str, filename: str) -> int:
- return self.SUCCESS
-
- def synthesizeToFile(self, text: str, params: Any, filename: str) -> int:
- return self.SUCCESS
-
- def setEngineByPackageName(self, package_name: str):
- self._engine_package = package_name
-
- def getDefaultEngine(self) -> Optional[str]:
- return "com.android.tts"
-
- def getEngines(self) -> List["EngineInfo"]:
- return []
-
- def getFeatures(self, locale: Any) -> Set[str]:
- return set()
-
- def areDefaultsEnforced(self) -> bool:
- return False
-
- def setQueueMode(self, queue_mode: int):
- pass
-
- def isSpeaking(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"TextToSpeech(lang={self._language})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EngineInfo
-# ═══════════════════════════════════════════════════════════════
-
-class EngineInfo(Stub):
- """EngineInfo — 引擎信息"""
-
- def __init__(self):
- super().__init__()
- self.name: str = ""
- self.label: str = ""
- self.icon: int = 0
- self.priority: int = 0
- self.system: bool = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "TextToSpeech",
- "TextToSpeechEngine",
- "TextToSpeechOnInitListener",
- "TextToSpeechOnUtteranceCompletedListener",
- "SynthesisCallback",
- "SynthesisRequest",
- "Voice",
- "UtteranceProgressListener",
- "Engine",
- "EngineInfo",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/system.py b/android_pyapi/android/system.py
deleted file mode 100644
index 8e2eae6..0000000
--- a/android_pyapi/android/system.py
+++ /dev/null
@@ -1,592 +0,0 @@
-"""
-Android System 组件 — Os, StructStat, StructUtsname, OsConstants 等
-方法签名完全对齐 Android SDK (android.system 包)
-"""
-
-import os as _os
-import stat as _stat
-import platform
-import errno
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# OsConstants
-# ═══════════════════════════════════════════════════════════════
-
-class OsConstants(Stub):
- """OsConstants — 系统调用常量,映射自 os/stat 模块"""
-
- # 文件访问常量
- R_OK = _os.R_OK
- W_OK = _os.W_OK
- X_OK = _os.X_OK
- F_OK = _os.F_OK
-
- # 文件权限常量
- S_IRWXU = _stat.S_IRWXU
- S_IRUSR = _stat.S_IRUSR
- S_IWUSR = _stat.S_IWUSR
- S_IXUSR = _stat.S_IXUSR
- S_IRWXG = _stat.S_IRWXG
- S_IRGRP = _stat.S_IRGRP
- S_IWGRP = _stat.S_IWGRP
- S_IXGRP = _stat.S_IXGRP
- S_IRWXO = _stat.S_IRWXO
- S_IROTH = _stat.S_IROTH
- S_IWOTH = _stat.S_IWOTH
- S_IXOTH = _stat.S_IXOTH
- S_ISUID = _stat.S_ISUID
- S_ISGID = _stat.S_ISGID
- S_ISVTX = _stat.S_ISVTX
-
- # 文件类型常量
- S_IFMT = _stat.S_IFMT
- S_IFSOCK = _stat.S_IFSOCK
- S_IFLNK = _stat.S_IFLNK
- S_IFREG = _stat.S_IFREG
- S_IFBLK = _stat.S_IFBLK
- S_IFDIR = _stat.S_IFDIR
- S_IFCHR = _stat.S_IFCHR
- S_IFIFO = _stat.S_IFIFO
-
- # 标准文件描述符
- STDIN_FILENO = 0
- STDOUT_FILENO = 1
- STDERR_FILENO = 2
-
- # 信号常量
- SIGHUP = 1
- SIGINT = 2
- SIGQUIT = 3
- SIGILL = 4
- SIGTRAP = 5
- SIGABRT = 6
- SIGBUS = 7
- SIGFPE = 8
- SIGKILL = 9
- SIGUSR1 = 10
- SIGSEGV = 11
- SIGUSR2 = 12
- SIGPIPE = 13
- SIGALRM = 14
- SIGTERM = 15
- SIGCHLD = 17
- SIGCONT = 18
- SIGSTOP = 19
- SIGTSTP = 20
- SIGTTIN = 21
- SIGTTOU = 22
-
- # errno 常量 (使用 getattr 处理 Windows 上不存在的常量)
- EPERM = errno.EPERM
- ENOENT = errno.ENOENT
- ESRCH = errno.ESRCH
- EINTR = errno.EINTR
- EIO = errno.EIO
- ENXIO = errno.ENXIO
- E2BIG = errno.E2BIG
- ENOEXEC = errno.ENOEXEC
- EBADF = errno.EBADF
- ECHILD = errno.ECHILD
- EAGAIN = errno.EAGAIN
- ENOMEM = errno.ENOMEM
- EACCES = errno.EACCES
- EFAULT = errno.EFAULT
- ENOTBLK = getattr(errno, 'ENOTBLK', 15) # Windows 不支持
- EBUSY = errno.EBUSY
- EEXIST = errno.EEXIST
- EXDEV = errno.EXDEV
- ENODEV = errno.ENODEV
- ENOTDIR = errno.ENOTDIR
- EISDIR = errno.EISDIR
- EINVAL = errno.EINVAL
- ENFILE = errno.ENFILE
- EMFILE = errno.EMFILE
- ENOTTY = errno.ENOTTY
- ETXTBSY = getattr(errno, 'ETXTBSY', 139)
- EFBIG = errno.EFBIG
- ENOSPC = errno.ENOSPC
- ESPIPE = errno.ESPIPE
- EROFS = errno.EROFS
- EMLINK = errno.EMLINK
- EPIPE = errno.EPIPE
- EDOM = errno.EDOM
- ERANGE = errno.ERANGE
- EDEADLK = errno.EDEADLK
- ENAMETOOLONG = errno.ENAMETOOLONG
- ENOLCK = errno.ENOLCK
- ENOSYS = errno.ENOSYS
- ENOTEMPTY = errno.ENOTEMPTY
- ELOOP = errno.ELOOP
- ENOMSG = errno.ENOMSG
- EIDRM = errno.EIDRM
- ENOSTR = getattr(errno, 'ENOSTR', 125)
- ENODATA = getattr(errno, 'ENODATA', 120)
- ETIME = getattr(errno, 'ETIME', 137)
- ENOSR = getattr(errno, 'ENOSR', 124)
- EREMOTE = getattr(errno, 'EREMOTE', 10071)
- ENOLINK = getattr(errno, 'ENOLINK', 121)
- EPROTO = errno.EPROTO
- EMULTIHOP = getattr(errno, 'EMULTIHOP', 10072) # Windows 不支持
- EBADMSG = getattr(errno, 'EBADMSG', 104)
- EOVERFLOW = getattr(errno, 'EOVERFLOW', 132)
- EILSEQ = errno.EILSEQ
- ENOTSOCK = errno.ENOTSOCK
- EDESTADDRREQ = errno.EDESTADDRREQ
- EMSGSIZE = errno.EMSGSIZE
- EPROTOTYPE = errno.EPROTOTYPE
- ENOPROTOOPT = errno.ENOPROTOOPT
- EPROTONOSUPPORT = errno.EPROTONOSUPPORT
- ESOCKTNOSUPPORT = getattr(errno, 'ESOCKTNOSUPPORT', 10044)
- EOPNOTSUPP = getattr(errno, 'EOPNOTSUPP', 10045)
- EPFNOSUPPORT = getattr(errno, 'EPFNOSUPPORT', 10046)
- EAFNOSUPPORT = getattr(errno, 'EAFNOSUPPORT', 10047)
- EADDRINUSE = errno.EADDRINUSE
- EADDRNOTAVAIL = errno.EADDRNOTAVAIL
- ENETDOWN = errno.ENETDOWN
- ENETUNREACH = errno.ENETUNREACH
- ENETRESET = errno.ENETRESET
- ECONNABORTED = errno.ECONNABORTED
- ECONNRESET = errno.ECONNRESET
- ENOBUFS = errno.ENOBUFS
- EISCONN = errno.EISCONN
- ENOTCONN = errno.ENOTCONN
- ESHUTDOWN = getattr(errno, 'ESHUTDOWN', 10058)
- ETOOMANYREFS = getattr(errno, 'ETOOMANYREFS', 10059)
- ETIMEDOUT = errno.ETIMEDOUT
- ECONNREFUSED = errno.ECONNREFUSED
- EHOSTDOWN = getattr(errno, 'EHOSTDOWN', 10064)
- EHOSTUNREACH = errno.EHOSTUNREACH
- EALREADY = errno.EALREADY
- EINPROGRESS = errno.EINPROGRESS
- ESTALE = getattr(errno, 'ESTALE', 10070)
- EUCLEAN = getattr(errno, 'EUCLEAN', 117) # Windows 不支持
- ENOTNAM = getattr(errno, 'ENOTNAM', 118) # Windows 不支持
- ENAVAIL = getattr(errno, 'ENAVAIL', 119) # Windows 不支持
- EISNAM = getattr(errno, 'EISNAM', 120) # Windows 不支持
- EREMOTEIO = getattr(errno, 'EREMOTEIO', 121) # Windows 不支持
- EDQUOT = getattr(errno, 'EDQUOT', 10069)
- ENOMEDIUM = getattr(errno, 'ENOMEDIUM', 123) # Windows 不支持
- EMEDIUMTYPE = getattr(errno, 'EMEDIUMTYPE', 124) # Windows 不支持
- ECANCELED = getattr(errno, 'ECANCELED', 105)
- ENOKEY = getattr(errno, 'ENOKEY', 126) # Windows 不支持
- EKEYEXPIRED = getattr(errno, 'EKEYEXPIRED', 127) # Windows 不支持
- EKEYREVOKED = getattr(errno, 'EKEYREVOKED', 128) # Windows 不支持
- EKEYREJECTED = getattr(errno, 'EKEYREJECTED', 129) # Windows 不支持
- EOWNERDEAD = getattr(errno, 'EOWNERDEAD', 133)
- ENOTRECOVERABLE = getattr(errno, 'ENOTRECOVERABLE', 127)
- ERFKILL = getattr(errno, 'ERFKILL', 132) # Windows 不支持
- EHWPOISON = getattr(errno, 'EHWPOISON', 1001) # Windows 不支持
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# StructStat
-# ═══════════════════════════════════════════════════════════════
-
-class StructStat(Stub):
- """StructStat — stat() 返回的文件状态结构体"""
-
- def __init__(self, st_mode: int = 0, st_ino: int = 0, st_dev: int = 0,
- st_nlink: int = 0, st_uid: int = 0, st_gid: int = 0,
- st_size: int = 0, st_atime: int = 0, st_mtime: int = 0,
- st_ctime: int = 0, st_blksize: int = 4096,
- st_blocks: int = 0, st_rdev: int = 0):
- super().__init__()
- self.st_mode = st_mode
- self.st_ino = st_ino
- self.st_dev = st_dev
- self.st_nlink = st_nlink
- self.st_uid = st_uid
- self.st_gid = st_gid
- self.st_size = st_size
- self.st_atime = st_atime
- self.st_mtime = st_mtime
- self.st_ctime = st_ctime
- self.st_blksize = st_blksize
- self.st_blocks = st_blocks
- self.st_rdev = st_rdev
- self.st_atime_ns = st_atime * 1_000_000_000
- self.st_mtime_ns = st_mtime * 1_000_000_000
- self.st_ctime_ns = st_ctime * 1_000_000_000
-
- @staticmethod
- def from_os_stat(st: _os.stat_result) -> "StructStat":
- """从 Python os.stat_result 创建 StructStat"""
- return StructStat(
- st_mode=st.st_mode,
- st_ino=st.st_ino,
- st_dev=st.st_dev,
- st_nlink=st.st_nlink,
- st_uid=st.st_uid,
- st_gid=st.st_gid,
- st_size=st.st_size,
- st_atime=int(st.st_atime),
- st_mtime=int(st.st_mtime),
- st_ctime=int(st.st_ctime),
- st_blksize=st.st_blksize,
- st_blocks=st.st_blocks,
- st_rdev=st.st_rdev,
- )
-
- def toString(self) -> str:
- return (f"StructStat(st_mode={oct(self.st_mode)}, st_size={self.st_size}, "
- f"st_mtime={self.st_mtime}, st_uid={self.st_uid}, st_gid={self.st_gid})")
-
- def hashCode(self) -> int:
- return hash((self.st_dev, self.st_ino, self.st_mode)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, StructStat):
- return False
- return (self.st_dev == other.st_dev and self.st_ino == other.st_ino
- and self.st_mode == other.st_mode and self.st_size == other.st_size)
-
-
-# ═══════════════════════════════════════════════════════════════
-# StructUtsname
-# ═══════════════════════════════════════════════════════════════
-
-class StructUtsname(Stub):
- """StructUtsname — uname() 返回的系统信息结构体"""
-
- def __init__(self, sysname: str = "", nodename: str = "",
- release: str = "", version: str = "", machine: str = ""):
- super().__init__()
- self.sysname = sysname or platform.system()
- self.nodename = nodename or platform.node()
- self.release = release or platform.release()
- self.version = version or platform.version()
- self.machine = machine or platform.machine()
-
- @staticmethod
- def from_platform() -> "StructUtsname":
- """从 Python platform 模块创建 StructUtsname"""
- uname = platform.uname()
- return StructUtsname(
- sysname=uname.system,
- nodename=uname.node,
- release=uname.release,
- version=uname.version,
- machine=uname.machine,
- )
-
- def toString(self) -> str:
- return (f"StructUtsname(sysname={self.sysname}, nodename={self.nodename}, "
- f"release={self.release}, version={self.version}, machine={self.machine})")
-
- def hashCode(self) -> int:
- return hash((self.sysname, self.nodename, self.release)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, StructUtsname):
- return False
- return (self.sysname == other.sysname and self.nodename == other.nodename
- and self.release == other.release)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Os
-# ═══════════════════════════════════════════════════════════════
-
-class Os(Stub):
- """Os — 系统调用包装器,代理到 Python os 模块"""
-
- def __init__(self):
- super().__init__()
-
- # ── 文件操作 ──
-
- @staticmethod
- def stat(path: str) -> StructStat:
- """获取文件状态"""
- st = _os.stat(path)
- return StructStat.from_os_stat(st)
-
- @staticmethod
- def lstat(path: str) -> StructStat:
- """获取符号链接自身状态"""
- st = _os.lstat(path)
- return StructStat.from_os_stat(st)
-
- @staticmethod
- def chmod(path: str, mode: int):
- """修改文件权限"""
- _os.chmod(path, mode)
-
- @staticmethod
- def chown(path: str, uid: int, gid: int):
- """修改文件所有者"""
- _os.chown(path, uid, gid)
-
- @staticmethod
- def link(oldpath: str, newpath: str):
- """创建硬链接"""
- _os.link(oldpath, newpath)
-
- @staticmethod
- def symlink(target: str, linkpath: str):
- """创建符号链接"""
- _os.symlink(target, linkpath)
-
- @staticmethod
- def readlink(path: str) -> str:
- """读取符号链接目标"""
- return _os.readlink(path)
-
- @staticmethod
- def unlink(pathname: str):
- """删除文件(解除链接)"""
- _os.unlink(pathname)
-
- @staticmethod
- def remove(path: str):
- """删除文件"""
- _os.remove(path)
-
- @staticmethod
- def rename(oldpath: str, newpath: str):
- """重命名文件"""
- _os.rename(oldpath, newpath)
-
- @staticmethod
- def mkdir(path: str, mode: int = 0o777):
- """创建目录"""
- _os.mkdir(path, mode)
-
- @staticmethod
- def rmdir(path: str):
- """删除空目录"""
- _os.rmdir(path)
-
- @staticmethod
- def listdir(path: str) -> List[str]:
- """列出目录内容"""
- return _os.listdir(path)
-
- @staticmethod
- def truncate(path: str, length: int):
- """截断文件到指定长度"""
- with open(path, 'ab') as f:
- f.truncate(length)
-
- @staticmethod
- def access(path: str, mode: int) -> bool:
- """检查文件访问权限"""
- return _os.access(path, mode)
-
- # ── 文件描述符操作 ──
-
- @staticmethod
- def dup(oldfd: int) -> int:
- """复制文件描述符"""
- return _os.dup(oldfd)
-
- @staticmethod
- def dup2(oldfd: int, newfd: int):
- """复制文件描述符到指定值"""
- _os.dup2(oldfd, newfd)
-
- @staticmethod
- def close(fd: int):
- """关闭文件描述符"""
- _os.close(fd)
-
- @staticmethod
- def read(fd: int, count: int) -> bytes:
- """从文件描述符读取"""
- return _os.read(fd, count)
-
- @staticmethod
- def write(fd: int, data: bytes) -> int:
- """写入文件描述符"""
- return _os.write(fd, data)
-
- @staticmethod
- def lseek(fd: int, offset: int, whence: int) -> int:
- """移动文件读写位置"""
- return _os.lseek(fd, offset, whence)
-
- @staticmethod
- def fsync(fd: int):
- """同步文件描述符"""
- _os.fsync(fd)
-
- @staticmethod
- def fstat(fd: int) -> StructStat:
- """获取文件描述符对应文件状态"""
- st = _os.fstat(fd)
- return StructStat.from_os_stat(st)
-
- @staticmethod
- def isatty(fd: int) -> bool:
- """判断文件描述符是否为终端"""
- return _os.isatty(fd)
-
- # ── 进程相关 ──
-
- @staticmethod
- def getpid() -> int:
- """获取当前进程 ID"""
- return _os.getpid()
-
- @staticmethod
- def getppid() -> int:
- """获取父进程 ID"""
- return _os.getppid()
-
- @staticmethod
- def getuid() -> int:
- """获取当前用户 ID"""
- return _os.getuid()
-
- @staticmethod
- def getgid() -> int:
- """获取当前组 ID"""
- return _os.getgid()
-
- @staticmethod
- def geteuid() -> int:
- """获取有效用户 ID"""
- return _os.geteuid()
-
- @staticmethod
- def getegid() -> int:
- """获取有效组 ID"""
- return _os.getegid()
-
- @staticmethod
- def setuid(uid: int):
- """设置用户 ID"""
- _os.setuid(uid)
-
- @staticmethod
- def setgid(gid: int):
- """设置组 ID"""
- _os.setgid(gid)
-
- @staticmethod
- def setsid() -> int:
- """创建新会话"""
- return _os.setsid()
-
- @staticmethod
- def umask(mask: int) -> int:
- """设置文件创建掩码"""
- return _os.umask(mask)
-
- @staticmethod
- def kill(pid: int, sig: int):
- """发送信号给进程"""
- _os.kill(pid, sig)
-
- @staticmethod
- def getenv(name: str, default: Optional[str] = None) -> Optional[str]:
- """获取环境变量"""
- return _os.environ.get(name, default)
-
- @staticmethod
- def setenv(name: str, value: str, overwrite: bool = True):
- """设置环境变量"""
- if overwrite or name not in _os.environ:
- _os.environ[name] = value
-
- @staticmethod
- def unsetenv(name: str):
- """删除环境变量"""
- _os.environ.pop(name, None)
-
- @staticmethod
- def environ() -> Dict[str, str]:
- """获取环境变量字典"""
- return dict(_os.environ)
-
- # ── 系统信息 ──
-
- @staticmethod
- def uname() -> StructUtsname:
- """获取系统信息"""
- return StructUtsname.from_platform()
-
- @staticmethod
- def sysconf(name: str) -> int:
- """获取系统配置值"""
- conf_names = {
- "SC_CLK_TCK": 100,
- "SC_PAGE_SIZE": 4096,
- "SC_NPROCESSORS_CONF": _os.cpu_count() or 1,
- "SC_NPROCESSORS_ONLN": _os.cpu_count() or 1,
- }
- return conf_names.get(name, -1)
-
- @staticmethod
- def getpagesize() -> int:
- """获取内存页大小"""
- return 4096
-
- @staticmethod
- def getloadavg() -> List[float]:
- """获取系统负载平均值"""
- try:
- return list(_os.getloadavg())
- except AttributeError:
- return [0.0, 0.0, 0.0]
-
- # ── 管道与 I/O ──
-
- @staticmethod
- def pipe() -> Tuple[int, int]:
- """创建管道"""
- return _os.pipe()
-
- @staticmethod
- def mkfifo(path: str, mode: int = 0o666):
- """创建命名管道 (FIFO)"""
- _os.mkfifo(path, mode)
-
- @staticmethod
- def tmpfile() -> str:
- """创建临时文件路径"""
- import tempfile
- return tempfile.mktemp()
-
- # ── 时间 ──
-
- @staticmethod
- def time() -> int:
- """获取当前时间戳 (秒)"""
- import time
- return int(time.time())
-
- # ── 其他 ──
-
- @staticmethod
- def strerror(errno: int) -> str:
- """将错误码转为错误描述"""
- return _os.strerror(errno)
-
- def toString(self) -> str:
- return f"Os(sysname={platform.system()}, release={platform.release()})"
-
- def hashCode(self) -> int:
- return hash("android.system.Os") & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return isinstance(other, Os)
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Os",
- "StructStat",
- "StructUtsname",
- "OsConstants",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/telecom.py b/android_pyapi/android/telecom.py
deleted file mode 100644
index f25dab4..0000000
--- a/android_pyapi/android/telecom.py
+++ /dev/null
@@ -1,737 +0,0 @@
-"""
-Android Telecom API — TelecomManager, Call, CallAudioState, DisconnectCause, PhoneAccount, Connection
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-import time
-from typing import Any, Dict, List, Optional, Set, Tuple, Callable
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "TelecomManager",
- "Call",
- "CallAudioState",
- "DisconnectCause",
- "PhoneAccount",
- "Connection",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# TelecomManager
-# ═══════════════════════════════════════════════════════════════
-
-class TelecomManager(Stub):
- """TelecomManager — 电信管理器 (桌面存根)"""
-
- ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER"
- ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS"
- ACTION_SETTINGS = "android.telecom.action.SETTINGS"
- ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION"
- ACTION_CALL_FORWARDING = "android.telecom.action.CALL_FORWARDING"
- ACTION_DEFAULT_CALL_SCREENING_APP = "android.telecom.action.DEFAULT_CALL_SCREENING_APP"
- ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED"
- ACTION_NEW_UNKNOWN_CALL = "android.telecom.action.NEW_UNKNOWN_CALL"
- ACTION_TTY_PREFERRED = "android.telecom.action.TTY_PREFERRED"
- ACTION_TTY_ENABLED = "android.telecom.action.TTY_ENABLED"
- ACTION_TTY_DISABLED = "android.telecom.action.TTY_DISABLED"
- ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE"
- ACTION_CALL_DIAGNOSTIC_STATE_CHANGED = "android.telecom.action.CALL_DIAGNOSTIC_STATE_CHANGED"
- DURATION_SHORT = "short"
- DURATION_LONG = "long"
- EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER"
- EXTRA_CALL_CREATED_TIME_MILLIS = "android.telecom.extra.CALL_CREATED_TIME_MILLIS"
- EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE"
- EXTRA_CALL_NETWORK_TYPE = "android.telecom.extra.CALL_NETWORK_TYPE"
- EXTRA_CALL_SUBSTATE = "android.telecom.extra.CALL_SUBSTATE"
- EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME"
- EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE"
- EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE"
- EXTRA_DISCONNECT_CAUSE_DESCRIPTION = "android.telecom.extra.DISCONNECT_CAUSE_DESCRIPTION"
- EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE"
- EXTRA_PRIORITY = "android.telecom.extra.PRIORITY"
- EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE"
- EXTRA_HANDOVER_FROM = "android.telecom.extra.HANDOVER_FROM"
- EXTRA_HANDOVER_TO = "android.telecom.extra.HANDOVER_TO"
- EXTRA_IS_HANDOVER = "android.telecom.extra.IS_HANDOVER"
- TTY_MODE_OFF = 0
- TTY_MODE_FULL = 1
- TTY_MODE_HCO = 2
- TTY_MODE_VCO = 3
- PRESENTATION_ALLOWED = 1
- PRESENTATION_RESTRICTED = 2
- PRESENTATION_UNKNOWN = 3
- PRESENTATION_PAYPHONE = 4
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._default_dialer = "com.android.dialer"
- self._phone_accounts: Dict[str, Any] = {}
-
- def getDefaultDialerPackage(self) -> str:
- """获取默认拨号器包名"""
- return self._default_dialer
-
- def getCurrentTtyMode(self) -> int:
- """获取当前 TTY 模式"""
- return self.TTY_MODE_OFF
-
- def getCallCapablePhoneAccounts(self) -> List[Any]:
- """获取可通话的电话账户"""
- return list(self._phone_accounts.values())
-
- def getPhoneAccount(self, accountHandle: Any) -> Optional[Any]:
- """获取指定电话账户"""
- return self._phone_accounts.get(str(accountHandle))
-
- def getPhoneAccountList(self) -> List[Any]:
- """获取电话账户列表"""
- return list(self._phone_accounts.values())
-
- def getSimConfig(self, accountHandle: Any) -> Optional[Any]:
- """获取 SIM 配置"""
- return None
-
- def registerPhoneAccount(self, account: "PhoneAccount"):
- """注册电话账户"""
- self._phone_accounts[str(account.getAccountHandle())] = account
-
- def unregisterPhoneAccount(self, accountHandle: Any):
- """注销电话账户"""
- self._phone_accounts.pop(str(accountHandle), None)
-
- def clearPhoneAccounts(self):
- """清除所有电话账户"""
- self._phone_accounts.clear()
-
- def clearAccounts(self):
- """清除所有账户"""
- self._phone_accounts.clear()
-
- def showInCallScreen(self, showDialpad: bool):
- """显示通话界面"""
- pass
-
- def acceptRingingCall(self):
- """接听响铃呼叫"""
- pass
-
- def silenceRinger(self):
- """静音铃声"""
- pass
-
- def isInCall(self) -> bool:
- """检查是否正在通话"""
- return False
-
- def isInManagedCall(self) -> bool:
- """检查是否在托管通话中"""
- return False
-
- def addNewIncomingCall(self, phoneAccount: "PhoneAccount", extras: Any = None):
- """添加新的来电"""
- pass
-
- def addNewUnknownCall(self, phoneAccount: "PhoneAccount", extras: Any = None):
- """添加新的未知呼叫"""
- pass
-
- def handleCreateConferenceComplete(
- self, callId: str, response: Any
- ):
- """处理创建会议完成"""
- pass
-
- def transferCall(self, callId: str, targetPhoneAccount: Any):
- """转移呼叫"""
- pass
-
- def setUserSelectedOutgoingPhoneAccount(
- self, accountHandle: Any
- ):
- """设置用户选择的呼出电话账户"""
- pass
-
- def toString(self) -> str:
- return f"TelecomManager@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# Call
-# ═══════════════════════════════════════════════════════════════
-
-class Call(Stub):
- """Call — 通话 (桌面存根)"""
-
- STATE_ACTIVE = 1
- STATE_HOLDING = 2
- STATE_DIALING = 3
- STATE_RINGING = 4
- STATE_CONNECTING = 5
- STATE_DISCONNECTED = 6
- STATE_DISCONNECTING = 7
- STATE_SELECT_PHONE_ACCOUNT = 8
- STATE_NEW = 9
- STATE_PULLING_CALL = 10
-
- def __init__(self):
- super().__init__()
- self._state = self.STATE_NEW
- self._details: Optional["Call.Details"] = None
- self._conferenceable_calls: List["Call"] = []
- self._callbacks: List[Callable] = []
- self._listeners: List[Callable] = []
-
- def getState(self) -> int:
- return self._state
-
- def getDetails(self) -> Optional["Call.Details"]:
- return self._details
-
- def getConferenceableCalls(self) -> List["Call"]:
- return list(self._conferenceable_calls)
-
- def registerCallback(self, callback: Callable):
- if callback not in self._callbacks:
- self._callbacks.append(callback)
-
- def unregisterCallback(self, callback: Callable):
- if callback in self._callbacks:
- self._callbacks.remove(callback)
-
- def addListener(self, listener: Callable):
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeListener(self, listener: Callable):
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def answer(self, videoState: int = 0):
- """接听通话"""
- self._state = self.STATE_ACTIVE
-
- def reject(self, rejectWithMessage: bool = False, textMessage: str = ""):
- """拒绝通话"""
- self._state = self.STATE_DISCONNECTED
-
- def disconnect(self):
- """挂断通话"""
- self._state = self.STATE_DISCONNECTED
-
- def hold(self):
- """保持通话"""
- self._state = self.STATE_HOLDING
-
- def unhold(self):
- """取消保持"""
- self._state = self.STATE_ACTIVE
-
- def playDtmfTone(self, digit: str):
- """播放 DTMF 音"""
- pass
-
- def stopDtmfTone(self):
- """停止 DTMF 音"""
- pass
-
- def postDialWait(self, remaining: str):
- """后拨号等待"""
- pass
-
- def mergeConference(self):
- """合并会议"""
- pass
-
- def splitFromConference(self):
- """从会议分离"""
- pass
-
- def sendCallEvent(self, event: str, extras: Any = None):
- """发送通话事件"""
- pass
-
- def putExtra(self, key: str, value: Any):
- """设置额外信息"""
- pass
-
- # ═══════════════════════════════════════════════════════════
- # Details
- # ═══════════════════════════════════════════════════════════
-
- class Details(Stub):
- """Call.Details — 通话详细信息"""
-
- DIRECTION_INCOMING = 1
- DIRECTION_OUTGOING = 2
-
- CAPABILITY_HOLD = 1
- CAPABILITY_SUPPORT_HOLD = 2
- CAPABILITY_MERGE_CONFERENCE = 4
- CAPABILITY_SWAP_CONFERENCE = 8
- CAPABILITY_RESPOND_VIA_TEXT = 16
- CAPABILITY_MUTE = 32
- CAPABILITY_MANAGE_CONFERENCE = 64
- CAPABILITY_SUPPORTS_VT_LOCAL = 128
- CAPABILITY_SUPPORTS_VT_REMOTE = 256
- CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 512
- CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 1024
- CAPABILITY_SUPPORTS_DOWNGRADE_VT_TO_AUDIO = 2048
- CAPABILITY_SUPPORTS_VIDEO_CALLING = 4096
- CAPABILITY_SUPPORTS_VT_LOCAL_RX = 8192
- CAPABILITY_SUPPORTS_VT_LOCAL_TX = 16384
- CAPABILITY_SUPPORTS_VT_REMOTE_RX = 32768
- CAPABILITY_SUPPORTS_VT_REMOTE_TX = 65536
- CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 131072
- CAPABILITY_CAN_PAUSE_VIDEO = 262144
- CAPABILITY_SELF_MANAGED = 524288
- CAPABILITY_SUPPORTS_VOIP = 1048576
- CAPABILITY_ADD_PARTICIPANT = 2097152
- CAPABILITY_CAN_UPGRADE_TO_VIDEO = 4194304
-
- PROPERTY_HIGH_DEF_AUDIO = 1
- PROPERTY_WIFI = 2
- PROPERTY_EMERGENCY_CALLBACK = 4
- PROPERTY_IS_EXTERNAL_CALL = 8
- PROPERTY_HAS_CDMA_VOICE_PRIVACY = 16
- PROPERTY_SELF_MANAGED = 32
- PROPERTY_ASSISTED_DIALING = 64
- PROPERTY_NETWORK_IDENTIFIED = 128
- PROPERTY_CALL_AUTO_FORWARDED = 256
- PROPERTY_CALL_TYPE_UNKNOWN = 512
- PROPERTY_IS_VOIP_AUDIO_MODE = 1024
- PROPERTY_IS_DOWNGRADED_CALL = 2048
- PROPERTY_ENTITLEMENT_CHANNEL = 4096
- PROPERTY_PULLED_CALL = 8192
- PROPERTY_CROSS_SIM = 16384
- PROPERTY_VIDEO_CALL = 32768
- PROPERTY_RTT = 65536
-
- def __init__(self):
- super().__init__()
- self._handle: Any = None
- self._gateway_info: Any = None
- self._caller_display_name: str = ""
- self._call_direction = self.DIRECTION_INCOMING
- self._account_handle: Any = None
- self._call_capabilities = 0
- self._call_properties = 0
- self._caller_info: Any = None
- self._creation_time_millis = 0
- self._connect_time_millis = 0
- self._disconnect_cause: Any = None
- self._video_state = 0
- self._intent_extras: Any = None
- self._extras: Any = None
-
- def getHandle(self) -> Optional[Any]:
- return self._handle
-
- def getGatewayInfo(self) -> Optional[Any]:
- return self._gateway_info
-
- def getCallerDisplayName(self) -> str:
- return self._caller_display_name
-
- def getCallDirection(self) -> int:
- return self._call_direction
-
- def getAccountHandle(self) -> Optional[Any]:
- return self._account_handle
-
- def getCallCapabilities(self) -> int:
- return self._call_capabilities
-
- def getCallProperties(self) -> int:
- return self._call_properties
-
- def getCallerInfo(self) -> Optional[Any]:
- return self._caller_info
-
- def getCreationTimeMillis(self) -> int:
- return self._creation_time_millis
-
- def getConnectTimeMillis(self) -> int:
- return self._connect_time_millis
-
- def getDisconnectCause(self) -> Optional["DisconnectCause"]:
- return self._disconnect_cause
-
- def getVideoState(self) -> int:
- return self._video_state
-
- def getIntentExtras(self) -> Optional[Any]:
- return self._intent_extras
-
- def getExtras(self) -> Optional[Any]:
- return self._extras
-
- def toString(self) -> str:
- return f"Call.Details(handle={self._handle})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"Call(state={self._state})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, Call):
- return False
- return self._state == other._state and self._details == other._details
-
- def hashCode(self) -> int:
- return self._state & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# CallAudioState
-# ═══════════════════════════════════════════════════════════════
-
-class CallAudioState(Stub):
- """CallAudioState — 通话音频状态"""
-
- ROUTE_EARPIECE = 1
- ROUTE_SPEAKER = 2
- ROUTE_BLUETOOTH = 4
- ROUTE_WIRED_HEADSET = 8
- ROUTE_WIRED_OR_EARPIECE = 9
-
- def __init__(self):
- super().__init__()
- self._route = self.ROUTE_EARPIECE
- self._supported_route_mask = (
- self.ROUTE_EARPIECE | self.ROUTE_SPEAKER | self.ROUTE_WIRED_HEADSET
- )
-
- def getRoute(self) -> int:
- return self._route
-
- def getSupportedRouteMask(self) -> int:
- return self._supported_route_mask
-
- def toString(self) -> str:
- return f"CallAudioState(route={self._route})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, CallAudioState):
- return False
- return self._route == other._route
-
- def hashCode(self) -> int:
- return self._route & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# DisconnectCause
-# ═══════════════════════════════════════════════════════════════
-
-class DisconnectCause(Stub):
- """DisconnectCause — 断连原因"""
-
- LOCAL = 1
- REMOTE = 2
- BUSY = 3
- CANCELED = 4
- NO_ANSWER = 5
- MISSED = 6
- ERROR = 7
- REJECTED = 8
- NUMBER_UNREACHABLE = 9
- RESTRICTED = 10
- OTHER = 11
- ANSWERED_ELSEWHERE = 12
- CALL_PULLED = 13
-
- def __init__(self, causeCode: int = OTHER):
- super().__init__()
- self._cause_code = causeCode
- self._reason: str = ""
- self._description: str = ""
-
- def getCode(self) -> int:
- return self._cause_code
-
- def getReason(self) -> str:
- return self._reason
-
- def getDescription(self) -> str:
- return self._description
-
- def toString(self) -> str:
- return f"DisconnectCause(code={self._cause_code})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, DisconnectCause):
- return False
- return self._cause_code == other._cause_code
-
- def hashCode(self) -> int:
- return self._cause_code & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# PhoneAccount
-# ═══════════════════════════════════════════════════════════════
-
-class PhoneAccount(Stub):
- """PhoneAccount — 电话账户"""
-
- CAP_HOLD = 1
- CAP_ADD_CALL = 2
- CAP_MULTI_ENDPOINT = 4
- CAP_CONFERENCE = 8
- CAP_VIDEO_CALLING = 16
- CAP_CALL_COMPOSER = 32
- CAP_CONNECTION_MANAGER = 64
-
- EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS"
- EXTRA_ADD_SELF_MANAGED_CALLS = "android.telecom.extra.ADD_SELF_MANAGED_CALLS"
-
- SCREENING_ALLOW = 0
- SCREENING_STOP = 1
- SCREENING_SILENCE = 2
- SCREENING_DISALLOW = 3
-
- SCHEME_SIP = "sip"
- SCHEME_TEL = "tel"
- SCHEME_VOICEMAIL = "voicemail"
-
- class Builder(Stub):
- """PhoneAccount.Builder — 电话账户构建器"""
-
- def __init__(self, accountHandle: Any, label: str):
- super().__init__()
- self._account = PhoneAccount()
- self._account._account_handle = accountHandle
- self._account._label = label
-
- def setCapabilities(self, capabilities: int) -> "PhoneAccount.Builder":
- self._account._capabilities = capabilities
- return self
-
- def setAddress(self, address: Any) -> "PhoneAccount.Builder":
- self._account._address = address
- return self
-
- def setSubscriptionAddress(self, address: Any) -> "PhoneAccount.Builder":
- self._account._subscription_address = address
- return self
-
- def setSupportedUriSchemes(
- self, uriSchemes: List[str]
- ) -> "PhoneAccount.Builder":
- self._account._supported_uri_schemes = list(uriSchemes)
- return self
-
- def setIcon(self, icon: Any) -> "PhoneAccount.Builder":
- self._account._icon = icon
- return self
-
- def setHighlightColor(self, color: int) -> "PhoneAccount.Builder":
- self._account._highlight_color = color
- return self
-
- def setShortDescription(self, description: str) -> "PhoneAccount.Builder":
- self._account._short_description = description
- return self
-
- def addSupportedUriScheme(
- self, uriScheme: str
- ) -> "PhoneAccount.Builder":
- if uriScheme not in self._account._supported_uri_schemes:
- self._account._supported_uri_schemes.append(uriScheme)
- return self
-
- def setExtras(self, extras: Any) -> "PhoneAccount.Builder":
- self._account._extras = extras
- return self
-
- def build(self) -> "PhoneAccount":
- return self._account
-
- def toString(self) -> str:
- return f"PhoneAccount.Builder(label={self._account._label})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self):
- super().__init__()
- self._account_handle: Any = None
- self._label: str = ""
- self._capabilities: int = 0
- self._address: Any = None
- self._subscription_address: Any = None
- self._supported_uri_schemes: List[str] = [self.SCHEME_TEL]
- self._icon: Any = None
- self._highlight_color: int = 0
- self._short_description: str = ""
- self._extras: Any = None
-
- def getAccountHandle(self) -> Optional[Any]:
- return self._account_handle
-
- def getLabel(self) -> str:
- return self._label
-
- def getCapabilities(self) -> int:
- return self._capabilities
-
- def getAddress(self) -> Optional[Any]:
- return self._address
-
- def getSubscriptionAddress(self) -> Optional[Any]:
- return self._subscription_address
-
- def getSupportedUriSchemes(self) -> List[str]:
- return list(self._supported_uri_schemes)
-
- def getIcon(self) -> Optional[Any]:
- return self._icon
-
- def getHighlightColor(self) -> int:
- return self._highlight_color
-
- def getShortDescription(self) -> str:
- return self._short_description
-
- def getExtras(self) -> Optional[Any]:
- return self._extras
-
- def toString(self) -> str:
- return f"PhoneAccount(label={self._label})"
-
- def equals(self, other) -> bool:
- if not isinstance(other, PhoneAccount):
- return False
- return self._account_handle == other._account_handle
-
- def hashCode(self) -> int:
- return hash(str(self._account_handle)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# Connection
-# ═══════════════════════════════════════════════════════════════
-
-class Connection(Stub):
- """Connection — 通话连接 (桌面存根)"""
-
- STATE_INITIALIZING = 0
- STATE_ACTIVE = 1
- STATE_DIALING = 2
- STATE_RINGING = 3
- STATE_HOLDING = 4
- STATE_DISCONNECTED = 5
- STATE_PULLING_CALL = 6
-
- CAPABILITY_HOLD = 1
- CAPABILITY_SUPPORT_HOLD = 2
- CAPABILITY_MERGE_CONFERENCE = 4
- CAPABILITY_SWAP_CONFERENCE = 8
- CAPABILITY_RESPOND_VIA_TEXT = 16
- CAPABILITY_MUTE = 32
- CAPABILITY_MANAGE_CONFERENCE = 64
- CAPABILITY_SUPPORTS_VT_LOCAL = 128
- CAPABILITY_SUPPORTS_VT_REMOTE = 256
- CAPABILITY_SUPPORTS_VIDEO_CALLING = 4096
- CAPABILITY_SELF_MANAGED = 524288
- CAPABILITY_SUPPORTS_VOIP = 1048576
- CAPABILITY_ADD_PARTICIPANT = 2097152
-
- PROPERTY_SELF_MANAGED = 32
- PROPERTY_IS_VOIP_AUDIO_MODE = 1024
- PROPERTY_HIGH_DEF_AUDIO = 1
- PROPERTY_WIFI = 2
-
- def __init__(self):
- super().__init__()
- self._state = self.STATE_INITIALIZING
- self._video_state = 0
- self._connection_capabilities = 0
- self._connection_properties = 0
- self._audio_mode_is_voip = False
- self._conferenceable_connections: List["Connection"] = []
- self._extras: Dict[str, Any] = {}
-
- def setVideoState(self, videoState: int):
- self._video_state = videoState
-
- def setActive(self):
- self._state = self.STATE_ACTIVE
-
- def setRinging(self):
- self._state = self.STATE_RINGING
-
- def setDialing(self):
- self._state = self.STATE_DIALING
-
- def setHolding(self):
- self._state = self.STATE_HOLDING
-
- def setDisconnected(self, disconnectCause: "DisconnectCause"):
- self._state = self.STATE_DISCONNECTED
-
- def setPostDialWait(self, remaining: str):
- pass
-
- def setConferenceableConnections(
- self, conferenceable: List["Connection"]
- ):
- self._conferenceable_connections = list(conferenceable)
-
- def setAudioModeIsVoip(self, isVoip: bool):
- self._audio_mode_is_voip = isVoip
-
- def setConnectionCapabilities(self, capabilities: int):
- self._connection_capabilities = capabilities
-
- def setConnectionProperties(self, properties: int):
- self._connection_properties = properties
-
- def putExtra(self, key: str, value: Any):
- self._extras[key] = value
-
- def onShowIncomingCallUi(self):
- pass
-
- def onCallAudioStateChanged(self, audioState: "CallAudioState"):
- pass
-
- def destroy(self):
- self._state = self.STATE_DISCONNECTED
-
- def onCallFilteringCompleted(self, completion: Any):
- pass
-
- def onSilence(self):
- pass
-
- def toString(self) -> str:
- return f"Connection(state={self._state})"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/telephony.py b/android_pyapi/android/telephony.py
deleted file mode 100644
index ce54f90..0000000
--- a/android_pyapi/android/telephony.py
+++ /dev/null
@@ -1,709 +0,0 @@
-"""
-Android Telephony 组件 — TelephonyManager, CellInfo, PhoneStateListener 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-import random
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-try:
- from .._linux_impl import IS_LINUX, LinuxNetwork, LinuxProcess, LinuxLocation
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# CellIdentity 基类集合
-# ═══════════════════════════════════════════════════════════════
-
-class CellIdentity(Stub):
- def __init__(self):
- super().__init__()
-
-
-class CellIdentityGsm(CellIdentity):
- def __init__(self, mcc: int = 0, mnc: int = 0, lac: int = 0, cid: int = 0, arfcn: int = 0):
- super().__init__()
- self._mcc = mcc
- self._mnc = mnc
- self._lac = lac
- self._cid = cid
- self._arfcn = arfcn
-
- def getMcc(self) -> int: return self._mcc
- def getMnc(self) -> int: return self._mnc
- def getLac(self) -> int: return self._lac
- def getCid(self) -> int: return self._cid
- def getArfcn(self) -> int: return self._arfcn
-
-
-class CellIdentityCdma(CellIdentity):
- def __init__(self, network_id: int = 0, system_id: int = 0, basestation_id: int = 0,
- latitude: int = 0, longitude: int = 0):
- super().__init__()
- self._network_id = network_id
- self._system_id = system_id
- self._basestation_id = basestation_id
- self._latitude = latitude
- self._longitude = longitude
-
- def getNetworkId(self) -> int: return self._network_id
- def getSystemId(self) -> int: return self._system_id
- def getBasestationId(self) -> int: return self._basestation_id
- def getLatitude(self) -> int: return self._latitude
- def getLongitude(self) -> int: return self._longitude
-
-
-class CellIdentityLte(CellIdentity):
- def __init__(self, mcc: int = 0, mnc: int = 0, ci: int = 0, pci: int = 0, tac: int = 0):
- super().__init__()
- self._mcc = mcc; self._mnc = mnc
- self._ci = ci; self._pci = pci; self._tac = tac
-
- def getMcc(self) -> int: return self._mcc
- def getMnc(self) -> int: return self._mnc
- def getCi(self) -> int: return self._ci
- def getPci(self) -> int: return self._pci
- def getTac(self) -> int: return self._tac
-
-
-class CellIdentityWcdma(CellIdentity):
- def __init__(self, mcc: int = 0, mnc: int = 0, lac: int = 0, cid: int = 0, psc: int = 0):
- super().__init__()
- self._mcc = mcc; self._mnc = mnc
- self._lac = lac; self._cid = cid; self._psc = psc
-
- def getMcc(self) -> int: return self._mcc
- def getMnc(self) -> int: return self._mnc
- def getLac(self) -> int: return self._lac
- def getCid(self) -> int: return self._cid
- def getPsc(self) -> int: return self._psc
-
-
-class CellIdentityNr(CellIdentity):
- def __init__(self, mcc: int = 0, mnc: int = 0, nci: int = 0, pci: int = 0, tac: int = 0):
- super().__init__()
- self._mcc = mcc; self._mnc = mnc
- self._nci = nci; self._pci = pci; self._tac = tac
-
- def getMcc(self) -> int: return self._mcc
- def getMnc(self) -> int: return self._mnc
- def getNci(self) -> int: return self._nci
- def getPci(self) -> int: return self._pci
- def getTac(self) -> int: return self._tac
-
-
-# ═══════════════════════════════════════════════════════════════
-# CellSignalStrength 基类集合
-# ═══════════════════════════════════════════════════════════════
-
-class CellSignalStrength(Stub):
- SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0
- SIGNAL_STRENGTH_POOR = 1
- SIGNAL_STRENGTH_MODERATE = 2
- SIGNAL_STRENGTH_GOOD = 3
- SIGNAL_STRENGTH_GREAT = 4
-
- def getLevel(self) -> int:
- return self.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
-
- def getAsuLevel(self) -> int:
- return 0
-
- def getDbm(self) -> int:
- return 0
-
-
-class CellSignalStrengthGsm(CellSignalStrength):
- def __init__(self, rssi: int = 0, ber: int = 0, ta: int = 0):
- super().__init__()
- self._rssi = rssi; self._ber = ber; self._ta = ta
-
- def getRssi(self) -> int: return self._rssi
- def getDbm(self) -> int: return self._rssi - 113 if self._rssi > 0 else 0
-
-
-class CellSignalStrengthCdma(CellSignalStrength):
- def __init__(self, dbm: int = 0, ecio: int = 0, evdo_dbm: int = 0, evdo_ecio: int = 0,
- evdo_snr: int = 0):
- super().__init__()
- self._dbm = dbm; self._ecio = ecio
- self._evdo_dbm = evdo_dbm; self._evdo_ecio = evdo_ecio; self._evdo_snr = evdo_snr
-
- def getDbm(self) -> int: return self._dbm
-
-
-class CellSignalStrengthLte(CellSignalStrength):
- def __init__(self, rssi: int = 0, rsrp: int = 0, rsrq: int = 0, rssnr: int = 0,
- cqi: int = 0, ta: int = 0):
- super().__init__()
- self._rssi = rssi; self._rsrp = rsrp; self._rsrq = rsrq
- self._rssnr = rssnr; self._cqi = cqi; self._ta = ta
-
- def getRsrp(self) -> int: return self._rsrp
- def getRsrq(self) -> int: return self._rsrq
- def getRssnr(self) -> int: return self._rssnr
- def getDbm(self) -> int: return self._rsrp
-
-
-class CellSignalStrengthWcdma(CellSignalStrength):
- def __init__(self, rscp: int = 0, ecno: int = 0):
- super().__init__()
- self._rscp = rscp; self._ecno = ecno
-
- def getRscp(self) -> int: return self._rscp
- def getEcno(self) -> int: return self._ecno
- def getDbm(self) -> int: return self._rscp - 113 if self._rscp > 0 else 0
-
-
-class CellSignalStrengthNr(CellSignalStrength):
- def __init__(self, ssRsrp: int = 0, ssRsrq: int = 0, ssSinr: int = 0, csiRsrp: int = 0):
- super().__init__()
- self._ssRsrp = ssRsrp; self._ssRsrq = ssRsrq
- self._ssSinr = ssSinr; self._csiRsrp = csiRsrp
-
- def getSsRsrp(self) -> int: return self._ssRsrp
- def getDbm(self) -> int: return self._ssRsrp
-
-
-# ═══════════════════════════════════════════════════════════════
-# CellInfo 基类集合
-# ═══════════════════════════════════════════════════════════════
-
-class CellInfo(Stub):
- UNAVAILABLE = 0x7FFFFFFF
- TIMESTAMP_TYPE_UNKNOWN = 0
- TIMESTAMP_TYPE_GSM = 1
- TIMESTAMP_TYPE_UMTS = 2
- TIMESTAMP_TYPE_CDMA = 3
- TIMESTAMP_TYPE_LTE = 4
- TIMESTAMP_TYPE_WCDMA = 5
- TIMESTAMP_TYPE_NR = 6
-
- def __init__(self):
- super().__init__()
- self._registered = False
- self._timestamp = 0
- self._connection_status = 0
-
- def isRegistered(self) -> bool: return self._registered
- def getTimeStamp(self) -> int: return self._timestamp
- def getCellConnectionStatus(self) -> int: return self._connection_status
-
-
-class CellInfoGsm(CellInfo):
- def __init__(self):
- super().__init__()
- self._identity = CellIdentityGsm()
- self._signal_strength = CellSignalStrengthGsm()
-
- def getCellIdentity(self) -> CellIdentityGsm: return self._identity
- def getCellSignalStrength(self) -> CellSignalStrengthGsm: return self._signal_strength
-
-
-class CellInfoCdma(CellInfo):
- def __init__(self):
- super().__init__()
- self._identity = CellIdentityCdma()
- self._signal_strength = CellSignalStrengthCdma()
-
- def getCellIdentity(self) -> CellIdentityCdma: return self._identity
- def getCellSignalStrength(self) -> CellSignalStrengthCdma: return self._signal_strength
-
-
-class CellInfoLte(CellInfo):
- def __init__(self):
- super().__init__()
- self._identity = CellIdentityLte()
- self._signal_strength = CellSignalStrengthLte()
-
- def getCellIdentity(self) -> CellIdentityLte: return self._identity
- def getCellSignalStrength(self) -> CellSignalStrengthLte: return self._signal_strength
-
-
-class CellInfoWcdma(CellInfo):
- def __init__(self):
- super().__init__()
- self._identity = CellIdentityWcdma()
- self._signal_strength = CellSignalStrengthWcdma()
-
- def getCellIdentity(self) -> CellIdentityWcdma: return self._identity
- def getCellSignalStrength(self) -> CellSignalStrengthWcdma: return self._signal_strength
-
-
-class CellInfoNr(CellInfo):
- def __init__(self):
- super().__init__()
- self._identity = CellIdentityNr()
- self._signal_strength = CellSignalStrengthNr()
-
- def getCellIdentity(self) -> CellIdentityNr: return self._identity
- def getCellSignalStrength(self) -> CellSignalStrengthNr: return self._signal_strength
-
-
-# ═══════════════════════════════════════════════════════════════
-# PhoneStateListener
-# ═══════════════════════════════════════════════════════════════
-
-class PhoneStateListener(Stub):
- LISTEN_NONE = 0
- LISTEN_SERVICE_STATE = 1
- LISTEN_SIGNAL_STRENGTHS = 2
- LISTEN_MESSAGE_WAITING_INDICATOR = 4
- LISTEN_CALL_FORWARDING_INDICATOR = 8
- LISTEN_CELL_LOCATION = 16
- LISTEN_CALL_STATE = 32
- LISTEN_DATA_CONNECTION_STATE = 64
- LISTEN_DATA_ACTIVITY = 128
- LISTEN_SIGNAL_STRENGTH = 256
- LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 512
- LISTEN_CELL_INFO = 1024
- LISTEN_PRECISE_CALL_STATE = 2048
- LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096
- LISTEN_DATA_CONNECTION_REAL_TIME_INFO = 8192
- LISTEN_OEM_HOOK_RAW_EVENT = 32768
- LISTEN_SRVCC_STATE_CHANGED = 65536
- LISTEN_CARRIER_NETWORK_CHANGE = 131072
- LISTEN_VOICE_ACTIVATION_STATE = 262144
- LISTEN_DATA_ACTIVATION_STATE = 524288
- LISTEN_USER_MOBILE_DATA_STATE = 1048576
- LISTEN_DISPLAY_INFO_CHANGED = 2097152
- LISTEN_PHONE_CAPABILITY_CHANGE = 4194304
- LISTEN_ACTIVE_PHONE_TYPE_CHANGE = 8388608
- LISTEN_EMERGENCY_NUMBER_LIST = 16777216
- LISTEN_EMERGENCY_NUMBER_SOURCE = 33554432
- LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864
- LISTEN_BARRING_INFO_CHANGED = 134217728
- LISTEN_ALL = 2147483647
-
- def __init__(self, looper: Any = None):
- super().__init__()
- self._looper = looper
-
- def onServiceStateChanged(self, service_state: "ServiceState"):
- pass
-
- def onSignalStrengthsChanged(self, signal_strength: "SignalStrength"):
- pass
-
- def onMessageWaitingIndicatorChanged(self, mwi: bool):
- pass
-
- def onCallForwardingIndicatorChanged(self, cfi: bool):
- pass
-
- def onCellLocationChanged(self, location: Any):
- pass
-
- def onCallStateChanged(self, state: int, phone_number: str):
- pass
-
- def onDataConnectionStateChanged(self, state: int, network_type: int = 0):
- pass
-
- def onDataActivity(self, direction: int):
- pass
-
- def onSignalStrengthChanged(self, asu: int):
- pass
-
- def onCellInfoChanged(self, cell_info: List[CellInfo]):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ServiceState / SignalStrength
-# ═══════════════════════════════════════════════════════════════
-
-class ServiceState(Stub):
- STATE_IN_SERVICE = 0
- STATE_OUT_OF_SERVICE = 1
- STATE_EMERGENCY_ONLY = 2
- STATE_POWER_OFF = 3
-
- def __init__(self):
- super().__init__()
- self._state = self.STATE_OUT_OF_SERVICE
- self._roaming = False
- self._operator_alpha_long: str = ""
- self._operator_alpha_short: str = ""
- self._operator_numeric: str = ""
- self._is_manual_selection = False
- self._cdma_default_roaming_indicator = -1
- self._cdma_eri_icon_index = -1
- self._cdma_eri_icon_mode = -1
- self._cdma_roaming_indicator = -1
- self._channel_number = 0
-
- def getState(self) -> int: return self._state
- def setState(self, state: int): self._state = state
- def getRoaming(self) -> bool: return self._roaming
- def setRoaming(self, roaming: bool): self._roaming = roaming
- def getOperatorAlphaLong(self) -> str: return self._operator_alpha_long
- def getOperatorAlphaShort(self) -> str: return self._operator_alpha_short
- def getOperatorNumeric(self) -> str: return self._operator_numeric
- def getIsManualSelection(self) -> bool: return self._is_manual_selection
- def getCdmaDefaultRoamingIndicator(self) -> int: return self._cdma_default_roaming_indicator
- def getCdmaEriIconIndex(self) -> int: return self._cdma_eri_icon_index
- def getCdmaEriIconMode(self) -> int: return self._cdma_eri_icon_mode
- def getCdmaRoamingIndicator(self) -> int: return self._cdma_roaming_indicator
- def getChannelNumber(self) -> int: return self._channel_number
- def getNetworkRegistrationInfo(self, domain: int, transport_type: int) -> Any:
- return None
- def toString(self) -> str:
- return f"ServiceState(state={self._state}, roaming={self._roaming})"
-
-
-class SignalStrength(Stub):
- NUM_SIGNAL_STRENGTH_BINS = 5
- SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0
- SIGNAL_STRENGTH_POOR = 1
- SIGNAL_STRENGTH_MODERATE = 2
- SIGNAL_STRENGTH_GOOD = 3
- SIGNAL_STRENGTH_GREAT = 4
-
- def __init__(self):
- super().__init__()
- self._gsm_signal_strength = 0
- self._cdma_dbm = 0
- self._cdma_ecio = 0
- self._evdo_dbm = 0
- self._evdo_ecio = 0
- self._evdo_snr = 0
- self._lte_signal_strength = 0
- self._td_scdma_rscp = 0
-
- def getGsmSignalStrength(self) -> int: return self._gsm_signal_strength
- def getCdmaDbm(self) -> int: return self._cdma_dbm
- def getCdmaEcio(self) -> int: return self._cdma_ecio
- def getEvdoDbm(self) -> int: return self._evdo_dbm
- def getEvdoEcio(self) -> int: return self._evdo_ecio
- def getEvdoSnr(self) -> int: return self._evdo_snr
- def getLteSignalStrength(self) -> int: return self._lte_signal_strength
- def getLevel(self) -> int: return self.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
- def getAsuLevel(self) -> int: return 0
- def getDbm(self) -> int: return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# SmsManager
-# ═══════════════════════════════════════════════════════════════
-
-class SmsManager(Stub):
- RESULT_ERROR_GENERIC_FAILURE = 1
- RESULT_ERROR_RADIO_OFF = 2
- RESULT_ERROR_NULL_PDU = 3
- RESULT_ERROR_NO_SERVICE = 4
- RESULT_ERROR_LIMIT_EXCEEDED = 5
- RESULT_ERROR_FDN_CHECK_FAILURE = 6
- RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 7
- RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 8
- RESULT_RIL_GENERIC_FAILURE = 9
- RESULT_RIL_RADIO_NOT_AVAILABLE = 10
- STATUS_ON_ICC_FREE = 0
- STATUS_ON_ICC_READ = 1
- STATUS_ON_ICC_UNREAD = 3
- STATUS_ON_ICC_SENT = 5
- STATUS_ON_ICC_UNSENT = 7
-
- _instance: Optional["SmsManager"] = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getDefault() -> "SmsManager":
- if SmsManager._instance is None:
- SmsManager._instance = SmsManager()
- return SmsManager._instance
-
- def sendTextMessage(self, dest_address: str, sc_address: Optional[str],
- text: str, sent_intent: Any, delivery_intent: Any):
- pass
-
- def sendMultipartTextMessage(self, dest_address: str, sc_address: Optional[str],
- parts: List[str], sent_intents: Optional[List[Any]],
- delivery_intents: Optional[List[Any]]):
- pass
-
- def sendDataMessage(self, dest_address: str, sc_address: Optional[str],
- dest_port: int, data: bytes, sent_intent: Any,
- delivery_intent: Any):
- pass
-
- def sendMultimediaMessage(self, context: Any, content_uri: str,
- location_url: Optional[str],
- config_overrides: Optional[Any],
- sent_intent: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# PhoneNumberUtils
-# ═══════════════════════════════════════════════════════════════
-
-class PhoneNumberUtils(Stub):
-
- FORMAT_JAPAN = 2
- FORMAT_NANP = 1
- FORMAT_UNKNOWN = 0
-
- @staticmethod
- def formatNumber(source: str) -> str:
- return source
-
- @staticmethod
- def isGlobalPhoneNumber(phone_number: str) -> bool:
- return bool(phone_number and len(phone_number) >= 7)
-
- @staticmethod
- def compare(a: str, b: str) -> bool:
- return a.replace("-", "").replace(" ", "") == b.replace("-", "").replace(" ", "")
-
- @staticmethod
- def formatNumberToE164(phone_number: str, default_country_iso: str) -> Optional[str]:
- return phone_number
-
- @staticmethod
- def formatNumberToRFC3966(phone_number: str, default_country_iso: str) -> Optional[str]:
- return phone_number
-
- @staticmethod
- def isEmergencyNumber(phone_number: str) -> bool:
- return phone_number in ("911", "112", "999", "000", "110", "119", "120", "122")
-
- @staticmethod
- def isVoiceMailNumber(phone_number: str) -> bool:
- return False
-
- @staticmethod
- def convertKeypadLettersToDigits(input_: str) -> str:
- mapping = {"A": "2", "B": "2", "C": "2", "D": "3", "E": "3",
- "F": "3", "G": "4", "H": "4", "I": "4", "J": "5",
- "K": "5", "L": "5", "M": "6", "N": "6", "O": "6",
- "P": "7", "Q": "7", "R": "7", "S": "7", "T": "8",
- "U": "8", "V": "8", "W": "9", "X": "9", "Y": "9", "Z": "9"}
- result = ""
- for c in input_.upper():
- result += mapping.get(c, c)
- return result
-
- @staticmethod
- def toCallerIDMinMatch(phone_number: str) -> str:
- return phone_number[-7:] if len(phone_number) >= 7 else phone_number
-
-
-# ═══════════════════════════════════════════════════════════════
-# TelephonyManager
-# ═══════════════════════════════════════════════════════════════
-
-class TelephonyManager(Stub):
- """TelephonyManager — 电话管理器"""
-
- PHONE_TYPE_NONE = 0
- PHONE_TYPE_GSM = 1
- PHONE_TYPE_CDMA = 2
- PHONE_TYPE_SIP = 3
-
- NETWORK_TYPE_UNKNOWN = 0
- NETWORK_TYPE_GPRS = 1
- NETWORK_TYPE_EDGE = 2
- NETWORK_TYPE_UMTS = 3
- NETWORK_TYPE_CDMA = 4
- NETWORK_TYPE_EVDO_0 = 5
- NETWORK_TYPE_EVDO_A = 6
- NETWORK_TYPE_1xRTT = 7
- NETWORK_TYPE_HSDPA = 8
- NETWORK_TYPE_HSUPA = 9
- NETWORK_TYPE_HSPA = 10
- NETWORK_TYPE_IDEN = 11
- NETWORK_TYPE_EVDO_B = 12
- NETWORK_TYPE_LTE = 13
- NETWORK_TYPE_EHRPD = 14
- NETWORK_TYPE_HSPAP = 15
- NETWORK_TYPE_GSM = 16
- NETWORK_TYPE_TD_SCDMA = 17
- NETWORK_TYPE_IWLAN = 18
- NETWORK_TYPE_LTE_CA = 19
- NETWORK_TYPE_NR = 20
-
- SIM_STATE_UNKNOWN = 0
- SIM_STATE_ABSENT = 1
- SIM_STATE_PIN_REQUIRED = 2
- SIM_STATE_PUK_REQUIRED = 3
- SIM_STATE_NETWORK_LOCKED = 4
- SIM_STATE_READY = 5
- SIM_STATE_NOT_READY = 6
- SIM_STATE_PERM_DISABLED = 7
-
- DATA_DISCONNECTED = 0
- DATA_CONNECTING = 1
- DATA_CONNECTED = 2
- DATA_SUSPENDED = 3
-
- CALL_STATE_IDLE = 0
- CALL_STATE_RINGING = 1
- CALL_STATE_OFFHOOK = 2
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
-
- def getNetworkOperatorName(self) -> str:
- if _USE_LINUX:
- loc = LinuxLocation.get_location()
- return loc.get("isp", "") or ""
- return "MockOperator"
-
- def getNetworkOperator(self) -> str:
- return "310260"
-
- def getNetworkCountryIso(self) -> str:
- return "us"
-
- def getNetworkType(self) -> int:
- if _USE_LINUX:
- if LinuxNetwork.get_connectivity():
- return self.NETWORK_TYPE_IWLAN
- return self.NETWORK_TYPE_UNKNOWN
- return self.NETWORK_TYPE_LTE
-
- def getPhoneType(self) -> int:
- if _USE_LINUX:
- return self.PHONE_TYPE_NONE
- return self.PHONE_TYPE_GSM
-
- def getDataNetworkType(self) -> int:
- return self.NETWORK_TYPE_LTE
-
- def getVoiceNetworkType(self) -> int:
- return self.NETWORK_TYPE_LTE
-
- def getSimOperator(self) -> str:
- if _USE_LINUX:
- return ""
- return "310260"
-
- def getSimOperatorName(self) -> str:
- return "MockSIM"
-
- def getSimCountryIso(self) -> str:
- return "us"
-
- def getSimSerialNumber(self) -> Optional[str]:
- if _USE_LINUX:
- return ""
- return "89014103211118510720"
-
- def getSubscriberId(self) -> Optional[str]:
- if _USE_LINUX:
- return ""
- return "310260123456789"
-
- def getDeviceId(self) -> Optional[str]:
- if _USE_LINUX:
- return LinuxNetwork.get_mac_address() or None
- return "000000000000000"
-
- def getDeviceSoftwareVersion(self) -> Optional[str]:
- if _USE_LINUX:
- info = LinuxProcess.get_system_info()
- return info.get("kernel", "")
- return "00.00.00.00"
-
- def getLine1Number(self) -> Optional[str]:
- if _USE_LINUX:
- return ""
- return "15551234567"
-
- def getGroupIdLevel1(self) -> Optional[str]:
- return ""
-
- def getIccAuthentication(self, app_type: int, aid: str, data: bytes) -> Optional[bytes]:
- return None
-
- def getVoiceMailNumber(self) -> Optional[str]:
- return "15551234567"
-
- def getVoiceMailAlphaTag(self) -> str:
- return "Voicemail"
-
- def isNetworkRoaming(self) -> bool:
- return False
-
- def hasIccCard(self) -> bool:
- return True
-
- def getSimState(self) -> int:
- return self.SIM_STATE_READY
-
- def getCellLocation(self) -> Any:
- # 桌面无基站,Linux 下返回 None
- if _USE_LINUX:
- return None
- return None
-
- def getAllCellInfo(self) -> Optional[List[CellInfo]]:
- return []
-
- def getMmsUserAgent(self) -> str:
- return "Android-Mms/1.0"
-
- def getMmsUAProfUrl(self) -> str:
- return "http://www.example.com/uaprof.xml"
-
- def listen(self, listener, events):
- if not hasattr(self, '_listeners'):
- self._listeners = []
- self._listeners.append((listener, events))
-
- def getDataState(self) -> int:
- return self.DATA_CONNECTED
-
- def getDataActivity(self) -> int:
- return 0 # DATA_ACTIVITY_NONE
-
- def getCallState(self) -> int:
- return self.CALL_STATE_IDLE
-
- def toString(self) -> str:
- return "TelephonyManager()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "TelephonyManager",
- "CellInfo",
- "CellInfoGsm",
- "CellInfoCdma",
- "CellInfoLte",
- "CellInfoWcdma",
- "CellInfoNr",
- "CellIdentityGsm",
- "CellIdentityCdma",
- "CellIdentityLte",
- "CellIdentityWcdma",
- "CellIdentityNr",
- "CellSignalStrengthGsm",
- "CellSignalStrengthCdma",
- "CellSignalStrengthLte",
- "CellSignalStrengthWcdma",
- "CellSignalStrengthNr",
- "PhoneStateListener",
- "PhoneNumberUtils",
- "ServiceState",
- "SignalStrength",
- "SmsManager",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/telephony_cdma.py b/android_pyapi/android/telephony_cdma.py
deleted file mode 100644
index 8b7b54b..0000000
--- a/android_pyapi/android/telephony_cdma.py
+++ /dev/null
@@ -1,714 +0,0 @@
-"""
-Android Telephony CDMA 组件 — CdmaCellLocation, SignalStrength (CDMA)
-方法签名完全对齐 Android SDK (android.telephony.cdma 包)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# CdmaCellLocation
-# ═══════════════════════════════════════════════════════════════
-
-class CdmaCellLocation(Stub):
- """CdmaCellLocation — CDMA 小区位置"""
-
- INVALID = -1
-
- def __init__(self):
- super().__init__()
- self._base_station_id: int = CdmaCellLocation.INVALID
- self._base_station_latitude: int = CdmaCellLocation.INVALID
- self._base_station_longitude: int = CdmaCellLocation.INVALID
- self._system_id: int = CdmaCellLocation.INVALID
- self._network_id: int = CdmaCellLocation.INVALID
- self._pseudo_network_id: int = CdmaCellLocation.INVALID
- self._pseudo_base_station_id: int = CdmaCellLocation.INVALID
- self._lac: int = CdmaCellLocation.INVALID
- self._cid: int = CdmaCellLocation.INVALID
-
- def getBaseStationId(self) -> int:
- return self._base_station_id
-
- def setBaseStationId(self, bsid: int):
- self._base_station_id = bsid
-
- def getBaseStationLatitude(self) -> int:
- return self._base_station_latitude
-
- def setBaseStationLatitude(self, latitude: int):
- self._base_station_latitude = latitude
-
- def getBaseStationLongitude(self) -> int:
- return self._base_station_longitude
-
- def setBaseStationLongitude(self, longitude: int):
- self._base_station_longitude = longitude
-
- def getSystemId(self) -> int:
- return self._system_id
-
- def setSystemId(self, sid: int):
- self._system_id = sid
-
- def getNetworkId(self) -> int:
- return self._network_id
-
- def setNetworkId(self, nid: int):
- self._network_id = nid
-
- def getLac(self) -> int:
- """获取位置区码 (仅 1xRTT)"""
- return self._lac
-
- def setLac(self, lac: int):
- self._lac = lac
-
- def getCid(self) -> int:
- """获取小区 ID (仅 1xRTT)"""
- return self._cid
-
- def setCid(self, cid: int):
- self._cid = cid
-
- def isEmpty(self) -> bool:
- """检查位置是否为空"""
- return (self._base_station_id == CdmaCellLocation.INVALID
- and self._base_station_latitude == CdmaCellLocation.INVALID
- and self._base_station_longitude == CdmaCellLocation.INVALID
- and self._system_id == CdmaCellLocation.INVALID
- and self._network_id == CdmaCellLocation.INVALID)
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, CdmaCellLocation):
- return (self._base_station_id == other._base_station_id
- and self._base_station_latitude == other._base_station_latitude
- and self._base_station_longitude == other._base_station_longitude
- and self._system_id == other._system_id
- and self._network_id == other._network_id)
- return False
-
- def hashCode(self) -> int:
- return hash((self._base_station_id, self._base_station_latitude,
- self._base_station_longitude, self._system_id,
- self._network_id)) & 0x7FFFFFFF
-
- def fillInNotifierBundle(self, bundle: Any):
- """填充通知包"""
- if bundle is not None:
- bundle.putInt("base_station_id", self._base_station_id)
- bundle.putInt("base_station_latitude", self._base_station_latitude)
- bundle.putInt("base_station_longitude", self._base_station_longitude)
- bundle.putInt("system_id", self._system_id)
- bundle.putInt("network_id", self._network_id)
-
- def toString(self) -> str:
- return f"CdmaCellLocation(bsid={self._base_station_id}, sid={self._system_id}, nid={self._network_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SignalStrength — CDMA
-# ═══════════════════════════════════════════════════════════════
-
-class SignalStrength(Stub):
- """SignalStrength — CDMA 信号强度"""
-
- SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0
- SIGNAL_STRENGTH_POOR = 1
- SIGNAL_STRENGTH_MODERATE = 2
- SIGNAL_STRENGTH_GOOD = 3
- SIGNAL_STRENGTH_GREAT = 4
-
- INVALID = -1
- MAX_DBM = -25
- MIN_DBM = -120
-
- CDMA_RSSI_MAX = -75
- CDMA_RSSI_MIN = -120
- CDMA_ECIO_MAX = 0
- CDMA_ECIO_MIN = -30
- EVDO_DBM_MAX = -60
- EVDO_DBM_MIN = -120
- EVDO_ECIO_MAX = 0
- EVDO_ECIO_MIN = -20
- EVDO_SNR_MAX = 10
- EVDO_SNR_MIN = 0
-
- def __init__(self, cdma_dbm: int = 0, cdma_ecio: int = 0,
- evdo_dbm: int = 0, evdo_ecio: int = 0, evdo_snr: int = 0):
- super().__init__()
- self._cdma_dbm = cdma_dbm
- self._cdma_ecio = cdma_ecio
- self._evdo_dbm = evdo_dbm
- self._evdo_ecio = evdo_ecio
- self._evdo_snr = evdo_snr
- self._is_gsm: bool = False
- self._lte_rssi: int = 0
- self._lte_rsrp: int = 0
- self._lte_rsrq: int = 0
- self._lte_rssnr: int = 0
- self._td_scdma_rscp: int = 0
- self._wcdma_rscp: int = 0
- self._wcdma_ecno: int = 0
-
- def getCdmaDbm(self) -> int:
- """获取 CDMA dBm"""
- return self._cdma_dbm
-
- def setCdmaDbm(self, dbm: int):
- self._cdma_dbm = dbm
-
- def getCdmaEcio(self) -> int:
- """获取 CDMA Ec/Io (0.5 dB 单位)"""
- return self._cdma_ecio
-
- def setCdmaEcio(self, ecio: int):
- self._cdma_ecio = ecio
-
- def getEvdoDbm(self) -> int:
- """获取 EVDO dBm"""
- return self._evdo_dbm
-
- def setEvdoDbm(self, dbm: int):
- self._evdo_dbm = dbm
-
- def getEvdoEcio(self) -> int:
- """获取 EVDO Ec/Io (0.5 dB 单位)"""
- return self._evdo_ecio
-
- def setEvdoEcio(self, ecio: int):
- self._evdo_ecio = ecio
-
- def getEvdoSnr(self) -> int:
- """获取 EVDO SNR"""
- return self._evdo_snr
-
- def setEvdoSnr(self, snr: int):
- self._evdo_snr = snr
-
- def getDbm(self) -> int:
- """获取整体 dBm"""
- if self._evdo_dbm > 0:
- return self._evdo_dbm
- return self._cdma_dbm
-
- def getLevel(self) -> int:
- """获取信号等级 (0-4)"""
- dbm = self.getDbm()
- if dbm >= -85:
- return SignalStrength.SIGNAL_STRENGTH_GREAT
- elif dbm >= -95:
- return SignalStrength.SIGNAL_STRENGTH_GOOD
- elif dbm >= -105:
- return SignalStrength.SIGNAL_STRENGTH_MODERATE
- elif dbm >= -115:
- return SignalStrength.SIGNAL_STRENGTH_POOR
- else:
- return SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
-
- def getAsuLevel(self) -> int:
- """获取 ASU 等级"""
- dbm = self.getDbm()
- if dbm <= -120:
- return 0
- if dbm >= -25:
- return 96
- return int((dbm + 120) * (96.0 / 95.0))
-
- def getEvdoLevel(self) -> int:
- """获取 EVDO 等级"""
- evdo_dbm = self._evdo_dbm
- if evdo_dbm >= -65:
- return SignalStrength.SIGNAL_STRENGTH_GREAT
- elif evdo_dbm >= -75:
- return SignalStrength.SIGNAL_STRENGTH_GOOD
- elif evdo_dbm >= -90:
- return SignalStrength.SIGNAL_STRENGTH_MODERATE
- elif evdo_dbm >= -105:
- return SignalStrength.SIGNAL_STRENGTH_POOR
- else:
- return SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
-
- def getCdmaLevel(self) -> int:
- """获取 CDMA 等级"""
- cdma_dbm = self._cdma_dbm
- if cdma_dbm >= -75:
- return SignalStrength.SIGNAL_STRENGTH_GREAT
- elif cdma_dbm >= -85:
- return SignalStrength.SIGNAL_STRENGTH_GOOD
- elif cdma_dbm >= -95:
- return SignalStrength.SIGNAL_STRENGTH_MODERATE
- elif cdma_dbm >= -105:
- return SignalStrength.SIGNAL_STRENGTH_POOR
- else:
- return SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
-
- def isGsm(self) -> bool:
- return self._is_gsm
-
- def setGsm(self, gsm: bool):
- self._is_gsm = gsm
-
- def getCdmaRssi(self) -> int:
- """获取 CDMA RSSI (dBm)"""
- return self._cdma_dbm
-
- def getCdmaEcioDb(self) -> float:
- """获取 CDMA Ec/Io (dB)"""
- return self._cdma_ecio / 2.0
-
- def getEvdoEcioDb(self) -> float:
- """获取 EVDO Ec/Io (dB)"""
- return self._evdo_ecio / 2.0
-
- def isValid(self) -> bool:
- """检查是否有效"""
- return self._cdma_dbm > SignalStrength.INVALID
-
- def toString(self) -> str:
- return f"CDMA_SignalStrength(cdmaDbm={self._cdma_dbm}, evdoDbm={self._evdo_dbm})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CDMA SMS
-# ═══════════════════════════════════════════════════════════════
-
-class CdmaSmsMessage(Stub):
- """CdmaSmsMessage — CDMA 短信"""
-
- ENCODING_7BIT_ASCII = 2
- ENCODING_UNICODE = 4
- ENCODING_SHIFT_JIS = 5
- ENCODING_KOREAN = 6
- ENCODING_LATIN = 8
- ENCODING_LATIN_HEBREW = 9
- ENCODING_GSM_7BIT = 10
- ENCODING_GSM_DCS = 11
-
- PRIORITY_NORMAL = 0
- PRIORITY_INTERACTIVE = 1
- PRIORITY_URGENT = 2
- PRIORITY_EMERGENCY = 3
-
- PRIVACY_NORMAL = 0
- PRIVACY_RESTRICTED = 1
- PRIVACY_CONFIDENTIAL = 2
- PRIVACY_SECRET = 3
-
- def __init__(self):
- super().__init__()
- self._message_body: str = ""
- self._originating_address: str = ""
- self._destination_address: str = ""
- self._encoding: int = CdmaSmsMessage.ENCODING_7BIT_ASCII
- self._priority: int = CdmaSmsMessage.PRIORITY_NORMAL
- self._privacy: int = CdmaSmsMessage.PRIVACY_NORMAL
- self._timestamp: int = 0
- self._bearer_data: bytes = b""
- self._service_category: int = 0
- self._language: str = ""
- self._is_urgent: bool = False
-
- def getMessageBody(self) -> str:
- return self._message_body
-
- def setMessageBody(self, body: str):
- self._message_body = body
-
- def getOriginatingAddress(self) -> str:
- return self._originating_address
-
- def setOriginatingAddress(self, addr: str):
- self._originating_address = addr
-
- def getDestinationAddress(self) -> str:
- return self._destination_address
-
- def setDestinationAddress(self, addr: str):
- self._destination_address = addr
-
- def getEncoding(self) -> int:
- return self._encoding
-
- def setEncoding(self, encoding: int):
- self._encoding = encoding
-
- def getPriority(self) -> int:
- return self._priority
-
- def setPriority(self, priority: int):
- self._priority = priority
-
- def getPrivacy(self) -> int:
- return self._privacy
-
- def setPrivacy(self, privacy: int):
- self._privacy = privacy
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def setTimestamp(self, ts: int):
- self._timestamp = ts
-
- def getBearerData(self) -> bytes:
- return self._bearer_data
-
- def setBearerData(self, data: bytes):
- self._bearer_data = data
-
- def toString(self) -> str:
- return f"CdmaSmsMessage(from={self._originating_address}, body={self._message_body[:20]})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CDMA 网络常量
-# ═══════════════════════════════════════════════════════════════
-
-class CdmaNetworkType(Stub):
- """CdmaNetworkType — CDMA 网络类型常量"""
-
- NETWORK_TYPE_CDMA = 4
- NETWORK_TYPE_EVDO_0 = 5
- NETWORK_TYPE_EVDO_A = 6
- NETWORK_TYPE_1xRTT = 7
- NETWORK_TYPE_EVDO_B = 12
- NETWORK_TYPE_EHRPD = 14
-
- @staticmethod
- def isCdma(network_type: int) -> bool:
- return network_type in (CdmaNetworkType.NETWORK_TYPE_CDMA,
- CdmaNetworkType.NETWORK_TYPE_EVDO_0,
- CdmaNetworkType.NETWORK_TYPE_EVDO_A,
- CdmaNetworkType.NETWORK_TYPE_1xRTT,
- CdmaNetworkType.NETWORK_TYPE_EVDO_B,
- CdmaNetworkType.NETWORK_TYPE_EHRPD)
-
- @staticmethod
- def toString(network_type: int) -> str:
- names = {
- CdmaNetworkType.NETWORK_TYPE_CDMA: "CDMA",
- CdmaNetworkType.NETWORK_TYPE_EVDO_0: "EVDO rev.0",
- CdmaNetworkType.NETWORK_TYPE_EVDO_A: "EVDO rev.A",
- CdmaNetworkType.NETWORK_TYPE_1xRTT: "1xRTT",
- CdmaNetworkType.NETWORK_TYPE_EVDO_B: "EVDO rev.B",
- CdmaNetworkType.NETWORK_TYPE_EHRPD: "eHRPD",
- }
- return names.get(network_type, f"UNKNOWN({network_type})")
-
- @staticmethod
- def getRatName(network_type: int) -> str:
- return CdmaNetworkType.toString(network_type)
-
-
-# ═══════════════════════════════════════════════════════════════
-# CDMA 补充业务
-# ═══════════════════════════════════════════════════════════════
-
-class CdmaServiceState(Stub):
- """CdmaServiceState — CDMA 服务状态"""
-
- STATE_IN_SERVICE = 0
- STATE_OUT_OF_SERVICE = 1
- STATE_EMERGENCY_ONLY = 2
- STATE_POWER_OFF = 3
-
- def __init__(self):
- super().__init__()
- self._state: int = CdmaServiceState.STATE_OUT_OF_SERVICE
- self._is_roaming: bool = False
- self._cdma_default_roaming_indicator: int = -1
- self._cdma_eri_icon_index: int = -1
- self._cdma_eri_icon_mode: int = -1
- self._cdma_roaming_indicator: int = -1
- self._system_id: int = -1
- self._network_id: int = -1
- self._base_station_id: int = -1
- self._base_station_latitude: int = -1
- self._base_station_longitude: int = -1
- self._operator_alpha_long: str = ""
- self._operator_alpha_short: str = ""
- self._operator_numeric: str = ""
- self._is_manual_selection: bool = False
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getRoaming(self) -> bool:
- return self._is_roaming
-
- def setRoaming(self, roaming: bool):
- self._is_roaming = roaming
-
- def getCdmaDefaultRoamingIndicator(self) -> int:
- return self._cdma_default_roaming_indicator
-
- def setCdmaDefaultRoamingIndicator(self, indicator: int):
- self._cdma_default_roaming_indicator = indicator
-
- def getCdmaEriIconIndex(self) -> int:
- return self._cdma_eri_icon_index
-
- def setCdmaEriIconIndex(self, index: int):
- self._cdma_eri_icon_index = index
-
- def getCdmaEriIconMode(self) -> int:
- return self._cdma_eri_icon_mode
-
- def setCdmaEriIconMode(self, mode: int):
- self._cdma_eri_icon_mode = mode
-
- def getCdmaRoamingIndicator(self) -> int:
- return self._cdma_roaming_indicator
-
- def setCdmaRoamingIndicator(self, indicator: int):
- self._cdma_roaming_indicator = indicator
-
- def getSystemId(self) -> int:
- return self._system_id
-
- def setSystemId(self, sid: int):
- self._system_id = sid
-
- def getNetworkId(self) -> int:
- return self._network_id
-
- def setNetworkId(self, nid: int):
- self._network_id = nid
-
- def getOperatorAlphaLong(self) -> str:
- return self._operator_alpha_long
-
- def setOperatorAlphaLong(self, op: str):
- self._operator_alpha_long = op
-
- def getOperatorAlphaShort(self) -> str:
- return self._operator_alpha_short
-
- def setOperatorAlphaShort(self, op: str):
- self._operator_alpha_short = op
-
- def getOperatorNumeric(self) -> str:
- return self._operator_numeric
-
- def setOperatorNumeric(self, op: str):
- self._operator_numeric = op
-
- def toString(self) -> str:
- return f"CdmaServiceState(state={self._state}, roaming={self._is_roaming})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CDMA ERI (Enhanced Roaming Indicator)
-# ═══════════════════════════════════════════════════════════════
-
-class CdmaEriInfo(Stub):
- """CdmaEriInfo — CDMA ERI 信息"""
-
- ERI_ON = 0
- ERI_OFF = 1
- ERI_FLASH = 2
-
- ROAMING_INDICATOR_NOT_ROAMING = 0
- ROAMING_INDICATOR_ROAMING = 1
- ROAMING_INDICATOR_SAMPLING = 2
- ROAMING_INDICATOR_AFFILIATED = 3
- ROAMING_INDICATOR_NOT_AFFILIATED = 4
- ROAMING_INDICATOR_FLASH = 5
-
- def __init__(self):
- super().__init__()
- self._icon_index: int = -1
- self._icon_mode: int = CdmaEriInfo.ERI_OFF
- self._roaming_indicator: int = CdmaEriInfo.ROAMING_INDICATOR_NOT_ROAMING
- self._eri_text: str = ""
- self._alert_show: bool = False
- self._call_guard: bool = False
-
- def getIconIndex(self) -> int:
- return self._icon_index
-
- def setIconIndex(self, index: int):
- self._icon_index = index
-
- def getIconMode(self) -> int:
- return self._icon_mode
-
- def setIconMode(self, mode: int):
- self._icon_mode = mode
-
- def getRoamingIndicator(self) -> int:
- return self._roaming_indicator
-
- def setRoamingIndicator(self, indicator: int):
- self._roaming_indicator = indicator
-
- def getEriText(self) -> str:
- return self._eri_text
-
- def setEriText(self, text: str):
- self._eri_text = text
-
- def isAlertShow(self) -> bool:
- return self._alert_show
-
- def setAlertShow(self, show: bool):
- self._alert_show = show
-
- def isCallGuard(self) -> bool:
- return self._call_guard
-
- def setCallGuard(self, guard: bool):
- self._call_guard = guard
-
- def isRoaming(self) -> bool:
- return self._roaming_indicator != CdmaEriInfo.ROAMING_INDICATOR_NOT_ROAMING
-
- def toString(self) -> str:
- return f"CdmaEriInfo(icon={self._icon_index}, roaming={self._roaming_indicator})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CDMA 语音/数据状态
-# ═══════════════════════════════════════════════════════════════
-
-class CdmaCallState(Stub):
- """CdmaCallState — CDMA 通话状态"""
-
- CALL_STATE_IDLE = 0
- CALL_STATE_ACTIVE = 1
- CALL_STATE_ALERTING = 2
- CALL_STATE_DIALING = 3
- CALL_STATE_INCOMING = 4
- CALL_STATE_HOLDING = 5
- CALL_STATE_DISCONNECTING = 6
- CALL_STATE_DISCONNECTED = 7
- CALL_STATE_CONFERENCE = 8
-
- CALL_TYPE_VOICE = 0
- CALL_TYPE_DATA = 1
- CALL_TYPE_FAX = 2
- CALL_TYPE_UNKNOWN = 3
-
- @staticmethod
- def toString(state: int) -> str:
- names = {
- CdmaCallState.CALL_STATE_IDLE: "IDLE",
- CdmaCallState.CALL_STATE_ACTIVE: "ACTIVE",
- CdmaCallState.CALL_STATE_ALERTING: "ALERTING",
- CdmaCallState.CALL_STATE_DIALING: "DIALING",
- CdmaCallState.CALL_STATE_INCOMING: "INCOMING",
- CdmaCallState.CALL_STATE_DISCONNECTED: "DISCONNECTED",
- }
- return names.get(state, f"UNKNOWN({state})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CDMA Data Connection
-# ═══════════════════════════════════════════════════════════════
-
-class CdmaDataConnectionState(Stub):
- """CdmaDataConnectionState — CDMA 数据连接状态"""
-
- DATA_STATE_DISCONNECTED = 0
- DATA_STATE_CONNECTING = 1
- DATA_STATE_CONNECTED = 2
- DATA_STATE_SUSPENDED = 3
- DATA_STATE_DORMANT = 4
- DATA_STATE_AUTHENTICATING = 5
-
- DATA_ACTIVITY_NONE = 0
- DATA_ACTIVITY_IN = 1
- DATA_ACTIVITY_OUT = 2
- DATA_ACTIVITY_INOUT = 3
- DATA_ACTIVITY_DORMANT = 4
-
- @staticmethod
- def toString(state: int) -> str:
- names = {
- CdmaDataConnectionState.DATA_STATE_DISCONNECTED: "DISCONNECTED",
- CdmaDataConnectionState.DATA_STATE_CONNECTING: "CONNECTING",
- CdmaDataConnectionState.DATA_STATE_CONNECTED: "CONNECTED",
- CdmaDataConnectionState.DATA_STATE_SUSPENDED: "SUSPENDED",
- CdmaDataConnectionState.DATA_STATE_DORMANT: "DORMANT",
- }
- return names.get(state, f"UNKNOWN({state})")
-
- @staticmethod
- def dataActivityToString(activity: int) -> str:
- names = {
- CdmaDataConnectionState.DATA_ACTIVITY_NONE: "NONE",
- CdmaDataConnectionState.DATA_ACTIVITY_IN: "IN",
- CdmaDataConnectionState.DATA_ACTIVITY_OUT: "OUT",
- CdmaDataConnectionState.DATA_ACTIVITY_INOUT: "INOUT",
- CdmaDataConnectionState.DATA_ACTIVITY_DORMANT: "DORMANT",
- }
- return names.get(activity, f"UNKNOWN({activity})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CDMA 网络注册
-# ═══════════════════════════════════════════════════════════════
-
-class CdmaRegistrationState(Stub):
- """CdmaRegistrationState — CDMA 注册状态"""
-
- REG_STATE_NOT_REGISTERED = 0
- REG_STATE_REGISTERED = 1
- REG_STATE_REGISTERING = 2
- REG_STATE_DENIED = 3
- REG_STATE_UNKNOWN = 4
- REG_STATE_ROAMING = 5
- REG_STATE_HOME = 6
-
- def __init__(self, state: int = REG_STATE_UNKNOWN):
- super().__init__()
- self._state = state
- self._system_id: int = -1
- self._network_id: int = -1
- self._base_id: int = -1
- self._zone_id: int = -1
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getSystemId(self) -> int:
- return self._system_id
-
- def setSystemId(self, sid: int):
- self._system_id = sid
-
- def getNetworkId(self) -> int:
- return self._network_id
-
- def setNetworkId(self, nid: int):
- self._network_id = nid
-
- def getBaseId(self) -> int:
- return self._base_id
-
- def setBaseId(self, base_id: int):
- self._base_id = base_id
-
- def isRegistered(self) -> bool:
- return self._state in (CdmaRegistrationState.REG_STATE_REGISTERED,
- CdmaRegistrationState.REG_STATE_HOME,
- CdmaRegistrationState.REG_STATE_ROAMING)
-
- def isRoaming(self) -> bool:
- return self._state == CdmaRegistrationState.REG_STATE_ROAMING
-
- def toString(self) -> str:
- return f"CdmaRegistrationState(state={self._state})"
\ No newline at end of file
diff --git a/android_pyapi/android/telephony_data.py b/android_pyapi/android/telephony_data.py
deleted file mode 100644
index 6fd4206..0000000
--- a/android_pyapi/android/telephony_data.py
+++ /dev/null
@@ -1,1200 +0,0 @@
-"""
-Android Telephony Data 组件 — TelephonyManager.Data, DataConnection, ApnSetting, DataProfile 等
-方法签名完全对齐 Android SDK (android.telephony.data 包)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# ApnSetting
-# ═══════════════════════════════════════════════════════════════
-
-class ApnSetting(Stub):
- """ApnSetting — APN 设置"""
-
- TYPE_DEFAULT = 1 << 0
- TYPE_MMS = 1 << 1
- TYPE_SUPL = 1 << 2
- TYPE_DUN = 1 << 3
- TYPE_HIPRI = 1 << 4
- TYPE_FOTA = 1 << 5
- TYPE_IMS = 1 << 6
- TYPE_CBS = 1 << 7
- TYPE_IA = 1 << 8
- TYPE_EMERGENCY = 1 << 9
- TYPE_MCX = 1 << 10
- TYPE_XCAP = 1 << 11
- TYPE_BIP = 1 << 12
- TYPE_VSIM = 1 << 13
- TYPE_ENTERPRISE = 1 << 14
- TYPE_ALL = 0xFFFFFFFF
-
- PROTOCOL_IP = "IP"
- PROTOCOL_IPV6 = "IPV6"
- PROTOCOL_IPV4V6 = "IPV4V6"
- PROTOCOL_PPP = "PPP"
- PROTOCOL_NON_IP = "NON-IP"
- PROTOCOL_UNSTRUCTURED = "UNSTRUCTURED"
-
- AUTH_TYPE_NONE = 0
- AUTH_TYPE_PAP = 1
- AUTH_TYPE_CHAP = 2
- AUTH_TYPE_PAP_OR_CHAP = 3
-
- MVNO_TYPE_IMSI = 0
- MVNO_TYPE_GID = 1
- MVNO_TYPE_SPN = 2
- MVNO_TYPE_PNN = 3
- MVNO_TYPE_ACQ = 4
- MVNO_TYPE_ICCID = 5
- MVNO_TYPE_PLMN = 6
- MVNO_TYPE_SIP = 7
- MVNO_TYPE_NONE = -1
-
- def __init__(self, apn: str = "", numeric: str = "",
- carrier: str = "", mcc: str = "", mnc: str = "",
- user: str = "", password: str = ""):
- super().__init__()
- self._apn = apn
- self._numeric = numeric
- self._carrier = carrier
- self._mcc = mcc
- self._mnc = mnc
- self._user = user
- self._password = password
- self._proxy: str = ""
- self._port: int = 0
- self._server: str = ""
- self._mmsc: str = ""
- self._mms_proxy: str = ""
- self._mms_port: int = 0
- self._types: int = ApnSetting.TYPE_DEFAULT
- self._protocol: str = ApnSetting.PROTOCOL_IP
- self._roaming_protocol: str = ApnSetting.PROTOCOL_IP
- self._auth_type: int = ApnSetting.AUTH_TYPE_NONE
- self._carrier_enabled: bool = True
- self._bearer: int = 0
- self._bearer_bitmask: int = 0
- self._roaming_bearer_bitmask: int = 0
- self._mtu: int = 0
- self._mvno_type: int = ApnSetting.MVNO_TYPE_NONE
- self._mvno_match_data: str = ""
- self._edited: int = 0
- self._id: int = 0
- self._network_type_bitmask: int = 0
- self._entry_name: str = ""
- self._entry_for_apn: str = ""
- self._always_on: bool = False
- self._skip_464xlat: bool = False
- self._persistent: bool = True
-
- def getApn(self) -> str:
- return self._apn
-
- def setApn(self, apn: str):
- self._apn = apn
-
- def getNumeric(self) -> str:
- return self._numeric
-
- def setNumeric(self, numeric: str):
- self._numeric = numeric
-
- def getCarrier(self) -> str:
- return self._carrier
-
- def setCarrier(self, carrier: str):
- self._carrier = carrier
-
- def getMcc(self) -> str:
- return self._mcc
-
- def setMcc(self, mcc: str):
- self._mcc = mcc
-
- def getMnc(self) -> str:
- return self._mnc
-
- def setMnc(self, mnc: str):
- self._mnc = mnc
-
- def getUser(self) -> str:
- return self._user
-
- def setUser(self, user: str):
- self._user = user
-
- def getPassword(self) -> str:
- return self._password
-
- def setPassword(self, password: str):
- self._password = password
-
- def getProxy(self) -> str:
- return self._proxy
-
- def setProxy(self, proxy: str):
- self._proxy = proxy
-
- def getPort(self) -> int:
- return self._port
-
- def setPort(self, port: int):
- self._port = port
-
- def getServer(self) -> str:
- return self._server
-
- def setServer(self, server: str):
- self._server = server
-
- def getMmsc(self) -> str:
- return self._mmsc
-
- def setMmsc(self, mmsc: str):
- self._mmsc = mmsc
-
- def getMmsProxy(self) -> str:
- return self._mms_proxy
-
- def setMmsProxy(self, proxy: str):
- self._mms_proxy = proxy
-
- def getMmsPort(self) -> int:
- return self._mms_port
-
- def setMmsPort(self, port: int):
- self._mms_port = port
-
- def getTypes(self) -> int:
- return self._types
-
- def setTypes(self, types: int):
- self._types = types
-
- def getProtocol(self) -> str:
- return self._protocol
-
- def setProtocol(self, protocol: str):
- self._protocol = protocol
-
- def getRoamingProtocol(self) -> str:
- return self._roaming_protocol
-
- def setRoamingProtocol(self, protocol: str):
- self._roaming_protocol = protocol
-
- def getAuthType(self) -> int:
- return self._auth_type
-
- def setAuthType(self, auth_type: int):
- self._auth_type = auth_type
-
- def isCarrierEnabled(self) -> bool:
- return self._carrier_enabled
-
- def setCarrierEnabled(self, enabled: bool):
- self._carrier_enabled = enabled
-
- def getBearer(self) -> int:
- return self._bearer
-
- def setBearer(self, bearer: int):
- self._bearer = bearer
-
- def hasType(self, type_: int) -> bool:
- return bool(self._types & type_)
-
- def isAlwaysOn(self) -> bool:
- return self._always_on
-
- def setAlwaysOn(self, always_on: bool):
- self._always_on = always_on
-
- def getMtu(self) -> int:
- return self._mtu
-
- def setMtu(self, mtu: int):
- self._mtu = mtu
-
- def getMvnoType(self) -> int:
- return self._mvno_type
-
- def setMvnoType(self, mvno_type: int):
- self._mvno_type = mvno_type
-
- def getMvnoMatchData(self) -> str:
- return self._mvno_match_data
-
- def setMvnoMatchData(self, data: str):
- self._mvno_match_data = data
-
- def getId(self) -> int:
- return self._id
-
- def setId(self, id_: int):
- self._id = id_
-
- def getEntryName(self) -> str:
- return self._entry_name
-
- def setEntryName(self, name: str):
- self._entry_name = name
-
- def toString(self) -> str:
- return f"ApnSetting(apn={self._apn}, carrier={self._carrier})"
-
- class Builder(Stub):
- """ApnSetting.Builder — APN 构建器"""
-
- def __init__(self):
- super().__init__()
- self._apn = ""
- self._numeric = ""
- self._carrier = ""
- self._mcc = ""
- self._mnc = ""
- self._user = ""
- self._password = ""
- self._proxy = ""
- self._port = 0
- self._server = ""
- self._mmsc = ""
- self._mms_proxy = ""
- self._mms_port = 0
- self._types = ApnSetting.TYPE_DEFAULT
- self._protocol = ApnSetting.PROTOCOL_IP
- self._roaming_protocol = ApnSetting.PROTOCOL_IP
- self._auth_type = ApnSetting.AUTH_TYPE_NONE
- self._carrier_enabled = True
- self._bearer = 0
- self._mvno_type = ApnSetting.MVNO_TYPE_NONE
- self._mvno_match_data = ""
- self._always_on = False
- self._mtu = 0
-
- def setApn(self, apn: str) -> ApnSetting.Builder:
- self._apn = apn; return self
-
- def setNumeric(self, numeric: str) -> ApnSetting.Builder:
- self._numeric = numeric; return self
-
- def setCarrier(self, carrier: str) -> ApnSetting.Builder:
- self._carrier = carrier; return self
-
- def setMcc(self, mcc: str) -> ApnSetting.Builder:
- self._mcc = mcc; return self
-
- def setMnc(self, mnc: str) -> ApnSetting.Builder:
- self._mnc = mnc; return self
-
- def setUser(self, user: str) -> ApnSetting.Builder:
- self._user = user; return self
-
- def setPassword(self, password: str) -> ApnSetting.Builder:
- self._password = password; return self
-
- def setProxy(self, proxy: str) -> ApnSetting.Builder:
- self._proxy = proxy; return self
-
- def setPort(self, port: int) -> ApnSetting.Builder:
- self._port = port; return self
-
- def setMmsc(self, mmsc: str) -> ApnSetting.Builder:
- self._mmsc = mmsc; return self
-
- def setMmsProxy(self, proxy: str) -> ApnSetting.Builder:
- self._mms_proxy = proxy; return self
-
- def setMmsPort(self, port: int) -> ApnSetting.Builder:
- self._mms_port = port; return self
-
- def setTypes(self, types: int) -> ApnSetting.Builder:
- self._types = types; return self
-
- def setProtocol(self, protocol: str) -> ApnSetting.Builder:
- self._protocol = protocol; return self
-
- def setRoamingProtocol(self, protocol: str) -> ApnSetting.Builder:
- self._roaming_protocol = protocol; return self
-
- def setAuthType(self, auth_type: int) -> ApnSetting.Builder:
- self._auth_type = auth_type; return self
-
- def setCarrierEnabled(self, enabled: bool) -> ApnSetting.Builder:
- self._carrier_enabled = enabled; return self
-
- def setAlwaysOn(self, always_on: bool) -> ApnSetting.Builder:
- self._always_on = always_on; return self
-
- def build(self) -> ApnSetting:
- apn = ApnSetting(self._apn, self._numeric, self._carrier,
- self._mcc, self._mnc, self._user, self._password)
- apn.setProxy(self._proxy)
- apn.setPort(self._port)
- apn.setMmsc(self._mmsc)
- apn.setMmsProxy(self._mms_proxy)
- apn.setMmsPort(self._mms_port)
- apn.setTypes(self._types)
- apn.setProtocol(self._protocol)
- apn.setRoamingProtocol(self._roaming_protocol)
- apn.setAuthType(self._auth_type)
- apn.setCarrierEnabled(self._carrier_enabled)
- apn.setAlwaysOn(self._always_on)
- return apn
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataProfile
-# ═══════════════════════════════════════════════════════════════
-
-class DataProfile(Stub):
- """DataProfile — 数据配置文件"""
-
- TYPE_COMMON = 0
- TYPE_3GPP = 1
- TYPE_3GPP2 = 2
- TYPE_IMS = 3
- TYPE_FOTA = 4
- TYPE_CBS = 5
- TYPE_IA = 6
- TYPE_EMERGENCY = 7
- TYPE_MCX = 8
- TYPE_XCAP = 9
- TYPE_ENTERPRISE = 10
-
- PROTOCOL_IPV4 = 0
- PROTOCOL_IPV6 = 1
- PROTOCOL_IPV4V6 = 2
- PROTOCOL_PPP = 3
- PROTOCOL_UNKNOWN = -1
-
- def __init__(self, profile_id: int = 0, apn: str = "",
- protocol: int = PROTOCOL_IPV4):
- super().__init__()
- self._profile_id = profile_id
- self._apn = apn
- self._protocol = protocol
- self._roaming_protocol: int = DataProfile.PROTOCOL_IPV4
- self._auth_type: int = 0
- self._user: str = ""
- self._password: str = ""
- self._type: int = DataProfile.TYPE_COMMON
- self._max_connections: int = 0
- self._wait_time: int = 0
- self._enabled: bool = True
- self._supported_apn_types_bitmask: int = 0
- self._bearer_bitmask: int = 0
- self._mtu: int = 0
- self._persistent: bool = True
- self._preferred: bool = False
-
- def getProfileId(self) -> int:
- return self._profile_id
-
- def setProfileId(self, profile_id: int):
- self._profile_id = profile_id
-
- def getApn(self) -> str:
- return self._apn
-
- def setApn(self, apn: str):
- self._apn = apn
-
- def getProtocol(self) -> int:
- return self._protocol
-
- def setProtocol(self, protocol: int):
- self._protocol = protocol
-
- def getRoamingProtocol(self) -> int:
- return self._roaming_protocol
-
- def setRoamingProtocol(self, protocol: int):
- self._roaming_protocol = protocol
-
- def getAuthType(self) -> int:
- return self._auth_type
-
- def setAuthType(self, auth_type: int):
- self._auth_type = auth_type
-
- def getUser(self) -> str:
- return self._user
-
- def setUser(self, user: str):
- self._user = user
-
- def getPassword(self) -> str:
- return self._password
-
- def setPassword(self, password: str):
- self._password = password
-
- def getType(self) -> int:
- return self._type
-
- def setType(self, type_: int):
- self._type = type_
-
- def getMaxConnections(self) -> int:
- return self._max_connections
-
- def setMaxConnections(self, max_conn: int):
- self._max_connections = max_conn
-
- def getWaitTime(self) -> int:
- return self._wait_time
-
- def setWaitTime(self, wait: int):
- self._wait_time = wait
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- def isPersistent(self) -> bool:
- return self._persistent
-
- def setPersistent(self, persistent: bool):
- self._persistent = persistent
-
- def isPreferred(self) -> bool:
- return self._preferred
-
- def setPreferred(self, preferred: bool):
- self._preferred = preferred
-
- def getMtu(self) -> int:
- return self._mtu
-
- def setMtu(self, mtu: int):
- self._mtu = mtu
-
- def getSupportedApnTypesBitmask(self) -> int:
- return self._supported_apn_types_bitmask
-
- def setSupportedApnTypesBitmask(self, bitmask: int):
- self._supported_apn_types_bitmask = bitmask
-
- def toString(self) -> str:
- return f"DataProfile(id={self._profile_id}, apn={self._apn})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataConnection
-# ═══════════════════════════════════════════════════════════════
-
-class DataConnection(Stub):
- """DataConnection — 数据连接"""
-
- STATE_DISCONNECTED = 0
- STATE_CONNECTING = 1
- STATE_CONNECTED = 2
- STATE_DISCONNECTING = 3
- STATE_SUSPENDED = 4
- STATE_UNKNOWN = -1
-
- LINK_PROPERTIES_IFACE_NAME = "iface"
- LINK_PROPERTIES_DNS1 = "dns1"
- LINK_PROPERTIES_DNS2 = "dns2"
- LINK_PROPERTIES_GATEWAY = "gateway"
- LINK_PROPERTIES_MTU = "mtu"
- LINK_PROPERTIES_ADDRESS = "address"
- LINK_PROPERTIES_PREFIX_LENGTH = "prefix_length"
- LINK_PROPERTIES_HTTP_PROXY = "http_proxy"
- LINK_PROPERTIES_PCSCF = "pcscf"
-
- def __init__(self, cid: int = 0):
- super().__init__()
- self._cid = cid
- self._state: int = DataConnection.STATE_DISCONNECTED
- self._apn: str = ""
- self._apn_type: int = ApnSetting.TYPE_DEFAULT
- self._network_type: int = 0
- self._link_properties: Dict[str, Any] = {}
- self._data_profile: Optional[DataProfile] = None
- self._is_internet: bool = False
- self._fail_cause: int = 0
- self._suggested_retry_time: int = 0
- self._time_connected: int = 0
- self._bearer_id: int = 0
- self._rat: int = 0
- self._is_roaming: bool = False
-
- def getCid(self) -> int:
- return self._cid
-
- def setCid(self, cid: int):
- self._cid = cid
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getApn(self) -> str:
- return self._apn
-
- def setApn(self, apn: str):
- self._apn = apn
-
- def getApnType(self) -> int:
- return self._apn_type
-
- def setApnType(self, apn_type: int):
- self._apn_type = apn_type
-
- def getNetworkType(self) -> int:
- return self._network_type
-
- def setNetworkType(self, network_type: int):
- self._network_type = network_type
-
- def getLinkProperties(self) -> Dict[str, Any]:
- return dict(self._link_properties)
-
- def setLinkProperties(self, props: Dict[str, Any]):
- self._link_properties = dict(props)
-
- def getDataProfile(self) -> Optional[DataProfile]:
- return self._data_profile
-
- def setDataProfile(self, profile: DataProfile):
- self._data_profile = profile
-
- def isInternet(self) -> bool:
- return self._is_internet
-
- def setInternet(self, internet: bool):
- self._is_internet = internet
-
- def getFailCause(self) -> int:
- return self._fail_cause
-
- def setFailCause(self, cause: int):
- self._fail_cause = cause
-
- def getSuggestedRetryTime(self) -> int:
- return self._suggested_retry_time
-
- def setSuggestedRetryTime(self, time_ms: int):
- self._suggested_retry_time = time_ms
-
- def getTimeConnected(self) -> int:
- return self._time_connected
-
- def setTimeConnected(self, time_ms: int):
- self._time_connected = time_ms
-
- def getBearerId(self) -> int:
- return self._bearer_id
-
- def setBearerId(self, bearer_id: int):
- self._bearer_id = bearer_id
-
- def isRoaming(self) -> bool:
- return self._is_roaming
-
- def setRoaming(self, roaming: bool):
- self._is_roaming = roaming
-
- def isConnected(self) -> bool:
- return self._state == DataConnection.STATE_CONNECTED
-
- def toString(self) -> str:
- return f"DataConnection(cid={self._cid}, state={self._state}, apn={self._apn})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataSpecificRegistrationInfo
-# ═══════════════════════════════════════════════════════════════
-
-class DataSpecificRegistrationInfo(Stub):
- """DataSpecificRegistrationInfo — 数据特定注册信息"""
-
- LVC_AVAILABLE = 0
- LVC_NOT_AVAILABLE = 1
- LVC_UNKNOWN = 2
-
- def __init__(self):
- super().__init__()
- self._lvc_state: int = DataSpecificRegistrationInfo.LVC_UNKNOWN
- self._is_dc_over_nr: bool = False
- self._is_enhanced_voice_roaming: bool = False
- self._is_endc_available: bool = False
- self._max_data_connectivity: int = 0
- self._nr_available: bool = False
- self._en_dc_available: bool = False
- self._voice_over_nr: bool = False
- self._is_roaming: bool = False
- self._registration_network_type: int = 0
- self._voice_registration_network_type: int = 0
- self._available_services: Set[int] = set()
- self._voice_registration_info: Any = None
- self._nr_voice_available: bool = False
- self._lte_voice_available: bool = False
-
- def getLvcState(self) -> int:
- return self._lvc_state
-
- def setLvcState(self, state: int):
- self._lvc_state = state
-
- def isDcOverNr(self) -> bool:
- return self._is_dc_over_nr
-
- def setDcOverNr(self, dc_over_nr: bool):
- self._is_dc_over_nr = dc_over_nr
-
- def isEnhancedVoiceRoaming(self) -> bool:
- return self._is_enhanced_voice_roaming
-
- def setEnhancedVoiceRoaming(self, roaming: bool):
- self._is_enhanced_voice_roaming = roaming
-
- def isEndcAvailable(self) -> bool:
- return self._is_endc_available
-
- def setEndcAvailable(self, available: bool):
- self._is_endc_available = available
-
- def getMaxDataConnectivity(self) -> int:
- return self._max_data_connectivity
-
- def setMaxDataConnectivity(self, max_: int):
- self._max_data_connectivity = max_
-
- def isNrAvailable(self) -> bool:
- return self._nr_available
-
- def setNrAvailable(self, available: bool):
- self._nr_available = available
-
- def isEnDcAvailable(self) -> bool:
- return self._en_dc_available
-
- def setEnDcAvailable(self, available: bool):
- self._en_dc_available = available
-
- def isVoiceOverNr(self) -> bool:
- return self._voice_over_nr
-
- def setVoiceOverNr(self, voice_over_nr: bool):
- self._voice_over_nr = voice_over_nr
-
- def getRegistrationNetworkType(self) -> int:
- return self._registration_network_type
-
- def setRegistrationNetworkType(self, type_: int):
- self._registration_network_type = type_
-
- def getVoiceRegistrationNetworkType(self) -> int:
- return self._voice_registration_network_type
-
- def setVoiceRegistrationNetworkType(self, type_: int):
- self._voice_registration_network_type = type_
-
- def getAvailableServices(self) -> Set[int]:
- return set(self._available_services)
-
- def setAvailableServices(self, services: Set[int]):
- self._available_services = set(services)
-
- def toString(self) -> str:
- return f"DataSpecificRegistrationInfo(nr={self._nr_available}, dcNr={self._is_dc_over_nr})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NetworkSlicingConfig
-# ═══════════════════════════════════════════════════════════════
-
-class NetworkSlicingConfig(Stub):
- """NetworkSlicingConfig — 网络切片配置"""
-
- def __init__(self):
- super().__init__()
- self._ursp_rules: List[UrspRule] = []
- self._nssais: List[Nssai] = []
- self._configured_s_nssais: List[Any] = []
- self._requested_s_nssais: List[Any] = []
- self._allowed_s_nssais: List[Any] = []
- self._default_s_nssai: Any = None
- self._mapped_hplmn_s_nssais: List[Any] = []
- self._rejected_s_nssais: List[Any] = []
-
- def getUrspRules(self) -> List[UrspRule]:
- return list(self._ursp_rules)
-
- def setUrspRules(self, rules: List[UrspRule]):
- self._ursp_rules = list(rules)
-
- def getNssais(self) -> List[Nssai]:
- return list(self._nssais)
-
- def setNssais(self, nssais: List[Nssai]):
- self._nssais = list(nssais)
-
- def getConfiguredSNssais(self) -> List[Any]:
- return list(self._configured_s_nssais)
-
- def setConfiguredSNssais(self, nssais: List[Any]):
- self._configured_s_nssais = list(nssais)
-
- def getRequestedSNssais(self) -> List[Any]:
- return list(self._requested_s_nssais)
-
- def setRequestedSNssais(self, nssais: List[Any]):
- self._requested_s_nssais = list(nssais)
-
- def addUrspRule(self, rule: UrspRule):
- self._ursp_rules.append(rule)
-
- def addNssai(self, nssai: Nssai):
- self._nssais.append(nssai)
-
- def toString(self) -> str:
- return f"NetworkSlicingConfig(ursp={len(self._ursp_rules)}, nssais={len(self._nssais)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# UrspRule
-# ═══════════════════════════════════════════════════════════════
-
-class UrspRule(Stub):
- """UrspRule — URSP (UE Route Selection Policy) 规则"""
-
- def __init__(self, precedence: int = 0, rule_id: int = 0):
- super().__init__()
- self._precedence = precedence
- self._rule_id = rule_id
- self._traffic_descriptors: List[TrafficDescriptor] = []
- self._route_selection_descriptors: List[RouteSelectionDescriptor] = []
-
- def getPrecedence(self) -> int:
- return self._precedence
-
- def setPrecedence(self, precedence: int):
- self._precedence = precedence
-
- def getRuleId(self) -> int:
- return self._rule_id
-
- def setRuleId(self, rule_id: int):
- self._rule_id = rule_id
-
- def getTrafficDescriptors(self) -> List[TrafficDescriptor]:
- return list(self._traffic_descriptors)
-
- def setTrafficDescriptors(self, descriptors: List[TrafficDescriptor]):
- self._traffic_descriptors = list(descriptors)
-
- def getRouteSelectionDescriptors(self) -> List[RouteSelectionDescriptor]:
- return list(self._route_selection_descriptors)
-
- def setRouteSelectionDescriptors(self, descriptors: List[RouteSelectionDescriptor]):
- self._route_selection_descriptors = list(descriptors)
-
- def addTrafficDescriptor(self, descriptor: TrafficDescriptor):
- self._traffic_descriptors.append(descriptor)
-
- def addRouteSelectionDescriptor(self, descriptor: RouteSelectionDescriptor):
- self._route_selection_descriptors.append(descriptor)
-
- def toString(self) -> str:
- return f"UrspRule(id={self._rule_id}, precedence={self._precedence})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TrafficDescriptor
-# ═══════════════════════════════════════════════════════════════
-
-class TrafficDescriptor(Stub):
- """TrafficDescriptor — 流量描述符"""
-
- def __init__(self):
- super().__init__()
- self._dnn: str = ""
- self._os_app_id: str = ""
- self._fqdn: str = ""
- self._ip_descriptors: List[Any] = []
- self._domain_descriptors: List[Any] = []
- self._connection_capabilities: List[int] = []
-
- def getDnn(self) -> str:
- return self._dnn
-
- def setDnn(self, dnn: str):
- self._dnn = dnn
-
- def getOsAppId(self) -> str:
- return self._os_app_id
-
- def setOsAppId(self, app_id: str):
- self._os_app_id = app_id
-
- def getFqdn(self) -> str:
- return self._fqdn
-
- def setFqdn(self, fqdn: str):
- self._fqdn = fqdn
-
- def getIpDescriptors(self) -> List[Any]:
- return list(self._ip_descriptors)
-
- def setIpDescriptors(self, descriptors: List[Any]):
- self._ip_descriptors = list(descriptors)
-
- def getDomainDescriptors(self) -> List[Any]:
- return list(self._domain_descriptors)
-
- def setDomainDescriptors(self, descriptors: List[Any]):
- self._domain_descriptors = list(descriptors)
-
- def getConnectionCapabilities(self) -> List[int]:
- return list(self._connection_capabilities)
-
- def setConnectionCapabilities(self, caps: List[int]):
- self._connection_capabilities = list(caps)
-
- def toString(self) -> str:
- return f"TrafficDescriptor(dnn={self._dnn})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RouteSelectionDescriptor
-# ═══════════════════════════════════════════════════════════════
-
-class RouteSelectionDescriptor(Stub):
- """RouteSelectionDescriptor — 路由选择描述符"""
-
- SSC_MODE_1 = 1
- SSC_MODE_2 = 2
- SSC_MODE_3 = 3
- SSC_MODE_UNKNOWN = 0
-
- def __init__(self):
- super().__init__()
- self._ssc_mode: int = RouteSelectionDescriptor.SSC_MODE_UNKNOWN
- self._s_nssai: Optional[Any] = None
- self._dnn: str = ""
- self._route_selection_info: bytes = b""
- self._precedence: int = 0
- self._pdu_session_type: int = 0
- self._access_type: int = 0
- self._data_network_name: str = ""
-
- def getSscMode(self) -> int:
- return self._ssc_mode
-
- def setSscMode(self, mode: int):
- self._ssc_mode = mode
-
- def getSNssai(self) -> Optional[Any]:
- return self._s_nssai
-
- def setSNssai(self, nssai: Any):
- self._s_nssai = nssai
-
- def getDnn(self) -> str:
- return self._dnn
-
- def setDnn(self, dnn: str):
- self._dnn = dnn
-
- def getPrecedence(self) -> int:
- return self._precedence
-
- def setPrecedence(self, prec: int):
- self._precedence = prec
-
- def getPduSessionType(self) -> int:
- return self._pdu_session_type
-
- def setPduSessionType(self, type_: int):
- self._pdu_session_type = type_
-
- def toString(self) -> str:
- return f"RouteSelectionDescriptor(sscMode={self._ssc_mode}, dnn={self._dnn})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Nssai
-# ═══════════════════════════════════════════════════════════════
-
-class Nssai(Stub):
- """Nssai — 网络切片选择辅助信息"""
-
- SST_EMBB = 1
- SST_URLLC = 2
- SST_MIOT = 3
- SST_V2X = 4
-
- def __init__(self, sst: int = 0, sd: int = 0):
- super().__init__()
- self._sst = sst
- self._sd = sd
- self._sd_string: str = ""
- self._mapped_hplmn_sst: int = 0
- self._mapped_hplmn_sd: int = 0
-
- def getSst(self) -> int:
- return self._sst
-
- def setSst(self, sst: int):
- self._sst = sst
-
- def getSd(self) -> int:
- return self._sd
-
- def setSd(self, sd: int):
- self._sd = sd
-
- def getSdString(self) -> str:
- return self._sd_string
-
- def setSdString(self, sd_str: str):
- self._sd_string = sd_str
-
- def getMappedHplmnSst(self) -> int:
- return self._mapped_hplmn_sst
-
- def setMappedHplmnSst(self, sst: int):
- self._mapped_hplmn_sst = sst
-
- def getMappedHplmnSd(self) -> int:
- return self._mapped_hplmn_sd
-
- def setMappedHplmnSd(self, sd: int):
- self._mapped_hplmn_sd = sd
-
- def toString(self) -> str:
- return f"Nssai(sst={self._sst}, sd={self._sd})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TelephonyManager.Data
-# ═══════════════════════════════════════════════════════════════
-
-class TelephonyManager_Data(Stub):
- """TelephonyManager.Data — TelephonyManager 数据相关子类"""
-
- DATA_DISCONNECTED = 0
- DATA_CONNECTING = 1
- DATA_CONNECTED = 2
- DATA_SUSPENDED = 3
- DATA_HANDOVER_IN_PROGRESS = 4
- DATA_UNKNOWN = -1
-
- DATA_ACTIVITY_NONE = 0
- DATA_ACTIVITY_IN = 1
- DATA_ACTIVITY_OUT = 2
- DATA_ACTIVITY_INOUT = 3
- DATA_ACTIVITY_DORMANT = 4
-
- def __init__(self, telephony_manager: Any = None):
- super().__init__()
- self._manager = telephony_manager
- self._data_connections: Dict[int, DataConnection] = {}
- self._data_state: int = TelephonyManager_Data.DATA_DISCONNECTED
-
- def getDataState(self) -> int:
- return self._data_state
-
- def setDataState(self, state: int):
- self._data_state = state
-
- def getDataActivity(self) -> int:
- return TelephonyManager_Data.DATA_ACTIVITY_NONE
-
- def getDataConnections(self) -> List[DataConnection]:
- return list(self._data_connections.values())
-
- def getDataConnection(self, cid: int) -> Optional[DataConnection]:
- return self._data_connections.get(cid)
-
- def addDataConnection(self, conn: DataConnection):
- self._data_connections[conn.getCid()] = conn
-
- def removeDataConnection(self, cid: int):
- self._data_connections.pop(cid, None)
-
- def isDataEnabled(self) -> bool:
- return True
-
- def isDataRoamingEnabled(self) -> bool:
- return False
-
- def getDataNetworkType(self) -> int:
- return 0
-
- def toString(self) -> str:
- return f"TelephonyManager.Data(state={self._data_state})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataFailCause
-# ═══════════════════════════════════════════════════════════════
-
-class DataFailCause(Stub):
- """DataFailCause — 数据连接失败原因码"""
-
- NONE = 0
- OPERATOR_BARRED = 8
- INSUFFICIENT_RESOURCES = 26
- MISSING_UKNOWN_APN = 27
- UNKNOWN_PDP_ADDRESS_TYPE = 28
- USER_AUTHENTICATION = 29
- ACTIVATION_REJECT_GGSN = 30
- ACTIVATION_REJECT_UNSPECIFIED = 31
- SERVICE_OPTION_NOT_SUPPORTED = 32
- SERVICE_OPTION_NOT_SUBSCRIBED = 33
- SERVICE_OPTION_OUT_OF_ORDER = 34
- NSAPI_IN_USE = 35
- REGULAR_DEACTIVATION = 36
- QOS_NOT_ACCEPTED = 37
- NETWORK_FAILURE = 38
- REACTIVATION_REQUESTED = 39
- PDP_DUPLICATE = 40
- PDP_AUTH_FAILURE = 41
- MAX_ACTIVE_PDP_CONTEXT_REACHED = 65
- UNSUPPORTED_APN_IN_CURRENT_PLMN = 66
- INVALID_TRANSACTION_ID = 81
- MESSAGE_INCORRECT_SEMANTIC = 83
- INVALID_MANDATORY_INFO = 84
- MESSAGE_TYPE_UNSUPPORTED = 97
- MSG_TYPE_NONCOMPATIBLE_STATE = 98
- UNKNOWN_INFO_ELEMENT = 99
- CONDITIONAL_IE_ERROR = 100
- PROTOCOL_ERRORS = 111
- APN_TYPE_CONFLICT = 112
- INVALID_PCO = 113
- INTERNAL_RETRY = 114
- PDP_ACTIVATE_MAX_RETRY_FAILED = 115
- RADIO_ACCESS_BEARER_FAILURE = 116
- RADIO_ACCESS_BEARER_SETUP_FAILURE = 117
- RADIO_ACCESS_BEARER_RELEASE_FAILURE = 118
- PDP_MODIFY_FAILURE = 119
- MAX_ACTIVE_NETWORK_TYPE = 120
- ONLY_SINGLE_BEARER_ALLOWED = 121
- ERROR_UNSPECIFIED = 65535
-
- @staticmethod
- def toString(cause: int) -> str:
- names = {v: k for k, v in DataFailCause.__dict__.items()
- if isinstance(v, int) and not k.startswith("_")}
- return names.get(cause, f"UNKNOWN({cause})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataServiceProvider
-# ═══════════════════════════════════════════════════════════════
-
-class DataServiceProvider(Stub):
- """DataServiceProvider — 数据服务提供商"""
-
- def __init__(self):
- super().__init__()
- self._name: str = ""
- self._plmn: str = ""
- self._is_roaming: bool = False
- self._is_registered: bool = False
-
- def getName(self) -> str:
- return self._name
-
- def setName(self, name: str):
- self._name = name
-
- def getPlmn(self) -> str:
- return self._plmn
-
- def setPlmn(self, plmn: str):
- self._plmn = plmn
-
- def isRoaming(self) -> bool:
- return self._is_roaming
-
- def setRoaming(self, roaming: bool):
- self._is_roaming = roaming
-
- def isRegistered(self) -> bool:
- return self._is_registered
-
- def setRegistered(self, registered: bool):
- self._is_registered = registered
-
- def toString(self) -> str:
- return f"DataServiceProvider(name={self._name}, plmn={self._plmn})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DataRegistrationState (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class DataRegistrationState(Stub):
- """DataRegistrationState — 数据注册状态"""
-
- REGISTRATION_STATE_NOT_REGISTERED = 0
- REGISTRATION_STATE_REGISTERED_HOME = 1
- REGISTRATION_STATE_REGISTERED_ROAMING = 2
- REGISTRATION_STATE_REGISTERED_NOT_KNOWN = 3
- REGISTRATION_STATE_DENIED = 4
- REGISTRATION_STATE_UNKNOWN = 5
- REGISTRATION_STATE_SCANNING = 6
-
- def __init__(self, state: int = REGISTRATION_STATE_UNKNOWN):
- super().__init__()
- self._state = state
- self._domain: int = 0
- self._transport_type: int = 0
- self._specific_info: Optional[DataSpecificRegistrationInfo] = None
- self._rat: int = 0
- self._reason_for_denial: int = 0
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getDomain(self) -> int:
- return self._domain
-
- def setDomain(self, domain: int):
- self._domain = domain
-
- def getTransportType(self) -> int:
- return self._transport_type
-
- def setTransportType(self, transport: int):
- self._transport_type = transport
-
- def getSpecificInfo(self) -> Optional[DataSpecificRegistrationInfo]:
- return self._specific_info
-
- def setSpecificInfo(self, info: DataSpecificRegistrationInfo):
- self._specific_info = info
-
- def getRat(self) -> int:
- return self._rat
-
- def setRat(self, rat: int):
- self._rat = rat
-
- def isRegistered(self) -> bool:
- return self._state in (DataRegistrationState.REGISTRATION_STATE_REGISTERED_HOME,
- DataRegistrationState.REGISTRATION_STATE_REGISTERED_ROAMING)
-
- def toString(self) -> str:
- return f"DataRegistrationState(state={self._state})"
\ No newline at end of file
diff --git a/android_pyapi/android/telephony_euicc.py b/android_pyapi/android/telephony_euicc.py
deleted file mode 100644
index 8313a82..0000000
--- a/android_pyapi/android/telephony_euicc.py
+++ /dev/null
@@ -1,1181 +0,0 @@
-"""
-Android Telephony EUICC 组件 — EuiccManager, EuiccCardManager, EuiccInfo, DownloadableSubscription 等
-方法签名完全对齐 Android SDK (android.telephony.euicc 包)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccManager
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccManager(Stub):
- """EuiccManager — eUICC 管理器"""
-
- ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"
- ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"
- ACTION_RESOLVE_ERROR = "android.telephony.euicc.action.RESOLVE_ERROR"
- ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED"
- ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED"
- ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED"
- ACTION_START_RESOLUTION = "android.telephony.euicc.action.START_RESOLUTION"
-
- EXTRA_ENABLE_SUBSCRIPTION = "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION"
- EXTRA_SUBSCRIPTION_ID = "android.telephony.euicc.extra.SUBSCRIPTION_ID"
- EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION"
- EXTRA_RESOLUTION_INTENT = "android.telephony.euicc.extra.RESOLUTION_INTENT"
- EXTRA_RESOLUTION_CALLBACK_INTENT = "android.telephony.euicc.extra.RESOLUTION_CALLBACK_INTENT"
- EXTRA_USE_QR_SCANNER = "android.telephony.euicc.extra.USE_QR_SCANNER"
- EXTRA_FORCE_COMMIT = "android.telephony.euicc.extra.FORCE_COMMIT"
- EXTRA_CONSENT = "android.telephony.euicc.extra.CONSENT"
- EXTRA_SUBSCRIPTION_ID_FOR_RESOLVING = "android.telephony.euicc.extra.SUBSCRIPTION_ID_FOR_RESOLVING"
- EXTRA_RESOLVING_ACTION = "android.telephony.euicc.extra.RESOLVING_ACTION"
- EXTRA_ACTIVE_SLOT = "android.telephony.euicc.extra.ACTIVE_SLOT"
- EXTRA_SIM_SLOT_INDEX = "android.telephony.euicc.extra.SIM_SLOT_INDEX"
- EXTRA_PHYSICAL_SLOT_ID = "android.telephony.euicc.extra.PHYSICAL_SLOT_ID"
-
- EMBEDDED_SUBSCRIPTION_RESULT_OK = 0
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 1
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_BUSY = 2
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INVALID_ACTIVATION_CODE = 3
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INVALID_CONFIRMATION_CODE = 4
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INVALID_RESPONSE = 5
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INVALID_MATCHING_ID = 6
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INVALID_SMDP_ADDRESS = 7
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_NETWORK = 8
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_UNSUPPORTED = 9
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_PROFILES_LIMIT_EXCEEDED = 10
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_DOWNLOAD_IN_PROGRESS = 11
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INVALID_PORT = 12
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_CARRIER_LOCKED = 13
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INVALID_PORT_INDEX = 14
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INVALID_ADDRESS = 15
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INTERNAL = 16
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_SIM_NOT_READY = 17
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_CARRIER_PRIVILEGE = 18
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_APDU = 19
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_CONFIRMATION_CODE_MISMATCH = 20
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_OPERATION_BUSY = 21
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_INVALID_SLOT_ID = 22
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_NOT_FOUND = 23
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_DISALLOWED = 24
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_NOT_ENABLED = 25
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_MULTI_SIM_NOT_SUPPORTED = 26
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_SUBSCRIPTION_NOT_FOUND = 27
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_SUBSCRIPTION_ALREADY_EXISTS = 28
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_RENAME_NOT_ALLOWED = 29
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_DELETE_NOT_ALLOWED = 30
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_REFRESH_NOT_ALLOWED = 31
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_OUT_OF_MEMORY = 32
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_REJECTED = 33
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_FRAME_TABLE_FULL = 34
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_APPLICATION_NOT_FOUND = 35
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_MISMATCH = 36
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_VERSION_NOT_SUPPORTED = 37
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_POLICY = 38
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_AUTH = 39
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_KEY = 40
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_SIGNATURE = 41
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_CERTIFICATE = 42
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_CERTIFICATE_EXPIRED = 43
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_CERTIFICATE_REVOKED = 44
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_IDENTITY_MISMATCH = 45
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_PROFILE_NOT_AVAILABLE = 46
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_PROFILE_ALREADY_INSTALLED = 47
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_PROFILE_NOT_INSTALLED = 48
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR_EUICC_PROFILE_INVALID = 49
-
- # eUICC 操作
- OPERATION_DOWNLOAD = 0
- OPERATION_DELETE = 1
- OPERATION_SWITCH = 2
- OPERATION_RENAME = 3
- OPERATION_REFRESH = 4
- OPERATION_RESOLVE = 5
- OPERATION_GET_DEFAULT = 6
- OPERATION_GET_EID = 7
- OPERATION_GET_EUICC_INFO = 8
- OPERATION_GET_EUICC_CHALLENGE = 9
- OPERATION_GET_PROFILE = 10
- OPERATION_GET_SUBSCRIPTION = 11
- OPERATION_LIST_SUBSCRIPTIONS = 12
- OPERATION_SET_NICKNAME = 13
- OPERATION_ERASE = 14
- OPERATION_UPDATE = 15
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._eid: str = ""
- self._euicc_info: Optional[EuiccInfo] = None
- self._subscriptions: List[EuiccSubscriptionInfo] = []
- self._enabled: bool = False
- self._slot_index: int = 0
-
- def isEnabled(self) -> bool:
- """检查 eUICC 是否启用"""
- return self._enabled
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- def getEid(self) -> str:
- """获取 eUICC ID (EID)"""
- return self._eid
-
- def setEid(self, eid: str):
- self._eid = eid
-
- def getEuiccInfo(self) -> Optional[EuiccInfo]:
- """获取 eUICC 信息"""
- return self._euicc_info
-
- def setEuiccInfo(self, info: EuiccInfo):
- self._euicc_info = info
-
- def getEuiccCardManager(self) -> Optional[EuiccCardManager]:
- """获取 eUICC 卡管理器"""
- return EuiccCardManager(self._context)
-
- def getSlotIndex(self) -> int:
- return self._slot_index
-
- def setSlotIndex(self, index: int):
- self._slot_index = index
-
- def getContext(self) -> Any:
- return self._context
-
- def downloadSubscription(self, subscription: DownloadableSubscription,
- switch_to_downloaded: bool = True,
- callback: Any = None) -> int:
- """下载订阅"""
- return EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK
-
- def startResolution(self, result: int, callback_intent: Any,
- resolution_intent: Any):
- """启动解析流程"""
- pass
-
- def listSubscriptions(self) -> List[EuiccSubscriptionInfo]:
- """列出所有订阅"""
- return list(self._subscriptions)
-
- def addSubscription(self, sub: EuiccSubscriptionInfo):
- self._subscriptions.append(sub)
-
- def removeSubscription(self, sub_id: int):
- self._subscriptions = [s for s in self._subscriptions if s.getSubscriptionId() != sub_id]
-
- def getDefaultDownloadableSubscription(self) -> Optional[DownloadableSubscription]:
- """获取默认可下载订阅"""
- return None
-
- def createForCardId(self, card_id: int) -> EuiccManager:
- """为指定卡 ID 创建 eUICC 管理器"""
- return self
-
- def switchToSubscription(self, sub_id: int, callback: Any = None):
- """切换到指定订阅"""
- pass
-
- def deleteSubscription(self, sub_id: int, callback: Any = None):
- """删除指定订阅"""
- pass
-
- def renameSubscription(self, sub_id: int, new_name: str):
- """重命名订阅"""
- for s in self._subscriptions:
- if s.getSubscriptionId() == sub_id:
- s.setNickname(new_name)
- break
-
- def eraseSubscriptions(self, callback: Any = None):
- """擦除所有订阅"""
- self._subscriptions.clear()
-
- def refreshSubscriptions(self, callback: Any = None):
- """刷新订阅列表"""
- pass
-
- def retainSubscriptionsForFactoryReset(self, callback: Any = None):
- """保留订阅以备恢复出厂设置"""
- pass
-
- def isSimPortAvailable(self, port_index: int) -> bool:
- return True
-
- def toString(self) -> str:
- return f"EuiccManager(enabled={self._enabled}, eid={self._eid[:8] if self._eid else ''}...)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccCardManager
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccCardManager(Stub):
- """EuiccCardManager — eUICC 卡管理器"""
-
- RESULT_OK = 0
- RESULT_UNKNOWN_ERROR = 1
- RESULT_INVALID_ARGUMENTS = 2
- RESULT_INTERNAL_ERROR = 3
- RESULT_SESSION_CLOSED = 4
- RESULT_NO_PENDING_COMMANDS = 5
- RESULT_COMMAND_FAILED = 6
- RESULT_APDU_ERROR = 7
- RESULT_CARD_NOT_ACCESSIBLE = 8
- RESULT_CARD_REMOVED = 9
- RESULT_CARD_RESET = 10
- RESULT_TIMEOUT = 11
- RESULT_CARD_IO_ERROR = 12
- RESULT_CARD_AUTH_ERROR = 13
- RESULT_PROFILE_NOT_AVAILABLE = 14
- RESULT_PROFILE_ALREADY_INSTALLED = 15
- RESULT_PROFILE_NOT_INSTALLED = 16
- RESULT_PROFILE_INSTALL_ERROR = 17
- RESULT_PROFILE_DELETE_ERROR = 18
- RESULT_PROFILE_EUICC_MISMATCH = 19
- RESULT_PROFILE_VERSION_MISMATCH = 20
- RESULT_PROFILE_CERTIFICATE_ERROR = 21
- RESULT_PROFILE_SIGNATURE_ERROR = 22
- RESULT_PROFILE_INTEGRITY_ERROR = 23
- RESULT_PROFILE_EXPIRED = 24
- RESULT_PROFILE_REVOKED = 25
- RESULT_PROFILE_POLICY_ERROR = 26
- RESULT_PROFILE_AUTH_ERROR = 27
- RESULT_PROFILE_KEY_ERROR = 28
- RESULT_PROFILE_MEMORY_ERROR = 29
- RESULT_PROFILE_UNSUPPORTED = 30
- RESULT_PROFILE_CONFLICT = 31
- RESULT_RAT_NOT_ALLOWED = 32
- RESULT_POLICY_RULES_NOT_SATISFIED = 33
- RESULT_NOT_ENABLED = 34
- RESULT_MULTISIM_NOT_SUPPORTED = 35
- RESULT_CARRIER_LOCKED = 36
- RESULT_OPERATION_BUSY = 37
- RESULT_CARD_ALREADY_ACTIVE = 38
- RESULT_CARD_INACTIVE = 39
-
- class ResultCallback(Stub):
- """EuiccCardManager.ResultCallback — eUICC 卡操作结果回调"""
-
- def onComplete(self, result: int, data: Any = None):
- pass
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._card_id: str = ""
- self._eid: str = ""
-
- def getContext(self) -> Any:
- return self._context
-
- def getCardId(self) -> str:
- return self._card_id
-
- def setCardId(self, card_id: str):
- self._card_id = card_id
-
- def getEid(self) -> str:
- return self._eid
-
- def setEid(self, eid: str):
- self._eid = eid
-
- def requestEvents(self, callback: ResultCallback):
- """请求 eUICC 事件"""
- pass
-
- def requestEvents(self, port_index: int, callback: ResultCallback):
- pass
-
- def listNotifications(self, callback: ResultCallback):
- """列出通知"""
- pass
-
- def listNotifications(self, port_index: int, callback: ResultCallback):
- pass
-
- def retrieveNotification(self, seq_number: int, callback: ResultCallback):
- """检索通知"""
- pass
-
- def retrieveNotificationList(self, seq_numbers: List[int], callback: ResultCallback):
- """检索通知列表"""
- pass
-
- def prepareDownload(self, subscription: DownloadableSubscription,
- callback: ResultCallback):
- """准备下载"""
- pass
-
- def prepareDownload(self, port_index: int, subscription: DownloadableSubscription,
- callback: ResultCallback):
- pass
-
- def loadBoundProfilePackage(self, bound_profile_package: bytes,
- callback: ResultCallback):
- """加载绑定配置文件包"""
- pass
-
- def loadBoundProfilePackage(self, port_index: int, bound_profile_package: bytes,
- callback: ResultCallback):
- pass
-
- def getProfile(self, iccid: str, callback: ResultCallback):
- """获取配置文件"""
- pass
-
- def getProfile(self, port_index: int, iccid: str, callback: ResultCallback):
- pass
-
- def listProfiles(self, callback: ResultCallback):
- """列出配置文件"""
- pass
-
- def listProfiles(self, port_index: int, callback: ResultCallback):
- pass
-
- def setNickname(self, iccid: str, nickname: str, callback: ResultCallback):
- """设置昵称"""
- pass
-
- def setNickname(self, port_index: int, iccid: str, nickname: str, callback: ResultCallback):
- pass
-
- def deleteProfile(self, iccid: str, callback: ResultCallback):
- """删除配置文件"""
- pass
-
- def deleteProfile(self, port_index: int, iccid: str, callback: ResultCallback):
- pass
-
- def enableProfile(self, iccid: str, callback: ResultCallback):
- """启用配置文件"""
- pass
-
- def enableProfile(self, port_index: int, iccid: str, callback: ResultCallback):
- pass
-
- def disableProfile(self, iccid: str, callback: ResultCallback):
- """禁用配置文件"""
- pass
-
- def disableProfile(self, port_index: int, iccid: str, callback: ResultCallback):
- pass
-
- def resetMemory(self, reset_options: int, callback: ResultCallback):
- """重置 eUICC 内存"""
- pass
-
- def resetMemory(self, port_index: int, reset_options: int, callback: ResultCallback):
- pass
-
- def setTestMode(self, test_mode: bool, callback: ResultCallback):
- """设置测试模式"""
- pass
-
- def getEuiccChallenge(self, callback: ResultCallback):
- """获取 eUICC 挑战"""
- pass
-
- def getEuiccChallenge(self, port_index: int, callback: ResultCallback):
- pass
-
- def getEuiccInfo(self, callback: ResultCallback):
- """获取 eUICC 信息"""
- pass
-
- def getEuiccInfo(self, port_index: int, callback: ResultCallback):
- pass
-
- def listSubscriptions(self, callback: ResultCallback):
- """列出订阅"""
- pass
-
- def toString(self) -> str:
- return f"EuiccCardManager(eid={self._eid[:8] if self._eid else ''}...)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccInfo
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccInfo(Stub):
- """EuiccInfo — eUICC 信息"""
-
- def __init__(self, gsid: str = "", svn: str = "",
- pp_version: str = "",
- global_platform_version: str = ""):
- super().__init__()
- self._gsid = gsid
- self._svn = svn
- self._pp_version = pp_version
- self._global_platform_version = global_platform_version
- self._euicc_firmware_version: str = ""
- self._euicc_hardware_version: str = ""
- self._oid: str = ""
- self._eid: str = ""
- self._profile_version: str = ""
- self._ext_card_resource: str = ""
- self._default_smdp_address: str = ""
-
- def getGsid(self) -> str:
- return self._gsid
-
- def setGsid(self, gsid: str):
- self._gsid = gsid
-
- def getSvn(self) -> str:
- return self._svn
-
- def setSvn(self, svn: str):
- self._svn = svn
-
- def getPpVersion(self) -> str:
- return self._pp_version
-
- def setPpVersion(self, pp_version: str):
- self._pp_version = pp_version
-
- def getGlobalPlatformVersion(self) -> str:
- return self._global_platform_version
-
- def setGlobalPlatformVersion(self, version: str):
- self._global_platform_version = version
-
- def getEuiccFirmwareVersion(self) -> str:
- return self._euicc_firmware_version
-
- def setEuiccFirmwareVersion(self, version: str):
- self._euicc_firmware_version = version
-
- def getEuiccHardwareVersion(self) -> str:
- return self._euicc_hardware_version
-
- def setEuiccHardwareVersion(self, version: str):
- self._euicc_hardware_version = version
-
- def getOid(self) -> str:
- return self._oid
-
- def setOid(self, oid: str):
- self._oid = oid
-
- def getEid(self) -> str:
- return self._eid
-
- def setEid(self, eid: str):
- self._eid = eid
-
- def getProfileVersion(self) -> str:
- return self._profile_version
-
- def setProfileVersion(self, version: str):
- self._profile_version = version
-
- def getExtCardResource(self) -> str:
- return self._ext_card_resource
-
- def setExtCardResource(self, resource: str):
- self._ext_card_resource = resource
-
- def getDefaultSmdpAddress(self) -> str:
- return self._default_smdp_address
-
- def setDefaultSmdpAddress(self, address: str):
- self._default_smdp_address = address
-
- def toString(self) -> str:
- return f"EuiccInfo(gsid={self._gsid}, svn={self._svn})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DownloadableSubscription
-# ═══════════════════════════════════════════════════════════════
-
-class DownloadableSubscription(Stub):
- """DownloadableSubscription — 可下载订阅"""
-
- def __init__(self, encoded_activation_code: str = ""):
- super().__init__()
- self._encoded_activation_code = encoded_activation_code
- self._confirmation_code: str = ""
- self._carrier_name: str = ""
- self._access_rule: Optional[EuiccRulesAuthTable] = None
- self._matching_id: str = ""
- self._smdp_address: str = ""
- self._profile_class: int = 0
- self._iccid: str = ""
- self._nickname: str = ""
-
- def getEncodedActivationCode(self) -> str:
- return self._encoded_activation_code
-
- def setEncodedActivationCode(self, code: str):
- self._encoded_activation_code = code
-
- def getConfirmationCode(self) -> str:
- return self._confirmation_code
-
- def setConfirmationCode(self, code: str):
- self._confirmation_code = code
-
- def getCarrierName(self) -> str:
- return self._carrier_name
-
- def setCarrierName(self, name: str):
- self._carrier_name = name
-
- def getAccessRule(self) -> Optional[EuiccRulesAuthTable]:
- return self._access_rule
-
- def setAccessRule(self, rule: EuiccRulesAuthTable):
- self._access_rule = rule
-
- def getMatchingId(self) -> str:
- return self._matching_id
-
- def setMatchingId(self, matching_id: str):
- self._matching_id = matching_id
-
- def getSmdpAddress(self) -> str:
- return self._smdp_address
-
- def setSmdpAddress(self, address: str):
- self._smdp_address = address
-
- def getProfileClass(self) -> int:
- return self._profile_class
-
- def setProfileClass(self, profile_class: int):
- self._profile_class = profile_class
-
- def getIccid(self) -> str:
- return self._iccid
-
- def setIccid(self, iccid: str):
- self._iccid = iccid
-
- def getNickname(self) -> str:
- return self._nickname
-
- def setNickname(self, nickname: str):
- self._nickname = nickname
-
- @staticmethod
- def forActivationCode(encoded_activation_code: str) -> DownloadableSubscription:
- return DownloadableSubscription(encoded_activation_code)
-
- def toString(self) -> str:
- return f"DownloadableSubscription(carrier={self._carrier_name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccNotification
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccNotification(Stub):
- """EuiccNotification — eUICC 通知"""
-
- EVENT_INSTALL = 1
- EVENT_DELETE = 2
- EVENT_ENABLE = 4
- EVENT_DISABLE = 8
- EVENT_REFRESH = 16
- EVENT_POLICY_RULES_CHANGE = 32
- EVENT_MEMORY_RESET = 64
- EVENT_PROFILE_METADATA_UPDATED = 128
- EVENT_NOTIFICATIONS_ENABLED = 256
- EVENT_ALL = 511
-
- ALL_EVENTS = EVENT_INSTALL | EVENT_DELETE | EVENT_ENABLE | EVENT_DISABLE | EVENT_REFRESH | EVENT_POLICY_RULES_CHANGE | EVENT_MEMORY_RESET | EVENT_PROFILE_METADATA_UPDATED | EVENT_NOTIFICATIONS_ENABLED
-
- def __init__(self, seq_number: int = 0, target_address: str = "",
- event: int = 0, timestamp: int = 0):
- super().__init__()
- self._seq_number = seq_number
- self._target_address = target_address
- self._event = event
- self._timestamp = timestamp
- self._iccid: str = ""
- self._displacement: Optional[bytes] = None
- self._notification_data: Optional[bytes] = None
-
- def getSeqNumber(self) -> int:
- return self._seq_number
-
- def setSeqNumber(self, seq: int):
- self._seq_number = seq
-
- def getTargetAddress(self) -> str:
- return self._target_address
-
- def setTargetAddress(self, address: str):
- self._target_address = address
-
- def getEvent(self) -> int:
- return self._event
-
- def setEvent(self, event: int):
- self._event = event
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def setTimestamp(self, ts: int):
- self._timestamp = ts
-
- def getIccid(self) -> str:
- return self._iccid
-
- def setIccid(self, iccid: str):
- self._iccid = iccid
-
- def getDisplacement(self) -> Optional[bytes]:
- return self._displacement
-
- def setDisplacement(self, data: bytes):
- self._displacement = data
-
- def getNotificationData(self) -> Optional[bytes]:
- return self._notification_data
-
- def setNotificationData(self, data: bytes):
- self._notification_data = data
-
- def toString(self) -> str:
- return f"EuiccNotification(seq={self._seq_number}, event={self._event})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccRulesAuthTable
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccRulesAuthTable(Stub):
- """EuiccRulesAuthTable — eUICC 规则授权表"""
-
- RULE_TYPE_ACCESS_RULES = 0
- RULE_TYPE_POLICY_RULES = 1
- RULE_TYPE_USAGE_RULES = 2
-
- POLICY_RULE_FLAG_CONSENT_REQUIRED = 1
- POLICY_RULE_FLAG_NOTIFY_REQUIRED = 2
- POLICY_RULE_FLAG_DELETE_BLOCKED = 4
- POLICY_RULE_FLAG_DISABLE_BLOCKED = 8
-
- class RulesAuthTableEntry(Stub):
- """EuiccRulesAuthTable.RulesAuthTableEntry — 规则授权表条目"""
-
- def __init__(self):
- super().__init__()
- self._certificate_hash: str = ""
- self._rule_type: int = 0
- self._flags: int = 0
- self._signature: str = ""
- self._pkid: str = ""
- self._valid_from: int = 0
- self._valid_until: int = 0
-
- def getCertificateHash(self) -> str:
- return self._certificate_hash
-
- def setCertificateHash(self, hash_val: str):
- self._certificate_hash = hash_val
-
- def getRuleType(self) -> int:
- return self._rule_type
-
- def setRuleType(self, rule_type: int):
- self._rule_type = rule_type
-
- def getFlags(self) -> int:
- return self._flags
-
- def setFlags(self, flags: int):
- self._flags = flags
-
- def getSignature(self) -> str:
- return self._signature
-
- def setSignature(self, sig: str):
- self._signature = sig
-
- def getPkid(self) -> str:
- return self._pkid
-
- def setPkid(self, pkid: str):
- self._pkid = pkid
-
- def hasFlags(self, flag: int) -> bool:
- return bool(self._flags & flag)
-
- def isValidFor(self, timestamp: int) -> bool:
- return self._valid_from <= timestamp < self._valid_until
-
- def toString(self) -> str:
- return f"RulesAuthTableEntry(type={self._rule_type})"
-
- def __init__(self):
- super().__init__()
- self._entries: List[EuiccRulesAuthTable.RulesAuthTableEntry] = []
-
- def getEntries(self) -> List[RulesAuthTableEntry]:
- return list(self._entries)
-
- def addEntry(self, entry: RulesAuthTableEntry):
- self._entries.append(entry)
-
- def removeEntry(self, entry: RulesAuthTableEntry):
- self._entries = [e for e in self._entries if e is not entry]
-
- def findEntryByCertHash(self, cert_hash: str) -> Optional[RulesAuthTableEntry]:
- for e in self._entries:
- if e.getCertificateHash() == cert_hash:
- return e
- return None
-
- def findEntryByPkid(self, pkid: str) -> Optional[RulesAuthTableEntry]:
- for e in self._entries:
- if e.getPkid() == pkid:
- return e
- return None
-
- def getSize(self) -> int:
- return len(self._entries)
-
- def isEmpty(self) -> bool:
- return len(self._entries) == 0
-
- def toString(self) -> str:
- return f"EuiccRulesAuthTable(entries={len(self._entries)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccSubscriptionInfo
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccSubscriptionInfo(Stub):
- """EuiccSubscriptionInfo — eUICC 订阅信息"""
-
- SUBSCRIPTION_TYPE_PROFILE = 0
- SUBSCRIPTION_TYPE_RESERVED = 1
- SUBSCRIPTION_TYPE_OPERATIONAL = 2
- SUBSCRIPTION_TYPE_TEST = 3
- SUBSCRIPTION_TYPE_PROVISIONING = 4
- SUBSCRIPTION_TYPE_UNKNOWN = -1
-
- def __init__(self, subscription_id: int = 0, iccid: str = "",
- nickname: str = ""):
- super().__init__()
- self._subscription_id = subscription_id
- self._iccid = iccid
- self._nickname = nickname
- self._carrier_name: str = ""
- self._subscription_type: int = EuiccSubscriptionInfo.SUBSCRIPTION_TYPE_PROFILE
- self._is_embedded: bool = True
- self._is_removable: bool = False
- self._is_active: bool = False
- self._profile_class: int = 0
- self._port_index: int = 0
- self._logical_slot_index: int = 0
- self._eid: str = ""
- self._access_rules: Optional[EuiccRulesAuthTable] = None
-
- def getSubscriptionId(self) -> int:
- return self._subscription_id
-
- def setSubscriptionId(self, sub_id: int):
- self._subscription_id = sub_id
-
- def getIccid(self) -> str:
- return self._iccid
-
- def setIccid(self, iccid: str):
- self._iccid = iccid
-
- def getNickname(self) -> str:
- return self._nickname
-
- def setNickname(self, nickname: str):
- self._nickname = nickname
-
- def getCarrierName(self) -> str:
- return self._carrier_name
-
- def setCarrierName(self, name: str):
- self._carrier_name = name
-
- def getSubscriptionType(self) -> int:
- return self._subscription_type
-
- def setSubscriptionType(self, sub_type: int):
- self._subscription_type = sub_type
-
- def isEmbedded(self) -> bool:
- return self._is_embedded
-
- def setEmbedded(self, embedded: bool):
- self._is_embedded = embedded
-
- def isRemovable(self) -> bool:
- return self._is_removable
-
- def setRemovable(self, removable: bool):
- self._is_removable = removable
-
- def isActive(self) -> bool:
- return self._is_active
-
- def setActive(self, active: bool):
- self._is_active = active
-
- def getProfileClass(self) -> int:
- return self._profile_class
-
- def setProfileClass(self, profile_class: int):
- self._profile_class = profile_class
-
- def getPortIndex(self) -> int:
- return self._port_index
-
- def setPortIndex(self, port: int):
- self._port_index = port
-
- def getLogicalSlotIndex(self) -> int:
- return self._logical_slot_index
-
- def setLogicalSlotIndex(self, index: int):
- self._logical_slot_index = index
-
- def getEid(self) -> str:
- return self._eid
-
- def setEid(self, eid: str):
- self._eid = eid
-
- def getAccessRules(self) -> Optional[EuiccRulesAuthTable]:
- return self._access_rules
-
- def setAccessRules(self, rules: EuiccRulesAuthTable):
- self._access_rules = rules
-
- def toString(self) -> str:
- return f"EuiccSubscriptionInfo(id={self._subscription_id}, carrier={self._carrier_name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccProfileInfo
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccProfileInfo(Stub):
- """EuiccProfileInfo — eUICC 配置文件信息"""
-
- PROFILE_CLASS_OPERATIONAL = 0
- PROFILE_CLASS_TEST = 1
- PROFILE_CLASS_PROVISIONING = 2
- PROFILE_CLASS_OPERATIONAL_V2 = 3
- PROFILE_CLASS_UNKNOWN = -1
-
- STATE_DISABLED = 0
- STATE_ENABLED = 1
-
- def __init__(self, iccid: str = ""):
- super().__init__()
- self._iccid = iccid
- self._nickname: str = ""
- self._carrier_name: str = ""
- self._profile_class: int = EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL
- self._state: int = EuiccProfileInfo.STATE_DISABLED
- self._service_provider_name: str = ""
- self._profile_name: str = ""
- self._profile_owner: str = ""
- self._carrier_privilege_rules: List[EuiccRulesAuthTable.RulesAuthTableEntry] = []
- self._is_visible: bool = True
- self._policy_rules: Optional[EuiccRulesAuthTable] = None
- self._icon: Optional[bytes] = None
-
- def getIccid(self) -> str:
- return self._iccid
-
- def setIccid(self, iccid: str):
- self._iccid = iccid
-
- def getNickname(self) -> str:
- return self._nickname
-
- def setNickname(self, nickname: str):
- self._nickname = nickname
-
- def getCarrierName(self) -> str:
- return self._carrier_name
-
- def setCarrierName(self, name: str):
- self._carrier_name = name
-
- def getProfileClass(self) -> int:
- return self._profile_class
-
- def setProfileClass(self, profile_class: int):
- self._profile_class = profile_class
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getServiceProviderName(self) -> str:
- return self._service_provider_name
-
- def setServiceProviderName(self, name: str):
- self._service_provider_name = name
-
- def getProfileName(self) -> str:
- return self._profile_name
-
- def setProfileName(self, name: str):
- self._profile_name = name
-
- def getCarrierPrivilegeRules(self) -> List[EuiccRulesAuthTable.RulesAuthTableEntry]:
- return list(self._carrier_privilege_rules)
-
- def setCarrierPrivilegeRules(self, rules: List[EuiccRulesAuthTable.RulesAuthTableEntry]):
- self._carrier_privilege_rules = list(rules)
-
- def isVisible(self) -> bool:
- return self._is_visible
-
- def setVisible(self, visible: bool):
- self._is_visible = visible
-
- def getPolicyRules(self) -> Optional[EuiccRulesAuthTable]:
- return self._policy_rules
-
- def setPolicyRules(self, rules: EuiccRulesAuthTable):
- self._policy_rules = rules
-
- def isEnabled(self) -> bool:
- return self._state == EuiccProfileInfo.STATE_ENABLED
-
- def toString(self) -> str:
- return f"EuiccProfileInfo(iccid={self._iccid}, carrier={self._carrier_name})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccActions (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccActions(Stub):
- """EuiccActions — eUICC 操作辅助类"""
-
- @staticmethod
- def createDownloadAction(subscription: DownloadableSubscription,
- switch_on_download: bool = True) -> Any:
- """创建下载操作意图"""
- return None
-
- @staticmethod
- def createDeleteAction(subscription_id: int) -> Any:
- """创建删除操作意图"""
- return None
-
- @staticmethod
- def createSwitchAction(subscription_id: int) -> Any:
- """创建切换操作意图"""
- return None
-
- @staticmethod
- def createRenameAction(subscription_id: int, new_name: str) -> Any:
- """创建重命名操作意图"""
- return None
-
- @staticmethod
- def createEraseAction() -> Any:
- """创建擦除操作意图"""
- return None
-
- @staticmethod
- def encodeActivationCode(matching_id: str, smdp_address: str) -> str:
- """编码激活码"""
- return f"1$^{matching_id}${smdp_address}$"
-
- @staticmethod
- def decodeActivationCode(activation_code: str) -> Optional[Tuple[str, str]]:
- """解码激活码"""
- try:
- parts = activation_code.split("$")
- if len(parts) >= 3:
- return parts[1], parts[2]
- except Exception:
- pass
- return None
-
- @staticmethod
- def isValidActivationCode(activation_code: str) -> bool:
- """验证激活码是否有效"""
- return activation_code.startswith("1$") and "$" in activation_code
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccChannel (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccChannel(Stub):
- """EuiccChannel — eUICC 通道辅助类"""
-
- CHANNEL_TYPE_APDU = 0
- CHANNEL_TYPE_HTTP = 1
- CHANNEL_TYPE_HTTPS = 2
-
- def __init__(self, channel_type: int = CHANNEL_TYPE_APDU):
- super().__init__()
- self._channel_type = channel_type
- self._is_open: bool = False
- self._buffer: bytes = b""
-
- def getChannelType(self) -> int:
- return self._channel_type
-
- def isOpen(self) -> bool:
- return self._is_open
-
- def open(self):
- self._is_open = True
-
- def close(self):
- self._is_open = False
- self._buffer = b""
-
- def send(self, data: bytes) -> bytes:
- self._buffer = data
- return b""
-
- def receive(self) -> bytes:
- return self._buffer
-
- def toString(self) -> str:
- return f"EuiccChannel(type={self._channel_type}, open={self._is_open})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccPortIndex (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccPortIndex(Stub):
- """EuiccPortIndex — eUICC 端口索引"""
-
- PORT_INDEX_DEFAULT = 0
- PORT_INDEX_FIRST = 0
- PORT_INDEX_SECOND = 1
-
- def __init__(self, port_index: int = PORT_INDEX_DEFAULT):
- super().__init__()
- self._port_index = port_index
-
- def getPortIndex(self) -> int:
- return self._port_index
-
- def setPortIndex(self, index: int):
- self._port_index = index
-
- def toString(self) -> str:
- return f"EuiccPortIndex({self._port_index})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccResetOption (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccResetOption(Stub):
- """EuiccResetOption — eUICC 重置选项"""
-
- RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1
- RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2
- RESET_OPTION_RESET_TO_DEFAULT = 3
- RESET_OPTION_DELETE_ALL_PROFILES = 4
-
- def __init__(self, option: int = RESET_OPTION_DELETE_OPERATIONAL_PROFILES):
- super().__init__()
- self._option = option
-
- def getOption(self) -> int:
- return self._option
-
- def setOption(self, option: int):
- self._option = option
-
- def toString(self) -> str:
- return f"EuiccResetOption({self._option})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccMemorySize (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccMemorySize(Stub):
- """EuiccMemorySize — eUICC 内存大小"""
-
- def __init__(self, free_bytes: int = 0, total_bytes: int = 0):
- super().__init__()
- self._free_bytes = free_bytes
- self._total_bytes = total_bytes
- self._used_bytes = total_bytes - free_bytes
-
- def getFreeBytes(self) -> int:
- return self._free_bytes
-
- def getTotalBytes(self) -> int:
- return self._total_bytes
-
- def getUsedBytes(self) -> int:
- return self._used_bytes
-
- def getUsedPercentage(self) -> float:
- if self._total_bytes == 0:
- return 0.0
- return (self._used_bytes / self._total_bytes) * 100.0
-
- def toString(self) -> str:
- return f"EuiccMemorySize(free={self._free_bytes}, total={self._total_bytes})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EuiccSmdpAddress (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class EuiccSmdpAddress(Stub):
- """EuiccSmdpAddress — SMDP 地址辅助类"""
-
- def __init__(self, address: str = ""):
- super().__init__()
- self._address = address
- self._is_default: bool = False
-
- def getAddress(self) -> str:
- return self._address
-
- def setAddress(self, address: str):
- self._address = address
-
- def isDefault(self) -> bool:
- return self._is_default
-
- def setDefault(self, is_default: bool):
- self._is_default = is_default
-
- @staticmethod
- def getDefaultAddress() -> EuiccSmdpAddress:
- return EuiccSmdpAddress("default-smdp.gsma.com")
-
- def toString(self) -> str:
- return f"EuiccSmdpAddress({self._address})"
\ No newline at end of file
diff --git a/android_pyapi/android/telephony_gsm.py b/android_pyapi/android/telephony_gsm.py
deleted file mode 100644
index f150fb5..0000000
--- a/android_pyapi/android/telephony_gsm.py
+++ /dev/null
@@ -1,1082 +0,0 @@
-"""
-Android Telephony GSM 组件 — GsmCellLocation, GsmSignalStrength, SmsManager (GSM扩展)
-方法签名完全对齐 Android SDK (android.telephony.gsm 包)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# GsmCellLocation
-# ═══════════════════════════════════════════════════════════════
-
-class GsmCellLocation(Stub):
- """GsmCellLocation — GSM 小区位置"""
-
- def __init__(self):
- super().__init__()
- self._lac: int = -1
- self._cid: int = -1
- self._psc: int = -1
- self._uarfcn: int = -1
- self._pci: int = -1
- self._arfcn: int = -1
- self._bsic: int = -1
- self._rssi: int = 0
- self._timing_advance: int = 0
-
- def getLac(self) -> int:
- """获取位置区码 (LAC)"""
- return self._lac
-
- def setLac(self, lac: int):
- self._lac = lac
-
- def getCid(self) -> int:
- """获取小区 ID (CID)"""
- return self._cid
-
- def setCid(self, cid: int):
- self._cid = cid
-
- def getPsc(self) -> int:
- """获取主扰码 (PSC)"""
- return self._psc
-
- def setPsc(self, psc: int):
- self._psc = psc
-
- def getUarfcn(self) -> int:
- """获取 UARFCN"""
- return self._uarfcn
-
- def setUarfcn(self, uarfcn: int):
- self._uarfcn = uarfcn
-
- def getPci(self) -> int:
- """获取物理小区 ID (PCI)"""
- return self._pci
-
- def setPci(self, pci: int):
- self._pci = pci
-
- def getArfcn(self) -> int:
- """获取 ARFCN"""
- return self._arfcn
-
- def setArfcn(self, arfcn: int):
- self._arfcn = arfcn
-
- def getBsic(self) -> int:
- """获取基站识别码 (BSIC)"""
- return self._bsic
-
- def setBsic(self, bsic: int):
- self._bsic = bsic
-
- def getRssi(self) -> int:
- return self._rssi
-
- def setRssi(self, rssi: int):
- self._rssi = rssi
-
- def getTimingAdvance(self) -> int:
- """获取时间提前量 (TA)"""
- return self._timing_advance
-
- def setTimingAdvance(self, ta: int):
- self._timing_advance = ta
-
- def isGprs(self) -> bool:
- """检查是否 GPRS"""
- return self._cid >= 0
-
- def toString(self) -> str:
- return f"GsmCellLocation(lac={self._lac}, cid={self._cid}, psc={self._psc})"
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, GsmCellLocation):
- return (self._lac == other._lac and self._cid == other._cid
- and self._psc == other._psc)
- return False
-
- def hashCode(self) -> int:
- return hash((self._lac, self._cid, self._psc)) & 0x7FFFFFFF
-
- def fillInNotifierBundle(self, bundle: Any):
- """填充通知包"""
- if bundle is not None:
- bundle.putInt("lac", self._lac)
- bundle.putInt("cid", self._cid)
- bundle.putInt("psc", self._psc)
-
-
-# ═══════════════════════════════════════════════════════════════
-# GsmSignalStrength
-# ═══════════════════════════════════════════════════════════════
-
-class GsmSignalStrength(Stub):
- """GsmSignalStrength — GSM 信号强度"""
-
- SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0
- SIGNAL_STRENGTH_POOR = 1
- SIGNAL_STRENGTH_MODERATE = 2
- SIGNAL_STRENGTH_GOOD = 3
- SIGNAL_STRENGTH_GREAT = 4
-
- INVALID = 99
- MAX_RSSI = 31
- MIN_RSSI = 0
-
- def __init__(self, rssi: int = 0, ber: int = -1, ta: int = -1):
- super().__init__()
- self._rssi = rssi
- self._ber = ber
- self._ta = ta
- self._signal_strength: int = GsmSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
- self._bit_error_rate: int = -1
- self._is_gsm: bool = True
-
- def getRssi(self) -> int:
- """获取 RSSI"""
- return self._rssi
-
- def setRssi(self, rssi: int):
- self._rssi = rssi
-
- def getBer(self) -> int:
- """获取误码率 (BER)"""
- return self._ber
-
- def setBer(self, ber: int):
- self._ber = ber
-
- def getTimingAdvance(self) -> int:
- """获取时间提前量"""
- return self._ta
-
- def setTimingAdvance(self, ta: int):
- self._ta = ta
-
- def getSignalStrength(self) -> int:
- """获取信号强度等级"""
- return self._signal_strength
-
- def setSignalStrength(self, strength: int):
- self._signal_strength = strength
-
- def getBitErrorRate(self) -> int:
- return self._bit_error_rate
-
- def setBitErrorRate(self, ber: int):
- self._bit_error_rate = ber
-
- def getDbm(self) -> int:
- """获取 dBm 值"""
- if self._rssi <= 0 or self._rssi == 99:
- return -113
- return -113 + 2 * self._rssi
-
- def getLevel(self) -> int:
- """获取信号等级 (0-4)"""
- dbm = self.getDbm()
- if dbm >= -85:
- return GsmSignalStrength.SIGNAL_STRENGTH_GREAT
- elif dbm >= -95:
- return GsmSignalStrength.SIGNAL_STRENGTH_GOOD
- elif dbm >= -105:
- return GsmSignalStrength.SIGNAL_STRENGTH_MODERATE
- elif dbm >= -115:
- return GsmSignalStrength.SIGNAL_STRENGTH_POOR
- else:
- return GsmSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
-
- def getAsuLevel(self) -> int:
- """获取 ASU 等级"""
- return self._rssi
-
- def isGsm(self) -> bool:
- return self._is_gsm
-
- def toString(self) -> str:
- return f"GsmSignalStrength(rssi={self._rssi}, dbm={self.getDbm()}, level={self.getLevel()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SmsManager — GSM 扩展
-# ═══════════════════════════════════════════════════════════════
-
-class SmsManager(Stub):
- """SmsManager — GSM SMS 管理器"""
-
- RESULT_ERROR_GENERIC_FAILURE = 1
- RESULT_ERROR_RADIO_OFF = 2
- RESULT_ERROR_NULL_PDU = 3
- RESULT_ERROR_NO_SERVICE = 4
- RESULT_ERROR_LIMIT_EXCEEDED = 5
- RESULT_ERROR_FDN_CHECK_FAILURE = 6
- RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 7
- RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 8
- RESULT_RIL_GENERIC_FAILURE = 9
- RESULT_RIL_RADIO_NOT_AVAILABLE = 10
- RESULT_RIL_NETWORK_FAILURE = 11
- RESULT_RIL_SMS_SEND_FAILURE = 12
- RESULT_RIL_SMS_DELIVERY_FAILURE = 13
- RESULT_RIL_CANCELLED = 14
- RESULT_RIL_MODEM_RESET = 15
- RESULT_RIL_SIM_ABSENT = 16
- RESULT_RIL_INVALID_SMSC_ADDRESS = 17
- RESULT_RIL_SIM_SMS_FAILURE = 18
- RESULT_RIL_NO_MEMORY = 19
- RESULT_RIL_SIM_PUK_REQUIRED = 20
- RESULT_RIL_SIM_PIN_REQUIRED = 21
- RESULT_RIL_RADIO_NOT_READY = 22
- RESULT_RIL_ENCODING_ERROR = 23
- RESULT_RIL_INVALID_STATE = 24
- RESULT_RIL_MODEM_ERROR = 25
- RESULT_RIL_INTERNAL_ERROR = 26
- RESULT_RIL_REQUEST_NOT_SUPPORTED = 27
- RESULT_RIL_INVALID_PARAMETER = 28
- RESULT_RIL_SIM_ERROR = 29
- RESULT_RIL_SIM_NOT_READY = 30
- RESULT_RIL_NETWORK_REJECT = 31
- RESULT_RIL_NETWORK_TIMEOUT = 32
- RESULT_RIL_NETWORK_CONGESTION = 33
- RESULT_RIL_NO_ACKNOWLEDGMENT = 34
- RESULT_RIL_SMSC_ADDRESS_NOT_SET = 35
- RESULT_RIL_FDN_CHECK_FAILURE = 36
- RESULT_RIL_RESET_CANCELLED = 37
- RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE = 38
- RESULT_RIL_SIM_SMS_PROVIDER_ERROR = 39
- RESULT_RIL_SMS_FORMAT_ERROR = 40
- RESULT_RIL_CODING_ERROR = 41
- RESULT_RIL_SMS_CAUSE_CODE_ERROR = 42
- RESULT_RIL_SMS_TRANSPORT_ERROR = 43
-
- STATUS_ON_ICC_FREE = 0
- STATUS_ON_ICC_READ = 1
- STATUS_ON_ICC_UNREAD = 3
- STATUS_ON_ICC_SENT = 5
- STATUS_ON_ICC_UNSENT = 7
-
- SMS_TYPE_INCOMING = 0
- SMS_TYPE_OUTGOING = 1
- SMS_TYPE_STATUS_REPORT = 2
- SMS_TYPE_CELL_BROADCAST = 3
- SMS_TYPE_WAP_PUSH = 4
-
- # SMS 编码方式
- ENCODING_7BIT = 0
- ENCODING_8BIT = 1
- ENCODING_16BIT = 2
- ENCODING_UNKNOWN = -1
-
- # 消息有效期
- VALIDITY_PERIOD_DEFAULT = -1
- VALIDITY_PERIOD_NO_EXPIRY = 0
- VALIDITY_PERIOD_1_HOUR = 1
- VALIDITY_PERIOD_6_HOURS = 2
- VALIDITY_PERIOD_24_HOURS = 3
- VALIDITY_PERIOD_MAX = 4
-
- _instance: Optional[SmsManager] = None
-
- def __init__(self):
- super().__init__()
- self._smsc_address: str = ""
- self._default_sms_app: bool = True
- self._is_sim_ready: bool = True
-
- @staticmethod
- def getDefault() -> SmsManager:
- """获取默认 SmsManager 实例"""
- if SmsManager._instance is None:
- SmsManager._instance = SmsManager()
- return SmsManager._instance
-
- def sendTextMessage(self, dest_address: str, sc_address: Optional[str],
- text: str, sent_intent: Any, delivery_intent: Any):
- """发送文本短信"""
- pass
-
- def sendMultipartTextMessage(self, dest_address: str, sc_address: Optional[str],
- parts: List[str], sent_intents: Optional[List[Any]],
- delivery_intents: Optional[List[Any]]):
- """发送多段文本短信"""
- pass
-
- def sendDataMessage(self, dest_address: str, sc_address: Optional[str],
- dest_port: int, data: bytes, sent_intent: Any,
- delivery_intent: Any):
- """发送数据短信"""
- pass
-
- def sendMultimediaMessage(self, context: Any, content_uri: str,
- location_url: Optional[str],
- config_overrides: Optional[Any],
- sent_intent: Any):
- """发送彩信"""
- pass
-
- def downloadMultimediaMessage(self, context: Any, content_uri: str,
- config_overrides: Optional[Any],
- downloaded_intent: Any):
- """下载彩信"""
- pass
-
- def copyMessageToIcc(self, status: int, pdu: bytes, smsc: bytes) -> bool:
- """复制短信到 ICC"""
- return True
-
- def deleteMessageFromIcc(self, message_index: int) -> bool:
- """从 ICC 删除短信"""
- return True
-
- def updateMessageOnIcc(self, message_index: int, status: int, pdu: bytes) -> bool:
- """更新 ICC 上的短信"""
- return True
-
- def copyMessageToSim(self, status: int, pdu: bytes, smsc: bytes) -> bool:
- """复制短信到 SIM 卡"""
- return True
-
- def deleteMessageFromSim(self, message_index: int) -> bool:
- """从 SIM 卡删除短信"""
- return True
-
- def updateMessageOnSim(self, message_index: int, status: int, pdu: bytes) -> bool:
- """更新 SIM 卡上的短信"""
- return True
-
- def getAllMessagesFromIcc(self) -> List[Any]:
- """从 ICC 获取所有短信"""
- return []
-
- def getAllMessagesFromSim(self) -> List[Any]:
- """从 SIM 卡获取所有短信"""
- return []
-
- def getSmscAddress(self) -> str:
- """获取 SMSC 地址"""
- return self._smsc_address
-
- def setSmscAddress(self, address: str):
- """设置 SMSC 地址"""
- self._smsc_address = address
-
- def getDefaultSmsSubscriptionId(self) -> int:
- """获取默认短信订阅 ID"""
- return 0
-
- def isDefaultSmsApp(self) -> bool:
- """检查是否为默认短信应用"""
- return self._default_sms_app
-
- def createAppSpecificSmsToken(self, prefixes: List[str]) -> str:
- """创建应用特定短信令牌"""
- return f"sms_token_{int(time.time())}"
-
- @staticmethod
- def getDefaultSmsSubscriptionId() -> int:
- return 0
-
- @staticmethod
- def getSmsManagerForSubscriptionId(sub_id: int) -> SmsManager:
- """获取指定订阅的 SmsManager"""
- return SmsManager()
-
- def sendTextMessageWithSelfPermissions(self, dest_address: str, sc_address: Optional[str],
- text: str, sent_intent: Any,
- delivery_intent: Any):
- """使用自身权限发送文本短信"""
- self.sendTextMessage(dest_address, sc_address, text, sent_intent, delivery_intent)
-
- def injectSmsPdu(self, pdu: bytes, format: str, result: Any):
- """注入短信 PDU"""
- pass
-
- def toString(self) -> str:
- return "SmsManager(default)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GSM 短信状态与事件
-# ═══════════════════════════════════════════════════════════════
-
-class SmsMessage(Stub):
- """SmsMessage — GSM 短信"""
-
- ENCODING_7BIT = 0
- ENCODING_8BIT = 1
- ENCODING_16BIT = 2
- ENCODING_UNKNOWN = -1
-
- MAX_USER_DATA_BYTES = 140
- MAX_USER_DATA_SEPTETS = 160
- MAX_USER_DATA_SEPTETS_WITH_HEADER = 153
-
- # 消息类型
- MESSAGE_TYPE_INBOX = 0
- MESSAGE_TYPE_SENT = 1
- MESSAGE_TYPE_DRAFT = 2
- MESSAGE_TYPE_OUTBOX = 3
- MESSAGE_TYPE_FAILED = 4
- MESSAGE_TYPE_QUEUED = 5
-
- def __init__(self):
- super().__init__()
- self._message_body: str = ""
- self._originating_address: str = ""
- self._service_center: str = ""
- self._timestamp: int = 0
- self._timestamp_sent: int = 0
- self._protocol_identifier: int = 0
- self._status: int = -1
- self._message_type: int = SmsMessage.MESSAGE_TYPE_INBOX
- self._index_on_icc: int = -1
- self._pdu: bytes = b""
- self._is_status_report: bool = False
- self._is_replace: bool = False
- self._is_cphs: bool = False
- self._email_body: str = ""
- self._email_from: str = ""
- self._pseudo_subject: str = ""
- self._user_data: bytes = b""
- self._user_data_header: bytes = b""
-
- def getMessageBody(self) -> str:
- return self._message_body
-
- def setMessageBody(self, body: str):
- self._message_body = body
-
- def getOriginatingAddress(self) -> str:
- return self._originating_address
-
- def setOriginatingAddress(self, address: str):
- self._originating_address = address
-
- def getServiceCenterAddress(self) -> str:
- return self._service_center
-
- def setServiceCenterAddress(self, sc: str):
- self._service_center = sc
-
- def getTimestampMillis(self) -> int:
- return self._timestamp
-
- def setTimestampMillis(self, ts: int):
- self._timestamp = ts
-
- def getStatus(self) -> int:
- return self._status
-
- def setStatus(self, status: int):
- self._status = status
-
- def getProtocolIdentifier(self) -> int:
- return self._protocol_identifier
-
- def setProtocolIdentifier(self, pid: int):
- self._protocol_identifier = pid
-
- def getIndexOnIcc(self) -> int:
- return self._index_on_icc
-
- def setIndexOnIcc(self, index: int):
- self._index_on_icc = index
-
- def isStatusReportMessage(self) -> bool:
- return self._is_status_report
-
- def setStatusReportMessage(self, report: bool):
- self._is_status_report = report
-
- def isReplaceMessage(self) -> bool:
- return self._is_replace
-
- def isCphsMessage(self) -> bool:
- return self._is_cphs
-
- def getEmailBody(self) -> str:
- return self._email_body
-
- def getEmailFrom(self) -> str:
- return self._email_from
-
- def getPseudoSubject(self) -> str:
- return self._pseudo_subject
-
- def getUserData(self) -> bytes:
- return self._user_data
-
- def getUserDataHeader(self) -> bytes:
- return self._user_data_header
-
- def getPdu(self) -> bytes:
- return self._pdu
-
- def setPdu(self, pdu: bytes):
- self._pdu = pdu
-
- @staticmethod
- def getSubmitPdu(sc_address: str, dest_address: str, message: str,
- status_report_requested: bool) -> Tuple[bytes, bytes]:
- """获取提交 PDU"""
- return (b"", b"")
-
- @staticmethod
- def getSubmitPduForData(dest_address: str, sc_address: str,
- dest_port: int, data: bytes,
- status_report_requested: bool) -> Tuple[bytes, bytes]:
- """获取数据提交 PDU"""
- return (b"", b"")
-
- @staticmethod
- def createFromPdu(pdu: bytes, format: str = "3gpp") -> Optional[SmsMessage]:
- """从 PDU 创建短信"""
- return SmsMessage()
-
- @staticmethod
- def calculateLength(message: str, use7bitOnly: bool = False) -> Any:
- """计算消息长度"""
- class LengthResult(Stub):
- def __init__(self):
- super().__init__()
- self.msg_count = 1
- self.remaining_septets = 0
- self.code_unit_size = 1
- return LengthResult()
-
- def toString(self) -> str:
- return f"SmsMessage(from={self._originating_address}, body={self._message_body[:20]})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GSM CellBroadcast
-# ═══════════════════════════════════════════════════════════════
-
-class CellBroadcastMessage(Stub):
- """CellBroadcastMessage — GSM 小区广播消息"""
-
- GEOGRAPHICAL_SCOPE_PLMN = 0
- GEOGRAPHICAL_SCOPE_CELL = 1
- GEOGRAPHICAL_SCOPE_LA = 2
- GEOGRAPHICAL_SCOPE_CELL_WIDE = 3
-
- def __init__(self):
- super().__init__()
- self._message_body: str = ""
- self._channel_id: int = 0
- self._serial_number: int = 0
- self._message_code: int = 0
- self._language_code: str = ""
- self._geographical_scope: int = 0
- self._update_number: int = 0
- self._is_emergency: bool = False
- self._is_etws: bool = False
- self._is_cmas: bool = False
- self._service_category: int = 0
- self._plmn: str = ""
- self._lac: int = -1
- self._cid: int = -1
-
- def getMessageBody(self) -> str:
- return self._message_body
-
- def setMessageBody(self, body: str):
- self._message_body = body
-
- def getChannelId(self) -> int:
- return self._channel_id
-
- def setChannelId(self, channel_id: int):
- self._channel_id = channel_id
-
- def getSerialNumber(self) -> int:
- return self._serial_number
-
- def setSerialNumber(self, sn: int):
- self._serial_number = sn
-
- def getMessageCode(self) -> int:
- return self._message_code
-
- def setMessageCode(self, code: int):
- self._message_code = code
-
- def getLanguageCode(self) -> str:
- return self._language_code
-
- def setLanguageCode(self, lang: str):
- self._language_code = lang
-
- def getGeographicalScope(self) -> int:
- return self._geographical_scope
-
- def setGeographicalScope(self, scope: int):
- self._geographical_scope = scope
-
- def isEmergencyMessage(self) -> bool:
- return self._is_emergency
-
- def setEmergencyMessage(self, emergency: bool):
- self._is_emergency = emergency
-
- def isEtwsMessage(self) -> bool:
- return self._is_etws
-
- def setEtwsMessage(self, etws: bool):
- self._is_etws = etws
-
- def isCmasMessage(self) -> bool:
- return self._is_cmas
-
- def setCmasMessage(self, cmas: bool):
- self._is_cmas = cmas
-
- def toString(self) -> str:
- return f"CellBroadcastMessage(channel={self._channel_id}, body={self._message_body[:20]})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GSM ServiceState (GSM-specific)
-# ═══════════════════════════════════════════════════════════════
-
-class GsmServiceState(Stub):
- """GsmServiceState — GSM 服务状态"""
-
- STATE_IN_SERVICE = 0
- STATE_OUT_OF_SERVICE = 1
- STATE_EMERGENCY_ONLY = 2
- STATE_POWER_OFF = 3
- STATE_RADIO_OFF = 3
-
- ROAMING_TYPE_NOT_ROAMING = 0
- ROAMING_TYPE_DOMESTIC = 1
- ROAMING_TYPE_INTERNATIONAL = 2
-
- def __init__(self):
- super().__init__()
- self._state: int = GsmServiceState.STATE_OUT_OF_SERVICE
- self._operator_alpha_long: str = ""
- self._operator_alpha_short: str = ""
- self._operator_numeric: str = ""
- self._is_manual_network_selection: bool = False
- self._roaming: bool = False
- self._roaming_type: int = GsmServiceState.ROAMING_TYPE_NOT_ROAMING
- self._emergency_only: bool = False
- self._voice_registered: bool = False
- self._data_registered: bool = False
- self._voice_network_type: int = 0
- self._data_network_type: int = 0
- self._css_indicator: bool = False
- self._network_id: str = ""
- self._plmn: str = ""
- self._lac: int = -1
- self._cid: int = -1
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getOperatorAlphaLong(self) -> str:
- return self._operator_alpha_long
-
- def setOperatorAlphaLong(self, op: str):
- self._operator_alpha_long = op
-
- def getOperatorAlphaShort(self) -> str:
- return self._operator_alpha_short
-
- def setOperatorAlphaShort(self, op: str):
- self._operator_alpha_short = op
-
- def getOperatorNumeric(self) -> str:
- return self._operator_numeric
-
- def setOperatorNumeric(self, op: str):
- self._operator_numeric = op
-
- def getIsManualNetworkSelection(self) -> bool:
- return self._is_manual_network_selection
-
- def setIsManualNetworkSelection(self, manual: bool):
- self._is_manual_network_selection = manual
-
- def getRoaming(self) -> bool:
- return self._roaming
-
- def setRoaming(self, roaming: bool):
- self._roaming = roaming
-
- def getRoamingType(self) -> int:
- return self._roaming_type
-
- def setRoamingType(self, roaming_type: int):
- self._roaming_type = roaming_type
-
- def isEmergencyOnly(self) -> bool:
- return self._emergency_only
-
- def setEmergencyOnly(self, emergency: bool):
- self._emergency_only = emergency
-
- def isVoiceRegistered(self) -> bool:
- return self._voice_registered
-
- def setVoiceRegistered(self, registered: bool):
- self._voice_registered = registered
-
- def isDataRegistered(self) -> bool:
- return self._data_registered
-
- def setDataRegistered(self, registered: bool):
- self._data_registered = registered
-
- def getVoiceNetworkType(self) -> int:
- return self._voice_network_type
-
- def setVoiceNetworkType(self, type_: int):
- self._voice_network_type = type_
-
- def getDataNetworkType(self) -> int:
- return self._data_network_type
-
- def setDataNetworkType(self, type_: int):
- self._data_network_type = type_
-
- def toString(self) -> str:
- return f"GsmServiceState(state={self._state}, op={self._operator_alpha_long})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GSM GPRS (数据相关)
-# ═══════════════════════════════════════════════════════════════
-
-class GprsCellLocation(Stub):
- """GprsCellLocation — GPRS 小区位置"""
-
- def __init__(self, lac: int = -1, cid: int = -1):
- super().__init__()
- self._lac = lac
- self._cid = cid
-
- def getLac(self) -> int:
- return self._lac
-
- def setLac(self, lac: int):
- self._lac = lac
-
- def getCid(self) -> int:
- return self._cid
-
- def setCid(self, cid: int):
- self._cid = cid
-
- def toString(self) -> str:
- return f"GprsCellLocation(lac={self._lac}, cid={self._cid})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GSM SMS Utils
-# ═══════════════════════════════════════════════════════════════
-
-class SmsUtils(Stub):
- """SmsUtils — GSM 短信工具类"""
-
- @staticmethod
- def getSmsFormat() -> str:
- """获取短信格式"""
- return "3gpp"
-
- @staticmethod
- def is7bitOnly(message: str) -> bool:
- """检查是否仅为 7 位字符"""
- for c in message:
- if ord(c) > 127:
- return False
- return True
-
- @staticmethod
- def countSeptets(message: str, use7bitOnly: bool = False) -> int:
- """计算 7 位编码消息的字节数"""
- if use7bitOnly or SmsUtils.is7bitOnly(message):
- return len(message)
- return len(message.encode("utf-16-be")) // 2
-
- @staticmethod
- def countGsmBytes(message: str) -> int:
- """计算 GSM 字节数"""
- if SmsUtils.is7bitOnly(message):
- return len(message)
- return len(message.encode("utf-16-be"))
-
- @staticmethod
- def splitMessage(text: str) -> List[str]:
- """分割长消息"""
- if len(text) <= 160:
- return [text]
- parts = []
- for i in range(0, len(text), 153):
- parts.append(text[i:i + 153])
- return parts
-
- @staticmethod
- def getMaxMessageLength() -> int:
- """获取最大消息长度"""
- return 160
-
- @staticmethod
- def getMaxUserDataBytes() -> int:
- return 140
-
- @staticmethod
- def encodePhoneNumber(number: str) -> str:
- """编码电话号码"""
- if number.startswith("+"):
- number = number[1:]
- return number
-
- @staticmethod
- def decodePhoneNumber(encoded: str) -> str:
- """解码电话号码"""
- return encoded
-
- @staticmethod
- def isValidSmsAddress(address: str) -> bool:
- """验证短信地址是否有效"""
- return len(address) > 0 and len(address) <= 20
-
- @staticmethod
- def getSmsPduType(pdu: bytes) -> int:
- """获取短信 PDU 类型"""
- if len(pdu) > 0:
- return pdu[0] & 0x03
- return -1
-
-
-# ═══════════════════════════════════════════════════════════════
-# GSM 网络相关常量
-# ═══════════════════════════════════════════════════════════════
-
-class GsmNetworkType(Stub):
- """GsmNetworkType — GSM 网络类型常量"""
-
- NETWORK_TYPE_UNKNOWN = 0
- NETWORK_TYPE_GPRS = 1
- NETWORK_TYPE_EDGE = 2
- NETWORK_TYPE_UMTS = 3
- NETWORK_TYPE_HSDPA = 8
- NETWORK_TYPE_HSUPA = 9
- NETWORK_TYPE_HSPA = 10
- NETWORK_TYPE_HSPAP = 15
- NETWORK_TYPE_LTE = 13
- NETWORK_TYPE_NR = 20
-
- @staticmethod
- def isGsm(network_type: int) -> bool:
- return network_type in (GsmNetworkType.NETWORK_TYPE_GPRS,
- GsmNetworkType.NETWORK_TYPE_EDGE)
-
- @staticmethod
- def isUmts(network_type: int) -> bool:
- return network_type in (GsmNetworkType.NETWORK_TYPE_UMTS,
- GsmNetworkType.NETWORK_TYPE_HSDPA,
- GsmNetworkType.NETWORK_TYPE_HSUPA,
- GsmNetworkType.NETWORK_TYPE_HSPA,
- GsmNetworkType.NETWORK_TYPE_HSPAP)
-
- @staticmethod
- def toString(network_type: int) -> str:
- names = {
- GsmNetworkType.NETWORK_TYPE_UNKNOWN: "UNKNOWN",
- GsmNetworkType.NETWORK_TYPE_GPRS: "GPRS",
- GsmNetworkType.NETWORK_TYPE_EDGE: "EDGE",
- GsmNetworkType.NETWORK_TYPE_UMTS: "UMTS",
- GsmNetworkType.NETWORK_TYPE_HSDPA: "HSDPA",
- GsmNetworkType.NETWORK_TYPE_HSUPA: "HSUPA",
- GsmNetworkType.NETWORK_TYPE_HSPA: "HSPA",
- GsmNetworkType.NETWORK_TYPE_HSPAP: "HSPA+",
- GsmNetworkType.NETWORK_TYPE_LTE: "LTE",
- GsmNetworkType.NETWORK_TYPE_NR: "NR",
- }
- return names.get(network_type, f"UNKNOWN({network_type})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# GSM SIM 操作
-# ═══════════════════════════════════════════════════════════════
-
-class SimUtils(Stub):
- """SimUtils — SIM 工具类"""
-
- @staticmethod
- def getSimSerialNumber() -> str:
- """获取 SIM 序列号"""
- return "89014103211118510720"
-
- @staticmethod
- def getSimOperator() -> str:
- """获取 SIM 运营商"""
- return "310410"
-
- @staticmethod
- def getSimOperatorName() -> str:
- """获取 SIM 运营商名称"""
- return "AT&T"
-
- @staticmethod
- def getSubscriberId() -> str:
- """获取订阅者 ID (IMSI)"""
- return "310410123456789"
-
- @staticmethod
- def getDeviceId() -> str:
- """获取设备 ID (IMEI)"""
- return "356938035643809"
-
- @staticmethod
- def getDeviceSoftwareVersion() -> str:
- """获取设备软件版本"""
- return "01"
-
- @staticmethod
- def getVoiceMailNumber() -> str:
- """获取语音信箱号码"""
- return "+1-555-123-4567"
-
- @staticmethod
- def getVoiceMailAlphaTag() -> str:
- """获取语音信箱标签"""
- return "Voicemail"
-
- @staticmethod
- def hasIccCard() -> bool:
- """检查是否有 ICC 卡"""
- return True
-
- @staticmethod
- def getSimState() -> int:
- """获取 SIM 状态"""
- return 5 # SIM_STATE_READY
-
- @staticmethod
- def isNetworkRoaming() -> bool:
- """检查是否网络漫游"""
- return False
-
- @staticmethod
- def getNetworkOperator() -> str:
- """获取网络运营商"""
- return "310410"
-
- @staticmethod
- def getNetworkOperatorName() -> str:
- """获取网络运营商名称"""
- return "AT&T"
-
- @staticmethod
- def getNetworkCountryIso() -> str:
- """获取网络国家 ISO 代码"""
- return "us"
-
- @staticmethod
- def getSimCountryIso() -> str:
- """获取 SIM 国家 ISO 代码"""
- return "us"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GSM 通话相关
-# ═══════════════════════════════════════════════════════════════
-
-class GsmCallState(Stub):
- """GsmCallState — GSM 通话状态常量"""
-
- CALL_STATE_IDLE = 0
- CALL_STATE_RINGING = 1
- CALL_STATE_OFFHOOK = 2
-
- CALL_STATE_ACTIVE = 3
- CALL_STATE_HOLDING = 4
- CALL_STATE_DIALING = 5
- CALL_STATE_ALERTING = 6
- CALL_STATE_INCOMING = 7
- CALL_STATE_WAITING = 8
- CALL_STATE_DISCONNECTED = 9
- CALL_STATE_DISCONNECTING = 10
-
- @staticmethod
- def toString(state: int) -> str:
- names = {
- GsmCallState.CALL_STATE_IDLE: "IDLE",
- GsmCallState.CALL_STATE_RINGING: "RINGING",
- GsmCallState.CALL_STATE_OFFHOOK: "OFFHOOK",
- }
- return names.get(state, f"UNKNOWN({state})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# GSM Supplementary Service
-# ═══════════════════════════════════════════════════════════════
-
-class SupplementaryService(Stub):
- """SupplementaryService — GSM 补充服务"""
-
- SERVICE_CLASS_NONE = 0
- SERVICE_CLASS_VOICE = 1
- SERVICE_CLASS_DATA = 2
- SERVICE_CLASS_FAX = 4
- SERVICE_CLASS_SMS = 8
- SERVICE_CLASS_DATA_SYNC = 16
- SERVICE_CLASS_DATA_ASYNC = 32
- SERVICE_CLASS_PACKET = 64
- SERVICE_CLASS_PAD = 128
- SERVICE_CLASS_MAX = 255
-
- CF_REASON_UNCONDITIONAL = 0
- CF_REASON_BUSY = 1
- CF_REASON_NO_REPLY = 2
- CF_REASON_NOT_REACHABLE = 3
- CF_REASON_ALL = 4
- CF_REASON_ALL_CONDITIONAL = 5
-
- CB_SERVICE_ALL = 0
- CB_SERVICE_OUTGOING = 1
- CB_SERVICE_INCOMING = 2
-
- def __init__(self):
- super().__init__()
- self._service_class: int = SupplementaryService.SERVICE_CLASS_NONE
- self._cf_reason: int = SupplementaryService.CF_REASON_UNCONDITIONAL
- self._cb_service: int = SupplementaryService.CB_SERVICE_ALL
-
- def getServiceClass(self) -> int:
- return self._service_class
-
- def setServiceClass(self, service_class: int):
- self._service_class = service_class
-
- def getCallForwardReason(self) -> int:
- return self._cf_reason
-
- def setCallForwardReason(self, reason: int):
- self._cf_reason = reason
-
- def getCallBarringService(self) -> int:
- return self._cb_service
-
- def setCallBarringService(self, service: int):
- self._cb_service = service
-
- def toString(self) -> str:
- return f"SupplementaryService(class={self._service_class})"
\ No newline at end of file
diff --git a/android_pyapi/android/telephony_ims.py b/android_pyapi/android/telephony_ims.py
deleted file mode 100644
index 6dc636f..0000000
--- a/android_pyapi/android/telephony_ims.py
+++ /dev/null
@@ -1,1545 +0,0 @@
-"""
-Android Telephony IMS 组件 — ImsManager, ImsService, ImsCall, ImsCallSession, MmTelFeature 等
-方法签名完全对齐 Android SDK (android.telephony.ims 包)
-"""
-
-from __future__ import annotations
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# IMS 常量
-# ═══════════════════════════════════════════════════════════════
-
-IMS_SERVICE_CLASS_NONE = 0
-IMS_SERVICE_CLASS_VOICE = 1
-IMS_SERVICE_CLASS_VIDEO = 2
-IMS_SERVICE_CLASS_SMS = 4
-IMS_SERVICE_CLASS_UT = 8
-
-IMS_REGISTRATION_STATE_NOT_REGISTERED = 0
-IMS_REGISTRATION_STATE_REGISTERING = 1
-IMS_REGISTRATION_STATE_REGISTERED = 2
-
-IMS_REGISTRATION_TECH_NONE = 0
-IMS_REGISTRATION_TECH_LTE = 1
-IMS_REGISTRATION_TECH_IWLAN = 2
-IMS_REGISTRATION_TECH_NR = 3
-
-IMS_CALL_STATE_IDLE = 0
-IMS_CALL_STATE_ACTIVE = 1
-IMS_CALL_STATE_HOLDING = 2
-IMS_CALL_STATE_DIALING = 3
-IMS_CALL_STATE_ALERTING = 4
-IMS_CALL_STATE_INCOMING = 5
-IMS_CALL_STATE_WAITING = 6
-IMS_CALL_STATE_DISCONNECTED = 7
-IMS_CALL_STATE_DISCONNECTING = 8
-
-IMS_CALL_STATE_UNKNOWN = -1
-IMS_CALL_STATE_CONFERENCE = 9
-IMS_CALL_STATE_REFER = 10
-IMS_CALL_STATE_UPDATE = 11
-
-IMS_FAILURE_REASON_UNKNOWN = 0
-IMS_FAILURE_REASON_NETWORK = 1
-IMS_FAILURE_REASON_SERVER = 2
-IMS_FAILURE_REASON_TIMEOUT = 3
-IMS_FAILURE_REASON_INTERNAL = 4
-IMS_FAILURE_REASON_BUSY = 5
-IMS_FAILURE_REASON_NOT_FOUND = 6
-IMS_FAILURE_REASON_FORBIDDEN = 7
-IMS_FAILURE_REASON_SERVICE_UNAVAILABLE = 8
-IMS_FAILURE_REASON_REQUEST_TIMEOUT = 9
-IMS_FAILURE_REASON_TEMPORARILY_UNAVAILABLE = 10
-IMS_FAILURE_REASON_MEDIA_NO_ANSWER = 11
-IMS_FAILURE_REASON_MEDIA_REJECTED = 12
-IMS_FAILURE_REASON_MEDIA_CANCELLED = 13
-IMS_FAILURE_REASON_MEDIA_INSUFFICIENT_BANDWIDTH = 14
-IMS_FAILURE_REASON_CODE_TEMPORARY_FAILURE = 15
-IMS_FAILURE_REASON_CODE_CONGESTION = 16
-IMS_FAILURE_REASON_CODE_REQUESTED_TERMINATED = 17
-IMS_FAILURE_REASON_CODE_BEARER_NOT_AVAILABLE = 18
-IMS_FAILURE_REASON_CODE_INSUFFICIENT_RESOURCES = 19
-IMS_FAILURE_REASON_CODE_REJECTED = 20
-IMS_FAILURE_REASON_CODE_UNSPECIFIED = 21
-
-IMS_MEDIA_TYPE_AUDIO = 1
-IMS_MEDIA_TYPE_VIDEO = 2
-IMS_MEDIA_TYPE_TEXT = 3
-
-IMS_SERVICE_TYPE_VOLTE = 0
-IMS_SERVICE_TYPE_VIDEO = 1
-IMS_SERVICE_TYPE_WFC = 2
-IMS_SERVICE_TYPE_SMS = 3
-IMS_SERVICE_TYPE_UT = 4
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsReasonInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ImsReasonInfo(Stub):
- """ImsReasonInfo — IMS 原因信息"""
-
- CODE_USER_TERMINATED = 0
- CODE_USER_TERMINATED_BY_REMOTE = 1
- CODE_USER_TRIGGERED_END_OF_CALL = 2
- CODE_USER_ANSWERED_ELSEWHERE = 3
- CODE_USER_IGNORE = 4
- CODE_USER_DECLINE = 5
- CODE_USER_NOANSWER = 6
- CODE_NETWORK_ERROR = 100
- CODE_SIP_REDIRECTED = 200
- CODE_SIP_BAD_REQUEST = 400
- CODE_SIP_FORBIDDEN = 403
- CODE_SIP_NOT_FOUND = 404
- CODE_SIP_REQUEST_TIMEOUT = 408
- CODE_SIP_TEMPORARILY_UNAVAILABLE = 480
- CODE_SIP_BUSY = 486
- CODE_SIP_REQUEST_TERMINATED = 487
- CODE_SIP_SERVER_INTERNAL_ERROR = 500
- CODE_SIP_SERVICE_UNAVAILABLE = 503
- CODE_SIP_SERVER_TIMEOUT = 504
- CODE_SIP_VERSION_NOT_SUPPORTED = 505
- CODE_SIP_BUSY_EVERYWHERE = 600
- CODE_SIP_DECLINE = 603
- CODE_SIP_DOES_NOT_EXIST_ANYWHERE = 604
- CODE_SIP_NOT_ACCEPTABLE = 606
- CODE_MEDIA_INIT_FAILED = 700
- CODE_MEDIA_NO_DATA = 701
- CODE_MEDIA_NOT_ACCEPTABLE = 702
- CODE_MEDIA_UNSUPPORTED = 703
- CODE_MEDIA_SESSION_TERMINATED = 704
- CODE_MEDIA_NO_SESSION = 705
- CODE_MEDIA_RTP_TIMEOUT = 706
- CODE_MEDIA_RTCP_TIMEOUT = 707
- CODE_MEDIA_RESOURCE_LIMIT = 708
- CODE_MEDIA_INSUFFICIENT_BANDWIDTH = 709
- CODE_MEDIA_LATE_MEDIA = 710
- CODE_MEDIA_UNKNOWN = 711
- CODE_SIP_ALTERNATE_EMERGENCY_CALL = 712
- CODE_LOCAL_ILLEGAL_ARGUMENT = 800
- CODE_LOCAL_ILLEGAL_STATE = 801
- CODE_LOCAL_INTERNAL_ERROR = 802
- CODE_LOCAL_IMS_SERVICE_DOWN = 803
- CODE_LOCAL_NO_PENDING_CALL = 804
- CODE_LOCAL_SERVICE_NOT_RUNNING = 805
- CODE_LOCAL_SERVICE_NOT_READY = 806
- CODE_LOCAL_SERVICE_TERMINATED = 807
- CODE_LOCAL_CALL_CS_RETRY_REQUIRED = 808
-
- EXTRA_CODE_CALL_RETRY_NEEDED = 1000
- EXTRA_CODE_CALL_RETRY_SIP = 1001
- EXTRA_CODE_CALL_RETRY_NORMAL = 1002
- EXTRA_CODE_CALL_RETRY_EMERGENCY = 1003
-
- def __init__(self, code: int = CODE_USER_TERMINATED,
- extra_code: int = 0, message: str = ""):
- super().__init__()
- self._code = code
- self._extra_code = extra_code
- self._message = message
-
- def getCode(self) -> int:
- return self._code
-
- def getExtraCode(self) -> int:
- return self._extra_code
-
- def getExtraMessage(self) -> str:
- return self._message
-
- def toString(self) -> str:
- return f"ImsReasonInfo(code={self._code}, extra={self._extra_code}, msg={self._message})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsCallProfile
-# ═══════════════════════════════════════════════════════════════
-
-class ImsCallProfile(Stub):
- """ImsCallProfile — IMS 呼叫配置文件"""
-
- SERVICE_TYPE_NORMAL = 0
- SERVICE_TYPE_EMERGENCY = 1
-
- CALL_TYPE_VOICE = 1
- CALL_TYPE_VT = 2
- CALL_TYPE_VT_TX = 3
- CALL_TYPE_VT_RX = 4
- CALL_TYPE_VT_NODIR = 5
- CALL_TYPE_SMS = 6
-
- DIALSTRING_NORMAL = 0
- DIALSTRING_SS_CONF = 1
- DIALSTRING_USSD = 2
-
- EXTRA_CALL_MODE_CHANGEABLE = "call_mode_changeable"
- EXTRA_CONFERENCE_ALLOWED = "conference_allowed"
- EXTRA_ADDITIONAL_CALL_INFO = "additional_call_info"
- EXTRA_CHILD_NETWORK_TYPE = "child_network_type"
- EXTRA_CNAPN = "cnapn"
- EXTRA_DIALSTRING = "dialstring"
- EXTRA_OI = "oi"
- EXTRA_OIR = "oir"
- EXTRA_CNAP = "cnap"
- EXTRA_USSD = "ussd"
- EXTRA_CALL_RAT = "call_rat"
- EXTRA_CALL_RAT_TYPE = "call_rat_type"
- EXTRA_RTT_STATE = "rtt_state"
- EXTRA_PRIORITY = "priority"
- EXTRA_PEER_CONNECTION_TYPE = "peer_connection_type"
- EXTRA_IS_PULL = "is_pull"
- EXTRA_ADD_IMS_HANDOVER = "add_ims_handover"
-
- def __init__(self, service_type: int = SERVICE_TYPE_NORMAL,
- call_type: int = CALL_TYPE_VOICE):
- super().__init__()
- self._service_type = service_type
- self._call_type = call_type
- self._media_profiles: List[ImsStreamMediaProfile] = []
- self._extras: Dict[str, Any] = {}
-
- def getServiceType(self) -> int:
- return self._service_type
-
- def setServiceType(self, service_type: int):
- self._service_type = service_type
-
- def getCallType(self) -> int:
- return self._call_type
-
- def setCallType(self, call_type: int):
- self._call_type = call_type
-
- def getMediaProfile(self) -> Optional[ImsStreamMediaProfile]:
- if self._media_profiles:
- return self._media_profiles[0]
- return None
-
- def setMediaProfile(self, profile: ImsStreamMediaProfile):
- if self._media_profiles:
- self._media_profiles[0] = profile
- else:
- self._media_profiles.append(profile)
-
- def getMediaProfiles(self) -> List[ImsStreamMediaProfile]:
- return list(self._media_profiles)
-
- def setMediaProfiles(self, profiles: List[ImsStreamMediaProfile]):
- self._media_profiles = list(profiles)
-
- def getExtra(self, key: str) -> Optional[Any]:
- return self._extras.get(key)
-
- def setExtra(self, key: str, value: Any):
- self._extras[key] = value
-
- def toString(self) -> str:
- return f"ImsCallProfile(type={self._call_type}, service={self._service_type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsStreamMediaProfile
-# ═══════════════════════════════════════════════════════════════
-
-class ImsStreamMediaProfile(Stub):
- """ImsStreamMediaProfile — IMS 流媒体配置文件"""
-
- DIRECTION_INVALID = -1
- DIRECTION_INACTIVE = 0
- DIRECTION_RECEIVE = 1
- DIRECTION_SEND = 2
- DIRECTION_SEND_RECEIVE = 3
-
- RTT_MODE_DISABLED = 0
- RTT_MODE_ENABLED = 1
- RTT_MODE_FULL = 2
-
- AUDIO_QUALITY_NONE = 0
- AUDIO_QUALITY_AMR = 1
- AUDIO_QUALITY_AMR_WB = 2
- AUDIO_QUALITY_QCELP13K = 3
- AUDIO_QUALITY_EVRC = 4
- AUDIO_QUALITY_EVRC_B = 5
- AUDIO_QUALITY_EVRC_WB = 6
- AUDIO_QUALITY_EVRC_NW = 7
- AUDIO_QUALITY_GSM_EFR = 8
- AUDIO_QUALITY_GSM_FR = 9
- AUDIO_QUALITY_GSM_HR = 10
- AUDIO_QUALITY_G722 = 11
- AUDIO_QUALITY_G723 = 12
- AUDIO_QUALITY_G711 = 13
- AUDIO_QUALITY_G729 = 14
- AUDIO_QUALITY_EVS_NB = 15
- AUDIO_QUALITY_EVS_WB = 16
- AUDIO_QUALITY_EVS_SWB = 17
- AUDIO_QUALITY_EVS_FB = 18
-
- VIDEO_QUALITY_NONE = 0
- VIDEO_QUALITY_QCIF = 1
- VIDEO_QUALITY_QVGA = 2
- VIDEO_QUALITY_CIF = 3
- VIDEO_QUALITY_VGA = 4
- VIDEO_QUALITY_720P = 5
- VIDEO_QUALITY_1080P = 6
- VIDEO_QUALITY_4K = 7
-
- def __init__(self):
- super().__init__()
- self._audio_quality = ImsStreamMediaProfile.AUDIO_QUALITY_NONE
- self._video_quality = ImsStreamMediaProfile.VIDEO_QUALITY_NONE
- self._audio_direction = ImsStreamMediaProfile.DIRECTION_INVALID
- self._video_direction = ImsStreamMediaProfile.DIRECTION_INVALID
- self._rtt_mode = ImsStreamMediaProfile.RTT_MODE_DISABLED
- self._audio_codec: str = ""
- self._video_codec: str = ""
- self._audio_bitrate: int = 0
- self._video_bitrate: int = 0
- self._audio_sample_rate: int = 0
-
- def getAudioQuality(self) -> int:
- return self._audio_quality
-
- def setAudioQuality(self, quality: int):
- self._audio_quality = quality
-
- def getVideoQuality(self) -> int:
- return self._video_quality
-
- def setVideoQuality(self, quality: int):
- self._video_quality = quality
-
- def getAudioDirection(self) -> int:
- return self._audio_direction
-
- def setAudioDirection(self, direction: int):
- self._audio_direction = direction
-
- def getVideoDirection(self) -> int:
- return self._video_direction
-
- def setVideoDirection(self, direction: int):
- self._video_direction = direction
-
- def getRttMode(self) -> int:
- return self._rtt_mode
-
- def setRttMode(self, mode: int):
- self._rtt_mode = mode
-
- def getAudioCodec(self) -> str:
- return self._audio_codec
-
- def setAudioCodec(self, codec: str):
- self._audio_codec = codec
-
- def getVideoCodec(self) -> str:
- return self._video_codec
-
- def setVideoCodec(self, codec: str):
- self._video_codec = codec
-
- def isRttCall(self) -> bool:
- return self._rtt_mode != ImsStreamMediaProfile.RTT_MODE_DISABLED
-
- def toString(self) -> str:
- return f"ImsStreamMediaProfile(audio={self._audio_quality}, video={self._video_quality})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsCallSession
-# ═══════════════════════════════════════════════════════════════
-
-class ImsCallSession(Stub):
- """ImsCallSession — IMS 呼叫会话"""
-
- STATE_IDLE = 0
- STATE_NEGOTIATION = 1
- STATE_ESTABLISHING = 2
- STATE_ESTABLISHED = 3
- STATE_TERMINATING = 4
- STATE_TERMINATED = 5
- STATE_MODIFYING = 6
- STATE_HOLDING = 7
- STATE_RESUMING = 8
- STATE_TRANSFERRING = 9
- STATE_CONFERENCE = 10
- STATE_REFER = 11
- STATE_UPDATE = 12
-
- class Listener(Stub):
- """ImsCallSession.Listener — 呼叫会话监听器"""
-
- def onCallStateChanged(self, session: ImsCallSession, state: int):
- pass
-
- def onCallProfileChanged(self, session: ImsCallSession, profile: ImsCallProfile):
- pass
-
- def onCallQualityChanged(self, session: ImsCallSession, quality: int, video_quality: int):
- pass
-
- def onCallSessionHeld(self, session: ImsCallSession, held: bool):
- pass
-
- def onCallSessionHoldFailed(self, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallSessionHoldReceived(self, session: ImsCallSession, profile: ImsCallProfile):
- pass
-
- def onCallSessionResumeFailed(self, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallSessionResumeReceived(self, session: ImsCallSession, profile: ImsCallProfile):
- pass
-
- def onCallSessionMergeStarted(self, session: ImsCallSession,
- new_session: ImsCallSession, profile: ImsCallProfile):
- pass
-
- def onCallSessionMergeComplete(self, session: ImsCallSession):
- pass
-
- def onCallSessionMergeFailed(self, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallSessionUpdated(self, session: ImsCallSession, profile: ImsCallProfile):
- pass
-
- def onCallSessionUpdateFailed(self, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallSessionUpdateReceived(self, session: ImsCallSession, profile: ImsCallProfile):
- pass
-
- def onCallSessionTtyModeReceived(self, session: ImsCallSession, mode: int):
- pass
-
- def onCallSessionHandover(self, session: ImsCallSession,
- src_tech: int, target_tech: int, reason: ImsReasonInfo):
- pass
-
- def onCallSessionHandoverFailed(self, session: ImsCallSession,
- src_tech: int, target_tech: int,
- reason: ImsReasonInfo):
- pass
-
- def onCallSessionMayHandover(self, session: ImsCallSession, src_tech: int, target_tech: int):
- pass
-
- def onCallSessionDisconnected(self, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallSessionInitiated(self, session: ImsCallSession, profile: ImsCallProfile):
- pass
-
- def onCallSessionRttModifyRequestReceived(self, session: ImsCallSession, profile: ImsCallProfile):
- pass
-
- def onCallSessionRttModifyResponseReceived(self, session: ImsCallSession, status: int):
- pass
-
- def onCallSessionRttMessageReceived(self, session: ImsCallSession, message: str):
- pass
-
- def onCallSessionMultipartyStateChanged(self, session: ImsCallSession, is_multi_party: bool):
- pass
-
- def onCallSessionConferenceStateUpdated(self, session: ImsCallSession, state: Any):
- pass
-
- def onCallSessionTerminated(self, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def __init__(self, context: Any = None, profile: ImsCallProfile = None):
- super().__init__()
- self._context = context
- self._profile = profile or ImsCallProfile()
- self._state = ImsCallSession.STATE_IDLE
- self._listener: Optional[ImsCallSession.Listener] = None
- self._call_id: str = ""
- self._callee: str = ""
- self._is_multiparty: bool = False
- self._media_profile: Optional[ImsStreamMediaProfile] = None
-
- def setListener(self, listener: ImsCallSession.Listener):
- self._listener = listener
-
- def getListener(self) -> Optional[ImsCallSession.Listener]:
- return self._listener
-
- def getCallId(self) -> str:
- return self._call_id
-
- def setCallId(self, call_id: str):
- self._call_id = call_id
-
- def getCallee(self) -> str:
- return self._callee
-
- def setCallee(self, callee: str):
- self._callee = callee
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getCallProfile(self) -> ImsCallProfile:
- return self._profile
-
- def getLocalCallProfile(self) -> ImsCallProfile:
- return self._profile
-
- def getRemoteCallProfile(self) -> ImsCallProfile:
- return self._profile
-
- def getMediaProfile(self) -> Optional[ImsStreamMediaProfile]:
- return self._media_profile
-
- def isMultiparty(self) -> bool:
- return self._is_multiparty
-
- def start(self, callee: str, profile: ImsCallProfile):
- self._callee = callee
- if profile:
- self._profile = profile
- self._state = ImsCallSession.STATE_ESTABLISHING
- self._call_id = f"ims_call_{int(time.time() * 1000)}"
- if self._listener:
- self._listener.onCallStateChanged(self, self._state)
- self._listener.onCallSessionInitiated(self, self._profile)
-
- def accept(self, call_type: int, profile: ImsStreamMediaProfile):
- self._state = ImsCallSession.STATE_ESTABLISHED
- self._media_profile = profile
- if self._listener:
- self._listener.onCallStateChanged(self, self._state)
- self._listener.onCallProfileChanged(self, self._profile)
-
- def reject(self, reason: int):
- self._state = ImsCallSession.STATE_TERMINATING
- if self._listener:
- reason_info = ImsReasonInfo(reason)
- self._listener.onCallSessionTerminated(self, reason_info)
-
- def terminate(self, reason: int = 0):
- self._state = ImsCallSession.STATE_TERMINATED
- if self._listener:
- reason_info = ImsReasonInfo(reason)
- self._listener.onCallSessionTerminated(self, reason_info)
- self._listener.onCallStateChanged(self, self._state)
-
- def hold(self):
- self._state = ImsCallSession.STATE_HOLDING
- if self._listener:
- self._listener.onCallStateChanged(self, self._state)
- self._listener.onCallSessionHeld(self, True)
-
- def resume(self):
- self._state = ImsCallSession.STATE_ESTABLISHED
- if self._listener:
- self._listener.onCallStateChanged(self, self._state)
- self._listener.onCallSessionResumeReceived(self, self._profile)
-
- def merge(self):
- if self._listener:
- self._listener.onCallSessionMergeStarted(self, ImsCallSession(), self._profile)
-
- def sendDtmf(self, c: str, result: Any = None):
- pass
-
- def update(self, profile: ImsCallProfile, media_profile: ImsStreamMediaProfile):
- if self._listener:
- self._listener.onCallSessionUpdated(self, profile)
-
- def sendRttMessage(self, message: str):
- if self._listener:
- self._listener.onCallSessionRttMessageReceived(self, message)
-
- def sendRttModifyRequest(self, profile: ImsCallProfile):
- if self._listener:
- self._listener.onCallSessionRttModifyRequestReceived(self, profile)
-
- def sendRttModifyResponse(self, response: int):
- if self._listener:
- self._listener.onCallSessionRttModifyResponseReceived(self, response)
-
- def close(self):
- self._state = ImsCallSession.STATE_TERMINATED
- self._listener = None
-
- def toString(self) -> str:
- return f"ImsCallSession(callId={self._call_id}, state={self._state})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsCall
-# ═══════════════════════════════════════════════════════════════
-
-class ImsCall(Stub):
- """ImsCall — IMS 呼叫"""
-
- class Listener(Stub):
- """ImsCall.Listener — IMS 呼叫监听器"""
-
- def onCallProgressing(self, call: ImsCall, session: ImsCallSession, state: Any):
- pass
-
- def onCallStarted(self, call: ImsCall, session: ImsCallSession):
- pass
-
- def onCallUpdated(self, call: ImsCall, session: ImsCallSession):
- pass
-
- def onCallUpdateFailed(self, call: ImsCall, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallHeld(self, call: ImsCall, session: ImsCallSession):
- pass
-
- def onCallHoldFailed(self, call: ImsCall, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallResumed(self, call: ImsCall, session: ImsCallSession):
- pass
-
- def onCallResumeFailed(self, call: ImsCall, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallMerged(self, call: ImsCall, session: ImsCallSession, merge_session: ImsCallSession):
- pass
-
- def onCallMergeFailed(self, call: ImsCall, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallBusy(self, call: ImsCall, session: ImsCallSession):
- pass
-
- def onCallDisconnected(self, call: ImsCall, session: ImsCallSession, reason: ImsReasonInfo):
- pass
-
- def onCallSuppServiceReceived(self, call: ImsCall, session: ImsCallSession,
- service: Any):
- pass
-
- def onCallHandover(self, call: ImsCall, session: ImsCallSession, src_tech: int,
- target_tech: int, reason: ImsReasonInfo):
- pass
-
- def onCallHandoverFailed(self, call: ImsCall, session: ImsCallSession,
- src_tech: int, target_tech: int,
- reason: ImsReasonInfo):
- pass
-
- def onCallRttMessageReceived(self, call: ImsCall, message: str):
- pass
-
- def onCallRttModifyRequestReceived(self, call: ImsCall, profile: ImsCallProfile):
- pass
-
- def onCallRttModifyResponseReceived(self, call: ImsCall, status: int):
- pass
-
- def onCallConferenceStateUpdated(self, call: ImsCall, state: Any):
- pass
-
- def onCallSessionEvent(self, call: ImsCall, session: ImsCallSession, event: Any):
- pass
-
- def __init__(self, context: Any = None, profile: ImsCallProfile = None):
- super().__init__()
- self._context = context
- self._profile = profile or ImsCallProfile()
- self._session: Optional[ImsCallSession] = None
- self._listener: Optional[ImsCall.Listener] = None
- self._is_multiparty: bool = False
- self._state: int = ImsCallSession.STATE_IDLE
-
- def setListener(self, listener: ImsCall.Listener):
- self._listener = listener
-
- def getListener(self) -> Optional[ImsCall.Listener]:
- return self._listener
-
- def getSession(self) -> Optional[ImsCallSession]:
- return self._session
-
- def getCallProfile(self) -> ImsCallProfile:
- return self._profile
-
- def getLocalCallProfile(self) -> ImsCallProfile:
- return self._profile
-
- def getRemoteCallProfile(self) -> ImsCallProfile:
- return self._profile
-
- def isMultiparty(self) -> bool:
- return self._is_multiparty
-
- def getState(self) -> int:
- return self._state
-
- def close(self):
- if self._session:
- self._session.close()
- self._session = None
- self._listener = None
-
- def toString(self) -> str:
- return f"ImsCall(state={self._state}, multi={self._is_multiparty})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsConfig
-# ═══════════════════════════════════════════════════════════════
-
-class ImsConfig(Stub):
- """ImsConfig — IMS 配置"""
-
- CONFIG_START = 0
- CONFIG_END = 1
-
- # VoLTE 配置
- VO_CONFIG_START = 100
- VO_CONFIG_END = 200
-
- # 功能开关
- FEATURE_TYPE_VOLTE = 0
- FEATURE_TYPE_VIDEO = 1
- FEATURE_TYPE_UT = 2
- FEATURE_TYPE_UT_OVER_VOLTE = 3
- FEATURE_TYPE_UT_OVER_WIFI = 4
- FEATURE_TYPE_UNKNOWN = -1
-
- # 操作结果
- OPERATION_SUCCESS = 0
- OPERATION_FAILED = 1
- OPERATION_NOT_SUPPORTED = 2
- OPERATION_TIMEOUT = 3
- OPERATION_INVALID_PARAM = 4
-
- # VoLTE 设置
- VO_SETTING_VOLTE_ENABLED = 101
- VO_SETTING_VIDEO_ENABLED = 102
- VO_SETTING_WFC_ENABLED = 103
- VO_SETTING_WFC_MODE = 104
- VO_SETTING_LBO_PCSCF_ADDRESS = 105
- VO_SETTING_DOMAIN_NAME = 106
- VO_SETTING_SIP_INVITE_TIMEOUT = 107
- VO_SETTING_RTT_ENABLED = 108
- VO_SETTING_AMR_WB_ENABLED = 109
- VO_SETTING_EVS_ENABLED = 110
- VO_SETTING_AMR_NB_ENABLED = 111
- VO_SETTING_GSM_WB_ENABLED = 112
- VO_SETTING_GSM_NB_ENABLED = 113
- VO_SETTING_PCSCF_DISCOVERY_ENABLED = 114
- VO_SETTING_PCSCF_ADDRESS = 115
- VO_SETTING_SIP_SERVER_ADDRESS = 116
- VO_SETTING_PUBLIC_USER_IDENTITY = 117
- VO_SETTING_PRIVATE_USER_IDENTITY = 118
- VO_SETTING_HOME_NETWORK_DOMAIN = 119
- VO_SETTING_AM_CODEC = 120
- VO_SETTING_VIDEO_CODEC = 121
- VO_SETTING_VT_ENABLED = 122
- VO_SETTING_LTE_TO_WIFI_HANDOVER_ENABLED = 123
- VO_SETTING_WIFI_TO_LTE_HANDOVER_ENABLED = 124
- VO_SETTING_LTE_TO_NR_HANDOVER_ENABLED = 125
- VO_SETTING_NR_TO_LTE_HANDOVER_ENABLED = 126
-
- class ConfigCallback(Stub):
- """ImsConfig.ConfigCallback — 配置更改回调"""
-
- def onConfigChanged(self, item: int, value: str):
- pass
-
- def onGetFeatureValueResponse(self, feature: int, network: int, value: int, status: int):
- pass
-
- def onSetFeatureValueResponse(self, feature: int, network: int, value: int, status: int):
- pass
-
- def onGetConfigResponse(self, item: int, value: str, status: int):
- pass
-
- def onSetConfigResponse(self, item: int, status: int):
- pass
-
- def __init__(self):
- super().__init__()
- self._config: Dict[int, str] = {}
- self._feature_values: Dict[Tuple[int, int], int] = {}
- self._callback: Optional[ImsConfig.ConfigCallback] = None
-
- def setConfig(self, item: int, value: str) -> int:
- self._config[item] = value
- return ImsConfig.OPERATION_SUCCESS
-
- def getConfig(self, item: int) -> str:
- return self._config.get(item, "")
-
- def getFeatureValue(self, feature: int, network: int) -> int:
- return self._feature_values.get((feature, network), 0)
-
- def setFeatureValue(self, feature: int, network: int, value: int) -> int:
- self._feature_values[(feature, network)] = value
- return ImsConfig.OPERATION_SUCCESS
-
- def setConfigCallback(self, callback: ConfigCallback):
- self._callback = callback
-
- def getConfigCallback(self) -> Optional[ConfigCallback]:
- return self._callback
-
- def toString(self) -> str:
- return f"ImsConfig(settings={len(self._config)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsRegistration
-# ═══════════════════════════════════════════════════════════════
-
-class ImsRegistration(Stub):
- """ImsRegistration — IMS 注册信息"""
-
- def __init__(self):
- super().__init__()
- self._registrant_id: int = 0
- self._registration_state: int = IMS_REGISTRATION_STATE_NOT_REGISTERED
- self._registration_technology: int = IMS_REGISTRATION_TECH_NONE
- self._sip_uri: str = ""
- self._feature_tags: List[str] = []
- self._supported_media_types: List[int] = []
-
- def getRegistrantId(self) -> int:
- return self._registrant_id
-
- def setRegistrantId(self, rid: int):
- self._registrant_id = rid
-
- def getRegistrationState(self) -> int:
- return self._registration_state
-
- def setRegistrationState(self, state: int):
- self._registration_state = state
-
- def getRegistrationTechnology(self) -> int:
- return self._registration_technology
-
- def setRegistrationTechnology(self, tech: int):
- self._registration_technology = tech
-
- def getSipUri(self) -> str:
- return self._sip_uri
-
- def setSipUri(self, uri: str):
- self._sip_uri = uri
-
- def getFeatureTags(self) -> List[str]:
- return list(self._feature_tags)
-
- def setFeatureTags(self, tags: List[str]):
- self._feature_tags = list(tags)
-
- def getSupportedMediaTypes(self) -> List[int]:
- return list(self._supported_media_types)
-
- def setSupportedMediaTypes(self, types: List[int]):
- self._supported_media_types = list(types)
-
- def isRegistered(self) -> bool:
- return self._registration_state == IMS_REGISTRATION_STATE_REGISTERED
-
- def toString(self) -> str:
- return f"ImsRegistration(state={self._registration_state}, tech={self._registration_technology})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsManager
-# ═══════════════════════════════════════════════════════════════
-
-class ImsManager(Stub):
- """ImsManager — IMS 管理器"""
-
- ACTION_IMS_SERVICE_UP = "android.telephony.ims.action.IMS_SERVICE_UP"
- ACTION_IMS_SERVICE_DOWN = "android.telephony.ims.action.IMS_SERVICE_DOWN"
- ACTION_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.IMS_REGISTRATION_ERROR"
-
- EXTRA_PHONE_ID = "android.telephony.ims.extra.PHONE_ID"
- EXTRA_SUBSCRIPTION_ID = "android.telephony.ims.extra.SUBSCRIPTION_ID"
-
- def __init__(self, context: Any = None, phone_id: int = 0):
- super().__init__()
- self._context = context
- self._phone_id = phone_id
- self._registration: Optional[ImsRegistration] = None
- self._config: Optional[ImsConfig] = None
- self._mmtel_features: Dict[int, MmTelFeature] = {}
- self._registration_callbacks: List[ImsRegistrationCallback] = []
-
- @staticmethod
- def getInstance(context: Any, phone_id: int) -> ImsManager:
- return ImsManager(context, phone_id)
-
- def getImsService(self) -> Optional[ImsService]:
- return ImsService(self._context)
-
- def getConfig(self) -> Optional[ImsConfig]:
- if self._config is None:
- self._config = ImsConfig()
- return self._config
-
- def getRegistration(self) -> Optional[ImsRegistration]:
- return self._registration
-
- def setRegistration(self, registration: ImsRegistration):
- self._registration = registration
-
- def getPhoneId(self) -> int:
- return self._phone_id
-
- def getContext(self) -> Any:
- return self._context
-
- def isServiceSupported(self) -> bool:
- return True
-
- def isServiceReady(self) -> bool:
- return self._registration is not None and self._registration.isRegistered()
-
- def getMmTelFeature(self, sub_id: int) -> Optional[MmTelFeature]:
- return self._mmtel_features.get(sub_id)
-
- def createMmTelFeature(self, sub_id: int) -> MmTelFeature:
- feature = MmTelFeature(self._context, sub_id)
- self._mmtel_features[sub_id] = feature
- return feature
-
- def addRegistrationCallback(self, callback: ImsRegistrationCallback):
- if callback not in self._registration_callbacks:
- self._registration_callbacks.append(callback)
-
- def removeRegistrationCallback(self, callback: ImsRegistrationCallback):
- self._registration_callbacks = [c for c in self._registration_callbacks if c is not callback]
-
- def getRegistrationCallbacks(self) -> List[ImsRegistrationCallback]:
- return list(self._registration_callbacks)
-
- def notifyRegistrationChange(self):
- for cb in self._registration_callbacks:
- cb.onRegistered(self._registration)
-
- def close(self):
- self._config = None
- self._registration = None
- self._registration_callbacks.clear()
- self._mmtel_features.clear()
-
- def toString(self) -> str:
- return f"ImsManager(phoneId={self._phone_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsRegistrationCallback
-# ═══════════════════════════════════════════════════════════════
-
-class ImsRegistrationCallback(Stub):
- """ImsRegistrationCallback — IMS 注册回调"""
-
- def onRegistered(self, registration: ImsRegistration):
- pass
-
- def onRegistering(self, registration: ImsRegistration):
- pass
-
- def onDeregistered(self, registration: ImsRegistration, reason: ImsReasonInfo):
- pass
-
- def onTechnologyChanged(self, registration: ImsRegistration):
- pass
-
- def onSubscriberAssociatedUriChanged(self, uris: List[str]):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsService
-# ═══════════════════════════════════════════════════════════════
-
-class ImsService(Stub):
- """ImsService — IMS 服务"""
-
- CAPABILITY_TYPE_VOLTE = 0
- CAPABILITY_TYPE_VIDEO = 1
- CAPABILITY_TYPE_UT = 2
- CAPABILITY_TYPE_SMS = 3
- CAPABILITY_TYPE_MMTEL = 4
- CAPABILITY_TYPE_RCS = 5
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._features: Dict[int, Any] = {}
- self._is_ready: bool = False
- self._capabilities: Set[int] = set()
-
- def getContext(self) -> Any:
- return self._context
-
- def isReady(self) -> bool:
- return self._is_ready
-
- def setReady(self, ready: bool):
- self._is_ready = ready
-
- def getCapabilities(self) -> Set[int]:
- return set(self._capabilities)
-
- def setCapabilities(self, caps: Set[int]):
- self._capabilities = set(caps)
-
- def hasCapability(self, capability: int) -> bool:
- return capability in self._capabilities
-
- def addCapability(self, capability: int):
- self._capabilities.add(capability)
-
- def removeCapability(self, capability: int):
- self._capabilities.discard(capability)
-
- def getFeature(self, feature_type: int) -> Optional[Any]:
- return self._features.get(feature_type)
-
- def addFeature(self, feature_type: int, feature: Any):
- self._features[feature_type] = feature
-
- def createCallSession(self, profile: ImsCallProfile) -> Optional[ImsCallSession]:
- return ImsCallSession(self._context, profile)
-
- def close(self):
- self._features.clear()
- self._capabilities.clear()
- self._is_ready = False
-
- def toString(self) -> str:
- return f"ImsService(ready={self._is_ready}, caps={len(self._capabilities)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MmTelFeature
-# ═══════════════════════════════════════════════════════════════
-
-class MmTelFeature(Stub):
- """MmTelFeature — MMTel 功能"""
-
- # MMTel 功能类型
- MMTEL_CAPABILITY_TYPE_VOICE = 0
- MMTEL_CAPABILITY_TYPE_VIDEO = 1
- MMTEL_CAPABILITY_TYPE_UT = 2
- MMTEL_CAPABILITY_TYPE_SMS = 3
- MMTEL_CAPABILITY_TYPE_NONE = 4
-
- # 网络类型
- NETWORK_TYPE_LTE = 0
- NETWORK_TYPE_IWLAN = 1
- NETWORK_TYPE_NR = 2
-
- # 功能可用性
- CAPABILITY_TYPE_UNKNOWN = -1
- CAPABILITY_TYPE_NONE = 0
- CAPABILITY_TYPE_VOICE = 1
- CAPABILITY_TYPE_VIDEO = 2
- CAPABILITY_TYPE_UT = 4
- CAPABILITY_TYPE_SMS = 8
- CAPABILITY_TYPE_ALL = 15
-
- class Listener(Stub):
- """MmTelFeature.Listener — MMTel 功能监听器"""
-
- def onIncomingCall(self, call_session: ImsCallSession, call_id: str, extras: Any):
- pass
-
- def onIncomingCallAnswered(self, call_session: ImsCallSession, call_id: str, extras: Any):
- pass
-
- def onRejectedCall(self, call_id: str, reason: ImsReasonInfo):
- pass
-
- def onVoiceMessageCountChanged(self, count: int):
- pass
-
- def __init__(self, context: Any = None, sub_id: int = 0):
- super().__init__()
- self._context = context
- self._sub_id = sub_id
- self._listener: Optional[MmTelFeature.Listener] = None
- self._mmtel_capabilities: Set[int] = set()
- self._is_available: bool = False
- self._network_type: int = MmTelFeature.NETWORK_TYPE_LTE
- self._call_sessions: Dict[str, ImsCallSession] = {}
-
- def setListener(self, listener: MmTelFeature.Listener):
- self._listener = listener
-
- def getListener(self) -> Optional[MmTelFeature.Listener]:
- return self._listener
-
- def getSubscriptionId(self) -> int:
- return self._sub_id
-
- def isAvailable(self) -> bool:
- return self._is_available
-
- def setAvailable(self, available: bool):
- self._is_available = available
-
- def getNetworkType(self) -> int:
- return self._network_type
-
- def setNetworkType(self, network_type: int):
- self._network_type = network_type
-
- def getMmTelCapabilities(self) -> Set[int]:
- return set(self._mmtel_capabilities)
-
- def setMmTelCapabilities(self, caps: Set[int]):
- self._mmtel_capabilities = set(caps)
-
- def hasCapability(self, capability: int) -> bool:
- return capability in self._mmtel_capabilities
-
- def createCallSession(self, profile: ImsCallProfile) -> ImsCallSession:
- session = ImsCallSession(self._context, profile)
- session.setCallId(f"mmtel_call_{len(self._call_sessions)}")
- self._call_sessions[session.getCallId()] = session
- return session
-
- def endCallSession(self, call_id: str):
- self._call_sessions.pop(call_id, None)
-
- def getCallSessions(self) -> List[ImsCallSession]:
- return list(self._call_sessions.values())
-
- def toString(self) -> str:
- return f"MmTelFeature(subId={self._sub_id}, available={self._is_available})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MmTelManager
-# ═══════════════════════════════════════════════════════════════
-
-class MmTelManager(Stub):
- """MmTelManager — MMTel 管理器"""
-
- CAPABILITY_TYPE_VOICE = 0
- CAPABILITY_TYPE_VIDEO = 1
- CAPABILITY_TYPE_UT = 2
- CAPABILITY_TYPE_SMS = 3
- CAPABILITY_TYPE_NONE = 4
-
- WIFI_CALLING_SETTING_ENABLED = 0
- WIFI_CALLING_SETTING_DISABLED = 1
- WIFI_CALLING_SETTING_UNKNOWN = 2
-
- class CapabilityCallback(Stub):
- """MmTelManager.CapabilityCallback — 能力回调"""
-
- def onCapabilitiesChanged(self, capabilities: Set[int]):
- pass
-
- class RegistrationCallback(Stub):
- """MmTelManager.RegistrationCallback — 注册回调"""
-
- def onRegistered(self, registration: ImsRegistration):
- pass
-
- def onRegistering(self, registration: ImsRegistration):
- pass
-
- def onUnregistered(self, reason: ImsReasonInfo):
- pass
-
- def onTechnologyChanged(self, registration: ImsRegistration):
- pass
-
- def onSubscriberAssociatedUriChanged(self, uris: List[str]):
- pass
-
- def __init__(self, context: Any = None, sub_id: int = 0):
- super().__init__()
- self._context = context
- self._sub_id = sub_id
- self._mmtel_feature: Optional[MmTelFeature] = None
- self._capability_callbacks: List[MmTelManager.CapabilityCallback] = []
- self._registration_callbacks: List[MmTelManager.RegistrationCallback] = []
-
- @staticmethod
- def getInstance(context: Any, sub_id: int) -> Optional[MmTelManager]:
- return MmTelManager(context, sub_id)
-
- def getSubscriptionId(self) -> int:
- return self._sub_id
-
- def getMmTelFeature(self) -> Optional[MmTelFeature]:
- return self._mmtel_feature
-
- def setMmTelFeature(self, feature: MmTelFeature):
- self._mmtel_feature = feature
-
- def addCapabilityCallback(self, callback: CapabilityCallback):
- if callback not in self._capability_callbacks:
- self._capability_callbacks.append(callback)
-
- def removeCapabilityCallback(self, callback: CapabilityCallback):
- self._capability_callbacks = [c for c in self._capability_callbacks if c is not callback]
-
- def addRegistrationCallback(self, callback: RegistrationCallback):
- if callback not in self._registration_callbacks:
- self._registration_callbacks.append(callback)
-
- def removeRegistrationCallback(self, callback: RegistrationCallback):
- self._registration_callbacks = [c for c in self._registration_callbacks if c is not callback]
-
- def isMmTelCapabilitySupported(self, capability: int, transport_type: int) -> bool:
- return True
-
- def isMmTelCapabilityEnabled(self, capability: int, transport_type: int) -> bool:
- return False
-
- def setMmTelCapabilityEnabled(self, capability: int, transport_type: int, enabled: bool):
- pass
-
- def isAdvancedCallingSettingEnabled(self) -> bool:
- return False
-
- def isVoLteSettingEnabled(self) -> bool:
- return False
-
- def isVtSettingEnabled(self) -> bool:
- return False
-
- def isWiFiCallingSettingEnabled(self) -> bool:
- return False
-
- def setVoLteSettingEnabled(self, enabled: bool):
- pass
-
- def setVtSettingEnabled(self, enabled: bool):
- pass
-
- def setWiFiCallingSettingEnabled(self, enabled: bool):
- pass
-
- def sendRttMessage(self, message: str):
- pass
-
- def sendRttModifyRequest(self, profile: ImsCallProfile):
- pass
-
- def sendRttModifyResponse(self, response: int):
- pass
-
- def toString(self) -> str:
- return f"MmTelManager(subId={self._sub_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsSsInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ImsSsInfo(Stub):
- """ImsSsInfo — IMS 补充业务信息"""
-
- NOT_REGISTERED = 0
- DISABLED = 0
- ENABLED = 1
- REGISTERED = 1
-
- SERVICE_TYPE_CFU = 0
- SERVICE_TYPE_CFB = 1
- SERVICE_TYPE_CFNRY = 2
- SERVICE_TYPE_CFNRC = 3
- SERVICE_TYPE_CF_ALL = 4
- SERVICE_TYPE_CF_ALL_CONDITIONAL = 5
- SERVICE_TYPE_CLIP = 6
- SERVICE_TYPE_CLIR = 7
- SERVICE_TYPE_COLP = 8
- SERVICE_TYPE_COLR = 9
- SERVICE_TYPE_CW = 10
- SERVICE_TYPE_HOLD = 11
- SERVICE_TYPE_ECT = 12
- SERVICE_TYPE_BAOC = 13
- SERVICE_TYPE_BAOIC = 14
- SERVICE_TYPE_BAOIC_EXC_HOME = 15
- SERVICE_TYPE_BIC_ROAM = 16
- SERVICE_TYPE_CB_ALL = 17
- SERVICE_TYPE_CB_ALL_OUTGOING = 18
- SERVICE_TYPE_CB_ALL_INCOMING = 19
-
- def __init__(self, status: int = NOT_REGISTERED, provision_status: int = 0):
- super().__init__()
- self._status = status
- self._provision_status = provision_status
- self._call_forwarding_info: Optional[ImsCallForwardInfo] = None
-
- def getStatus(self) -> int:
- return self._status
-
- def setStatus(self, status: int):
- self._status = status
-
- def getProvisionStatus(self) -> int:
- return self._provision_status
-
- def setProvisionStatus(self, status: int):
- self._provision_status = status
-
- def isProvisioned(self) -> bool:
- return self._provision_status == 1
-
- def isRegistered(self) -> bool:
- return self._status == ImsSsInfo.REGISTERED
-
- def getCallForwardInfo(self) -> Optional[ImsCallForwardInfo]:
- return self._call_forwarding_info
-
- def setCallForwardInfo(self, info: ImsCallForwardInfo):
- self._call_forwarding_info = info
-
- def toString(self) -> str:
- return f"ImsSsInfo(status={self._status})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsCallForwardInfo
-# ═══════════════════════════════════════════════════════════════
-
-class ImsCallForwardInfo(Stub):
- """ImsCallForwardInfo — IMS 呼叫前转信息"""
-
- CDIV_CF_UNCONDITIONAL = 0
- CDIV_CF_BUSY = 1
- CDIV_CF_NO_REPLY = 2
- CDIV_CF_NOT_REACHABLE = 3
- CDIV_CF_ALL = 4
- CDIV_CF_ALL_CONDITIONAL = 5
-
- def __init__(self, condition: int = CDIV_CF_UNCONDITIONAL,
- status: int = 0, number: str = "",
- time_seconds: int = 20):
- super().__init__()
- self._condition = condition
- self._status = status
- self._number = number
- self._time_seconds = time_seconds
-
- def getCondition(self) -> int:
- return self._condition
-
- def setCondition(self, condition: int):
- self._condition = condition
-
- def getStatus(self) -> int:
- return self._status
-
- def setStatus(self, status: int):
- self._status = status
-
- def getNumber(self) -> str:
- return self._number
-
- def setNumber(self, number: str):
- self._number = number
-
- def getTimeSeconds(self) -> int:
- return self._time_seconds
-
- def setTimeSeconds(self, seconds: int):
- self._time_seconds = seconds
-
- def toString(self) -> str:
- return f"ImsCallForwardInfo(condition={self._condition}, number={self._number})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsUt
-# ═══════════════════════════════════════════════════════════════
-
-class ImsUt(Stub):
- """ImsUt — IMS 补充服务"""
-
- OPERATION_SUCCESS = 0
- OPERATION_FAILED = 1
- OPERATION_NOT_SUPPORTED = 2
- OPERATION_TIMEOUT = 3
- OPERATION_NETWORK_ERROR = 4
- OPERATION_INVALID_PARAM = 5
-
- class Listener(Stub):
- """ImsUt.Listener — 补充服务监听器"""
-
- def onUtConfigurationUpdated(self, result: int):
- pass
-
- def onUtConfigurationUpdateFailed(self, result: int):
- pass
-
- def onUtConfigurationQueried(self, result: int, ss_info: List[ImsSsInfo]):
- pass
-
- def onUtConfigurationQueryFailed(self, result: int):
- pass
-
- def onUtConfigurationCallBarringQueried(self, result: int, ss_info: List[ImsSsInfo]):
- pass
-
- def onUtConfigurationCallForwardQueried(self, result: int, ss_info: List[ImsSsInfo]):
- pass
-
- def onUtConfigurationCallWaitingQueried(self, result: int, ss_info: List[ImsSsInfo]):
- pass
-
- def __init__(self):
- super().__init__()
- self._listener: Optional[ImsUt.Listener] = None
-
- def setListener(self, listener: ImsUt.Listener):
- self._listener = listener
-
- def getListener(self) -> Optional[ImsUt.Listener]:
- return self._listener
-
- def queryCallBarring(self, cb_type: int):
- pass
-
- def queryCallForward(self, condition: int):
- pass
-
- def queryCallWaiting(self):
- pass
-
- def updateCallBarring(self, cb_type: int, enabled: bool,
- password: str = "", service_class: int = 0):
- pass
-
- def updateCallForward(self, condition: int, enabled: bool,
- number: str = "", time_seconds: int = 20):
- pass
-
- def updateCallWaiting(self, enabled: bool, service_class: int = 0):
- pass
-
- def close(self):
- self._listener = None
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsCallSessionCallback
-# ═══════════════════════════════════════════════════════════════
-
-class ImsCallSessionCallback(Stub):
- """ImsCallSessionCallback — IMS 呼叫会话回调"""
-
- def onCallStateChanged(self, state: int):
- pass
-
- def onCallProfileChanged(self, profile: ImsCallProfile):
- pass
-
- def onCallQualityChanged(self, quality: int, video_quality: int):
- pass
-
- def onCallSessionHeld(self, held: bool):
- pass
-
- def onCallSessionHoldFailed(self, reason: ImsReasonInfo):
- pass
-
- def onCallSessionResumed(self, resume: bool):
- pass
-
- def onCallSessionResumeFailed(self, reason: ImsReasonInfo):
- pass
-
- def onCallSessionMergeStarted(self, session: ImsCallSession, profile: ImsCallProfile):
- pass
-
- def onCallSessionMergeComplete(self, session: ImsCallSession):
- pass
-
- def onCallSessionMergeFailed(self, reason: ImsReasonInfo):
- pass
-
- def onCallSessionUpdated(self, profile: ImsCallProfile):
- pass
-
- def onCallSessionUpdateFailed(self, reason: ImsReasonInfo):
- pass
-
- def onCallSessionTerminated(self, reason: ImsReasonInfo):
- pass
-
- def onCallSessionInitiated(self, profile: ImsCallProfile):
- pass
-
- def onCallSessionHandover(self, src_tech: int, target_tech: int, reason: ImsReasonInfo):
- pass
-
- def onCallSessionHandoverFailed(self, src_tech: int, target_tech: int, reason: ImsReasonInfo):
- pass
-
- def onCallSessionMayHandover(self, src_tech: int, target_tech: int):
- pass
-
- def onCallSessionRttMessageReceived(self, message: str):
- pass
-
- def onCallSessionRttModifyRequestReceived(self, profile: ImsCallProfile):
- pass
-
- def onCallSessionRttModifyResponseReceived(self, status: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImsStateCallback
-# ═══════════════════════════════════════════════════════════════
-
-class ImsStateCallback(Stub):
- """ImsStateCallback — IMS 状态回调"""
-
- def onServiceAvailable(self):
- pass
-
- def onServiceUnavailable(self):
- pass
-
- def onUnavailable(self, reason: int):
- pass
-
- def onConnected(self):
- pass
-
- def onDisconnected(self, reason: int):
- pass
-
- def onResume(self):
- pass
-
- def onSuspend(self):
- pass
-
- def onFeatureStateChanged(self, feature_state: int, network: int):
- pass
-
- def onRegistrationStateChanged(self, state: int):
- pass
\ No newline at end of file
diff --git a/android_pyapi/android/telephony_mbms.py b/android_pyapi/android/telephony_mbms.py
deleted file mode 100644
index e73db86..0000000
--- a/android_pyapi/android/telephony_mbms.py
+++ /dev/null
@@ -1,1180 +0,0 @@
-"""
-Android Telephony MBMS 组件 — MbmsDownloadManager, MbmsStreamingManager, DownloadRequest, StreamingService 等
-方法签名完全对齐 Android SDK (android.telephony.mbms 包)
-"""
-
-from __future__ import annotations
-
-import os
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsErrors
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsErrors(Stub):
- """MbmsErrors — MBMS 错误代码基类"""
-
- SUCCESS = 0
- ERROR_NO_UNIQUE_MIDDLEWARE = 1
- ERROR_MIDDLEWARE_NOT_BOUND = 2
- ERROR_MIDDLEWARE_LOST = 3
- ERROR_MIDDLEWARE_NOT_YET_READY = 4
- ERROR_OUT_OF_MEMORY = 5
- ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE = 6
- ERROR_MIDDLEWARE_PERMANENTLY_UNAVAILABLE = 7
- ERROR_MIDDLEWARE_UNABLE_TO_CREATE_SESSION = 8
- ERROR_MIDDLEWARE_UNABLE_TO_CREATE_DATA_SESSION = 9
- ERROR_MIDDLEWARE_UNABLE_TO_CREATE_DOWNLOAD = 10
- ERROR_MIDDLEWARE_UNABLE_TO_CREATE_STREAMING = 11
- ERROR_MIDDLEWARE_INTERNAL_ERROR = 12
- ERROR_MIDDLEWARE_NOT_SUPPORTED = 13
- ERROR_MIDDLEWARE_INVALID_INPUT = 14
- ERROR_MIDDLEWARE_INVALID_SERVICE_ID = 15
- ERROR_MIDDLEWARE_INVALID_FILE_PATH = 16
- ERROR_MIDDLEWARE_DUPLICATE_SERVICE = 17
- ERROR_MIDDLEWARE_SERVICE_NOT_FOUND = 18
- ERROR_MIDDLEWARE_SERVICE_ALREADY_RUNNING = 19
- ERROR_MIDDLEWARE_SERVICE_NOT_RUNNING = 20
- ERROR_MIDDLEWARE_INVALID_SAI = 21
- ERROR_MIDDLEWARE_INVALID_CELL_ID = 22
- ERROR_MIDDLEWARE_UNABLE_TO_FETCH_PREFIX = 23
- ERROR_MIDDLEWARE_TEMP_FILE_EXPIRED = 24
- ERROR_MIDDLEWARE_FILE_ALREADY_COMPLETE = 25
- ERROR_MIDDLEWARE_FILE_ALREADY_IN_PROGRESS = 26
- ERROR_MIDDLEWARE_STALE_SERVICE_ANNOUNCEMENT = 27
- ERROR_MIDDLEWARE_MISSING_FILE_INFO = 28
- ERROR_MIDDLEWARE_NO_EXPIRATION = 29
- ERROR_MIDDLEWARE_UNKNOWN_FILE_INFO = 30
- ERROR_MIDDLEWARE_UNKNOWN_SIGNAL = 31
- ERROR_MIDDLEWARE_INSUFFICIENT_STORAGE = 32
- ERROR_MIDDLEWARE_INSUFFICIENT_MEMORY = 33
- ERROR_MIDDLEWARE_UNABLE_TO_CLOSE_FILE = 34
- ERROR_MIDDLEWARE_UNABLE_TO_OPEN_FILE = 35
- ERROR_MIDDLEWARE_IO_ERROR = 36
- ERROR_MIDDLEWARE_CONCURRENT_SERVICE_LIMIT = 37
- ERROR_MIDDLEWARE_INVALID_DOWNLOAD_ID = 38
-
- class InitializationErrors(Stub):
- """MbmsErrors.InitializationErrors — 初始化错误"""
- ERROR_DUPLICATE_INITIALIZE = 101
- ERROR_APP_PERMISSIONS_NOT_GRANTED = 102
- ERROR_UNABLE_TO_INITIALIZE = 103
- ERROR_INTERNAL = 104
- ERROR_MIDDLEWARE_NOT_BOUND = 105
-
- class DownloadErrors(Stub):
- """MbmsErrors.DownloadErrors — 下载错误"""
- ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT = 201
- ERROR_UNKNOWN_DOWNLOAD_REQUEST = 202
- ERROR_DOWNLOAD_NOT_FOUND = 203
- ERROR_DOWNLOAD_ALREADY_EXISTS = 204
- ERROR_DOWNLOAD_INACTIVE = 205
- ERROR_FILE_UNAVAILABLE = 206
- ERROR_SERVICE_ID_NOT_DOWNLOAD = 207
- ERROR_MALFORMED_FILE_URI = 208
- ERROR_STALE_FILE_INFO = 209
- ERROR_TEMP_FILE_ROOT_NOT_SET = 210
- ERROR_UNKNOWN_FILE_INFO = 211
- ERROR_NO_DOWNLOAD_FOR_FILE = 212
-
- class StreamingErrors(Stub):
- """MbmsErrors.StreamingErrors — 流错误"""
- ERROR_STREAMING_NOT_ALLOWED = 301
- ERROR_STREAMING_SERVICE_NOT_STARTED = 302
- ERROR_STREAMING_SERVICE_ALREADY_STARTED = 303
- ERROR_STREAMING_SERVICE_NOT_VISIBLE = 304
- ERROR_STREAMING_MALFORMED_SERVICE_ANNOUNCEMENT = 305
- ERROR_STREAMING_DUPLICATE_SERVICE_ANNOUNCEMENT = 306
- ERROR_STREAMING_SERVICE_ANNOUNCEMENT_EXPIRED = 307
- ERROR_STREAMING_RADIO_RESOURCE_REJECTED = 308
- ERROR_STREAMING_RADIO_RESOURCE_NOT_AVAILABLE = 309
- ERROR_STREAMING_INVALID_SAI_LIST = 310
- ERROR_STREAMING_UNABLE_TO_UPDATE_SUBFLOW = 311
-
- class NameTypeErrors(Stub):
- """MbmsErrors.NameTypeErrors — 名称类型错误"""
- ERROR_NAME_SYSTEM_ERROR = 401
- ERROR_NAME_INVALID_FORMAT = 402
- ERROR_NAME_UNSUPPORTED_CHARACTER_ENCODING = 403
- ERROR_NAME_CONTAINS_INVALID_CHARACTERS = 404
-
- class GeneralErrors(Stub):
- """MbmsErrors.GeneralErrors — 通用错误"""
- ERROR_MIDDLEWARE_NOT_BOUND = 501
- ERROR_OUT_OF_MEMORY = 502
- ERROR_MIDDLEWARE_LOST = 503
- ERROR_MIDDLEWARE_NOT_YET_READY = 504
- ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE = 505
- ERROR_MIDDLEWARE_UNABLE_TO_CREATE_SESSION = 506
-
-
-# ═══════════════════════════════════════════════════════════════
-# DownloadRequest
-# ═══════════════════════════════════════════════════════════════
-
-class DownloadRequest(Stub):
- """DownloadRequest — MBMS 下载请求"""
-
- # 下载请求常量
- DOWNLOAD_RESULT_SUCCESS = 0
- DOWNLOAD_RESULT_ERROR = 1
- DOWNLOAD_RESULT_ERROR_MEDIA_NOT_FOUND = 2
- DOWNLOAD_RESULT_ERROR_MEDIA_UNAVAILABLE = 3
- DOWNLOAD_RESULT_ERROR_MEDIA_FAILED = 4
- DOWNLOAD_RESULT_ERROR_SERVICE_UNAVAILABLE = 5
- DOWNLOAD_RESULT_ERROR_INSUFFICIENT_STORAGE = 6
- DOWNLOAD_RESULT_ERROR_IO_ERROR = 7
- DOWNLOAD_RESULT_ERROR_FILE_NOT_FOUND = 8
- DOWNLOAD_RESULT_ERROR_OUT_OF_MEMORY = 9
- DOWNLOAD_RESULT_ERROR_RADIO_OFF = 10
- DOWNLOAD_RESULT_ERROR_INTERRUPTED = 11
- DOWNLOAD_RESULT_ERROR_TIMEOUT = 12
- DOWNLOAD_RESULT_ERROR_CANCELLED = 13
- DOWNLOAD_RESULT_ERROR_DOWNLOAD_NOT_STARTED = 14
-
- # 下载状态
- DOWNLOAD_STATUS_INACTIVE = 0
- DOWNLOAD_STATUS_ACTIVE = 1
- DOWNLOAD_STATUS_PENDING = 2
- DOWNLOAD_STATUS_PAUSED = 3
- DOWNLOAD_STATUS_COMPLETED = 4
- DOWNLOAD_STATUS_CANCELED = 5
- DOWNLOAD_STATUS_FAILED = 6
-
- def __init__(self, service_id: str = "", file_uri: str = "",
- source: Any = None, destination: Any = None,
- app_intent: Any = None):
- super().__init__()
- self._service_id = service_id
- self._file_uri = file_uri
- self._source = source
- self._destination = destination
- self._app_intent = app_intent
- self._subscription_id: int = 0
- self._sai: List[int] = []
- self._app_name: str = ""
- self._app_version: str = ""
- self._storage_type: int = 0
- self._hash: str = ""
- self._request_id: int = 0
-
- def getServiceId(self) -> str:
- return self._service_id
-
- def getFileUri(self) -> str:
- return self._file_uri
-
- def getSource(self) -> Any:
- return self._source
-
- def getDestination(self) -> Any:
- return self._destination
-
- def getIntent(self) -> Any:
- return self._app_intent
-
- def getSubscriptionId(self) -> int:
- return self._subscription_id
-
- def setSubscriptionId(self, sub_id: int):
- self._subscription_id = sub_id
-
- def getSai(self) -> List[int]:
- return list(self._sai)
-
- def setSai(self, sai: List[int]):
- self._sai = list(sai)
-
- def getAppName(self) -> str:
- return self._app_name
-
- def setAppName(self, name: str):
- self._app_name = name
-
- def getAppVersion(self) -> str:
- return self._app_version
-
- def setAppVersion(self, version: str):
- self._app_version = version
-
- def getStorageType(self) -> int:
- return self._storage_type
-
- def setStorageType(self, storage_type: int):
- self._storage_type = storage_type
-
- def getHash(self) -> str:
- return self._hash
-
- def getRequestId(self) -> int:
- return self._request_id
-
- def setRequestId(self, request_id: int):
- self._request_id = request_id
-
- def toString(self) -> str:
- return f"DownloadRequest(serviceId={self._service_id}, fileUri={self._file_uri})"
-
- class Builder(Stub):
- """DownloadRequest.Builder — 下载请求构建器"""
-
- def __init__(self, service_id: str, file_uri: str):
- super().__init__()
- self._service_id = service_id
- self._file_uri = file_uri
- self._source: Any = None
- self._destination: Any = None
- self._app_intent: Any = None
- self._subscription_id: int = 0
- self._sai: List[int] = []
- self._app_name: str = ""
- self._app_version: str = ""
- self._storage_type: int = 0
-
- def setServiceId(self, service_id: str) -> DownloadRequest.Builder:
- self._service_id = service_id
- return self
-
- def setFileUri(self, file_uri: str) -> DownloadRequest.Builder:
- self._file_uri = file_uri
- return self
-
- def setSource(self, source: Any) -> DownloadRequest.Builder:
- self._source = source
- return self
-
- def setDestination(self, destination: Any) -> DownloadRequest.Builder:
- self._destination = destination
- return self
-
- def setIntent(self, intent: Any) -> DownloadRequest.Builder:
- self._app_intent = intent
- return self
-
- def setSubscriptionId(self, sub_id: int) -> DownloadRequest.Builder:
- self._subscription_id = sub_id
- return self
-
- def setSai(self, sai: List[int]) -> DownloadRequest.Builder:
- self._sai = list(sai)
- return self
-
- def setAppName(self, name: str) -> DownloadRequest.Builder:
- self._app_name = name
- return self
-
- def setAppVersion(self, version: str) -> DownloadRequest.Builder:
- self._app_version = version
- return self
-
- def setStorageType(self, storage_type: int) -> DownloadRequest.Builder:
- self._storage_type = storage_type
- return self
-
- def build(self) -> DownloadRequest:
- req = DownloadRequest(self._service_id, self._file_uri,
- self._source, self._destination,
- self._app_intent)
- req.setSubscriptionId(self._subscription_id)
- req.setSai(self._sai)
- req.setAppName(self._app_name)
- req.setAppVersion(self._app_version)
- req.setStorageType(self._storage_type)
- return req
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileInfo
-# ═══════════════════════════════════════════════════════════════
-
-class FileInfo(Stub):
- """FileInfo — MBMS 文件信息"""
-
- def __init__(self, uri: str = "", mime_type: str = "",
- file_size: int = 0, name: str = ""):
- super().__init__()
- self._uri = uri
- self._mime_type = mime_type
- self._file_size = file_size
- self._name = name
-
- def getUri(self) -> str:
- return self._uri
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def getFileSize(self) -> int:
- return self._file_size
-
- def getName(self) -> str:
- return self._name
-
- def toString(self) -> str:
- return f"FileInfo(uri={self._uri}, mimeType={self._mime_type}, size={self._file_size})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DownloadStatusListener
-# ═══════════════════════════════════════════════════════════════
-
-class DownloadStatusListener(Stub):
- """DownloadStatusListener — MBMS 下载状态监听器"""
-
- def onStatusChanged(self, request: DownloadRequest, info: FileInfo, status: int):
- """下载状态改变回调"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileServiceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class FileServiceInfo(Stub):
- """FileServiceInfo — MBMS 文件服务信息"""
-
- def __init__(self, service_id: str = "", service_class: str = "",
- service_announcement: Any = None):
- super().__init__()
- self._service_id = service_id
- self._service_class = service_class
- self._service_announcement = service_announcement
- self._sais: List[int] = []
- self._cells: List[int] = []
- self._files: List[FileInfo] = []
-
- def getServiceId(self) -> str:
- return self._service_id
-
- def getServiceClass(self) -> str:
- return self._service_class
-
- def getServiceAnnouncement(self) -> Any:
- return self._service_announcement
-
- def getSai(self) -> List[int]:
- return list(self._sais)
-
- def getCells(self) -> List[int]:
- return list(self._cells)
-
- def getFiles(self) -> List[FileInfo]:
- return list(self._files)
-
- def toString(self) -> str:
- return f"FileServiceInfo(serviceId={self._service_id}, class={self._service_class})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# StreamingService
-# ═══════════════════════════════════════════════════════════════
-
-class StreamingService(Stub):
- """StreamingService — MBMS 流媒体服务"""
-
- # 流媒体服务状态
- STATE_STOPPED = 0
- STATE_STARTED = 1
- STATE_STALLED = 2
- STATE_PENDING = 3
- STATE_ERROR = 4
-
- # 流媒体服务广播标志
- BROADCAST_METHOD_UNICAST = 0
- BROADCAST_METHOD_MULTICAST = 1
- BROADCAST_METHOD_BROADCAST = 2
-
- # 流媒体服务信息
- STREAMING_SERVICE_STATE_STOPPED = 0
- STREAMING_SERVICE_STATE_STARTED = 1
- STREAMING_SERVICE_STATE_STALLED = 2
- STREAMING_SERVICE_STATE_PENDING = 3
- STREAMING_SERVICE_STATE_ERROR = 4
-
- REASON_NONE = 0
- REASON_BY_USER_REQUEST = 1
- REASON_BY_MIDDLEWARE = 2
- REASON_BY_RADIO_RESOURCE = 3
- REASON_BY_OUT_OF_MEMORY = 4
- REASON_BY_SIGNAL_LOST = 5
- REASON_BY_TEMPORARILY_UNAVAILABLE = 6
- REASON_BY_PERMANENTLY_UNAVAILABLE = 7
- REASON_BY_SERVICE_SHUTDOWN = 8
- REASON_BY_SERVICE_NOT_VISIBLE = 9
- REASON_BY_RADIO_NOT_AVAILABLE = 10
-
- def __init__(self, service_id: str = "", service_class: str = ""):
- super().__init__()
- self._service_id = service_id
- self._service_class = service_class
- self._state = StreamingService.STATE_STOPPED
- self._broadcast_method = StreamingService.BROADCAST_METHOD_MULTICAST
- self._callback: Optional[StreamingServiceCallback] = None
- self._audio_description: Any = None
- self._video_description: Any = None
- self._subtitle_descriptions: List[Any] = []
- self._estimated_bitrate: int = 0
-
- def getServiceId(self) -> str:
- return self._service_id
-
- def getServiceClass(self) -> str:
- return self._service_class
-
- def getState(self) -> int:
- return self._state
-
- def setState(self, state: int):
- self._state = state
-
- def getBroadcastMethod(self) -> int:
- return self._broadcast_method
-
- def setBroadcastMethod(self, method: int):
- self._broadcast_method = method
-
- def getAudioDescription(self) -> Any:
- return self._audio_description
-
- def setAudioDescription(self, desc: Any):
- self._audio_description = desc
-
- def getVideoDescription(self) -> Any:
- return self._video_description
-
- def setVideoDescription(self, desc: Any):
- self._video_description = desc
-
- def getSubtitleDescriptions(self) -> List[Any]:
- return list(self._subtitle_descriptions)
-
- def setSubtitleDescriptions(self, descs: List[Any]):
- self._subtitle_descriptions = list(descs)
-
- def getEstimatedBitrate(self) -> int:
- return self._estimated_bitrate
-
- def setEstimatedBitrate(self, bitrate: int):
- self._estimated_bitrate = bitrate
-
- def setCallback(self, callback: StreamingServiceCallback):
- self._callback = callback
-
- def getCallback(self) -> Optional[StreamingServiceCallback]:
- return self._callback
-
- def start(self):
- """启动流媒体服务"""
- self._state = StreamingService.STATE_STARTED
- if self._callback:
- self._callback.onStreamStateUpdated(self._state,
- StreamingService.REASON_BY_USER_REQUEST)
-
- def stop(self):
- """停止流媒体服务"""
- self._state = StreamingService.STATE_STOPPED
- if self._callback:
- self._callback.onStreamStateUpdated(self._state,
- StreamingService.REASON_BY_USER_REQUEST)
-
- def close(self):
- """关闭流媒体服务"""
- self._state = StreamingService.STATE_STOPPED
- self._callback = None
-
- def toString(self) -> str:
- return f"StreamingService(serviceId={self._service_id}, state={self._state})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# StreamingServiceCallback
-# ═══════════════════════════════════════════════════════════════
-
-class StreamingServiceCallback(Stub):
- """StreamingServiceCallback — MBMS 流媒体服务回调"""
-
- SIGNAL_STRENGTH_UNKNOWN = 0
- SIGNAL_STRENGTH_POOR = 1
- SIGNAL_STRENGTH_MODERATE = 2
- SIGNAL_STRENGTH_GOOD = 3
- SIGNAL_STRENGTH_GREAT = 4
-
- def onStreamStateUpdated(self, state: int, reason: int):
- """流状态更新回调"""
- pass
-
- def onMediaDescriptionUpdated(self):
- """媒体描述更新回调"""
- pass
-
- def onBroadcastSignalStrengthUpdated(self, signal_strength: int):
- """广播信号强度更新回调"""
- pass
-
- def onStreamMethodUpdated(self, broadcast_method: int):
- """流方法更新回调"""
- pass
-
- def onError(self, error_code: int, message: str = ""):
- """错误回调"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# DownloadProgressListener
-# ═══════════════════════════════════════════════════════════════
-
-class DownloadProgressListener(Stub):
- """DownloadProgressListener — MBMS 下载进度监听器"""
-
- def onProgressUpdated(self, request: DownloadRequest, info: FileInfo,
- current_bytes: int, total_bytes: int, current_files: int,
- total_files: int):
- """下载进度更新回调"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# DownloadRequestListener
-# ═══════════════════════════════════════════════════════════════
-
-class DownloadRequestListener(Stub):
- """DownloadRequestListener — MBMS 下载请求监听器"""
-
- def onProgressUpdated(self, request: DownloadRequest, info: FileInfo,
- current_bytes: int, total_bytes: int, current_files: int,
- total_files: int):
- pass
-
- def onDownloadStateChanged(self, request: DownloadRequest, state: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsDownloadSession (pre-API 30)
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsDownloadSession(Stub):
- """MbmsDownloadSession — MBMS 下载会话 (旧版 API)"""
-
- EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.mbms.extra.MBMS_DOWNLOAD_RESULT"
- EXTRA_MBMS_DOWNLOAD_REQUEST = "android.telephony.mbms.extra.MBMS_DOWNLOAD_REQUEST"
- EXTRA_MBMS_FILE_INFO = "android.telephony.mbms.extra.MBMS_FILE_INFO"
- EXTRA_MBMS_COMPLETED_FILES = "android.telephony.mbms.extra.MBMS_COMPLETED_FILES"
-
- RESULT_SUCCESSFUL_DOWNLOAD = 0
- RESULT_EXPIRED_CHARGES = 1
- RESULT_FILE_UNAVAILABLE = 2
- RESULT_IO_ERROR = 3
- RESULT_OUT_OF_STORAGE = 4
- RESULT_SERVICE_NOT_DOWNLOAD = 5
- RESULT_DOWNLOAD_NOT_STARTED = 6
- RESULT_FILE_NOT_FOUND = 7
- RESULT_FILE_IN_PROGRESS = 8
- RESULT_FILE_ALREADY_DOWNLOADED = 9
- RESULT_MALFORMED_URI = 10
- RESULT_CANCELLED = 11
- RESULT_INTERRUPTED = 12
- RESULT_TIMEOUT = 13
- RESULT_SERVICE_UNAVAILABLE = 14
- RESULT_MEDIA_NOT_FOUND = 15
- RESULT_MEDIA_FAILED = 16
- RESULT_ERROR_RADIO_OFF = 17
- RESULT_ERROR_OUT_OF_MEMORY = 18
-
- _instance_map: Dict[int, MbmsDownloadSession] = {}
-
- def __init__(self, context: Any = None, subscription_id: int = 0,
- callback: Any = None):
- super().__init__()
- self._context = context
- self._subscription_id = subscription_id
- self._callback = callback
- self._middleware_bound = False
- self._download_requests: Dict[int, DownloadRequest] = {}
- self._file_services: Dict[str, FileServiceInfo] = {}
- self._temp_root: str = ""
-
- @staticmethod
- def create(context: Any, callback: Any,
- subscription_id: int = 0) -> MbmsDownloadSession:
- session = MbmsDownloadSession(context, subscription_id, callback)
- MbmsDownloadSession._instance_map[subscription_id] = session
- return session
-
- def requestUpdate(self, file_service_list: List[FileServiceInfo]):
- """请求更新文件服务列表"""
- pass
-
- def download(self, request: DownloadRequest):
- """开始下载"""
- request_id = int(time.time() * 1000)
- request.setRequestId(request_id)
- self._download_requests[request_id] = request
-
- def cancelDownload(self, download_request: DownloadRequest):
- """取消下载"""
- rid = download_request.getRequestId()
- if rid in self._download_requests:
- del self._download_requests[rid]
-
- def getCurrentPendingDownloadRequests(self) -> List[DownloadRequest]:
- """获取当前待处理的下载请求"""
- return list(self._download_requests.values())
-
- def getTempFileRoot(self) -> str:
- """获取临时文件根目录"""
- return self._temp_root
-
- def setTempFileRoot(self, temp_root: str, storage_type: int):
- """设置临时文件根目录"""
- self._temp_root = temp_root
-
- def getMiddlewareVersion(self) -> int:
- """获取中间件版本"""
- return 0
-
- def getSubscriptionId(self) -> int:
- return self._subscription_id
-
- def close(self):
- """关闭会话"""
- self._download_requests.clear()
- self._file_services.clear()
-
- @staticmethod
- def getDownloadStatus(context: Any, subscription_id: int,
- download_request: DownloadRequest) -> int:
- return DownloadRequest.DOWNLOAD_STATUS_INACTIVE
-
- def getFileServices(self) -> Dict[str, FileServiceInfo]:
- return dict(self._file_services)
-
- def getName(self) -> str:
- return "MbmsDownloadSession"
-
- def toString(self) -> str:
- return f"MbmsDownloadSession(subId={self._subscription_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsStreamingSession (pre-API 30)
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsStreamingSession(Stub):
- """MbmsStreamingSession — MBMS 流媒体会话 (旧版 API)"""
-
- EXTRA_MBMS_STREAMING_SERVICE = "android.telephony.mbms.extra.MBMS_STREAMING_SERVICE"
- EXTRA_MBMS_STREAMING_SERVICE_INFO = "android.telephony.mbms.extra.MBMS_STREAMING_SERVICE_INFO"
-
- _instance_map: Dict[int, MbmsStreamingSession] = {}
-
- def __init__(self, context: Any = None, subscription_id: int = 0,
- callback: Any = None):
- super().__init__()
- self._context = context
- self._subscription_id = subscription_id
- self._callback = callback
- self._middleware_bound = False
- self._streaming_services: Dict[str, StreamingService] = {}
-
- @staticmethod
- def create(context: Any, callback: Any,
- subscription_id: int = 0) -> MbmsStreamingSession:
- session = MbmsStreamingSession(context, subscription_id, callback)
- MbmsStreamingSession._instance_map[subscription_id] = session
- return session
-
- def startStreaming(self, service_info: FileServiceInfo,
- callback: StreamingServiceCallback) -> StreamingService:
- """开始流媒体"""
- service = StreamingService(service_info.getServiceId(),
- service_info.getServiceClass())
- service.setCallback(callback)
- self._streaming_services[service_info.getServiceId()] = service
- return service
-
- def stopStreaming(self, streaming_service: StreamingService):
- """停止流媒体"""
- sid = streaming_service.getServiceId()
- if sid in self._streaming_services:
- streaming_service.stop()
- del self._streaming_services[sid]
-
- def requestUpdate(self, file_service_list: List[FileServiceInfo]):
- """请求更新服务列表"""
- pass
-
- def getCurrentStreamingServices(self) -> List[StreamingService]:
- """获取当前流媒体服务"""
- return list(self._streaming_services.values())
-
- def getMiddlewareVersion(self) -> int:
- return 0
-
- def getSubscriptionId(self) -> int:
- return self._subscription_id
-
- def close(self):
- """关闭会话"""
- for service in self._streaming_services.values():
- service.close()
- self._streaming_services.clear()
-
- def getName(self) -> str:
- return "MbmsStreamingSession"
-
- def toString(self) -> str:
- return f"MbmsStreamingSession(subId={self._subscription_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsDownloadManager (API 30+)
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsDownloadManager(Stub):
- """MbmsDownloadManager — MBMS 下载管理器 (API 30+)"""
-
- EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.mbms.extra.MBMS_DOWNLOAD_RESULT"
- EXTRA_MBMS_DOWNLOAD_REQUEST = "android.telephony.mbms.extra.MBMS_DOWNLOAD_REQUEST"
- EXTRA_MBMS_FILE_INFO = "android.telephony.mbms.extra.MBMS_FILE_INFO"
- EXTRA_MBMS_COMPLETED_FILES = "android.telephony.mbms.extra.MBMS_COMPLETED_FILES"
-
- # 下载结果码
- DOWNLOAD_RESULT_SUCCESS = 0
- DOWNLOAD_RESULT_ERROR = 1
- DOWNLOAD_RESULT_ERROR_MEDIA_NOT_FOUND = 2
- DOWNLOAD_RESULT_ERROR_MEDIA_UNAVAILABLE = 3
- DOWNLOAD_RESULT_ERROR_MEDIA_FAILED = 4
- DOWNLOAD_RESULT_ERROR_SERVICE_UNAVAILABLE = 5
- DOWNLOAD_RESULT_ERROR_INSUFFICIENT_STORAGE = 6
- DOWNLOAD_RESULT_ERROR_IO_ERROR = 7
- DOWNLOAD_RESULT_ERROR_FILE_NOT_FOUND = 8
- DOWNLOAD_RESULT_ERROR_OUT_OF_MEMORY = 9
- DOWNLOAD_RESULT_ERROR_RADIO_OFF = 10
- DOWNLOAD_RESULT_ERROR_INTERRUPTED = 11
- DOWNLOAD_RESULT_ERROR_TIMEOUT = 12
- DOWNLOAD_RESULT_ERROR_CANCELLED = 13
- DOWNLOAD_RESULT_ERROR_DOWNLOAD_NOT_STARTED = 14
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._download_requests: Dict[int, DownloadRequest] = {}
- self._file_services: Dict[str, FileServiceInfo] = {}
- self._listeners: List[DownloadStatusListener] = []
- self._progress_listeners: List[DownloadProgressListener] = []
-
- @staticmethod
- def getService(context: Any, sub_id: int = 0) -> Optional[MbmsDownloadManager]:
- return MbmsDownloadManager(context)
-
- def addDownloadRequest(self, download_request: DownloadRequest):
- """添加下载请求"""
- request_id = len(self._download_requests) + 1
- download_request.setRequestId(request_id)
- self._download_requests[request_id] = download_request
-
- def removeDownloadRequest(self, download_request: DownloadRequest):
- """移除下载请求"""
- rid = download_request.getRequestId()
- self._download_requests.pop(rid, None)
-
- def getCurrentDownloadRequests(self) -> List[DownloadRequest]:
- """获取当前所有下载请求"""
- return list(self._download_requests.values())
-
- def getPendingDownloadRequests(self) -> List[DownloadRequest]:
- """获取待处理的下载请求"""
- return [r for r in self._download_requests.values()
- if r.getHash() == ""]
-
- def getCompletedDownloadRequests(self) -> List[DownloadRequest]:
- """获取已完成的下载请求"""
- return [r for r in self._download_requests.values()
- if r.getHash() != ""]
-
- def addStatusListener(self, listener: DownloadStatusListener):
- """添加状态监听器"""
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeStatusListener(self, listener: DownloadStatusListener):
- """移除状态监听器"""
- self._listeners = [l for l in self._listeners if l is not listener]
-
- def addProgressListener(self, listener: DownloadProgressListener):
- """添加进度监听器"""
- if listener not in self._progress_listeners:
- self._progress_listeners.append(listener)
-
- def removeProgressListener(self, listener: DownloadProgressListener):
- """移除进度监听器"""
- self._progress_listeners = [l for l in self._progress_listeners
- if l is not listener]
-
- def getMaxDownloadRequests(self) -> int:
- """获取最大下载请求数"""
- return 100
-
- def getFileServices(self) -> Dict[str, FileServiceInfo]:
- return dict(self._file_services)
-
- def setTempFileRoot(self, temp_root: str, storage_type: int):
- """设置临时文件根目录"""
- pass
-
- def getTempFileRoot(self) -> str:
- return ""
-
- def getMiddlewareVersion(self) -> int:
- return 0
-
- def close(self):
- """关闭下载管理器"""
- self._download_requests.clear()
- self._listeners.clear()
- self._progress_listeners.clear()
-
- def toString(self) -> str:
- return f"MbmsDownloadManager(requests={len(self._download_requests)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsStreamingManager (API 30+)
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsStreamingManager(Stub):
- """MbmsStreamingManager — MBMS 流媒体管理器 (API 30+)"""
-
- EXTRA_MBMS_STREAMING_SERVICE_INFO = "android.telephony.mbms.extra.MBMS_STREAMING_SERVICE_INFO"
-
- STREAMING_SERVICE_STATE_STOPPED = 0
- STREAMING_SERVICE_STATE_STARTED = 1
- STREAMING_SERVICE_STATE_STALLED = 2
- STREAMING_SERVICE_STATE_PENDING = 3
- STREAMING_SERVICE_STATE_ERROR = 4
-
- BROADCAST_METHOD_UNICAST = 0
- BROADCAST_METHOD_MULTICAST = 1
- BROADCAST_METHOD_BROADCAST = 2
-
- REASON_BY_USER_REQUEST = 1
- REASON_BY_MIDDLEWARE = 2
- REASON_BY_RADIO_RESOURCE = 3
- REASON_BY_OUT_OF_MEMORY = 4
- REASON_BY_SIGNAL_LOST = 5
- REASON_BY_TEMPORARILY_UNAVAILABLE = 6
- REASON_BY_PERMANENTLY_UNAVAILABLE = 7
- REASON_BY_SERVICE_SHUTDOWN = 8
- REASON_BY_SERVICE_NOT_VISIBLE = 9
- REASON_BY_RADIO_NOT_AVAILABLE = 10
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._streaming_services: Dict[str, StreamingService] = {}
- self._service_info_map: Dict[str, FileServiceInfo] = {}
-
- @staticmethod
- def getService(context: Any, sub_id: int = 0) -> Optional[MbmsStreamingManager]:
- return MbmsStreamingManager(context)
-
- def startStreaming(self, service_info: FileServiceInfo,
- callback: StreamingServiceCallback) -> StreamingService:
- """启动流媒体服务"""
- service = StreamingService(service_info.getServiceId(),
- service_info.getServiceClass())
- service.setCallback(callback)
- self._streaming_services[service_info.getServiceId()] = service
- self._service_info_map[service_info.getServiceId()] = service_info
- return service
-
- def stopStreaming(self, streaming_service: StreamingService):
- """停止流媒体服务"""
- sid = streaming_service.getServiceId()
- if sid in self._streaming_services:
- streaming_service.stop()
- del self._streaming_services[sid]
-
- def getCurrentStreamingServices(self) -> List[StreamingService]:
- return list(self._streaming_services.values())
-
- def getServiceInfoForStreamingService(self, service: StreamingService) -> Optional[FileServiceInfo]:
- return self._service_info_map.get(service.getServiceId())
-
- def getMaxStreamingServices(self) -> int:
- return 10
-
- def getMiddlewareVersion(self) -> int:
- return 0
-
- def close(self):
- """关闭流媒体管理器"""
- for service in self._streaming_services.values():
- service.close()
- self._streaming_services.clear()
- self._service_info_map.clear()
-
- def toString(self) -> str:
- return f"MbmsStreamingManager(services={len(self._streaming_services)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsUtils
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsUtils(Stub):
- """MbmsUtils — MBMS 工具类"""
-
- @staticmethod
- def getCellBroadcastServiceInfo(context: Any,
- service_id: str,
- subscription_id: int) -> Optional[FileServiceInfo]:
- """获取小区广播服务信息"""
- return None
-
- @staticmethod
- def isFileService(service_announcement: Any) -> bool:
- """判断是否为文件服务"""
- return True
-
- @staticmethod
- def isStreamingService(service_announcement: Any) -> bool:
- """判断是否为流媒体服务"""
- return True
-
- @staticmethod
- def getServiceClassFromServiceAnnouncement(service_announcement: Any) -> Optional[str]:
- """从服务公告中获取服务类"""
- return None
-
- @staticmethod
- def getServiceIdFromServiceAnnouncement(service_announcement: Any) -> Optional[str]:
- """从服务公告中获取服务 ID"""
- return None
-
- @staticmethod
- def getFileInfoFromFileService(service_info: FileServiceInfo) -> List[FileInfo]:
- """从文件服务信息中获取文件信息列表"""
- return service_info.getFiles()
-
- @staticmethod
- def createDownloadRequest(service_id: str, file_uri: str,
- source: Any, destination: Any) -> DownloadRequest:
- """创建下载请求"""
- return DownloadRequest(service_id, file_uri, source, destination)
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsGroupCallService
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsGroupCallService(Stub):
- """MbmsGroupCallService — MBMS 组呼服务"""
-
- REASON_BY_USER_REQUEST = 1
- REASON_BY_MIDDLEWARE = 2
- REASON_BY_RADIO_RESOURCE = 3
- REASON_BY_OUT_OF_MEMORY = 4
- REASON_BY_SIGNAL_LOST = 5
- REASON_BY_TEMPORARILY_UNAVAILABLE = 6
- REASON_BY_PERMANENTLY_UNAVAILABLE = 7
- REASON_BY_SERVICE_SHUTDOWN = 8
- REASON_BY_SERVICE_NOT_VISIBLE = 9
- REASON_BY_RADIO_NOT_AVAILABLE = 10
-
- STATE_STOPPED = 0
- STATE_STARTED = 1
- STATE_STALLED = 2
- STATE_PENDING = 3
- STATE_ERROR = 4
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._group_calls: Dict[str, Any] = {}
-
- @staticmethod
- def getService(context: Any, sub_id: int = 0) -> Optional[MbmsGroupCallService]:
- return MbmsGroupCallService(context)
-
- def startGroupCall(self, service_id: str, sai_list: List[int],
- frequency: int, tmgi: Any, callback: Any):
- """启动组呼"""
- pass
-
- def stopGroupCall(self, service_id: str):
- """停止组呼"""
- self._group_calls.pop(service_id, None)
-
- def getCurrentGroupCalls(self) -> List[Any]:
- return list(self._group_calls.values())
-
- def close(self):
- self._group_calls.clear()
-
- def toString(self) -> str:
- return f"MbmsGroupCallService(calls={len(self._group_calls)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsDownloadSessionCallback
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsDownloadSessionCallback(Stub):
- """MbmsDownloadSessionCallback — MBMS 下载会话回调"""
-
- def onError(self, error_code: int, message: str = ""):
- pass
-
- def onFileServicesUpdated(self, services: List[FileServiceInfo]):
- pass
-
- def onMiddlewareReady(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsStreamingSessionCallback
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsStreamingSessionCallback(Stub):
- """MbmsStreamingSessionCallback — MBMS 流媒体会话回调"""
-
- def onError(self, error_code: int, message: str = ""):
- pass
-
- def onStreamingServicesUpdated(self, services: List[FileServiceInfo]):
- pass
-
- def onMiddlewareReady(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ServiceAnnouncement
-# ═══════════════════════════════════════════════════════════════
-
-class ServiceAnnouncement(Stub):
- """ServiceAnnouncement — MBMS 服务公告"""
-
- def __init__(self, service_id: str = "", service_class: str = "",
- announcement_data: bytes = b""):
- super().__init__()
- self._service_id = service_id
- self._service_class = service_class
- self._announcement_data = announcement_data
- self._sais: List[int] = []
- self._cells: List[int] = []
- self._expiry_time: int = 0
-
- def getServiceId(self) -> str:
- return self._service_id
-
- def getServiceClass(self) -> str:
- return self._service_class
-
- def getAnnouncementData(self) -> bytes:
- return self._announcement_data
-
- def getSais(self) -> List[int]:
- return list(self._sais)
-
- def setSais(self, sais: List[int]):
- self._sais = list(sais)
-
- def getCells(self) -> List[int]:
- return list(self._cells)
-
- def setCells(self, cells: List[int]):
- self._cells = list(cells)
-
- def getExpiryTime(self) -> int:
- return self._expiry_time
-
- def setExpiryTime(self, expiry: int):
- self._expiry_time = expiry
-
- def toString(self) -> str:
- return f"ServiceAnnouncement(serviceId={self._service_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# InternalDownloadSession (helper)
-# ═══════════════════════════════════════════════════════════════
-
-class InternalDownloadSession(Stub):
- """InternalDownloadSession — 内部下载会话辅助类"""
-
- def __init__(self):
- super().__init__()
- self._session_id: int = 0
- self._active: bool = False
- self._downloads: Dict[int, DownloadRequest] = {}
-
- def getSessionId(self) -> int:
- return self._session_id
-
- def setSessionId(self, session_id: int):
- self._session_id = session_id
-
- def isActive(self) -> bool:
- return self._active
-
- def setActive(self, active: bool):
- self._active = active
-
- def addDownload(self, request: DownloadRequest):
- self._downloads[request.getRequestId()] = request
-
- def removeDownload(self, request_id: int):
- self._downloads.pop(request_id, None)
-
- def getDownloads(self) -> List[DownloadRequest]:
- return list(self._downloads.values())
-
- def clear(self):
- self._downloads.clear()
- self._active = False
-
- def toString(self) -> str:
- return f"InternalDownloadSession(id={self._session_id}, active={self._active})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MbmsResourceUtils
-# ═══════════════════════════════════════════════════════════════
-
-class MbmsResourceUtils(Stub):
- """MbmsResourceUtils — MBMS 资源工具"""
-
- @staticmethod
- def getServiceIdList(services: List[FileServiceInfo]) -> List[str]:
- return [s.getServiceId() for s in services]
-
- @staticmethod
- def getServiceNameList(services: List[FileServiceInfo]) -> List[str]:
- return [s.getServiceClass() for s in services]
-
- @staticmethod
- def findServiceById(services: List[FileServiceInfo],
- service_id: str) -> Optional[FileServiceInfo]:
- for s in services:
- if s.getServiceId() == service_id:
- return s
- return None
-
- @staticmethod
- def mergeServiceLists(a: List[FileServiceInfo],
- b: List[FileServiceInfo]) -> List[FileServiceInfo]:
- merged = {s.getServiceId(): s for s in a}
- for s in b:
- merged[s.getServiceId()] = s
- return list(merged.values())
\ No newline at end of file
diff --git a/android_pyapi/android/test.py b/android_pyapi/android/test.py
deleted file mode 100644
index e730422..0000000
--- a/android_pyapi/android/test.py
+++ /dev/null
@@ -1,485 +0,0 @@
-"""
-Android Test 组件 — InstrumentationTestRunner, InstrumentationTestCase,
-ActivityInstrumentationTestCase2, ActivityUnitTestCase, ServiceTestCase,
-ProviderTestCase2, ApplicationTestCase, Instrumentation 等
-方法签名完全对齐 Android SDK (android.test 包)
-"""
-
-import os
-import sys
-import time
-import threading
-from typing import Any, Callable, Dict, List, Optional, Tuple, Type
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# Instrumentation
-# ═══════════════════════════════════════════════════════════════
-
-class Instrumentation(Stub):
- """Instrumentation — 测试仪器 (桌面版)"""
-
- # 报告标志
- REPORT_KEY_IDENTIFIER = "id"
- REPORT_KEY_STREAM_RESULTS = "stream"
-
- def __init__(self):
- super().__init__()
- self._context: Optional[Any] = None
- self._target_context: Optional[Any] = None
- self._started = False
- self._finished = False
- self._automatic_performance_snapshots = False
- self._instr_result: Dict[str, Any] = {}
-
- def onCreate(self, arguments: Any):
- """创建仪器"""
- self._started = True
-
- def onStart(self):
- """启动仪器"""
- pass
-
- def onDestroy(self):
- """销毁仪器"""
- self._finished = True
-
- def getContext(self) -> Optional[Any]:
- """获取上下文"""
- return self._context
-
- def getTargetContext(self) -> Optional[Any]:
- """获取目标上下文"""
- return self._target_context
-
- def setContext(self, context: Any):
- self._context = context
-
- def setTargetContext(self, target_context: Any):
- self._target_context = target_context
-
- def startActivitySync(self, intent: Any) -> Any:
- """同步启动 Activity"""
- return None
-
- def sendKeySync(self, key_event: Any):
- """发送按键事件"""
- pass
-
- def sendCharacterSync(self, character: int):
- """发送字符事件"""
- pass
-
- def sendStringSync(self, text: str):
- """发送字符串"""
- pass
-
- def sendPointerSync(self, motion_event: Any):
- """发送指针事件"""
- pass
-
- def sendTrackballEventSync(self, motion_event: Any):
- """发送轨迹球事件"""
- pass
-
- def runOnMainSync(self, runner: Callable):
- """在主线程上同步运行"""
- runner()
-
- def waitForIdle(self):
- """等待空闲"""
- pass
-
- def waitForIdleSync(self):
- """同步等待空闲"""
- pass
-
- def callActivityOnCreate(self, activity: Any, icicle: Any):
- """调用 Activity.onCreate"""
- if hasattr(activity, 'onCreate'):
- activity.onCreate(icicle)
-
- def callActivityOnStart(self, activity: Any):
- """调用 Activity.onStart"""
- if hasattr(activity, 'onStart'):
- activity.onStart()
-
- def callActivityOnResume(self, activity: Any):
- """调用 Activity.onResume"""
- if hasattr(activity, 'onResume'):
- activity.onResume()
-
- def callActivityOnPause(self, activity: Any):
- """调用 Activity.onPause"""
- if hasattr(activity, 'onPause'):
- activity.onPause()
-
- def callActivityOnStop(self, activity: Any):
- """调用 Activity.onStop"""
- if hasattr(activity, 'onStop'):
- activity.onStop()
-
- def callActivityOnDestroy(self, activity: Any):
- """调用 Activity.onDestroy"""
- if hasattr(activity, 'onDestroy'):
- activity.onDestroy()
-
- def callActivityOnRestart(self, activity: Any):
- """调用 Activity.onRestart"""
- if hasattr(activity, 'onRestart'):
- activity.onRestart()
-
- def isProfiling(self) -> bool:
- return False
-
- def startProfiling(self):
- pass
-
- def stopProfiling(self):
- pass
-
- def setInTouchMode(self, in_touch: bool):
- pass
-
- def finish(self, result_code: int, results: Any = None):
- """完成测试"""
- self._finished = True
- if results:
- self._instr_result.update(results)
-
- def getComponentName(self) -> Any:
- return None
-
- def getUiAutomation(self) -> Any:
- return None
-
- def toString(self) -> str:
- return (f"Instrumentation(started={self._started}, "
- f"finished={self._finished})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# InstrumentationTestRunner
-# ═══════════════════════════════════════════════════════════════
-
-class InstrumentationTestRunner(Stub):
- """InstrumentationTestRunner — 仪器化测试运行器"""
-
- REPORT_KEY_NAME = "name"
- REPORT_KEY_CLASS = "class"
- REPORT_KEY_TEST = "test"
- REPORT_KEY_NUM_TOTAL = "numtests"
- REPORT_KEY_NUM_CURRENT = "current"
- REPORT_KEY_NUM_ITERATIONS = "numiterations"
-
- def __init__(self):
- super().__init__()
- self._instrumentation = Instrumentation()
- self._test_results: List[Dict[str, Any]] = []
-
- def onCreate(self, arguments: Any):
- """创建测试运行器"""
- self._instrumentation.onCreate(arguments)
-
- def onStart(self):
- """开始测试"""
- self._instrumentation.onStart()
-
- def onDestroy(self):
- """销毁"""
- self._instrumentation.onDestroy()
-
- def getInstrumentation(self) -> Instrumentation:
- return self._instrumentation
-
- def runTest(self, test_case: Any):
- """运行测试用例"""
- try:
- if hasattr(test_case, 'setUp'):
- test_case.setUp()
- if hasattr(test_case, 'runTest'):
- test_case.runTest()
- if hasattr(test_case, 'tearDown'):
- test_case.tearDown()
- self._test_results.append({"success": True, "test": str(test_case)})
- except Exception as e:
- self._test_results.append({
- "success": False, "test": str(test_case), "error": str(e),
- })
-
- def getTestResults(self) -> List[Dict[str, Any]]:
- return list(self._test_results)
-
- def toString(self) -> str:
- return (f"InstrumentationTestRunner("
- f"results={len(self._test_results)})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
-
-# ═══════════════════════════════════════════════════════════════
-# InstrumentationTestCase
-# ═══════════════════════════════════════════════════════════════
-
-class InstrumentationTestCase(Stub):
- """InstrumentationTestCase — 仪器化测试用例基类"""
-
- def __init__(self):
- super().__init__()
- self._instrumentation: Optional[Instrumentation] = None
- self._test_name: str = ""
-
- def injectInstrumentation(self, instrumentation: Instrumentation):
- """注入仪器"""
- self._instrumentation = instrumentation
-
- def getInstrumentation(self) -> Optional[Instrumentation]:
- return self._instrumentation
-
- def setUp(self):
- """测试前准备"""
- pass
-
- def tearDown(self):
- """测试后清理"""
- pass
-
- def runTest(self):
- """执行测试"""
- pass
-
- def sendKeys(self, *keys: str):
- """发送按键"""
- pass
-
- def touchDown(self, view: Any, x: float, y: float):
- """触摸按下"""
- pass
-
- def touchUp(self, view: Any, x: float, y: float):
- """触摸抬起"""
- pass
-
- def touchAndHold(self, view: Any, x: float, y: float):
- """触摸并按住"""
- pass
-
- def click(self, view: Any):
- """点击"""
- pass
-
- def typeText(self, view: Any, text: str):
- """输入文本"""
- pass
-
- def assertActivityRequiresFeature(self, activity_class: Any,
- feature: str) -> bool:
- return True
-
- def toString(self) -> str:
- return f"InstrumentationTestCase(name={self._test_name})"
-
- def hashCode(self) -> int:
- return hash(self._test_name) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, InstrumentationTestCase):
- return False
- return self._test_name == other._test_name
-
-
-# ═══════════════════════════════════════════════════════════════
-# ActivityInstrumentationTestCase2
-# ═══════════════════════════════════════════════════════════════
-
-class ActivityInstrumentationTestCase2(InstrumentationTestCase):
- """ActivityInstrumentationTestCase2 — Activity 测试用例"""
-
- def __init__(self, pkg: str, activity_class: Type):
- super().__init__()
- self._pkg = pkg
- self._activity_class = activity_class
- self._activity: Optional[Any] = None
-
- def setActivityIntent(self, intent: Any):
- """设置 Activity Intent"""
- pass
-
- def getActivity(self) -> Optional[Any]:
- """获取 Activity 实例"""
- return self._activity
-
- def testActivityCreated(self) -> bool:
- return self._activity is not None
-
- def testActivityResumed(self) -> bool:
- return self._activity is not None
-
- def testActivityStarted(self) -> bool:
- return self._activity is not None
-
- def toString(self) -> str:
- return (f"ActivityInstrumentationTestCase2("
- f"pkg={self._pkg}, cls={self._activity_class})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ActivityUnitTestCase
-# ═══════════════════════════════════════════════════════════════
-
-class ActivityUnitTestCase(InstrumentationTestCase):
- """ActivityUnitTestCase — Activity 单元测试"""
-
- def __init__(self, activity_class: Type):
- super().__init__()
- self._activity_class = activity_class
- self._activity: Optional[Any] = None
-
- def setActivityContext(self, context: Any):
- """设置 Activity 上下文"""
- if self._activity and hasattr(self._activity, 'setContext'):
- self._activity.setContext(context)
-
- def setApplication(self, application: Any):
- """设置 Application"""
- if self._activity and hasattr(self._activity, 'setApplication'):
- self._activity.setApplication(application)
-
- def getActivity(self) -> Optional[Any]:
- return self._activity
-
- def startActivity(self, intent: Any, bundle: Any = None,
- last_non_config_instance: Any = None) -> Any:
- """启动 Activity"""
- return self._activity
-
- def toString(self) -> str:
- return f"ActivityUnitTestCase(cls={self._activity_class})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ServiceTestCase
-# ═══════════════════════════════════════════════════════════════
-
-class ServiceTestCase(InstrumentationTestCase):
- """ServiceTestCase — Service 测试用"""
-
- def __init__(self, service_class: Type):
- super().__init__()
- self._service_class = service_class
- self._service: Optional[Any] = None
- self._service_binder: Optional[Any] = None
- self._service_created = False
-
- def getService(self) -> Optional[Any]:
- return self._service
-
- def bindService(self, intent: Any) -> Any:
- """绑定 Service"""
- return self._service_binder
-
- def bindServiceNotNeeded(self):
- """Service 不需要绑定"""
- pass
-
- def setService(self, service: Any):
- self._service = service
-
- def testServiceCreated(self) -> bool:
- return self._service_created
-
- def testServiceBound(self) -> bool:
- return self._service_binder is not None
-
- def testServiceStarted(self) -> bool:
- return self._service is not None
-
- def testServiceStopped(self) -> bool:
- return not self._service_created
-
- def toString(self) -> str:
- return f"ServiceTestCase(cls={self._service_class})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ProviderTestCase2
-# ═══════════════════════════════════════════════════════════════
-
-class ProviderTestCase2(InstrumentationTestCase):
- """ProviderTestCase2 — ContentProvider 测试用例"""
-
- def __init__(self, provider_class: Type, provider_authority: str):
- super().__init__()
- self._provider_class = provider_class
- self._provider_authority = provider_authority
- self._provider: Optional[Any] = None
- self._resolver: Optional[Any] = None
-
- def getProvider(self) -> Optional[Any]:
- return self._provider
-
- def getMockContentResolver(self) -> Optional[Any]:
- return self._resolver
-
- def setProvider(self, provider: Any):
- self._provider = provider
-
- def setMockContentResolver(self, resolver: Any):
- self._resolver = resolver
-
- def toString(self) -> str:
- return (f"ProviderTestCase2(cls={self._provider_class}, "
- f"authority={self._provider_authority})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ApplicationTestCase
-# ═══════════════════════════════════════════════════════════════
-
-class ApplicationTestCase(InstrumentationTestCase):
- """ApplicationTestCase — Application 测试用例"""
-
- def __init__(self, application_class: Type):
- super().__init__()
- self._application_class = application_class
- self._application: Optional[Any] = None
-
- def getApplication(self) -> Optional[Any]:
- return self._application
-
- def setApplication(self, application: Any):
- self._application = application
-
- def testApplicationCreated(self) -> bool:
- return self._application is not None
-
- def toString(self) -> str:
- return f"ApplicationTestCase(cls={self._application_class})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "InstrumentationTestRunner",
- "InstrumentationTestCase",
- "ActivityInstrumentationTestCase2",
- "ActivityUnitTestCase",
- "ServiceTestCase",
- "ProviderTestCase2",
- "ApplicationTestCase",
- "Instrumentation",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/text.py b/android_pyapi/android/text.py
deleted file mode 100644
index d4ac87d..0000000
--- a/android_pyapi/android/text.py
+++ /dev/null
@@ -1,1167 +0,0 @@
-"""
-Android Text 组件 — TextUtils, SpannableString, Html, Layout 等
-方法签名完全对齐 Android SDK
-"""
-
-import html as _html
-import re as _re
-import sys
-from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, Union
-from urllib.parse import quote_plus as _quote_plus, unquote_plus as _unquote_plus
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Typeface
-# ═══════════════════════════════════════════════════════════════
-
-class Typeface(Stub):
- """Typeface — 字体"""
-
- NORMAL = 0
- BOLD = 1
- ITALIC = 2
- BOLD_ITALIC = 3
-
- DEFAULT: "Typeface" = None
- DEFAULT_BOLD: "Typeface" = None
- MONOSPACE: "Typeface" = None
- SANS_SERIF: "Typeface" = None
- SERIF: "Typeface" = None
-
- def __init__(self, family_name: str = "", style: int = NORMAL):
- super().__init__()
- self._family_name = family_name
- self._style = style
- self._weight = 400 if style in (self.NORMAL,) else 700
-
- @staticmethod
- def defaultFromStyle(style: int) -> "Typeface":
- tf = Typeface("sans-serif", style)
- return tf
-
- @staticmethod
- def create(family_name: str, style: int) -> "Typeface":
- return Typeface(family_name, style)
-
- @staticmethod
- def createFromFile(path: str) -> "Typeface":
- return Typeface("custom")
-
- def getStyle(self) -> int:
- return self._style
-
- def getWeight(self) -> int:
- return self._weight
-
- def isBold(self) -> bool:
- return self._style in (self.BOLD, self.BOLD_ITALIC)
-
- def isItalic(self) -> bool:
- return self._style in (self.ITALIC, self.BOLD_ITALIC)
-
- def toString(self) -> str:
- return f"Typeface({self._family_name}, style={self._style})"
-
-
-# Initialize Typeface constants
-Typeface.DEFAULT = Typeface("sans-serif", Typeface.NORMAL)
-Typeface.DEFAULT_BOLD = Typeface("sans-serif", Typeface.BOLD)
-Typeface.MONOSPACE = Typeface("monospace", Typeface.NORMAL)
-Typeface.SANS_SERIF = Typeface("sans-serif", Typeface.NORMAL)
-Typeface.SERIF = Typeface("serif", Typeface.NORMAL)
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextPaint
-# ═══════════════════════════════════════════════════════════════
-
-class TextPaint(Stub):
- """TextPaint — 文本绘制画笔"""
-
- def __init__(self, flags: int = 0):
- super().__init__()
- self.bgColor = 0
- self.bgColorSet = False
- self.linkColor = 0xFF0000FF # blue
- self.underlineWidth = 0.0
- self.baselineShift = 0
- self.bulletRadius = 0.0
- self.bulletGap = 0
- self.bulletColor = 0
- self.color = 0xFF000000
- self.textSize = 14.0
- self.typeface: Optional[Typeface] = Typeface.DEFAULT
- self.flags = flags
- self.antiAlias = True
- self.style = Typeface.NORMAL
- self.strokeWidth = 0.0
- self.strokeCap = "butt"
- self.strokeJoin = "miter"
- self.shadowDx = 0.0
- self.shadowDy = 0.0
- self.shadowRadius = 0.0
- self.shadowColor = 0
- self.elevation = 0.0
- self.letterSpacing = 0.0
- self.fontFeatureSettings = ""
- self.fontVariationSettings = ""
-
- def setUnderlineText(self, underline: bool):
- if underline:
- self.underlineWidth = 1.0
- else:
- self.underlineWidth = 0.0
-
- def getColor(self) -> int:
- return self.color
-
- def setColor(self, color: int):
- self.color = color
-
- def setARGB(self, a: int, r: int, g: int, b: int):
- self.color = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF)
-
- def getTextSize(self) -> float:
- return self.textSize
-
- def setTextSize(self, size: float):
- self.textSize = size
-
- def getTypeface(self) -> Optional[Typeface]:
- return self.typeface
-
- def setTypeface(self, tf: Typeface):
- self.typeface = tf
-
- def setAntiAlias(self, aa: bool):
- self.antiAlias = aa
-
- def measureText(self, text: str) -> float:
- return len(text) * self.textSize * 0.5
-
- def toString(self) -> str:
- return f"TextPaint(size={self.textSize}, color={self.color})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextUtils
-# ═══════════════════════════════════════════════════════════════
-
-class TextUtils(Stub):
- """TextUtils — 文本工具"""
-
- CAP_MODE_SENTENCES = 0
- CAP_MODE_WORDS = 1
- CAP_MODE_CHARACTERS = 2
-
- @staticmethod
- def isEmpty(str_: Optional[str]) -> bool:
- return str_ is None or len(str_) == 0
-
- @staticmethod
- def isBlank(str_: Optional[str]) -> bool:
- return str_ is None or str_.strip() == ""
-
- @staticmethod
- def equals(a: Optional[str], b: Optional[str]) -> bool:
- return a == b
-
- @staticmethod
- def join(delimiter: str, tokens: Sequence[str]) -> str:
- return delimiter.join(tokens)
-
- @staticmethod
- def split(text: str, delimiter: str) -> List[str]:
- if text is None or len(text) == 0:
- return []
- return _re.split(delimiter, text)
-
- @staticmethod
- def htmlEncode(s: str) -> str:
- return _html.escape(s, quote=True)
-
- @staticmethod
- def htmlDecode(s: str) -> str:
- return _html.unescape(s)
-
- @staticmethod
- def concat(*texts: Any) -> str:
- parts = []
- for t in texts:
- if t is not None:
- parts.append(str(t))
- return "".join(parts)
-
- @staticmethod
- def indexOf(s: Any, needle: Any, start: int = 0) -> int:
- if s is None:
- return -1
- s = str(s)
- needle = str(needle)
- if start < 0:
- start = 0
- return s.find(needle, start)
-
- @staticmethod
- def lastIndexOf(s: Any, needle: Any, last: Optional[int] = None) -> int:
- if s is None:
- return -1
- s = str(s)
- needle = str(needle)
- if last is None:
- return s.rfind(needle)
- if last < 0:
- return -1
- return s.rfind(needle, 0, last + 1)
-
- @staticmethod
- def urlEncode(s: str) -> str:
- if s is None:
- return ""
- return _quote_plus(str(s))
-
- @staticmethod
- def urlDecode(s: str) -> str:
- if s is None:
- return ""
- return _unquote_plus(str(s))
-
- @staticmethod
- def getReverse(s: str, start: int, end: int) -> str:
- return s[start:end][::-1]
-
- @staticmethod
- def substring(text: str, start: int, end: int) -> str:
- return text[start:end]
-
- @staticmethod
- def delimitedListToStringArray(text: str, delimiter: str, delimiter2: str = "") -> List[str]:
- if not text:
- return []
- return [t.strip() for t in text.split(delimiter)]
-
- @staticmethod
- def commaEllipsize(text: str, max_width: int, paint: Any,
- one_origin: bool = False, ellipsize: bool = False) -> str:
- if len(text) <= max_width:
- return text
- return text[:max_width] + "..."
-
- @staticmethod
- def ellipsize(text: str, paint: Any, avail: float,
- where: Any, ellipsis: str = "...") -> str:
- if paint and hasattr(paint, 'measureText'):
- text_width = paint.measureText(text)
- if text_width <= avail:
- return text
- max_chars = int(avail / 7) if avail else len(text) // 2
- if max_chars >= len(text):
- return text
- if str(where) == "END":
- return text[:max_chars] + ellipsis
- elif str(where) == "START":
- return ellipsis + text[-max_chars:]
- elif str(where) == "MIDDLE":
- half = max_chars // 2
- return text[:half] + ellipsis + text[-(max_chars - half):]
- return text[:max_chars] + ellipsis
-
- @staticmethod
- def isDigitsOnly(s: Any) -> bool:
- if s is None:
- return False
- s = str(s)
- if len(s) == 0:
- return False
- return s.isdigit()
-
- @staticmethod
- def isGraphical(s: str) -> bool:
- return bool(s and s.isprintable())
-
- @staticmethod
- def capitalize(s: str) -> str:
- return s.capitalize()
-
- @staticmethod
- def trim(s: str) -> str:
- return s.strip()
-
- @staticmethod
- def getTrimmedLength(s: str) -> int:
- return len(s.strip())
-
- @staticmethod
- def stringOrEmpty(s: Optional[str]) -> str:
- return s or ""
-
- @staticmethod
- def copySpansFrom(source: Any, start: int, end: int, kind: type,
- dest: Any, dest_offset: int = 0):
- pass
-
- @staticmethod
- def removeEmptySpans(spans: List, source: Any, kind: type) -> List:
- return [s for s in spans if s is not None]
-
- @staticmethod
- def expandTemplate(template: str, values: List[str]) -> str:
- result = template
- for i, v in enumerate(values):
- result = result.replace("$" + str(i + 1), v)
- return result
-
-
-# ═══════════════════════════════════════════════════════════════
-# Span 相关接口和基类
-# ═══════════════════════════════════════════════════════════════
-
-class Spanned(Stub):
- """Spanned 接口 — 带标记的字符串"""
-
- SPAN_POINT_MARK = 0
- SPAN_MARK_MARK = 1
- SPAN_POINT_POINT = 2
- SPAN_MARK_POINT = 3
- SPAN_PARAGRAPH = 3
- SPAN_INCLUSIVE_EXCLUSIVE = SPAN_MARK_POINT
- SPAN_INCLUSIVE_INCLUSIVE = SPAN_MARK_MARK
- SPAN_EXCLUSIVE_EXCLUSIVE = SPAN_POINT_POINT
- SPAN_EXCLUSIVE_INCLUSIVE = SPAN_POINT_MARK
- SPAN_COMPOSING = 256
- SPAN_USER = 0x01000000
- SPAN_USER_SHIFT = 24
- SPAN_PRIORITY = 0x0000FF00
- SPAN_PRIORITY_SHIFT = 8
- SPAN_INTERMEDIATE = 0x00100000
-
- def __init__(self, source: str = ""):
- super().__init__()
- self._source = source
- self._spans: Dict[Tuple[type, int], Tuple[int, int, int, Any]] = {} # (type, id) -> (start, end, flags, span_obj)
-
- def setSpan(self, span_obj: Any, start: int, end: int, flags: int):
- span_id = id(span_obj)
- span_type = type(span_obj)
- self._spans[(span_type, span_id)] = (start, end, flags, span_obj)
-
- def removeSpan(self, span_obj: Any):
- span_id = id(span_obj)
- span_type = type(span_obj)
- self._spans.pop((span_type, span_id), None)
-
- def getSpans(self, start: int, end: int, span_type: Optional[type] = None) -> List[Any]:
- collected = []
- for (st, sid), (s, e, flags, obj) in self._spans.items():
- if span_type is None or st == span_type:
- if s < end and e > start:
- collected.append((s, obj))
- collected.sort(key=lambda t: t[0])
- return [obj for _, obj in collected]
-
- def getSpanStart(self, span_obj: Any) -> int:
- span_id = id(span_obj)
- span_type = type(span_obj)
- data = self._spans.get((span_type, span_id))
- return data[0] if data else -1
-
- def getSpanEnd(self, span_obj: Any) -> int:
- span_id = id(span_obj)
- span_type = type(span_obj)
- data = self._spans.get((span_type, span_id))
- return data[1] if data else -1
-
- def getSpanFlags(self, span_obj: Any) -> int:
- span_id = id(span_obj)
- span_type = type(span_obj)
- data = self._spans.get((span_type, span_id))
- return data[2] if data else 0
-
- def nextSpanTransition(self, start: int, end: int, span_type: Optional[type] = None) -> int:
- result = end
- for (st, sid), (s, e, flags, obj) in self._spans.items():
- if span_type is not None and st != span_type:
- continue
- if start < s < result:
- result = s
- if start < e < result:
- result = e
- return result
-
- def toString(self) -> str:
- return self._source
-
- def __len__(self) -> int:
- return len(self._source)
-
- def __getitem__(self, index):
- return self._source[index]
-
- def __str__(self):
- return self._source
-
- def length(self) -> int:
- return len(self._source)
-
-
-class Editable(Spanned):
- """Editable — 可编辑文本接口"""
-
- def __init__(self, source: str = ""):
- super().__init__(source)
-
- def append(self, text: Any) -> "Editable":
- self._source += str(text)
- return self
-
- def insert(self, where: int, text: Any):
- self._source = self._source[:where] + str(text) + self._source[where:]
-
- def replace(self, start: int, end: int, text: Any):
- self._source = self._source[:start] + str(text) + self._source[end:]
-
- def delete(self, start: int, end: int):
- self._source = self._source[:start] + self._source[end:]
-
- def clear(self):
- self._source = ""
-
- def clearSpans(self):
- self._spans.clear()
-
- def getChars(self, start: int, end: int, dest: List[str], destoff: int):
- for i, c in enumerate(self._source[start:end]):
- if destoff + i < len(dest):
- dest[destoff + i] = c
-
-
-# ═══════════════════════════════════════════════════════════════
-# SpannableString
-# ═══════════════════════════════════════════════════════════════
-
-class SpannableString(Spanned):
- """SpannableString — 不可变但可标记的字符串"""
-
- def __init__(self, source: str):
- super().__init__(source)
- self._source = source
-
- def setSpan(self, span_obj: Any, start: int, end: int, flags: int):
- super().setSpan(span_obj, start, end, flags)
-
- def removeSpan(self, span_obj: Any):
- super().removeSpan(span_obj)
-
- def toString(self) -> str:
- return self._source
-
- def __str__(self):
- return self._source
-
- @staticmethod
- def valueOf(source: str) -> "SpannableString":
- return SpannableString(source)
-
- def length(self) -> int:
- return len(self._source)
-
- def charAt(self, index: int) -> str:
- return self._source[index]
-
- def subSequence(self, start: int, end: int) -> str:
- return self._source[start:end]
-
-
-# ═══════════════════════════════════════════════════════════════
-# SpannableStringBuilder
-# ═══════════════════════════════════════════════════════════════
-
-class SpannableStringBuilder(Editable):
- """SpannableStringBuilder — 可变可标记字符串构建器"""
-
- def __init__(self, source: Any = None):
- if source is None:
- super().__init__("")
- elif isinstance(source, str):
- super().__init__(source)
- elif isinstance(source, Spanned):
- super().__init__(source.toString())
- else:
- super().__init__(str(source))
-
- def append(self, text: Any, start: Optional[int] = None,
- end: Optional[int] = None) -> "SpannableStringBuilder":
- if text is None:
- return self
- if start is None and end is None:
- self._source += str(text)
- else:
- s = 0 if start is None else start
- text_str = str(text)
- e = len(text_str) if end is None else end
- self._source += text_str[s:e]
- return self
-
- def insert(self, where: int, text: Any) -> "SpannableStringBuilder":
- super().insert(where, text)
- return self
-
- def replace(self, start: int, end: int, text: Any) -> "SpannableStringBuilder":
- super().replace(start, end, text)
- return self
-
- def delete(self, start: int, end: int) -> "SpannableStringBuilder":
- super().delete(start, end)
- return self
-
- def setSpan(self, span_obj: Any, start: int, end: int, flags: int):
- super().setSpan(span_obj, start, end, flags)
-
- def clear(self):
- super().clear()
-
- def clearSpans(self):
- super().clearSpans()
-
- def length(self) -> int:
- return len(self._source)
-
- def charAt(self, index: int) -> str:
- return self._source[index] if 0 <= index < len(self._source) else ""
-
- def subSequence(self, start: int, end: int) -> str:
- return self._source[start:end]
-
- def toString(self) -> str:
- return self._source
-
- def __str__(self):
- return self._source
-
- def __iadd__(self, other: Any) -> "SpannableStringBuilder":
- self.append(str(other))
- return self
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextWatcher
-# ═══════════════════════════════════════════════════════════════
-
-class TextWatcher(Stub):
- """TextWatcher — 文本变化监听器"""
-
- def beforeTextChanged(self, s: str, start: int, count: int, after: int):
- pass
-
- def onTextChanged(self, s: str, start: int, before: int, count: int):
- pass
-
- def afterTextChanged(self, s: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputFilter / LengthFilter
-# ═══════════════════════════════════════════════════════════════
-
-class InputFilter(Stub):
- """InputFilter — 输入过滤器接口"""
-
- class LengthFilter(Stub):
- """LengthFilter — 长度限制过滤器"""
-
- def __init__(self, max_length: int):
- super().__init__()
- self._max_length = max_length
-
- def filter(self, source: str, start: int, end: int, dest: Spanned,
- dstart: int, dend: int) -> Optional[str]:
- keep = self._max_length - (len(dest.toString()) - (dend - dstart))
- if keep <= 0:
- return ""
- if keep >= (end - start):
- return None # keep original
- return source[start:start + keep]
-
- def getMax(self) -> int:
- return self._max_length
-
- @staticmethod
- def allCaps() -> "InputFilter":
- f = InputFilter()
- f._transform = lambda s: s.upper()
- return f
-
- def filter(self, source: str, start: int, end: int, dest: Spanned,
- dstart: int, dend: int) -> Optional[str]:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# Html
-# ═══════════════════════════════════════════════════════════════
-
-class Html(Stub):
- """Html — HTML 文本处理"""
-
- FROM_HTML_MODE_COMPACT = 0
- FROM_HTML_MODE_LEGACY = 1
- FROM_HTML_OPTION_USE_CSS_COLORS = 256
- FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 0x00000001
- FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 0x00000002
- FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 0x00000004
- FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 0x00000008
- FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 0x00000020
- FROM_HTML_SEPARATOR_LINE_BREAK_TABLE = 0x00000040
- TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 0x00000001
- TO_HTML_PARAGRAPH_LINE_CONSECUTIVE = 0x00000002
-
- _TAG_RE = _re.compile(r"<[^>]*>")
- _BR_RE = _re.compile(r"
", _re.IGNORECASE)
- _P_RE = _re.compile(r"
|]*>", _re.IGNORECASE)
-
- @staticmethod
- def fromHtml(html_text: str, flags: int = 0) -> str:
- """将 HTML 转为纯文本"""
- text = html_text
- text = Html._BR_RE.sub("\n", text)
- text = Html._P_RE.sub("\n\n", text)
- text = Html._TAG_RE.sub("", text)
- text = _html.unescape(text)
- return text.strip()
-
- @staticmethod
- def toHtml(text: str, option: int = 0) -> str:
- """将纯文本转为 HTML"""
- paragraphs = text.split("\n")
- html_parts = []
- for p in paragraphs:
- escaped = _html.escape(p)
- html_parts.append(f"
{escaped}
")
- return "".join(html_parts)
-
- @staticmethod
- def fromHtml(html_text: str, image_getter: Any, tag_handler: Any) -> str:
- return Html.fromHtml(html_text)
-
- @staticmethod
- def toHtmlWithOptions(text: str, options: int) -> str:
- return Html.toHtml(text)
-
- class ImageGetter:
- def getDrawable(self, source: str):
- return None
-
- class TagHandler:
- def handleTag(self, opening: bool, tag: str, output: Editable, xml_reader: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# CharacterStyle / 各 Span 实现
-# ═══════════════════════════════════════════════════════════════
-
-class CharacterStyle(Stub):
- """CharacterStyle — 字符样式基类"""
-
- def underLine(self):
- pass
-
- def updateDrawState(self, tp: TextPaint):
- pass
-
- def getUnderline(self) -> bool:
- return False
-
- @staticmethod
- def wrap(cs: "CharacterStyle") -> "CharacterStyle":
- return cs
-
-
-class StyleSpan(CharacterStyle):
- """StyleSpan — 字体样式"""
-
- def __init__(self, style: int):
- super().__init__()
- self._style = style
-
- def getStyle(self) -> int:
- return self._style
-
- def updateDrawState(self, tp: TextPaint):
- tp.style = self._style
-
-
-class TypefaceSpan(CharacterStyle):
- """TypefaceSpan — 字体族"""
-
- def __init__(self, family: str):
- super().__init__()
- self._family = family
-
- def getFamily(self) -> str:
- return self._family
-
- def updateDrawState(self, tp: TextPaint):
- if self._family == "monospace":
- tp.typeface = Typeface.MONOSPACE
- elif self._family == "serif":
- tp.typeface = Typeface.SERIF
- else:
- tp.typeface = Typeface.DEFAULT
-
-
-class RelativeSizeSpan(CharacterStyle):
- """RelativeSizeSpan — 相对大小"""
-
- def __init__(self, size: float):
- super().__init__()
- self._size = size
-
- def getSizeChange(self) -> float:
- return self._size
-
- def updateDrawState(self, tp: TextPaint):
- tp.textSize *= self._size
-
-
-class ForegroundColorSpan(CharacterStyle):
- """ForegroundColorSpan — 前景色"""
-
- def __init__(self, color: int):
- super().__init__()
- self._color = color
-
- def getForegroundColor(self) -> int:
- return self._color
-
- def updateDrawState(self, tp: TextPaint):
- tp.color = self._color
-
-
-class BackgroundColorSpan(CharacterStyle):
- """BackgroundColorSpan — 背景色"""
-
- def __init__(self, color: int):
- super().__init__()
- self._color = color
-
- def getBackgroundColor(self) -> int:
- return self._color
-
- def updateDrawState(self, tp: TextPaint):
- tp.bgColor = self._color
- tp.bgColorSet = True
-
-
-class UnderlineSpan(CharacterStyle):
- """UnderlineSpan — 下划线"""
-
- def updateDrawState(self, tp: TextPaint):
- tp.setUnderlineText(True)
-
-
-class StrikethroughSpan(CharacterStyle):
- """StrikethroughSpan — 删除线"""
-
- def updateDrawState(self, tp: TextPaint):
- pass # desktop 无直接等价
-
-
-class SubscriptSpan(CharacterStyle):
- """SubscriptSpan — 下标"""
-
- def updateDrawState(self, tp: TextPaint):
- tp.baselineShift = -tp.textSize / 4
-
-
-class SuperscriptSpan(CharacterStyle):
- """SuperscriptSpan — 上标"""
-
- def updateDrawState(self, tp: TextPaint):
- tp.baselineShift = tp.textSize / 2
-
-
-class ImageSpan(CharacterStyle):
- """ImageSpan — 图片"""
-
- ALIGN_BOTTOM = 0
- ALIGN_BASELINE = 1
- ALIGN_CENTER = 2
- ALIGN_TOP = 3
-
- def __init__(self, drawable: Any, source: str = "", align: int = ALIGN_BOTTOM):
- super().__init__()
- self._drawable = drawable
- self._source = source
- self._align = align
-
- def getDrawable(self):
- return self._drawable
-
- def getSource(self) -> str:
- return self._source
-
- def getAlignment(self) -> int:
- return self._align
-
-
-class ClickableSpan(CharacterStyle):
- """ClickableSpan — 可点击文本"""
-
- def __init__(self):
- super().__init__()
-
- def onClick(self, view: Any):
- pass
-
- def updateDrawState(self, tp: TextPaint):
- tp.color = tp.linkColor
- tp.setUnderlineText(True)
-
-
-class URLSpan(ClickableSpan):
- """URLSpan — URL 链接"""
-
- def __init__(self, url: str):
- super().__init__()
- self._url = url
-
- def getURL(self) -> str:
- return self._url
-
- def onClick(self, view: Any):
- sys.stderr.write(f"[URLSpan] onClick: {self._url}\n")
-
- def updateDrawState(self, tp: TextPaint):
- super().updateDrawState(tp)
-
-
-# ═══════════════════════════════════════════════════════════════
-# NoCopySpan / ParagraphStyle 接口
-# ═══════════════════════════════════════════════════════════════
-
-class NoCopySpan(Stub):
- """NoCopySpan — 标记不在拷贝时复制的 span"""
- pass
-
-class NoCopySpanConcise(NoCopySpan):
- """NoCopySpan.Concrete — 具体实现"""
- pass
-
-
-class ParagraphStyle(Stub):
- """ParagraphStyle — 段落样式接口"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Ellipsize / TruncateAt 枚举
-# ═══════════════════════════════════════════════════════════════
-
-class Ellipsize(Stub):
- """Ellipsize 常量"""
- END = "END"
- MIDDLE = "MIDDLE"
- MARQUEE = "MARQUEE"
- START = "START"
- NONE = "NONE"
-
-
-class TruncateAt(Stub):
- """TruncateAt 常量"""
- END = "END"
- MIDDLE = "MIDDLE"
- MARQUEE = "MARQUEE"
- START = "START"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Align
-# ═══════════════════════════════════════════════════════════════
-
-class Align(Stub):
- """Layout.Alignment 枚举"""
- ALIGN_NORMAL = 0
- ALIGN_OPPOSITE = 1
- ALIGN_CENTER = 2
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextDirectionHeuristic / TextDirectionHeuristics
-# ═══════════════════════════════════════════════════════════════
-
-class TextDirectionHeuristic(Stub):
- """TextDirectionHeuristic — 文本方向启发式"""
- pass
-
-
-class TextDirectionHeuristics(Stub):
- """TextDirectionHeuristics — 文本方向启发式常量"""
-
- FIRSTSTRONG_LTR = TextDirectionHeuristic()
- FIRSTSTRONG_RTL = TextDirectionHeuristic()
- ANYRTL_LTR = TextDirectionHeuristic()
- LTR = TextDirectionHeuristic()
- RTL = TextDirectionHeuristic()
- LOCALE = TextDirectionHeuristic()
-
-
-# ═══════════════════════════════════════════════════════════════
-# LoginFilter
-# ═══════════════════════════════════════════════════════════════
-
-class LoginFilter(InputFilter):
- """LoginFilter — 登录名输入过滤器"""
-
- def __init__(self, append_ok: bool = True):
- super().__init__()
- self._append_ok = append_ok
-
- def isAllowed(self, c: str) -> bool:
- return c.isalnum() or c in "@._-"
-
- def filter(self, source: str, start: int, end: int, dest: Spanned,
- dstart: int, dend: int) -> Optional[str]:
- filtered = []
- for c in source[start:end]:
- if self.isAllowed(c):
- filtered.append(c)
- elif self._append_ok:
- pass
- result = "".join(filtered)
- return result if result != source else None
-
- class UsernameFilterGMail(InputFilter):
- def filter(self, source, start, end, dest, dstart, dend):
- result = []
- for c in source[start:end]:
- if c.isalnum() or c in "@._-":
- result.append(c)
- return "".join(result) or None
-
- class PasswordFilterGMail(InputFilter):
- def filter(self, source, start, end, dest, dstart, dend):
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# Method / MovementMethod
-# ═══════════════════════════════════════════════════════════════
-
-class Method(Stub):
- """Method — 输入法接口"""
- pass
-
-
-class MovementMethod(Stub):
- """MovementMethod — 移动方式接口"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Layout / StaticLayout / DynamicLayout / BoringLayout
-# ═══════════════════════════════════════════════════════════════
-
-class Layout(Stub):
- """Layout — 布局基类"""
-
- Alignment = Align
-
- BREAK_STRATEGY_SIMPLE = 0
- BREAK_STRATEGY_HIGH_QUALITY = 1
- BREAK_STRATEGY_BALANCED = 2
-
- HYPHENATION_FREQUENCY_NONE = 0
- HYPHENATION_FREQUENCY_NORMAL = 1
- HYPHENATION_FREQUENCY_FULL = 2
-
- JUSTIFICATION_MODE_NONE = 0
- JUSTIFICATION_MODE_INTER_WORD = 1
-
- def __init__(self, text: str, paint: TextPaint, width: int, alignment: int,
- spacing_mult: float, spacing_add: float):
- super().__init__()
- self._text = text
- self._paint = paint
- self._width = width
- self._alignment = alignment
- self._spacing_mult = spacing_mult
- self._spacing_add = spacing_add
- self._line_count = max(1, len(text) // max(1, width // 10) + 1)
-
- def getLineCount(self) -> int:
- return self._line_count
-
- def getLineBounds(self, line: int, bounds: Optional[Any]) -> int:
- line_height = int(self._paint.textSize * self._spacing_mult + self._spacing_add)
- return line * line_height
-
- def getPrimaryHorizontal(self, offset: int) -> float:
- line = 0
- return (offset % max(1, self._width)) * self._paint.measureText("x")
-
- def getSecondaryHorizontal(self, offset: int) -> float:
- return 0.0
-
- def getLineTop(self, line: int) -> int:
- line_height = int(self._paint.textSize * self._spacing_mult + self._spacing_add)
- return line * line_height
-
- def getLineBottom(self, line: int) -> int:
- line_height = int(self._paint.textSize * self._spacing_mult + self._spacing_add)
- return (line + 1) * line_height
-
- def getLineStart(self, line: int) -> int:
- chars_per_line = max(1, self._width // max(1, int(self._paint.measureText("x"))))
- return line * chars_per_line
-
- def getLineEnd(self, line: int) -> int:
- chars_per_line = max(1, self._width // max(1, int(self._paint.measureText("x"))))
- return min((line + 1) * chars_per_line, len(self._text))
-
- def getText(self) -> str:
- return self._text
-
- def getPaint(self) -> TextPaint:
- return self._paint
-
- def getWidth(self) -> int:
- return self._width
-
- def getAlignment(self) -> int:
- return self._alignment
-
- def getSpacingMultiplier(self) -> float:
- return self._spacing_mult
-
- def getSpacingAdd(self) -> float:
- return self._spacing_add
-
- def isRtlCharAt(self, offset: int) -> bool:
- return False
-
- def getParagraphDirection(self, line: int) -> int:
- return 1
-
- def draw(self, canvas: Any):
- pass
-
-
-class StaticLayout(Layout):
- """StaticLayout — 静态布局"""
-
- def __init__(self, source: str, paint: TextPaint, width: int, alignment: int,
- spacing_mult: float, spacing_add: float, include_pad: bool):
- super().__init__(source, paint, width, alignment, spacing_mult, spacing_add)
- self._include_pad = include_pad
-
-
-class DynamicLayout(Layout):
- """DynamicLayout — 动态布局"""
-
- def __init__(self, base: Any, paint: TextPaint, width: int, alignment: int,
- spacing_mult: float, spacing_add: float, include_pad: bool,
- ellipsize: Any = None, ellipsize_width: int = 0):
- super().__init__(str(base), paint, width, alignment, spacing_mult, spacing_add)
- self._include_pad = include_pad
-
-
-class BoringLayout(Layout):
- """BoringLayout — 单行布局"""
-
- def __init__(self, source: str, paint: TextPaint, width: int, alignment: int,
- spacing_mult: float, spacing_add: float, include_pad: bool,
- ellipsize: Any = None, ellipsize_width: int = 0):
- super().__init__(source, paint, width, alignment, spacing_mult, spacing_add)
- self._include_pad = include_pad
- self._line_count = 1 if source else 0
-
- class Metrics(Stub):
- """Metrics for BoringLayout"""
- width = 0
- height = 0
-
- @staticmethod
- def isBoring(text: str, paint: TextPaint) -> Optional["BoringLayout.Metrics"]:
- m = BoringLayout.Metrics()
- m.width = int(paint.measureText(text))
- m.height = int(paint.textSize)
- return m if text else None
-
- @staticmethod
- def make(source: str, paint: TextPaint, width: int, alignment: int,
- spacing_mult: float, spacing_add: float, metrics: "BoringLayout.Metrics",
- include_pad: bool) -> "BoringLayout":
- return BoringLayout(source, paint, width, alignment, spacing_mult, spacing_add, include_pad)
-
-
-class ClipRectangle(Stub):
- """ClipRectangle — 裁剪矩形"""
- def __init__(self, left: int = 0, top: int = 0, right: int = 0, bottom: int = 0):
- super().__init__()
- self.left = left
- self.top = top
- self.right = right
- self.bottom = bottom
-
-
-# ═══════════════════════════════════════════════════════════════
-# Spannable (接口别名)
-# ═══════════════════════════════════════════════════════════════
-
-class Spannable(Spanned):
- """Spannable — 可标记接口"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "TextUtils",
- "SpannableString",
- "SpannableStringBuilder",
- "Spannable",
- "Editable",
- "Spanned",
- "TextWatcher",
- "InputFilter",
- "Html",
- "Layout",
- "StaticLayout",
- "DynamicLayout",
- "BoringLayout",
- "ClipRectangle",
- "TextPaint",
- "TextDirectionHeuristic",
- "TextDirectionHeuristics",
- "Align",
- "Ellipsize",
- "TruncateAt",
- "LoginFilter",
- "Method",
- "MovementMethod",
- "NoCopySpan",
- "ParagraphStyle",
- "CharacterStyle",
- "StyleSpan",
- "TypefaceSpan",
- "RelativeSizeSpan",
- "ForegroundColorSpan",
- "BackgroundColorSpan",
- "UnderlineSpan",
- "StrikethroughSpan",
- "SubscriptSpan",
- "SuperscriptSpan",
- "ImageSpan",
- "ClickableSpan",
- "URLSpan",
- "Typeface",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/text_format.py b/android_pyapi/android/text_format.py
deleted file mode 100644
index 37bbf43..0000000
--- a/android_pyapi/android/text_format.py
+++ /dev/null
@@ -1,456 +0,0 @@
-"""
-Android text.format 包 — DateFormat, Time, Formatter, DateUtils 等
-方法签名完全对齐 Android SDK;使用 Python datetime 模块实现真实逻辑
-"""
-
-from __future__ import annotations
-
-import datetime
-import math
-import re
-import time as _time
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "DateFormat",
- "Time",
- "Formatter",
- "DateUtils",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# DateFormat
-# ═══════════════════════════════════════════════════════════════
-
-class DateFormat(Stub):
- """DateFormat — 日期格式化工具 (使用 Python datetime 实现)"""
-
- DAY_OF_WEEK = 1
- DAY_OF_MONTH = 2
- DAY_OF_YEAR = 3
- HOUR_OF_DAY = 4
- MINUTE = 5
- SECOND = 6
- MONTH = 7
- YEAR = 8
-
- _PATTERNS = {
- "short": "%m/%d/%y",
- "medium": "%b %d, %Y",
- "long": "%B %d, %Y",
- "full": "%A, %B %d, %Y",
- "time_short": "%I:%M %p",
- "time_medium": "%I:%M:%S %p",
- "time_long": "%I:%M:%S %p %Z",
- }
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getDateFormat(context: Any) -> "DateFormat":
- """获取日期格式"""
- return DateFormat()
-
- @staticmethod
- def getTimeFormat(context: Any) -> "DateFormat":
- """获取时间格式"""
- return DateFormat()
-
- @staticmethod
- def getDateTimeFormat(context: Any) -> "DateFormat":
- """获取日期时间格式"""
- return DateFormat()
-
- @staticmethod
- def is24HourFormat(context: Any) -> bool:
- """检查是否使用 24 小时制"""
- return False
-
- @staticmethod
- def format(date_str: str, in_format: str = "%Y-%m-%d",
- out_format: str = "%b %d, %Y") -> str:
- """格式化日期字符串"""
- try:
- dt = datetime.datetime.strptime(date_str, in_format)
- return dt.strftime(out_format)
- except (ValueError, TypeError):
- return date_str
-
- @staticmethod
- def formatDateRange(context: Any, start_millis: int, end_millis: int,
- flags: int = 0) -> str:
- """格式化日期范围"""
- start_dt = datetime.datetime.fromtimestamp(start_millis / 1000.0)
- end_dt = datetime.datetime.fromtimestamp(end_millis / 1000.0)
- if start_dt.date() == end_dt.date():
- return start_dt.strftime("%b %d, %Y")
- return f"{start_dt.strftime('%b %d')} - {end_dt.strftime('%b %d, %Y')}"
-
- @staticmethod
- def getBestDateTimePattern(pattern: str, locale: Any) -> str:
- """获取最佳日期时间模式"""
- return pattern
-
- @staticmethod
- def getLongDateFormat(context: Any) -> "DateFormat":
- return DateFormat()
-
- @staticmethod
- def getMediumDateFormat(context: Any) -> "DateFormat":
- return DateFormat()
-
- @staticmethod
- def getShortDateFormat(context: Any) -> "DateFormat":
- return DateFormat()
-
- @staticmethod
- def getTimePeriodString(time_period: int) -> str:
- """获取时间段字符串"""
- periods = {
- 0: "morning",
- 1: "afternoon",
- 2: "evening",
- 3: "night",
- }
- return periods.get(time_period, "unknown")
-
- @staticmethod
- def formatElapsedTime(elapsed_millis: int) -> str:
- """格式化经过的时间"""
- seconds = elapsed_millis // 1000
- minutes = seconds // 60
- hours = minutes // 60
- seconds = seconds % 60
- minutes = minutes % 60
- if hours > 0:
- return f"{hours}:{minutes:02d}:{seconds:02d}"
- return f"{minutes}:{seconds:02d}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Time
-# ═══════════════════════════════════════════════════════════════
-
-class Time(Stub):
- """Time — 时间类 (使用 Python datetime 实现)"""
-
- TIMEZONE_UTC = "UTC"
- EPOCH_JULIAN_DAY = 2440588
- MONDAY = 2
- SUNDAY = 1
- JANUARY = 0
- DECEMBER = 11
-
- def __init__(self, timezone: str = "UTC"):
- super().__init__()
- self._dt = datetime.datetime.utcnow()
- self.timezone = timezone
- self.allDay = False
- self.julianDay = self._to_julian(self._dt)
- self.weekNumber = 0
- self.gmtoff = 0
- self.hour = self._dt.hour
- self.minute = self._dt.minute
- self.second = self._dt.second
- self.weekDay = self._dt.isoweekday()
- self.yearDay = self._dt.timetuple().tm_yday
- self.month = self._dt.month - 1 # 0-based
- self.monthDay = self._dt.day
- self.year = self._dt.year
- self.isDst = 0
-
- @staticmethod
- def _to_julian(dt: datetime.datetime) -> int:
- """将 datetime 转换为儒略日"""
- timestamp = dt.timestamp()
- return int(Time.EPOCH_JULIAN_DAY + timestamp / 86400.0)
-
- @staticmethod
- def _from_julian(jd: int) -> datetime.datetime:
- """将儒略日转换为 datetime"""
- timestamp = (jd - Time.EPOCH_JULIAN_DAY) * 86400.0
- return datetime.datetime.fromtimestamp(timestamp)
-
- def setToNow(self) -> None:
- """设置当前时间"""
- self._dt = datetime.datetime.now()
- self._update_fields()
-
- def set(self, second: int, minute: int, hour: int, monthDay: int,
- month: int, year: int) -> None:
- """设置时间"""
- self._dt = datetime.datetime(year, month + 1, monthDay, hour, minute, second)
- self._update_fields()
-
- def setTimezone(self, timezone: str) -> None:
- """设置时区"""
- self.timezone = timezone
-
- def normalize(self, ignoreDst: bool = False) -> int:
- """标准化时间,返回毫秒"""
- self._update_fields()
- return int(self._dt.timestamp() * 1000)
-
- def format(self, pattern: str = "%Y-%m-%d %H:%M:%S") -> str:
- """格式化输出"""
- return self._dt.strftime(pattern)
-
- def toString(self) -> str:
- return self._dt.isoformat()
-
- def parse(self, s: str) -> bool:
- """解析时间字符串"""
- formats = [
- "%Y-%m-%d %H:%M:%S",
- "%Y-%m-%dT%H:%M:%S",
- "%Y-%m-%d",
- "%m/%d/%Y %H:%M:%S",
- "%m/%d/%Y",
- ]
- for fmt in formats:
- try:
- self._dt = datetime.datetime.strptime(s, fmt)
- self._update_fields()
- return True
- except ValueError:
- continue
- return False
-
- def parse3339(self, s: str) -> bool:
- """解析 RFC 3339 时间字符串"""
- try:
- self._dt = datetime.datetime.fromisoformat(s.replace("Z", "+00:00"))
- self._update_fields()
- return True
- except (ValueError, TypeError):
- return False
-
- def switchTimezone(self, timezone: str) -> None:
- """切换时区"""
- self.timezone = timezone
-
- def toMillis(self) -> int:
- """转换为毫秒"""
- return int(self._dt.timestamp() * 1000)
-
- def setJulianDay(self, julianDay: int) -> None:
- """设置儒略日"""
- self.julianDay = julianDay
- self._dt = self._from_julian(julianDay)
- self._update_fields()
-
- @staticmethod
- def getJulianDay(millis: int, gmtoff: int) -> int:
- """从毫秒获取儒略日"""
- dt = datetime.datetime.fromtimestamp(millis / 1000.0)
- return Time._to_julian(dt)
-
- def getWeekNumber(self) -> int:
- """获取周数"""
- return self._dt.isocalendar()[1]
-
- def _update_fields(self) -> None:
- """更新所有字段"""
- self.hour = self._dt.hour
- self.minute = self._dt.minute
- self.second = self._dt.second
- self.weekDay = self._dt.isoweekday()
- self.yearDay = self._dt.timetuple().tm_yday
- self.month = self._dt.month - 1
- self.monthDay = self._dt.day
- self.year = self._dt.year
- self.julianDay = self._to_julian(self._dt)
- self.weekNumber = self.getWeekNumber()
-
-
-# ═══════════════════════════════════════════════════════════════
-# Formatter
-# ═══════════════════════════════════════════════════════════════
-
-class Formatter(Stub):
- """Formatter — 格式化工具 (使用真实实现)"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def formatFileSize(context: Any, size_bytes: int) -> str:
- """格式化文件大小"""
- if size_bytes < 0:
- return "0 B"
- units = ["B", "KB", "MB", "GB", "TB"]
- unit_idx = 0
- size_f = float(size_bytes)
- while size_f >= 1024 and unit_idx < len(units) - 1:
- size_f /= 1024.0
- unit_idx += 1
- if unit_idx == 0:
- return f"{int(size_f)} {units[unit_idx]}"
- return f"{size_f:.1f} {units[unit_idx]}"
-
- @staticmethod
- def formatShortFileSize(context: Any, size_bytes: int) -> str:
- """格式化短文件大小"""
- return Formatter.formatFileSize(context, size_bytes)
-
- @staticmethod
- def formatIpAddress(addr: int) -> str:
- """格式化 IP 地址"""
- return f"{(addr >> 24) & 0xFF}.{(addr >> 16) & 0xFF}.{(addr >> 8) & 0xFF}.{addr & 0xFF}"
-
- @staticmethod
- def formatDateFromDB(context: Any, date_str: str) -> str:
- """格式化数据库日期"""
- return DateFormat.format(date_str, "%Y-%m-%d", "%b %d, %Y")
-
- @staticmethod
- def formatShortDateFromDB(context: Any, date_str: str) -> str:
- """格式化短数据库日期"""
- return DateFormat.format(date_str, "%Y-%m-%d", "%m/%d/%y")
-
-
-# ═══════════════════════════════════════════════════════════════
-# DateUtils
-# ═══════════════════════════════════════════════════════════════
-
-class DateUtils(Stub):
- """DateUtils — 日期工具类 (使用 Python datetime 实现)"""
-
- DAY_IN_MILLIS = 86400000
- HOUR_IN_MILLIS = 3600000
- MINUTE_IN_MILLIS = 60000
- SECOND_IN_MILLIS = 1000
- WEEK_IN_MILLIS = 604800000
- YEAR_IN_MILLIS = 31536000000
-
- FORMAT_SHOW_TIME = 0x00001
- FORMAT_SHOW_DATE = 0x00002
- FORMAT_SHOW_YEAR = 0x00004
- FORMAT_NO_MIDNIGHT = 0x00008
- FORMAT_SHOW_WEEKDAY = 0x00010
- FORMAT_UTC = 0x00020
- FORMAT_ABBREV_MONTH = 0x00040
- FORMAT_ABBREV_WEEKDAY = 0x00080
- FORMAT_NO_NOON = 0x00100
- FORMAT_CAP_AMPM = 0x00200
- FORMAT_NO_YEAR = 0x00400
- FORMAT_NUMERIC_DATE = 0x00800
- FORMAT_ABBREV_ALL = 0x01000
- FORMAT_12HOUR = 0x02000
- FORMAT_24HOUR = 0x04000
-
- _WEEKDAYS = ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
- _WEEKDAYS_ABBREV = ["", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
- _MONTHS = ["January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"]
- _MONTHS_ABBREV = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def formatDateTime(context: Any, millis: int, flags: int) -> str:
- """格式化日期时间"""
- dt = datetime.datetime.fromtimestamp(millis / 1000.0)
- parts = []
- if flags & DateUtils.FORMAT_SHOW_WEEKDAY:
- abbrev = bool(flags & DateUtils.FORMAT_ABBREV_WEEKDAY)
- wd = DateUtils._WEEKDAYS_ABBREV[dt.isoweekday()] if abbrev else DateUtils._WEEKDAYS[dt.isoweekday()]
- parts.append(wd)
- if flags & DateUtils.FORMAT_SHOW_DATE:
- abbrev = bool(flags & DateUtils.FORMAT_ABBREV_MONTH)
- if flags & DateUtils.FORMAT_NUMERIC_DATE:
- parts.append(f"{dt.month}/{dt.day}")
- else:
- mn = DateUtils._MONTHS_ABBREV[dt.month - 1] if abbrev else DateUtils._MONTHS[dt.month - 1]
- parts.append(f"{mn} {dt.day}")
- if flags & DateUtils.FORMAT_SHOW_YEAR:
- parts.append(str(dt.year))
- if flags & DateUtils.FORMAT_SHOW_TIME:
- if flags & DateUtils.FORMAT_24HOUR:
- parts.append(dt.strftime("%H:%M"))
- else:
- parts.append(dt.strftime("%I:%M %p"))
- return " ".join(parts)
-
- @staticmethod
- def formatDateRange(context: Any, start_millis: int, end_millis: int,
- flags: int = 0) -> str:
- """格式化日期范围"""
- return DateFormat.formatDateRange(context, start_millis, end_millis, flags)
-
- @staticmethod
- def formatElapsedTime(now: int, past: int) -> str:
- """格式化经过的时间"""
- diff = now - past
- return DateFormat.formatElapsedTime(diff)
-
- @staticmethod
- def getRelativeTimeSpanString(time_millis: int, now_millis: int,
- min_resolution: int = MINUTE_IN_MILLIS,
- flags: int = 0) -> str:
- """获取相对时间字符串"""
- diff = now_millis - time_millis
- if diff < 0:
- return "just now"
- if diff < DateUtils.MINUTE_IN_MILLIS:
- return "just now"
- if diff < DateUtils.HOUR_IN_MILLIS:
- minutes = int(diff / DateUtils.MINUTE_IN_MILLIS)
- return f"{minutes} minute{'s' if minutes > 1 else ''} ago"
- if diff < DateUtils.DAY_IN_MILLIS:
- hours = int(diff / DateUtils.HOUR_IN_MILLIS)
- return f"{hours} hour{'s' if hours > 1 else ''} ago"
- if diff < DateUtils.WEEK_IN_MILLIS:
- days = int(diff / DateUtils.DAY_IN_MILLIS)
- return f"{days} day{'s' if days > 1 else ''} ago"
- if diff < DateUtils.YEAR_IN_MILLIS:
- weeks = int(diff / DateUtils.WEEK_IN_MILLIS)
- return f"{weeks} week{'s' if weeks > 1 else ''} ago"
- years = int(diff / DateUtils.YEAR_IN_MILLIS)
- return f"{years} year{'s' if years > 1 else ''} ago"
-
- @staticmethod
- def getRelativeDateTimeString(time_millis: int, now_millis: int,
- min_resolution: int, transition_resolution: int,
- flags: int) -> str:
- """获取相对日期时间字符串"""
- return DateUtils.getRelativeTimeSpanString(time_millis, now_millis, min_resolution, flags)
-
- @staticmethod
- def getDayOfWeekString(day_of_week: int, flags: int) -> str:
- """获取星期字符串"""
- abbrev = bool(flags & DateUtils.FORMAT_ABBREV_WEEKDAY)
- if 1 <= day_of_week <= 7:
- return DateUtils._WEEKDAYS_ABBREV[day_of_week] if abbrev else DateUtils._WEEKDAYS[day_of_week]
- return ""
-
- @staticmethod
- def getMonthString(month: int, flags: int) -> str:
- """获取月份字符串"""
- abbrev = bool(flags & DateUtils.FORMAT_ABBREV_MONTH)
- if 0 <= month <= 11:
- return DateUtils._MONTHS_ABBREV[month] if abbrev else DateUtils._MONTHS[month]
- return ""
-
- @staticmethod
- def isToday(millis: int) -> bool:
- """检查是否是今天"""
- today = datetime.date.today()
- dt = datetime.datetime.fromtimestamp(millis / 1000.0)
- return dt.date() == today
-
- @staticmethod
- def sameDay(millis1: int, millis2: int) -> bool:
- """检查是否是同一天"""
- dt1 = datetime.datetime.fromtimestamp(millis1 / 1000.0)
- dt2 = datetime.datetime.fromtimestamp(millis2 / 1000.0)
- return dt1.date() == dt2.date()
\ No newline at end of file
diff --git a/android_pyapi/android/text_method.py b/android_pyapi/android/text_method.py
deleted file mode 100644
index e262474..0000000
--- a/android_pyapi/android/text_method.py
+++ /dev/null
@@ -1,676 +0,0 @@
-"""
-Android text.method 包 — KeyListener, MovementMethod, TransformationMethod 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-import time
-from typing import Any, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "KeyListener",
- "MetaKeyKeyListener",
- "NumberKeyListener",
- "DigitsKeyListener",
- "TextKeyListener",
- "MovementMethod",
- "ArrowKeyMovementMethod",
- "LinkMovementMethod",
- "Touch",
- "BaseMovementMethod",
- "ScrollingMovementMethod",
- "WordIterator",
- "PasswordTransformationMethod",
- "TransformationMethod",
- "TransformationMethod2",
- "SingleLineTransformationMethod",
- "HideReturnsTransformationMethod",
- "TimeDisplayTruncationMethod",
- "DateTimeKeyListener",
- "DateKeyListener",
- "TimeKeyListener",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# KeyListener
-# ═══════════════════════════════════════════════════════════════
-
-class KeyListener(Stub):
- """KeyListener — 按键监听器接口 (桌面存根)"""
-
- META_SHIFT_MASK = 0x1
- META_ALT_MASK = 0x2
- META_SYM_MASK = 0x4
- META_CTRL_MASK = 0x1000
- META_META_MASK = 0x10000
- META_CAPS_LOCK = 0x100000
- META_ALT_LOCK = 0x200000
- META_SYM_LOCK = 0x400000
- META_SELECTING = 0x800000
- META_SHIFTING = 0x1000000
-
- def __init__(self):
- super().__init__()
- self._input_type = 0
- self._meta_state = 0
-
- def clearMetaKeyState(self, view: Any, content: Any, states: int) -> None:
- """清除元键状态"""
- self._meta_state = self._meta_state & ~states
-
- def getInputType(self) -> int:
- """获取输入类型"""
- return self._input_type
-
- def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- """按键按下事件"""
- return False
-
- def onKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- """按键释放事件"""
- return False
-
- def onKeyOther(self, view: Any, content: Any, event: Any) -> bool:
- """其他按键事件"""
- return False
-
- @staticmethod
- def metaStateHasNoModifiers(metaState: int) -> bool:
- """检查元状态是否没有修饰键"""
- return (metaState & 0x0000FFFF) == 0
-
- @staticmethod
- def metaStateHasModifiers(metaState: int, modifiers: int) -> bool:
- """检查元状态是否有指定修饰键"""
- return (metaState & modifiers) != 0
-
- @staticmethod
- def metaStateFilterDirectionLocked(metaState: int) -> int:
- """过滤方向锁定"""
- return metaState & ~(KeyListener.META_CAPS_LOCK | KeyListener.META_ALT_LOCK | KeyListener.META_SYM_LOCK)
-
- def __repr__(self) -> str:
- return f"KeyListener(inputType={self._input_type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MetaKeyKeyListener
-# ═══════════════════════════════════════════════════════════════
-
-class MetaKeyKeyListener(KeyListener):
- """MetaKeyKeyListener — 元键按键监听器 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
- self._locked_meta: Dict[int, int] = {}
-
- def clearMetaKeyState(self, view: Any, content: Any, states: int) -> None:
- """清除元键状态"""
- self._meta_state = self._meta_state & ~states
- for state_bit in [KeyListener.META_CAPS_LOCK, KeyListener.META_ALT_LOCK, KeyListener.META_SYM_LOCK]:
- if states & state_bit:
- self._locked_meta.pop(state_bit, None)
-
- @staticmethod
- def resetMetaState(content: Any) -> None:
- """重置元状态"""
- if hasattr(content, '_meta_state'):
- content._meta_state = 0
-
- def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- """按键按下事件处理"""
- return super().onKeyDown(view, content, keyCode, event)
-
- def onKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- """按键释放事件处理"""
- return super().onKeyUp(view, content, keyCode, event)
-
- @staticmethod
- def adjustMetaAfterKeypress(content: Any) -> None:
- """按键后调整元状态"""
- pass
-
- def handleKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- """处理按键按下 (内部)"""
- return self.onKeyDown(view, content, keyCode, event)
-
- def handleKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- """处理按键释放 (内部)"""
- return self.onKeyUp(view, content, keyCode, event)
-
- @staticmethod
- def getMetaState(content: Any) -> int:
- """获取元状态"""
- return getattr(content, '_meta_state', 0)
-
- @staticmethod
- def getMetaState_ex(content: Any, meta: int) -> bool:
- """检查特定元状态"""
- state = getattr(content, '_meta_state', 0)
- return (state & meta) != 0
-
- @staticmethod
- def isMetaTracker(content: Any) -> bool:
- """检查是否是元追踪器"""
- return hasattr(content, '_meta_state')
-
- @staticmethod
- def isSelectingMetaTracker(content: Any) -> bool:
- """检查是否是选择元追踪器"""
- return hasattr(content, '_meta_state') and (getattr(content, '_meta_state', 0) & KeyListener.META_SELECTING) != 0
-
- @staticmethod
- def peekMetaState(content: Any) -> int:
- """窥视元状态"""
- return getattr(content, '_meta_state', 0)
-
- def resetLockedMeta(self, content: Any) -> None:
- """重置锁定元键"""
- self._locked_meta.clear()
-
- def clearLockedMeta(self, content: Any) -> None:
- """清除锁定元键"""
- self._locked_meta.clear()
-
- @staticmethod
- def releaseAllMetaKeys(content: Any) -> None:
- """释放所有元键"""
- if hasattr(content, '_meta_state'):
- content._meta_state = 0
-
- def toString(self) -> str:
- return f"MetaKeyKeyListener(metaState={self._meta_state}, locked={self._locked_meta})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NumberKeyListener
-# ═══════════════════════════════════════════════════════════════
-
-class NumberKeyListener(MetaKeyKeyListener):
- """NumberKeyListener — 数字按键监听器 (桌面存根)"""
-
- _ACCEPTED_CHARS: str = ""
-
- def __init__(self):
- super().__init__()
- self._input_type = 0x0002 # TYPE_CLASS_NUMBER
-
- def getAcceptedChars(self) -> List[str]:
- """获取接受的字符列表"""
- return list(self._ACCEPTED_CHARS)
-
- def filter(self, source: str, start: int, end: int, dest: str, dstart: int, dend: int) -> str:
- """过滤输入,只保留接受的字符"""
- result = ""
- for i in range(start, end):
- ch = source[i] if i < len(source) else ''
- if ch in self._ACCEPTED_CHARS:
- result += ch
- return result if result != source[start:end] else ""
-
- def lookup(self, key: int, event: Any) -> Optional[str]:
- """查找按键映射的字符"""
- key_map = {
- 7: '0', 8: '1', 9: '2', 10: '3', 11: '4',
- 12: '5', 13: '6', 14: '7', 15: '8', 16: '9',
- }
- return key_map.get(key)
-
- def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- """按键按下事件"""
- char = self.lookup(keyCode, event)
- if char and char in self._ACCEPTED_CHARS:
- return True
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# DigitsKeyListener
-# ═══════════════════════════════════════════════════════════════
-
-class DigitsKeyListener(NumberKeyListener):
- """DigitsKeyListener — 数字按键监听器 (桌面存根)"""
-
- _instances: Dict[str, "DigitsKeyListener"] = {}
-
- def __init__(self, accepted: str = "0123456789"):
- super().__init__()
- self._ACCEPTED_CHARS = accepted
- self._input_type = 0x0002
-
- @staticmethod
- def getInstance(locale: Any = None, sign: bool = False, decimal: bool = False) -> "DigitsKeyListener":
- """获取实例"""
- key = f"{locale}_{sign}_{decimal}"
- if key not in DigitsKeyListener._instances:
- accepted = "0123456789"
- if sign:
- accepted += "-"
- if decimal:
- accepted += "."
- DigitsKeyListener._instances[key] = DigitsKeyListener(accepted)
- return DigitsKeyListener._instances[key]
-
- def getAcceptedChars(self) -> List[str]:
- return list(self._ACCEPTED_CHARS)
-
- def filter(self, source: str, start: int, end: int, dest: str, dstart: int, dend: int) -> str:
- return super().filter(source, start, end, dest, dstart, dend)
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextKeyListener
-# ═══════════════════════════════════════════════════════════════
-
-class TextKeyListener(MetaKeyKeyListener):
- """TextKeyListener — 文本按键监听器 (桌面存根)"""
-
- CAP_MODE_CHARACTERS = 0x1
- CAP_MODE_WORDS = 0x2
- CAP_MODE_SENTENCES = 0x4
-
- _instance: Optional["TextKeyListener"] = None
-
- def __init__(self):
- super().__init__()
- self._input_type = 0x0001 # TYPE_CLASS_TEXT
- self._auto_cap_mode = 0
-
- @staticmethod
- def getInstance() -> "TextKeyListener":
- """获取单例实例"""
- if TextKeyListener._instance is None:
- TextKeyListener._instance = TextKeyListener()
- return TextKeyListener._instance
-
- def clear(self, view: Any, content: Any) -> None:
- """清除内容"""
- if hasattr(content, 'clear'):
- content.clear()
-
- def release(self, view: Any) -> None:
- """释放资源"""
- pass
-
- def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- return True
-
- def onKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- return True
-
- def toString(self) -> str:
- return f"TextKeyListener(capMode={self._auto_cap_mode})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MovementMethod
-# ═══════════════════════════════════════════════════════════════
-
-class MovementMethod(Stub):
- """MovementMethod — 移动方法接口 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
- self._movement_meta_state = 0
-
- def initialize(self, view: Any, content: Any) -> None:
- """初始化"""
- pass
-
- def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- """按键按下"""
- return False
-
- def onKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- """按键释放"""
- return False
-
- def onTakeFocus(self, view: Any, content: Any, direction: int) -> bool:
- """获取焦点"""
- return False
-
- def canSelectArbitrarily(self) -> bool:
- """能否任意选择"""
- return False
-
- def dispatchTouchEvent(self, view: Any, content: Any, event: Any) -> bool:
- """分发触摸事件"""
- return False
-
- def onGenericMotionEvent(self, view: Any, content: Any, event: Any) -> bool:
- """通用运动事件"""
- return False
-
- def getMovementMetaState(self) -> int:
- """获取移动元状态"""
- return self._movement_meta_state
-
- def setMovementMetaState(self, state: int) -> None:
- """设置移动元状态"""
- self._movement_meta_state = state
-
- def toString(self) -> str:
- return f"{self.__class__.__name__}@MovementMethod"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ArrowKeyMovementMethod
-# ═══════════════════════════════════════════════════════════════
-
-class ArrowKeyMovementMethod(MovementMethod):
- """ArrowKeyMovementMethod — 箭头键移动方法 (桌面存根)"""
-
- _instance: Optional["ArrowKeyMovementMethod"] = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance() -> "ArrowKeyMovementMethod":
- if ArrowKeyMovementMethod._instance is None:
- ArrowKeyMovementMethod._instance = ArrowKeyMovementMethod()
- return ArrowKeyMovementMethod._instance
-
- def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- return True
-
- def canSelectArbitrarily(self) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinkMovementMethod
-# ═══════════════════════════════════════════════════════════════
-
-class LinkMovementMethod(MovementMethod):
- """LinkMovementMethod — 链接移动方法 (桌面存根)"""
-
- _instance: Optional["LinkMovementMethod"] = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance() -> "LinkMovementMethod":
- if LinkMovementMethod._instance is None:
- LinkMovementMethod._instance = LinkMovementMethod()
- return LinkMovementMethod._instance
-
- def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- return True
-
- def canSelectArbitrarily(self) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Touch
-# ═══════════════════════════════════════════════════════════════
-
-class Touch(Stub):
- """Touch — 触摸工具类 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
- self._initial_scroll_x = 0
- self._initial_scroll_y = 0
-
- @staticmethod
- def getInitialScrollX(widget: Any, content: Any) -> int:
- """获取初始滚动 X"""
- return getattr(widget, '_initial_scroll_x', 0)
-
- @staticmethod
- def getInitialScrollY(widget: Any, content: Any) -> int:
- """获取初始滚动 Y"""
- return getattr(widget, '_initial_scroll_y', 0)
-
- @staticmethod
- def scrollTo(widget: Any, content: Any, x: int, y: int) -> None:
- """滚动到指定位置"""
- if hasattr(widget, '_scroll_x'):
- widget._scroll_x = x
- if hasattr(widget, '_scroll_y'):
- widget._scroll_y = y
-
-
-# ═══════════════════════════════════════════════════════════════
-# BaseMovementMethod
-# ═══════════════════════════════════════════════════════════════
-
-class BaseMovementMethod(MovementMethod):
- """BaseMovementMethod — 基本移动方法 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
-
- def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- return False
-
- def canSelectArbitrarily(self) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScrollingMovementMethod
-# ═══════════════════════════════════════════════════════════════
-
-class ScrollingMovementMethod(BaseMovementMethod):
- """ScrollingMovementMethod — 滚动移动方法 (桌面存根)"""
-
- _instance: Optional["ScrollingMovementMethod"] = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance() -> "ScrollingMovementMethod":
- if ScrollingMovementMethod._instance is None:
- ScrollingMovementMethod._instance = ScrollingMovementMethod()
- return ScrollingMovementMethod._instance
-
- def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# WordIterator
-# ═══════════════════════════════════════════════════════════════
-
-class WordIterator(Stub):
- """WordIterator — 单词迭代器 (桌面存根)"""
-
- def __init__(self, locale: Optional[Any] = None):
- super().__init__()
- self._locale = locale
- self._text = ""
- self._cursor = 0
-
- def setText(self, text: str, start: int, end: int) -> None:
- """设置文本"""
- self._text = text[start:end] if end <= len(text) else text[start:]
- self._cursor = 0
-
- def next(self) -> int:
- """下一个单词边界"""
- self._cursor += 1
- return self._cursor
-
- def prev(self) -> int:
- """上一个单词边界"""
- self._cursor -= 1
- return max(self._cursor, 0)
-
- def getEnd(self) -> int:
- """获取结束位置"""
- return len(self._text)
-
- def getBegin(self) -> int:
- """获取开始位置"""
- return 0
-
- def isBoundary(self, offset: int) -> bool:
- """检查是否是单词边界"""
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# TransformationMethod / PasswordTransformationMethod
-# ═══════════════════════════════════════════════════════════════
-
-class TransformationMethod(Stub):
- """TransformationMethod — 变换方法接口 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
-
- def getTransformation(self, source: Any, view: Any) -> Any:
- """获取变换后的文本"""
- return source
-
- def onFocusChanged(self, view: Any, source: Any, focused: bool, direction: int, previouslyFocused: Any) -> None:
- """焦点变化事件"""
- pass
-
-
-class TransformationMethod2(TransformationMethod):
- """TransformationMethod2 — 带长度变化通知的变换方法"""
-
- def __init__(self):
- super().__init__()
- self._length_changes_allowed = True
-
- def setLengthChangesAllowed(self, allowLengthChanges: bool) -> None:
- """设置是否允许长度变化"""
- self._length_changes_allowed = allowLengthChanges
-
-
-class PasswordTransformationMethod(TransformationMethod):
- """PasswordTransformationMethod — 密码变换方法 (桌面存根)"""
-
- _instance: Optional["PasswordTransformationMethod"] = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance() -> "PasswordTransformationMethod":
- if PasswordTransformationMethod._instance is None:
- PasswordTransformationMethod._instance = PasswordTransformationMethod()
- return PasswordTransformationMethod._instance
-
- def getTransformation(self, source: Any, view: Any) -> Any:
- """将文本转换为掩码字符"""
- text = str(source) if source else ""
- return "\u2022" * len(text) # bullet character
-
- def onFocusChanged(self, view: Any, source: Any, focused: bool, direction: int, previouslyFocused: Any) -> None:
- pass
-
-
-class SingleLineTransformationMethod(TransformationMethod):
- """SingleLineTransformationMethod — 单行变换方法 (桌面存根)"""
-
- _instance: Optional["SingleLineTransformationMethod"] = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance() -> "SingleLineTransformationMethod":
- if SingleLineTransformationMethod._instance is None:
- SingleLineTransformationMethod._instance = SingleLineTransformationMethod()
- return SingleLineTransformationMethod._instance
-
- def getTransformation(self, source: Any, view: Any) -> Any:
- """移除换行符"""
- text = str(source) if source else ""
- return text.replace("\n", " ").replace("\r", "")
-
-
-class HideReturnsTransformationMethod(SingleLineTransformationMethod):
- """HideReturnsTransformationMethod — 隐藏回车变换方法 (桌面存根)"""
-
- _instance: Optional["HideReturnsTransformationMethod"] = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance() -> "HideReturnsTransformationMethod":
- if HideReturnsTransformationMethod._instance is None:
- HideReturnsTransformationMethod._instance = HideReturnsTransformationMethod()
- return HideReturnsTransformationMethod._instance
-
- def getTransformation(self, source: Any, view: Any) -> Any:
- text = str(source) if source else ""
- return text.replace("\r", "")
-
-
-class TimeDisplayTruncationMethod(TransformationMethod):
- """TimeDisplayTruncationMethod — 时间显示截断方法 (桌面存根)"""
-
- def __init__(self, max_digits: int = 4):
- super().__init__()
- self._max_digits = max_digits
-
- def getTransformation(self, source: Any, view: Any) -> Any:
- text = str(source) if source else ""
- if len(text) > self._max_digits:
- return text[:self._max_digits]
- return text
-
-
-# ═══════════════════════════════════════════════════════════════
-# DateTimeKeyListener / DateKeyListener / TimeKeyListener
-# ═══════════════════════════════════════════════════════════════
-
-class DateTimeKeyListener(NumberKeyListener):
- """DateTimeKeyListener — 日期时间按键监听器 (桌面存根)"""
-
- def __init__(self, locale: Optional[Any] = None):
- super().__init__()
- self._locale = locale
- self._ACCEPTED_CHARS = "0123456789/: "
-
-
-class DateKeyListener(NumberKeyListener):
- """DateKeyListener — 日期按键监听器 (桌面存根)"""
-
- _instance: Optional["DateKeyListener"] = None
-
- def __init__(self, locale: Optional[Any] = None):
- super().__init__()
- self._locale = locale
- self._ACCEPTED_CHARS = "0123456789/"
-
- @staticmethod
- def getInstance(locale: Any = None) -> "DateKeyListener":
- if DateKeyListener._instance is None:
- DateKeyListener._instance = DateKeyListener(locale)
- return DateKeyListener._instance
-
-
-class TimeKeyListener(NumberKeyListener):
- """TimeKeyListener — 时间按键监听器 (桌面存根)"""
-
- _instance: Optional["TimeKeyListener"] = None
-
- def __init__(self, locale: Optional[Any] = None):
- super().__init__()
- self._locale = locale
- self._ACCEPTED_CHARS = "0123456789:"
-
- @staticmethod
- def getInstance(locale: Any = None) -> "TimeKeyListener":
- if TimeKeyListener._instance is None:
- TimeKeyListener._instance = TimeKeyListener(locale)
- return TimeKeyListener._instance
\ No newline at end of file
diff --git a/android_pyapi/android/text_style.py b/android_pyapi/android/text_style.py
deleted file mode 100644
index adf620f..0000000
--- a/android_pyapi/android/text_style.py
+++ /dev/null
@@ -1,974 +0,0 @@
-"""
-Android text.style 包 — CharacterStyle, AlignmentSpan, BulletSpan, URLSpan 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "CharacterStyle",
- "MetricAffectingSpan",
- "BackgroundColorSpan",
- "ForegroundColorSpan",
- "StyleSpan",
- "TypefaceSpan",
- "AbsoluteSizeSpan",
- "RelativeSizeSpan",
- "ScaleXSpan",
- "StrikethroughSpan",
- "UnderlineSpan",
- "SubscriptSpan",
- "SuperscriptSpan",
- "URLSpan",
- "ClickableSpan",
- "ImageSpan",
- "AlignmentSpan",
- "BulletSpan",
- "QuoteSpan",
- "LeadingMarginSpan",
- "LeadingMarginSpan2",
- "LineBackgroundSpan",
- "LineHeightSpan",
- "TabStopSpan",
- "WrapTogetherSpan",
- "ParagraphStyle",
- "DrawableMarginSpan",
- "IconMarginSpan",
- "EasyEditSpan",
- "SpellCheckSpan",
- "SuggestionSpan",
- "TextAppearanceSpan",
- "LocaleSpan",
- "ReplacementSpan",
- "DynamicDrawableSpan",
- "MaskFilterSpan",
- "RasterizerSpan",
- "ShadowStyleSpan",
- "TtsSpan",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# CharacterStyle
-# ═══════════════════════════════════════════════════════════════
-
-class CharacterStyle(Stub):
- """CharacterStyle — 字符样式基类 (桌面存根)"""
-
- def __init__(self):
- super().__init__()
-
- def setSpan(self, text: Any, start: int, end: int, flags: int) -> None:
- """设置 span 范围"""
- pass
-
- def getUnderlying(self) -> "CharacterStyle":
- """获取底层样式"""
- return self
-
- @staticmethod
- def wrap(cs: "CharacterStyle") -> "CharacterStyle":
- """包装样式"""
- return cs
-
- def updateDrawState(self, tp: Any) -> None:
- """更新绘制状态"""
- pass
-
- def toString(self) -> str:
- return f"{self.__class__.__name__}@CharacterStyle"
-
-
-class MetricAffectingSpan(CharacterStyle):
- """MetricAffectingSpan — 影响度量的 Span"""
-
- def __init__(self):
- super().__init__()
-
- def updateMeasureState(self, tp: Any) -> None:
- """更新度量状态"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# BackgroundColorSpan
-# ═══════════════════════════════════════════════════════════════
-
-class BackgroundColorSpan(CharacterStyle):
- """BackgroundColorSpan — 背景颜色 Span"""
-
- def __init__(self, color: int = 0):
- super().__init__()
- self._color = color
-
- def setColor(self, color: int) -> None:
- """设置背景颜色"""
- self._color = color
-
- def getBackgroundColor(self) -> int:
- """获取背景颜色"""
- return self._color
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'bgColor'):
- tp.bgColor = self._color
-
-
-# ═══════════════════════════════════════════════════════════════
-# ForegroundColorSpan
-# ═══════════════════════════════════════════════════════════════
-
-class ForegroundColorSpan(CharacterStyle):
- """ForegroundColorSpan — 前景颜色 Span"""
-
- def __init__(self, color: int = 0):
- super().__init__()
- self._color = color
-
- def setColor(self, color: int) -> None:
- """设置前景颜色"""
- self._color = color
-
- def getForegroundColor(self) -> int:
- """获取前景颜色"""
- return self._color
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'color'):
- tp.color = self._color
-
-
-# ═══════════════════════════════════════════════════════════════
-# StyleSpan
-# ═══════════════════════════════════════════════════════════════
-
-class StyleSpan(MetricAffectingSpan):
- """StyleSpan — 字体样式 Span"""
-
- NORMAL = 0
- BOLD = 1
- ITALIC = 2
- BOLD_ITALIC = 3
-
- def __init__(self, style: int = NORMAL):
- super().__init__()
- self._style = style
-
- def getStyle(self) -> int:
- """获取字体样式"""
- return self._style
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'style'):
- tp.style = self._style
-
- def updateMeasureState(self, tp: Any) -> None:
- if hasattr(tp, 'style'):
- tp.style = self._style
-
-
-# ═══════════════════════════════════════════════════════════════
-# TypefaceSpan
-# ═══════════════════════════════════════════════════════════════
-
-class TypefaceSpan(MetricAffectingSpan):
- """TypefaceSpan — 字体 Span"""
-
- def __init__(self, family: str = "sans-serif"):
- super().__init__()
- self._family = family
-
- def getFamily(self) -> str:
- """获取字体名称"""
- return self._family
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'typeface'):
- tp.typeface = self._family
-
- def updateMeasureState(self, tp: Any) -> None:
- if hasattr(tp, 'typeface'):
- tp.typeface = self._family
-
-
-# ═══════════════════════════════════════════════════════════════
-# AbsoluteSizeSpan
-# ═══════════════════════════════════════════════════════════════
-
-class AbsoluteSizeSpan(MetricAffectingSpan):
- """AbsoluteSizeSpan — 绝对字号 Span"""
-
- def __init__(self, size: int = 0, dip: bool = False):
- super().__init__()
- self._size = size
- self._dip = dip
-
- def getSize(self) -> int:
- """获取字号"""
- return self._size
-
- def getDip(self) -> bool:
- """检查是否使用 dip 单位"""
- return self._dip
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'textSize'):
- tp.textSize = float(self._size)
-
- def updateMeasureState(self, tp: Any) -> None:
- if hasattr(tp, 'textSize'):
- tp.textSize = float(self._size)
-
-
-# ═══════════════════════════════════════════════════════════════
-# RelativeSizeSpan
-# ═══════════════════════════════════════════════════════════════
-
-class RelativeSizeSpan(MetricAffectingSpan):
- """RelativeSizeSpan — 相对字号 Span"""
-
- def __init__(self, proportion: float = 1.0):
- super().__init__()
- self._proportion = proportion
-
- def getSizeChange(self) -> float:
- """获取字号变化比例"""
- return self._proportion
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'textSize') and hasattr(tp, '_baseTextSize'):
- tp.textSize = tp._baseTextSize * self._proportion
-
- def updateMeasureState(self, tp: Any) -> None:
- if hasattr(tp, 'textSize') and hasattr(tp, '_baseTextSize'):
- tp.textSize = tp._baseTextSize * self._proportion
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScaleXSpan
-# ═══════════════════════════════════════════════════════════════
-
-class ScaleXSpan(MetricAffectingSpan):
- """ScaleXSpan — X 轴缩放 Span"""
-
- def __init__(self, scale_x: float = 1.0):
- super().__init__()
- self._scale_x = scale_x
-
- def getScaleX(self) -> float:
- """获取 X 轴缩放比例"""
- return self._scale_x
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'textScaleX'):
- tp.textScaleX = self._scale_x
-
- def updateMeasureState(self, tp: Any) -> None:
- if hasattr(tp, 'textScaleX'):
- tp.textScaleX = self._scale_x
-
-
-# ═══════════════════════════════════════════════════════════════
-# StrikethroughSpan / UnderlineSpan / SubscriptSpan / SuperscriptSpan
-# ═══════════════════════════════════════════════════════════════
-
-class StrikethroughSpan(CharacterStyle):
- """StrikethroughSpan — 删除线 Span"""
-
- def __init__(self):
- super().__init__()
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'strikethru'):
- tp.strikethru = True
-
-
-class UnderlineSpan(CharacterStyle):
- """UnderlineSpan — 下划线 Span"""
-
- def __init__(self):
- super().__init__()
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'underline'):
- tp.underline = True
-
-
-class SubscriptSpan(MetricAffectingSpan):
- """SubscriptSpan — 下标 Span"""
-
- def __init__(self):
- super().__init__()
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'subscript'):
- tp.subscript = True
-
-
-class SuperscriptSpan(MetricAffectingSpan):
- """SuperscriptSpan — 上标 Span"""
-
- def __init__(self):
- super().__init__()
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'superscript'):
- tp.superscript = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# URLSpan / ClickableSpan
-# ═══════════════════════════════════════════════════════════════
-
-class URLSpan(CharacterStyle):
- """URLSpan — 超链接 Span"""
-
- def __init__(self, url: str = ""):
- super().__init__()
- self._url = url
-
- def getURL(self) -> str:
- """获取 URL"""
- return self._url
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'color'):
- tp.color = 0xFF0000FF # blue
- if hasattr(tp, 'underline'):
- tp.underline = True
-
- def onClick(self, view: Any) -> None:
- """点击事件"""
- pass
-
-
-class ClickableSpan(CharacterStyle):
- """ClickableSpan — 可点击 Span"""
-
- def __init__(self):
- super().__init__()
-
- def onClick(self, view: Any) -> None:
- """点击事件"""
- pass
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'color'):
- tp.color = 0xFF0000FF
- if hasattr(tp, 'underline'):
- tp.underline = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImageSpan
-# ═══════════════════════════════════════════════════════════════
-
-class ImageSpan(CharacterStyle):
- """ImageSpan — 图片 Span"""
-
- def __init__(self, drawable: Any = None, source: str = "", vertical_alignment: int = 0):
- super().__init__()
- self._drawable = drawable
- self._source = source
- self._vertical_alignment = vertical_alignment
-
- def getDrawable(self) -> Any:
- """获取 Drawable"""
- return self._drawable
-
- def getSource(self) -> str:
- """获取资源源"""
- return self._source
-
- def getContentUri(self) -> Optional[str]:
- """获取内容 URI"""
- return None
-
- def draw(self, canvas: Any, text: str, x: int, y: int, top: int, bottom: int) -> None:
- """绘制图片"""
- if self._drawable and hasattr(self._drawable, 'draw'):
- self._drawable.draw(canvas)
-
- def toString(self) -> str:
- return f"ImageSpan(source={self._source})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AlignmentSpan
-# ═══════════════════════════════════════════════════════════════
-
-class AlignmentSpan(CharacterStyle):
- """AlignmentSpan — 对齐 Span"""
-
- class Standard(CharacterStyle):
- """标准对齐实现"""
-
- def __init__(self, alignment: int):
- super().__init__()
- self._alignment = alignment
-
- def getAlignment(self) -> int:
- return self._alignment
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'alignment'):
- tp.alignment = self._alignment
-
- def __init__(self, alignment: int = 0):
- super().__init__()
- self._alignment = alignment
-
- def getAlignment(self) -> int:
- """获取对齐方式"""
- return self._alignment
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'alignment'):
- tp.alignment = self._alignment
-
-
-# ═══════════════════════════════════════════════════════════════
-# BulletSpan
-# ═══════════════════════════════════════════════════════════════
-
-class BulletSpan(CharacterStyle):
- """BulletSpan — 项目符号 Span"""
-
- STANDARD_GAP_WIDTH = 2
-
- def __init__(self, leading_margin: int = 0, gap_width: int = STANDARD_GAP_WIDTH,
- bullet_radius: int = 4, color: int = 0xFF000000):
- super().__init__()
- self._leading_margin = leading_margin
- self._gap_width = gap_width
- self._bullet_radius = bullet_radius
- self._color = color
-
- def getLeadingMargin(self) -> int:
- """获取前导边距"""
- return self._leading_margin
-
- def getGapWidth(self) -> int:
- """获取间隙宽度"""
- return self._gap_width
-
- def getBulletRadius(self) -> int:
- """获取项目符号半径"""
- return self._bullet_radius
-
- def getColor(self) -> int:
- """获取颜色"""
- return self._color
-
- def updateDrawState(self, tp: Any) -> None:
- pass
-
- def drawLeadingMargin(self, canvas: Any, paint: Any, x: int, dir_: int,
- top: int, baseline: int, bottom: int, text: str,
- start: int, end: int, first: bool, margin: int) -> None:
- """绘制前导边距中的项目符号"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# QuoteSpan
-# ═══════════════════════════════════════════════════════════════
-
-class QuoteSpan(CharacterStyle):
- """QuoteSpan — 引用 Span"""
-
- STANDARD_GAP_WIDTH = 2
- STANDARD_COLOR = 0xFF0000FF
-
- def __init__(self, color: int = STANDARD_COLOR, gap_width: int = STANDARD_GAP_WIDTH, stripe_width: int = 2):
- super().__init__()
- self._color = color
- self._gap_width = gap_width
- self._stripe_width = stripe_width
-
- def getColor(self) -> int:
- """获取引用颜色"""
- return self._color
-
- def getGapWidth(self) -> int:
- """获取间隙宽度"""
- return self._gap_width
-
- def getStripeWidth(self) -> int:
- """获取条纹宽度"""
- return self._stripe_width
-
- def updateDrawState(self, tp: Any) -> None:
- pass
-
- def drawLeadingMargin(self, canvas: Any, paint: Any, x: int, dir_: int,
- top: int, baseline: int, bottom: int, text: str,
- start: int, end: int, first: bool, margin: int) -> None:
- """绘制引用条纹"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# LeadingMarginSpan / LeadingMarginSpan2
-# ═══════════════════════════════════════════════════════════════
-
-class LeadingMarginSpan(CharacterStyle):
- """LeadingMarginSpan — 前导边距 Span"""
-
- def __init__(self):
- super().__init__()
-
- def getLeadingMargin(self, first: bool) -> int:
- """获取前导边距"""
- return 0
-
- def drawLeadingMargin(self, canvas: Any, paint: Any, x: int, dir_: int,
- top: int, baseline: int, bottom: int, text: str,
- start: int, end: int, first: bool, margin: int) -> None:
- """绘制前导边距"""
- pass
-
-
-class LeadingMarginSpan2(LeadingMarginSpan):
- """LeadingMarginSpan2 — 支持行数限制的前导边距 Span"""
-
- def __init__(self):
- super().__init__()
-
- def getLeadingMarginLineCount(self) -> int:
- """获取前导边距行数"""
- return 1
-
-
-# ═══════════════════════════════════════════════════════════════
-# LineBackgroundSpan / LineHeightSpan
-# ═══════════════════════════════════════════════════════════════
-
-class LineBackgroundSpan(CharacterStyle):
- """LineBackgroundSpan — 行背景 Span"""
-
- def __init__(self):
- super().__init__()
-
- def drawBackground(self, canvas: Any, paint: Any, left: int, right: int,
- top: int, baseline: int, bottom: int, text: str,
- start: int, end: int, line_num: int) -> None:
- """绘制行背景"""
- pass
-
-
-class LineHeightSpan(CharacterStyle):
- """LineHeightSpan — 行高 Span"""
-
- class WithDensity(CharacterStyle):
- """带密度参数的行高实现"""
-
- def __init__(self):
- super().__init__()
-
- def chooseHeight(self, text: str, start: int, end: int, spanstart: int,
- spanend: int, height: List[int], fontMetrics: Any) -> None:
- pass
-
- def __init__(self):
- super().__init__()
-
- def chooseHeight(self, text: str, start: int, end: int, spanstart: int,
- spanend: int, height: List[int], fontMetrics: Any) -> None:
- """选择行高"""
- pass
-
- @staticmethod
- def increaseHeight(height: List[int], increase: int) -> None:
- """增加高度"""
- if height:
- height[0] = height[0] + increase
-
-
-# ═══════════════════════════════════════════════════════════════
-# TabStopSpan / WrapTogetherSpan / ParagraphStyle
-# ═══════════════════════════════════════════════════════════════
-
-class TabStopSpan(CharacterStyle):
- """TabStopSpan — 制表符停靠 Span"""
-
- class Standard(CharacterStyle):
- """标准制表符停靠实现"""
-
- def __init__(self, tab_stop: int = 40):
- super().__init__()
- self._tab_stop = tab_stop
-
- def getTabStop(self) -> int:
- return self._tab_stop
-
- def __init__(self, tab_stop: int = 40):
- super().__init__()
- self._tab_stop = tab_stop
-
- def getTabStop(self) -> int:
- """获取制表符停靠位置"""
- return self._tab_stop
-
-
-class WrapTogetherSpan(CharacterStyle):
- """WrapTogetherSpan — 一起换行 Span"""
-
- def __init__(self):
- super().__init__()
-
-
-class ParagraphStyle(Stub):
- """ParagraphStyle — 段落样式标记接口"""
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# DrawableMarginSpan / IconMarginSpan
-# ═══════════════════════════════════════════════════════════════
-
-class DrawableMarginSpan(CharacterStyle):
- """DrawableMarginSpan — 可绘制边距 Span"""
-
- def __init__(self, drawable: Any = None, pad: int = 0):
- super().__init__()
- self._drawable = drawable
- self._pad = pad
-
-
-class IconMarginSpan(CharacterStyle):
- """IconMarginSpan — 图标边距 Span"""
-
- def __init__(self, bitmap: Any = None, pad: int = 0):
- super().__init__()
- self._bitmap = bitmap
- self._pad = pad
-
-
-# ═══════════════════════════════════════════════════════════════
-# EasyEditSpan / SpellCheckSpan
-# ═══════════════════════════════════════════════════════════════
-
-class EasyEditSpan(CharacterStyle):
- """EasyEditSpan — 简易编辑 Span"""
-
- def __init__(self):
- super().__init__()
-
-
-class SpellCheckSpan(CharacterStyle):
- """SpellCheckSpan — 拼写检查 Span"""
-
- def __init__(self, spell_checking: bool = True):
- super().__init__()
- self._spell_checking = spell_checking
-
- def isSpellCheckEnabled(self) -> bool:
- """检查拼写检查是否启用"""
- return self._spell_checking
-
- def setSpellCheckEnabled(self, enabled: bool) -> None:
- """设置拼写检查启用"""
- self._spell_checking = enabled
-
-
-# ═══════════════════════════════════════════════════════════════
-# SuggestionSpan
-# ═══════════════════════════════════════════════════════════════
-
-class SuggestionSpan(CharacterStyle):
- """SuggestionSpan — 建议 Span"""
-
- FLAG_EASY_CORRECT = 0x0001
- FLAG_MISSPELLED = 0x0002
- FLAG_AUTO_CORRECTION = 0x0004
- FLAG_GRAMMAR_ERROR = 0x0008
- FLAG_PERSONAL_NAME = 0x0010
- FLAG_COMPATIBILITY = 0x0020
- SUGGESTIONS_MAX_SIZE = 5
-
- def __init__(self, locale: Optional[Any] = None, suggestions: Optional[List[str]] = None,
- flags: int = 0, underline_color: int = 0):
- super().__init__()
- self._locale = locale
- self._suggestions = suggestions or []
- self._flags = flags
- self._underline_color = underline_color
-
- def getLocale(self) -> Optional[Any]:
- """获取区域设置"""
- return self._locale
-
- def getSuggestions(self) -> List[str]:
- """获取建议列表"""
- return self._suggestions.copy()
-
- def getUnderlineColor(self) -> int:
- """获取下划线颜色"""
- return self._underline_color
-
- def setUnderlineColor(self, color: int) -> None:
- """设置下划线颜色"""
- self._underline_color = color
-
- def getFlags(self) -> int:
- """获取标志"""
- return self._flags
-
- def setFlags(self, flags: int) -> None:
- """设置标志"""
- self._flags = flags
-
- @staticmethod
- def getSuggestionsFromContext(context: Any, locale: Any, query: str,
- max_results: int = SUGGESTIONS_MAX_SIZE) -> List[str]:
- """从上下文中获取建议"""
- return []
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextAppearanceSpan
-# ═══════════════════════════════════════════════════════════════
-
-class TextAppearanceSpan(MetricAffectingSpan):
- """TextAppearanceSpan — 文字外观 Span"""
-
- def __init__(self, context: Any = None, appearance_id: int = 0,
- family: str = "sans-serif", text_size: Optional[int] = None,
- text_color: Optional[int] = None, link_text_color: Optional[int] = None):
- super().__init__()
- self._family = family
- self._text_size = text_size
- self._text_color = text_color
- self._link_text_color = link_text_color
-
- def getFamily(self) -> str:
- """获取字体名称"""
- return self._family
-
- def getTextSize(self) -> Optional[int]:
- """获取字号"""
- return self._text_size
-
- def getTextColor(self) -> Optional[int]:
- """获取文字颜色"""
- return self._text_color
-
- def getTextColorLink(self) -> Optional[int]:
- """获取链接文字颜色"""
- return self._link_text_color
-
- def getLinkTextColor(self) -> Optional[int]:
- """获取链接文字颜色"""
- return self._link_text_color
-
- def updateDrawState(self, tp: Any) -> None:
- if self._text_color is not None and hasattr(tp, 'color'):
- tp.color = self._text_color
- if self._text_size is not None and hasattr(tp, 'textSize'):
- tp.textSize = float(self._text_size)
- if hasattr(tp, 'typeface'):
- tp.typeface = self._family
-
- def updateMeasureState(self, tp: Any) -> None:
- if self._text_size is not None and hasattr(tp, 'textSize'):
- tp.textSize = float(self._text_size)
-
-
-# ═══════════════════════════════════════════════════════════════
-# LocaleSpan
-# ═══════════════════════════════════════════════════════════════
-
-class LocaleSpan(MetricAffectingSpan):
- """LocaleSpan — 区域设置 Span"""
-
- def __init__(self, locale: Any = None):
- super().__init__()
- self._locale = locale
-
- def getLocale(self) -> Any:
- """获取区域设置"""
- return self._locale
-
- def updateDrawState(self, tp: Any) -> None:
- pass
-
- def updateMeasureState(self, tp: Any) -> None:
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ReplacementSpan
-# ═══════════════════════════════════════════════════════════════
-
-class ReplacementSpan(CharacterStyle):
- """ReplacementSpan — 替换 Span"""
-
- def __init__(self):
- super().__init__()
-
- def draw(self, canvas: Any, text: str, start: int, end: int, x: float,
- top: int, y: float, bottom: int, paint: Any) -> None:
- """绘制替换内容"""
- pass
-
- def getSize(self, paint: Any, text: str, start: int, end: int,
- fontMetrics: Optional[Any]) -> int:
- """获取尺寸"""
- return 0
-
- def updateMeasureState(self, tp: Any) -> None:
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# DynamicDrawableSpan
-# ═══════════════════════════════════════════════════════════════
-
-class DynamicDrawableSpan(ReplacementSpan):
- """DynamicDrawableSpan — 动态可绘制 Span"""
-
- ALIGN_BOTTOM = 0
- ALIGN_BASELINE = 1
- ALIGN_CENTER = 2
-
- def __init__(self, vertical_alignment: int = ALIGN_BOTTOM):
- super().__init__()
- self._vertical_alignment = vertical_alignment
-
- def getDrawable(self) -> Any:
- """获取可绘制对象"""
- return None
-
- def draw(self, canvas: Any, text: str, start: int, end: int, x: float,
- top: int, y: float, bottom: int, paint: Any) -> None:
- drawable = self.getDrawable()
- if drawable:
- pass
-
- def getSize(self, paint: Any, text: str, start: int, end: int,
- fontMetrics: Optional[Any]) -> int:
- drawable = self.getDrawable()
- if drawable and hasattr(drawable, 'getIntrinsicWidth'):
- return drawable.getIntrinsicWidth()
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# MaskFilterSpan / RasterizerSpan / ShadowStyleSpan
-# ═══════════════════════════════════════════════════════════════
-
-class MaskFilterSpan(CharacterStyle):
- """MaskFilterSpan — 遮罩滤镜 Span"""
-
- def __init__(self, filter_: Any = None):
- super().__init__()
- self._filter = filter_
-
- def getMaskFilter(self) -> Any:
- """获取遮罩滤镜"""
- return self._filter
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'maskFilter'):
- tp.maskFilter = self._filter
-
-
-class RasterizerSpan(CharacterStyle):
- """RasterizerSpan — 光栅化 Span"""
-
- def __init__(self, rasterizer: Any = None):
- super().__init__()
- self._rasterizer = rasterizer
-
- def getRasterizer(self) -> Any:
- """获取光栅化器"""
- return self._rasterizer
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'rasterizer'):
- tp.rasterizer = self._rasterizer
-
-
-class ShadowStyleSpan(CharacterStyle):
- """ShadowStyleSpan — 阴影样式 Span"""
-
- def __init__(self, radius: float = 1.0, dx: float = 0, dy: float = 0, color: int = 0):
- super().__init__()
- self._radius = radius
- self._dx = dx
- self._dy = dy
- self._color = color
-
- def updateDrawState(self, tp: Any) -> None:
- if hasattr(tp, 'setShadowLayer'):
- tp.setShadowLayer(self._radius, self._dx, self._dy, self._color)
-
-
-# ═══════════════════════════════════════════════════════════════
-# TtsSpan
-# ═══════════════════════════════════════════════════════════════
-
-class TtsSpan(CharacterStyle):
- """TtsSpan — 文本转语音 Span"""
-
- TYPE_DATE = "android.type.date"
- TYPE_DELIMITER = "android.type.delimiter"
- TYPE_DIGITS = "android.type.digits"
- TYPE_ELECTRONIC = "android.type.electronic"
- TYPE_FRACTION = "android.type.fraction"
- TYPE_MEASURE = "android.type.measure"
- TYPE_MONEY = "android.type.money"
- TYPE_NUMBER = "android.type.number"
- TYPE_ORDINAL = "android.type.ordinal"
- TYPE_PERCENTAGE = "android.type.percentage"
- TYPE_TELEPHONE = "android.type.telephone"
- TYPE_TEXT = "android.type.text"
- TYPE_TIME = "android.type.time"
- TYPE_VERBATIM = "android.type.verbatim"
-
- ARG_TEXT = "android.arg.text"
- ARG_QUANTITY = "android.arg.quantity"
- ARG_MINUTES = "android.arg.minutes"
- ARG_HOURS = "android.arg.hours"
- ARG_DAY = "android.arg.day"
- ARG_MONTH = "android.arg.month"
- ARG_YEAR = "android.arg.year"
- ARG_WEEKDAY = "android.arg.weekday"
- ARG_COUNTRY_CODE = "android.arg.country_code"
- ARG_NUMBER_PARTS = "android.arg.number_parts"
- ARG_NUMBER_TYPE = "android.arg.number_type"
- ARG_NUMBER_GROUP = "android.arg.number_group"
- ARG_MONEY = "android.arg.money"
- ARG_CURRENCY = "android.arg.currency"
- ARG_AMOUNT = "android.arg.amount"
- ARG_FRACTION_DENOMINATOR = "android.arg.fraction_denominator"
- ARG_FRACTION_NUMERATOR = "android.arg.fraction_numerator"
- ARG_FRACTION_TYPE = "android.arg.fraction_type"
- ARG_INTEGER_PART = "android.arg.integer_part"
-
- def __init__(self, type_: str = TYPE_TEXT, args: Optional[Dict[str, str]] = None):
- super().__init__()
- self._type = type_
- self._args = args or {}
-
- def getType(self) -> str:
- """获取 TTS 类型"""
- return self._type
-
- def getArgs(self) -> Dict[str, str]:
- """获取参数"""
- return self._args.copy()
-
- def toString(self) -> str:
- return f"TtsSpan(type={self._type}, args={self._args})"
\ No newline at end of file
diff --git a/android_pyapi/android/text_util.py b/android_pyapi/android/text_util.py
deleted file mode 100644
index c2f4d4a..0000000
--- a/android_pyapi/android/text_util.py
+++ /dev/null
@@ -1,297 +0,0 @@
-"""
-Android text.util 包 — Linkify, Rfc822Token, Rfc822Tokenizer, Selection, LinkSpec
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import re
-from typing import Any, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "Linkify",
- "Rfc822Token",
- "Rfc822Tokenizer",
- "Selection",
- "LinkSpec",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# Linkify
-# ═══════════════════════════════════════════════════════════════
-
-class Linkify(Stub):
- """Linkify — 自动链接工具 (使用正则表达式检测 URL/邮件/电话)"""
-
- ALL = 0xFFFFFFFF
- PHONE_NUMBERS = 0x1
- WEB_URLS = 0x2
- EMAIL_ADDRESSES = 0x4
- MAP_ADDRESSES = 0x8
-
- _WEB_URL_PATTERN = re.compile(
- r'(https?://|www\.)[a-zA-Z0-9\-\.]+\.\w{2,}(/\S*)?'
- )
- _EMAIL_PATTERN = re.compile(
- r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
- )
- _PHONE_PATTERN = re.compile(
- r'(\+?\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}'
- )
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def addLinks(text: Any, mask: int = ALL) -> bool:
- """向文本中添加链接"""
- if hasattr(text, '_links'):
- text._links = []
- s = str(text)
- if mask & Linkify.WEB_URLS:
- for m in Linkify._WEB_URL_PATTERN.finditer(s):
- spec = LinkSpec()
- spec.url = m.group()
- spec.start = m.start()
- spec.end = m.end()
- text._links.append(spec)
- if mask & Linkify.EMAIL_ADDRESSES:
- for m in Linkify._EMAIL_PATTERN.finditer(s):
- spec = LinkSpec()
- spec.url = f"mailto:{m.group()}"
- spec.start = m.start()
- spec.end = m.end()
- text._links.append(spec)
- if mask & Linkify.PHONE_NUMBERS:
- for m in Linkify._PHONE_PATTERN.finditer(s):
- spec = LinkSpec()
- spec.url = f"tel:{m.group()}"
- spec.start = m.start()
- spec.end = m.end()
- text._links.append(spec)
- return len(text._links) > 0
- return False
-
- @staticmethod
- def addLinks_ext(text: Any, pattern: Any, scheme: str,
- linkMatchFilter: Any = None, urlFilter: Any = None) -> bool:
- """使用自定义模式添加链接"""
- if hasattr(text, '_links'):
- text._links = []
- s = str(text)
- if isinstance(pattern, str):
- compiled = re.compile(pattern)
- else:
- compiled = pattern
- for m in compiled.finditer(s):
- spec = LinkSpec()
- spec.url = f"{scheme}:{m.group()}"
- spec.start = m.start()
- spec.end = m.end()
- text._links.append(spec)
- return len(text._links) > 0
- return False
-
- @staticmethod
- def removeLinks(text: Any) -> None:
- """移除文本中的链接"""
- if hasattr(text, '_links'):
- text._links = []
-
- @staticmethod
- def applyLinks(text: Any, mask: int) -> bool:
- """应用链接"""
- return Linkify.addLinks(text, mask)
-
- def toString(self) -> str:
- return f"Linkify()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Rfc822Token
-# ═══════════════════════════════════════════════════════════════
-
-class Rfc822Token(Stub):
- """Rfc822Token — RFC 822 电子邮件令牌"""
-
- def __init__(self, name: str = "", address: str = "", comment: str = ""):
- super().__init__()
- self._name = name
- self._address = address
- self._comment = comment
-
- def getName(self) -> str:
- """获取名称"""
- return self._name
-
- def getAddress(self) -> str:
- """获取地址"""
- return self._address
-
- def getComment(self) -> str:
- """获取注释"""
- return self._comment
-
- def setAddress(self, address: str) -> None:
- """设置地址"""
- self._address = address
-
- def setComment(self, comment: str) -> None:
- """设置注释"""
- self._comment = comment
-
- def setName(self, name: str) -> None:
- """设置名称"""
- self._name = name
-
- def toString(self) -> str:
- """返回完整的 RFC 822 字符串"""
- parts = []
- if self._name:
- parts.append(f"{self._name} <{self._address}>")
- else:
- parts.append(self._address)
- if self._comment:
- parts.append(f"({self._comment})")
- return " ".join(parts)
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, Rfc822Token):
- return False
- return (self._name == other._name and
- self._address == other._address and
- self._comment == other._comment)
-
- def hashCode(self) -> int:
- return hash((self._name, self._address, self._comment)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# Rfc822Tokenizer
-# ═══════════════════════════════════════════════════════════════
-
-class Rfc822Tokenizer(Stub):
- """Rfc822Tokenizer — RFC 822 分词器"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def tokenize(text: str) -> List[Rfc822Token]:
- """分词"""
- tokens = []
- pattern = re.compile(r'([^<,]+)?<([^>]+)>\s*\(([^)]*)\)|([^<,]+)?<([^>]+)>|([^@,\s]+@[^,\s]+)')
- for m in pattern.finditer(text):
- if m.group(1) or m.group(2):
- name = (m.group(1) or "").strip()
- addr = (m.group(2) or m.group(5) or "").strip()
- comment = (m.group(3) or "").strip()
- tokens.append(Rfc822Token(name, addr, comment))
- elif m.group(6):
- tokens.append(Rfc822Token("", m.group(6).strip(), ""))
- return tokens
-
- @staticmethod
- def getTokenStart(text: str, cursor: int) -> int:
- """获取令牌起始位置"""
- return cursor
-
- @staticmethod
- def getTokenEnd(text: str, cursor: int) -> int:
- """获取令牌结束位置"""
- return cursor
-
- @staticmethod
- def advance(text: str, cursor: int) -> int:
- """前进光标"""
- return cursor + 1
-
-
-# ═══════════════════════════════════════════════════════════════
-# Selection
-# ═══════════════════════════════════════════════════════════════
-
-class Selection(Stub):
- """Selection — 文本选择工具"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def setSelection(content: Any, start: int, stop: Optional[int] = None) -> None:
- """设置选择范围"""
- if hasattr(content, '_selection_start'):
- content._selection_start = start
- content._selection_end = stop if stop is not None else start
- if hasattr(content, '_selection'):
- content._selection = (start, stop if stop is not None else start)
-
- @staticmethod
- def extendSelection(content: Any, index: int) -> None:
- """扩展选择范围"""
- if hasattr(content, '_selection_end'):
- content._selection_end = index
-
- @staticmethod
- def extendUp(content: Any, view: Any) -> bool:
- """向上扩展选择"""
- return False
-
- @staticmethod
- def extendDown(content: Any, view: Any) -> bool:
- """向下扩展选择"""
- return False
-
- @staticmethod
- def extendLeft(content: Any, view: Any) -> bool:
- """向左扩展选择"""
- return False
-
- @staticmethod
- def extendRight(content: Any, view: Any) -> bool:
- """向右扩展选择"""
- return False
-
- @staticmethod
- def moveUp(content: Any, view: Any) -> bool:
- """向上移动选择"""
- return False
-
- @staticmethod
- def moveDown(content: Any, view: Any) -> bool:
- """向下移动选择"""
- return False
-
- @staticmethod
- def moveLeft(content: Any, view: Any) -> bool:
- """向左移动选择"""
- return False
-
- @staticmethod
- def moveRight(content: Any, view: Any) -> bool:
- """向右移动选择"""
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinkSpec
-# ═══════════════════════════════════════════════════════════════
-
-class LinkSpec(Stub):
- """LinkSpec — 链接规范"""
-
- def __init__(self):
- super().__init__()
- self.url: str = ""
- self.start: int = 0
- self.end: int = 0
- self.frameworkAddedSpan: bool = False
-
- def toString(self) -> str:
- return f"LinkSpec(url={self.url}, start={self.start}, end={self.end})"
\ No newline at end of file
diff --git a/android_pyapi/android/transition.py b/android_pyapi/android/transition.py
deleted file mode 100644
index f7064cc..0000000
--- a/android_pyapi/android/transition.py
+++ /dev/null
@@ -1,504 +0,0 @@
-"""
-Android Transition 组件 — Transition, TransitionManager, Scene, Fade, Slide, Explode 等
-方法签名完全对齐 Android SDK (android.transition 包)
-"""
-
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# Scene
-# ═══════════════════════════════════════════════════════════════
-
-class Scene(Stub):
- """Scene — 转场场景"""
-
- def __init__(self, root: Any = None, layout: Any = None):
- super().__init__()
- self._root = root
- self._layout = layout
- self._entered = False
-
- @staticmethod
- def getSceneForLayout(root: Any, layout_id: int, context: Any) -> "Scene":
- """从布局资源创建场景"""
- return Scene(root, layout_id)
-
- def getRoot(self) -> Any:
- return self._root
-
- def enter(self):
- """进入场景"""
- self._entered = True
-
- def exit(self):
- """退出场景"""
- self._entered = False
-
- def isEntered(self) -> bool:
- return self._entered
-
- def setEnterAction(self, action: Callable):
- """设置进入动作"""
- self._enter_action = action
-
- def setExitAction(self, action: Callable):
- """设置退出动作"""
- self._exit_action = action
-
- def toString(self) -> str:
- return f"Scene(root={self._root}, entered={self._entered})"
-
- def hashCode(self) -> int:
- return hash(id(self._root)) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Scene):
- return False
- return self._root is other._root
-
-
-# ═══════════════════════════════════════════════════════════════
-# Transition
-# ═══════════════════════════════════════════════════════════════
-
-class Transition(Stub):
- """Transition — 转场动画基类"""
-
- # 匹配模式
- MATCH_VIEW_NAME = 0
- MATCH_ID = 1
- MATCH_INSTANCE = 2
- MATCH_ITEM_ID = 3
-
- def __init__(self):
- super().__init__()
- self._duration: int = 300
- self._start_delay: int = 0
- self._interpolator: Optional[Any] = None
- self._targets: Set[Any] = set()
- self._target_ids: Set[int] = set()
- self._target_names: Set[str] = set()
- self._target_types: Set[type] = set()
- self._exclude_targets: Set[Any] = set()
- self._exclude_ids: Set[int] = set()
- self._exclude_names: Set[str] = set()
- self._exclude_types: Set[type] = set()
- self._listeners: List[Any] = []
- self._name: str = ""
- self._epicenter_callback: Optional[Callable] = None
- self._path_motion: Optional[Any] = None
- self._propagation: Optional[Any] = None
- self._paused: bool = False
- self._started: bool = False
- self._ended: bool = False
-
- def setDuration(self, duration_ms: int) -> "Transition":
- """设置持续时间 (毫秒)"""
- self._duration = max(0, duration_ms)
- return self
-
- def getDuration(self) -> int:
- return self._duration
-
- def setStartDelay(self, start_delay: int) -> "Transition":
- """设置起始延迟 (毫秒)"""
- self._start_delay = max(0, start_delay)
- return self
-
- def getStartDelay(self) -> int:
- return self._start_delay
-
- def setInterpolator(self, interpolator: Any) -> "Transition":
- """设置插值器"""
- self._interpolator = interpolator
- return self
-
- def getInterpolator(self) -> Any:
- return self._interpolator
-
- def addTarget(self, target: Any) -> "Transition":
- """添加动画目标"""
- if isinstance(target, int):
- self._target_ids.add(target)
- elif isinstance(target, str):
- self._target_names.add(target)
- elif isinstance(target, type):
- self._target_types.add(target)
- else:
- self._targets.add(target)
- return self
-
- def removeTarget(self, target: Any) -> "Transition":
- """移除动画目标"""
- if isinstance(target, int):
- self._target_ids.discard(target)
- elif isinstance(target, str):
- self._target_names.discard(target)
- elif isinstance(target, type):
- self._target_types.discard(target)
- else:
- self._targets.discard(target)
- return self
-
- def getTargets(self) -> List[Any]:
- return list(self._targets)
-
- def excludeTarget(self, target: Any, exclude: bool = True) -> "Transition":
- """排除目标"""
- if exclude:
- if isinstance(target, int):
- self._exclude_ids.add(target)
- elif isinstance(target, str):
- self._exclude_names.add(target)
- elif isinstance(target, type):
- self._exclude_types.add(target)
- else:
- self._exclude_targets.add(target)
- else:
- if isinstance(target, int):
- self._exclude_ids.discard(target)
- elif isinstance(target, str):
- self._exclude_names.discard(target)
- elif isinstance(target, type):
- self._exclude_types.discard(target)
- else:
- self._exclude_targets.discard(target)
- return self
-
- def addListener(self, listener: Any) -> "Transition":
- """添加转场监听器"""
- if listener not in self._listeners:
- self._listeners.append(listener)
- return self
-
- def removeListener(self, listener: Any) -> "Transition":
- """移除转场监听器"""
- if listener in self._listeners:
- self._listeners.remove(listener)
- return self
-
- def getListeners(self) -> List[Any]:
- return list(self._listeners)
-
- def setName(self, name: str) -> "Transition":
- self._name = name
- return self
-
- def getName(self) -> str:
- return self._name
-
- def setEpicenterCallback(self, callback: Callable) -> "Transition":
- self._epicenter_callback = callback
- return self
-
- def getEpicenterCallback(self) -> Optional[Callable]:
- return self._epicenter_callback
-
- def setPathMotion(self, path_motion: Any) -> "Transition":
- self._path_motion = path_motion
- return self
-
- def getPathMotion(self) -> Any:
- return self._path_motion
-
- def setPropagation(self, propagation: Any) -> "Transition":
- self._propagation = propagation
- return self
-
- def getPropagation(self) -> Any:
- return self._propagation
-
- def isPaused(self) -> bool:
- return self._paused
-
- def pause(self):
- """暂停转场"""
- self._paused = True
-
- def resume(self):
- """恢复转场"""
- self._paused = False
-
- def cancel(self):
- """取消转场"""
- self._started = False
- self._ended = True
-
- def end(self):
- """结束转场"""
- self._ended = True
-
- def toString(self) -> str:
- return (f"{self.__class__.__name__}(duration={self._duration}, "
- f"startDelay={self._start_delay}, targets={len(self._targets)})")
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return self is other
-
- def captureStartValues(self, view: Any):
- """捕获视图起始值"""
- pass
-
- def captureEndValues(self, view: Any):
- """捕获视图结束值"""
- pass
-
- def createAnimator(self, view: Any, start_values: Any,
- end_values: Any) -> Optional[Any]:
- """创建动画器"""
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# TransitionSet
-# ═══════════════════════════════════════════════════════════════
-
-class TransitionSet(Transition):
- """TransitionSet — 转场合集"""
-
- ORDERING_TOGETHER = 0
- ORDERING_SEQUENTIAL = 1
-
- def __init__(self):
- super().__init__()
- self._ordering = TransitionSet.ORDERING_TOGETHER
- self._transitions: List[Transition] = []
-
- def setOrdering(self, ordering: int) -> "TransitionSet":
- """设置播放顺序"""
- self._ordering = ordering
- return self
-
- def getOrdering(self) -> int:
- return self._ordering
-
- def addTransition(self, transition: Transition) -> "TransitionSet":
- """添加子转场"""
- self._transitions.append(transition)
- return self
-
- def removeTransition(self, transition: Transition) -> "TransitionSet":
- """移除子转场"""
- if transition in self._transitions:
- self._transitions.remove(transition)
- return self
-
- def getTransitionAt(self, index: int) -> Optional[Transition]:
- """获取指定索引的子转场"""
- if 0 <= index < len(self._transitions):
- return self._transitions[index]
- return None
-
- def getTransitionCount(self) -> int:
- return len(self._transitions)
-
- def toString(self) -> str:
- return (f"TransitionSet(ordering={self._ordering}, "
- f"count={len(self._transitions)})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# AutoTransition
-# ═══════════════════════════════════════════════════════════════
-
-class AutoTransition(TransitionSet):
- """AutoTransition — 自动过渡转场"""
-
- def __init__(self):
- super().__init__()
- self.setOrdering(TransitionSet.ORDERING_TOGETHER)
- self._duration = 300
-
- def toString(self) -> str:
- return f"AutoTransition(duration={self._duration})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Fade
-# ═══════════════════════════════════════════════════════════════
-
-class Fade(Transition):
- """Fade — 淡入淡出转场"""
-
- IN = 0x00000001
- OUT = 0x00000002
-
- def __init__(self, fading_mode: int = IN | OUT):
- super().__init__()
- self._fading_mode = fading_mode
-
- def getFadingMode(self) -> int:
- return self._fading_mode
-
- def setFadingMode(self, fading_mode: int):
- self._fading_mode = fading_mode
-
- def toString(self) -> str:
- return f"Fade(mode={self._fading_mode}, duration={self._duration})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ChangeBounds
-# ═══════════════════════════════════════════════════════════════
-
-class ChangeBounds(Transition):
- """ChangeBounds — 位置变化转场"""
-
- def __init__(self):
- super().__init__()
- self._resize_clip: bool = False
- self._reparent: bool = False
- self._reparent_with_overlay: bool = True
-
- def setResizeClip(self, resize_clip: bool):
- self._resize_clip = resize_clip
-
- def getResizeClip(self) -> bool:
- return self._resize_clip
-
- def setReparent(self, reparent: bool):
- self._reparent = reparent
-
- def getReparent(self) -> bool:
- return self._reparent
-
- def setReparentWithOverlay(self, reparent_with_overlay: bool):
- self._reparent_with_overlay = reparent_with_overlay
-
- def getReparentWithOverlay(self) -> bool:
- return self._reparent_with_overlay
-
- def toString(self) -> str:
- return f"ChangeBounds(duration={self._duration}, resizeClip={self._resize_clip})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ChangeTransform
-# ═══════════════════════════════════════════════════════════════
-
-class ChangeTransform(Transition):
- """ChangeTransform — 变换属性转场"""
-
- def __init__(self):
- super().__init__()
- self._reparent: bool = False
- self._reparent_with_overlay: bool = True
-
- def setReparent(self, reparent: bool):
- self._reparent = reparent
-
- def getReparent(self) -> bool:
- return self._reparent
-
- def setReparentWithOverlay(self, reparent_with_overlay: bool):
- self._reparent_with_overlay = reparent_with_overlay
-
- def getReparentWithOverlay(self) -> bool:
- return self._reparent_with_overlay
-
- def toString(self) -> str:
- return f"ChangeTransform(duration={self._duration})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Slide
-# ═══════════════════════════════════════════════════════════════
-
-class Slide(Transition):
- """Slide — 滑动转场"""
-
- TOP = 0x00000001
- BOTTOM = 0x00000002
- START = 0x00000003
- END = 0x00000004
- RIGHT = 0x00000005
- LEFT = 0x00000006
-
- def __init__(self, slide_edge: int = BOTTOM):
- super().__init__()
- self._slide_edge = slide_edge
-
- def getSlideEdge(self) -> int:
- return self._slide_edge
-
- def setSlideEdge(self, slide_edge: int):
- self._slide_edge = slide_edge
-
- def toString(self) -> str:
- return f"Slide(edge={self._slide_edge}, duration={self._duration})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Explode
-# ═══════════════════════════════════════════════════════════════
-
-class Explode(Transition):
- """Explode — 爆炸/散开转场"""
-
- def __init__(self):
- super().__init__()
-
- def toString(self) -> str:
- return f"Explode(duration={self._duration})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TransitionManager
-# ═══════════════════════════════════════════════════════════════
-
-class TransitionManager(Stub):
- """TransitionManager — 转场管理器"""
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def beginDelayedTransition(scene_root: Any,
- transition: Optional[Transition] = None):
- """开始延迟转场"""
- pass
-
- @staticmethod
- def endTransitions(scene_root: Any):
- """结束转场"""
- pass
-
- @staticmethod
- def go(scene: Scene, transition: Optional[Transition] = None):
- """执行场景转场"""
- if scene:
- scene.enter()
-
- def toString(self) -> str:
- return "TransitionManager(desktop-stub)"
-
- def hashCode(self) -> int:
- return hash("android.transition.TransitionManager") & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- return isinstance(other, TransitionManager)
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Transition",
- "TransitionManager",
- "AutoTransition",
- "Fade",
- "ChangeBounds",
- "ChangeTransform",
- "Slide",
- "Explode",
- "TransitionSet",
- "Scene",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/util.py b/android_pyapi/android/util.py
deleted file mode 100644
index 9f2a5f7..0000000
--- a/android_pyapi/android/util.py
+++ /dev/null
@@ -1,1111 +0,0 @@
-"""
-Android Util 组件 — Log, SparseArray, LruCache, DisplayMetrics 等
-方法签名完全对齐 Android SDK
-"""
-
-import math
-import re as _re
-import struct
-import sys
-from datetime import datetime
-from typing import Any, Callable, Dict, Generic, List, Optional, Set, Tuple, TypeVar, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Log
-# ═══════════════════════════════════════════════════════════════
-
-class Log(Stub):
- """Log — 日志输出"""
-
- ASSERT = 7
- DEBUG = 3
- ERROR = 6
- INFO = 4
- VERBOSE = 2
- WARN = 5
-
- _min_log_level = VERBOSE
-
- @staticmethod
- def v(tag: str, msg: str) -> int:
- if Log._min_log_level <= Log.VERBOSE:
- sys.stderr.write(f"V/{tag}: {msg}\n")
- return 0
-
- @staticmethod
- def d(tag: str, msg: str) -> int:
- if Log._min_log_level <= Log.DEBUG:
- sys.stderr.write(f"D/{tag}: {msg}\n")
- return 0
-
- @staticmethod
- def i(tag: str, msg: str) -> int:
- if Log._min_log_level <= Log.INFO:
- sys.stderr.write(f"I/{tag}: {msg}\n")
- return 0
-
- @staticmethod
- def w(tag: str, msg: str = None, tr: Exception = None) -> int:
- if Log._min_log_level <= Log.WARN:
- # 支持 w(tag, Throwable) 调用形式
- if msg is None and tr is not None:
- msg = Log.getStackTraceString(tr)
- elif tr is not None:
- msg = f"{msg}\n{Log.getStackTraceString(tr)}"
- sys.stderr.write(f"W/{tag}: {msg}\n")
- return 0
-
- @staticmethod
- def e(tag: str, msg: str = None, tr: Exception = None) -> int:
- if Log._min_log_level <= Log.ERROR:
- # 支持 e(tag, Throwable) 调用形式
- if msg is None and tr is not None:
- msg = Log.getStackTraceString(tr)
- elif tr is not None:
- msg = f"{msg}\n{Log.getStackTraceString(tr)}"
- sys.stderr.write(f"E/{tag}: {msg}\n")
- return 0
-
- @staticmethod
- def wtf(tag: str, msg=None, tr: Exception = None) -> int:
- """What a Terrible Failure。支持以下调用形式:
- - wtf(tag, msg)
- - wtf(tag, Throwable)
- - wtf(tag, msg, Throwable)
- """
- # 如果 msg 是异常对象,则当作 tr 处理
- if isinstance(msg, BaseException):
- tr = msg
- msg = None
- if msg is None and tr is not None:
- msg = Log.getStackTraceString(tr)
- elif tr is not None:
- msg = f"{msg}\n{Log.getStackTraceString(tr)}"
- if msg is None:
- msg = ""
- sys.stderr.write(f"WTF/{tag}: {msg}\n")
- return 0
-
- @staticmethod
- def println(log_level: int, tag: str, msg: str) -> int:
- level_map = {
- Log.VERBOSE: "V",
- Log.DEBUG: "D",
- Log.INFO: "I",
- Log.WARN: "W",
- Log.ERROR: "E",
- Log.ASSERT: "A",
- }
- prefix = level_map.get(log_level, "?")
- sys.stderr.write(f"{prefix}/{tag}: {msg}\n")
- return 0
-
- @staticmethod
- def isLoggable(tag: str, level: int) -> bool:
- return level >= Log._min_log_level
-
- @staticmethod
- def getStackTraceString(tr: Exception) -> str:
- import traceback
- if tr is None:
- return ""
- if isinstance(tr, str):
- return tr
- return "".join(traceback.format_exception(type(tr), tr, tr.__traceback__))
-
- @staticmethod
- def setMinLogLevel(level: int):
- Log._min_log_level = level
-
-
-# ═══════════════════════════════════════════════════════════════
-# SparseArray
-# ═══════════════════════════════════════════════════════════════
-
-T = TypeVar("T")
-
-class SparseArray(Generic[T], Stub):
- """SparseArray — 稀疏数组(int 键映射)"""
-
- def __init__(self, initial_capacity: int = 10):
- super().__init__()
- self._keys: List[int] = []
- self._values: List[Optional[T]] = []
- self._size = 0
-
- def put(self, key: int, value: T):
- """如果 key 已存在则替换"""
- try:
- idx = self._keys.index(key)
- self._values[idx] = value
- except ValueError:
- self._keys.append(key)
- self._values.append(value)
- self._size += 1
-
- def get(self, key: int, default: Optional[T] = None) -> Optional[T]:
- try:
- idx = self._keys.index(key)
- return self._values[idx]
- except ValueError:
- return default
-
- def delete(self, key: int):
- try:
- idx = self._keys.index(key)
- self._keys.pop(idx)
- self._values.pop(idx)
- self._size -= 1
- except ValueError:
- pass
-
- def remove(self, key: int):
- self.delete(key)
-
- def removeAt(self, index: int):
- if 0 <= index < self._size:
- self._keys.pop(index)
- self._values.pop(index)
- self._size -= 1
-
- def size(self) -> int:
- return self._size
-
- def keyAt(self, index: int) -> int:
- if 0 <= index < self._size:
- return self._keys[index]
- return 0
-
- def valueAt(self, index: int) -> Optional[T]:
- if 0 <= index < self._size:
- return self._values[index]
- return None
-
- def setValueAt(self, index: int, value: T):
- if 0 <= index < self._size:
- self._values[index] = value
-
- def indexOfKey(self, key: int) -> int:
- try:
- return self._keys.index(key)
- except ValueError:
- return -1
-
- def indexOfValue(self, value: T) -> int:
- try:
- return self._values.index(value)
- except ValueError:
- return -1
-
- def clear(self):
- self._keys.clear()
- self._values.clear()
- self._size = 0
-
- def append(self, key: int, value: T):
- self.put(key, value)
-
- def containsKey(self, key: int) -> bool:
- return key in self._keys
-
- def putAll(self, other: "SparseArray[T]"):
- for i in range(other.size()):
- self.put(other.keyAt(i), other.valueAt(i))
-
- def clone(self) -> "SparseArray[T]":
- sa = SparseArray[T]()
- sa._keys = list(self._keys)
- sa._values = list(self._values)
- sa._size = self._size
- return sa
-
- def toString(self) -> str:
- pairs = ", ".join(
- f"{k}={v}" for k, v in zip(self._keys, self._values)
- )
- return f"SparseArray{{{pairs}}}"
-
- def __getitem__(self, key: int) -> Optional[T]:
- return self.get(key)
-
- def __setitem__(self, key: int, value: T):
- self.put(key, value)
-
- def __delitem__(self, key: int):
- self.delete(key)
-
- def __len__(self) -> int:
- return self._size
-
- def __contains__(self, key: int) -> bool:
- return key in self._keys
-
-
-class SparseIntArray(Stub):
- """SparseIntArray — int 到 int 的映射"""
-
- def __init__(self, initial_capacity: int = 10):
- super().__init__()
- self._keys: List[int] = []
- self._values: List[int] = []
-
- def put(self, key: int, value: int):
- try:
- idx = self._keys.index(key)
- self._values[idx] = value
- except ValueError:
- self._keys.append(key)
- self._values.append(value)
-
- def get(self, key: int, default: int = 0) -> int:
- try:
- idx = self._keys.index(key)
- return self._values[idx]
- except ValueError:
- return default
-
- def delete(self, key: int):
- try:
- idx = self._keys.index(key)
- self._keys.pop(idx)
- self._values.pop(idx)
- except ValueError:
- pass
-
- def removeAt(self, index: int):
- if 0 <= index < len(self._keys):
- self._keys.pop(index)
- self._values.pop(index)
-
- def size(self) -> int:
- return len(self._keys)
-
- def keyAt(self, index: int) -> int:
- if 0 <= index < len(self._keys):
- return self._keys[index]
- return 0
-
- def valueAt(self, index: int) -> int:
- if 0 <= index < len(self._values):
- return self._values[index]
- return 0
-
- def indexOfKey(self, key: int) -> int:
- try:
- return self._keys.index(key)
- except ValueError:
- return -1
-
- def indexOfValue(self, value: int) -> int:
- try:
- return self._values.index(value)
- except ValueError:
- return -1
-
- def clear(self):
- self._keys.clear()
- self._values.clear()
-
- def append(self, key: int, value: int):
- self.put(key, value)
-
- def toString(self) -> str:
- pairs = ", ".join(f"{k}={v}" for k, v in zip(self._keys, self._values))
- return f"SparseIntArray{{{pairs}}}"
-
-
-class SparseBooleanArray(Stub):
- """SparseBooleanArray — int 到 bool 的映射"""
-
- def __init__(self, initial_capacity: int = 10):
- super().__init__()
- self._keys: List[int] = []
- self._values: List[bool] = []
-
- def put(self, key: int, value: bool):
- try:
- idx = self._keys.index(key)
- self._values[idx] = value
- except ValueError:
- self._keys.append(key)
- self._values.append(value)
-
- def get(self, key: int, default: bool = False) -> bool:
- try:
- idx = self._keys.index(key)
- return self._values[idx]
- except ValueError:
- return default
-
- def delete(self, key: int):
- try:
- idx = self._keys.index(key)
- self._keys.pop(idx)
- self._values.pop(idx)
- except ValueError:
- pass
-
- def size(self) -> int:
- return len(self._keys)
-
- def keyAt(self, index: int) -> int:
- if 0 <= index < len(self._keys):
- return self._keys[index]
- return 0
-
- def valueAt(self, index: int) -> bool:
- if 0 <= index < len(self._values):
- return self._values[index]
- return False
-
- def indexOfKey(self, key: int) -> int:
- try:
- return self._keys.index(key)
- except ValueError:
- return -1
-
- def indexOfValue(self, value: bool) -> int:
- try:
- return self._values.index(value)
- except ValueError:
- return -1
-
- def clear(self):
- self._keys.clear()
- self._values.clear()
-
- def append(self, key: int, value: bool):
- self.put(key, value)
-
- def toString(self) -> str:
- pairs = ", ".join(f"{k}={v}" for k, v in zip(self._keys, self._values))
- return f"SparseBooleanArray{{{pairs}}}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LruCache
-# ═══════════════════════════════════════════════════════════════
-
-class LruCache(Stub):
- """LruCache — LRU 缓存"""
-
- def __init__(self, max_size: int):
- super().__init__()
- self._max_size = max_size
- self._size = 0
- self._map: Dict[Any, Any] = {}
-
- def get(self, key: Any) -> Optional[Any]:
- return self._map.get(key)
-
- def put(self, key: Any, value: Any) -> Optional[Any]:
- old = self._map.get(key)
- self._map[key] = value
- self._size += self._safe_size_of(key, value)
- if old is not None:
- self._size -= self._safe_size_of(key, old)
- self._trim_to_size(self._max_size)
- return old
-
- def remove(self, key: Any) -> Optional[Any]:
- value = self._map.pop(key, None)
- if value is not None:
- self._size -= self._safe_size_of(key, value)
- return value
-
- def size(self) -> int:
- return self._size
-
- def maxSize(self) -> int:
- return self._max_size
-
- def trimToSize(self, max_size: int):
- self._trim_to_size(max_size)
-
- def _trim_to_size(self, max_size: int):
- while self._size > max_size and self._map:
- # Remove oldest (first key)
- oldest_key = next(iter(self._map))
- self.remove(oldest_key)
-
- def snapshot(self) -> Dict[Any, Any]:
- return dict(self._map)
-
- def evictAll(self):
- self._map.clear()
- self._size = 0
-
- def _safe_size_of(self, key: Any, value: Any) -> int:
- try:
- return self.sizeOf(key, value)
- except Exception:
- return 1
-
- def sizeOf(self, key: Any, value: Any) -> int:
- return 1
-
- def entryRemoved(self, evicted: bool, key: Any, old_value: Any, new_value: Optional[Any]):
- pass
-
- def create(self, key: Any) -> Optional[Any]:
- return None
-
- def getCount(self) -> int:
- return len(self._map)
-
- def putCount(self) -> int:
- return len(self._map)
-
- def evictionCount(self) -> int:
- return 0
-
- def hitCount(self) -> int:
- return 0
-
- def missCount(self) -> int:
- return 0
-
- def toString(self) -> str:
- return f"LruCache(maxSize={self._max_size}, size={self._size})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DisplayMetrics
-# ═══════════════════════════════════════════════════════════════
-
-class DisplayMetrics(Stub):
- """DisplayMetrics — 屏幕显示度量"""
-
- DENSITY_LOW = 120
- DENSITY_MEDIUM = 160
- DENSITY_TV = 213
- DENSITY_HIGH = 240
- DENSITY_XHIGH = 320
- DENSITY_XXHIGH = 480
- DENSITY_XXXHIGH = 640
- DENSITY_DEFAULT = DENSITY_MEDIUM
- DENSITY_DEVICE_STABLE = DENSITY_XXXHIGH
-
- def __init__(self):
- super().__init__()
- self.widthPixels = 1080
- self.heightPixels = 1920
- self.density = 2.75
- self.densityDpi = 440
- self.scaledDensity = 2.75
- self.xdpi = 440.0
- self.ydpi = 440.0
- self.noncompatWidthPixels = 1080
- self.noncompatHeightPixels = 1920
- self.noncompatDensity = 2.75
- self.noncompatDensityDpi = 440
- self.noncompatScaledDensity = 2.75
- self.noncompatXdpi = 440.0
- self.noncompatYdpi = 440.0
-
- def setTo(self, other: "DisplayMetrics"):
- self.widthPixels = other.widthPixels
- self.heightPixels = other.heightPixels
- self.density = other.density
- self.densityDpi = other.densityDpi
- self.scaledDensity = other.scaledDensity
- self.xdpi = other.xdpi
- self.ydpi = other.ydpi
-
- def setToDefaults(self):
- self.__init__()
-
- def toString(self) -> str:
- return (f"DisplayMetrics({self.widthPixels}x{self.heightPixels}, "
- f"density={self.density}, dpi={self.densityDpi})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# TypedValue
-# ═══════════════════════════════════════════════════════════════
-
-class TypedValue(Stub):
- """TypedValue — 类型化值的容器"""
-
- COMPLEX_UNIT_PX = 0
- COMPLEX_UNIT_DIP = 1
- COMPLEX_UNIT_SP = 2
- COMPLEX_UNIT_PT = 3
- COMPLEX_UNIT_IN = 4
- COMPLEX_UNIT_MM = 5
- COMPLEX_UNIT_FRACTION = 6
- COMPLEX_UNIT_FRACTION_PARENT = 7
-
- COMPLEX_UNIT_SHIFT = 0
- COMPLEX_UNIT_MASK = 0xF
-
- COMPLEX_RADIX_SHIFT = 4
- COMPLEX_RADIX_MASK = 0x3
-
- COMPLEX_MANTISSA_SHIFT = 8
- COMPLEX_MANTISSA_MASK = 0x00ffffff
-
- # 复数值的基数乘数(与 AOSP TypedValue.RADIX_MULTS 一致)
- _RADIX_MULTS = (
- 0.00390625, # 1/256, radix 0
- 3.0517578e-5, # 1/32768, radix 1
- 1.1920929e-7, # 1/8388608, radix 2
- 4.6566129e-10, # 1/2147483648, radix 3
- )
-
- TYPE_NULL = 0x00
- TYPE_REFERENCE = 0x01
- TYPE_ATTRIBUTE = 0x02
- TYPE_STRING = 0x03
- TYPE_FLOAT = 0x04
- TYPE_DIMENSION = 0x05
- TYPE_FRACTION = 0x06
- TYPE_FIRST_INT = 0x10
- TYPE_INT_DEC = 0x10
- TYPE_INT_HEX = 0x11
- TYPE_INT_BOOLEAN = 0x12
- TYPE_INT_COLOR_ARGB8 = 0x1C
- TYPE_INT_COLOR_RGB8 = 0x1D
- TYPE_INT_COLOR_ARGB4 = 0x1E
- TYPE_INT_COLOR_RGB4 = 0x1F
- TYPE_LAST_COLOR_INT = 0x1F
- TYPE_LAST_INT = 0x1F
-
- DATA_NULL_UNDEFINED = 0
- DATA_NULL_EMPTY = 1
-
- def __init__(self):
- super().__init__()
- self.type = self.TYPE_NULL
- self.data = 0
- self.assetCookie = 0
- self.resourceId = 0
- self.changingConfigurations = 0
- self.string = None
- self.density = 0
-
- @staticmethod
- def applyDimension(unit: int, value: float, metrics: DisplayMetrics) -> float:
- if unit == TypedValue.COMPLEX_UNIT_PX:
- return value
- if unit == TypedValue.COMPLEX_UNIT_DIP:
- return value * metrics.density
- if unit == TypedValue.COMPLEX_UNIT_SP:
- return value * metrics.scaledDensity
- if unit == TypedValue.COMPLEX_UNIT_PT:
- return value * metrics.xdpi * (1.0 / 72)
- if unit == TypedValue.COMPLEX_UNIT_IN:
- return value * metrics.xdpi
- if unit == TypedValue.COMPLEX_UNIT_MM:
- return value * metrics.xdpi * (1.0 / 25.4)
- return value
-
- @staticmethod
- def complexToDimension(data: int, metrics: DisplayMetrics) -> float:
- """将复数维度值转换为像素值。
- 复数值格式:bits 0-3=unit, bits 4-5=radix, bits 8-31=mantissa(有符号24位)"""
- unit = (data >> TypedValue.COMPLEX_UNIT_SHIFT) & TypedValue.COMPLEX_UNIT_MASK
- radix = (data >> TypedValue.COMPLEX_RADIX_SHIFT) & TypedValue.COMPLEX_RADIX_MASK
- mantissa = (data >> TypedValue.COMPLEX_MANTISSA_SHIFT) & TypedValue.COMPLEX_MANTISSA_MASK
- # 24 位有符号数符号扩展
- if mantissa & 0x800000:
- mantissa = mantissa - 0x1000000
- value = mantissa * TypedValue._RADIX_MULTS[radix]
- return TypedValue.applyDimension(unit, value, metrics)
-
- @staticmethod
- def complexToFloat(data: int) -> float:
- """将复数值转换为浮点数(与 AOSP complexToFloat 一致)。"""
- radix = (data >> TypedValue.COMPLEX_RADIX_SHIFT) & TypedValue.COMPLEX_RADIX_MASK
- # mantissa 保持在原始位位置(左移 8 位),与 AOSP 一致
- mantissa = data & (TypedValue.COMPLEX_MANTISSA_MASK << TypedValue.COMPLEX_MANTISSA_SHIFT)
- # 处理符号(Java int 是有符号的,bit 31 为符号位)
- if mantissa & 0x80000000:
- mantissa = mantissa - 0x100000000
- return float(mantissa) * TypedValue._RADIX_MULTS[radix]
-
- @staticmethod
- def complexToDimensionPixelOffset(data: int, metrics: DisplayMetrics) -> int:
- return int(TypedValue.complexToDimension(data, metrics))
-
- @staticmethod
- def complexToDimensionPixelSize(data: int, metrics: DisplayMetrics) -> int:
- val = TypedValue.complexToDimension(data, metrics)
- if val >= 0:
- return int(val + 0.5)
- return int(val - 0.5)
-
- def getFloat(self) -> float:
- """将 data 字段按 IEEE 754 单精度浮点数解读(与 Float.intBitsToFloat 一致)。"""
- bits = self.data & 0xFFFFFFFF
- return struct.unpack('f', struct.pack('I', bits))[0]
-
- def toString(self) -> str:
- return f"TypedValue(type={self.type}, data={self.data})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Pair
-# ═══════════════════════════════════════════════════════════════
-
-class Pair(Stub):
- """Pair — 有序对"""
-
- def __init__(self, first: Any, second: Any):
- super().__init__()
- self.first = first
- self.second = second
-
- @staticmethod
- def create(a: Any, b: Any) -> "Pair":
- return Pair(a, b)
-
- def hashCode(self) -> int:
- return hash((self.first, self.second))
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, Pair):
- return False
- return self.first == other.first and self.second == other.second
-
- def toString(self) -> str:
- return f"Pair({self.first}, {self.second})"
-
- def __eq__(self, other):
- return self.equals(other)
-
- def __hash__(self):
- return self.hashCode()
-
- def __repr__(self):
- return self.toString()
-
- def __iter__(self):
- return iter((self.first, self.second))
-
-
-# ═══════════════════════════════════════════════════════════════
-# Size / SizeF
-# ═══════════════════════════════════════════════════════════════
-
-class Size(Stub):
- """Size — 整数尺寸"""
-
- def __init__(self, width: int, height: int):
- super().__init__()
- self._width = width
- self._height = height
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, Size):
- return False
- return self._width == other._width and self._height == other._height
-
- def hashCode(self) -> int:
- return (self._height << 16) ^ self._width
-
- def toString(self) -> str:
- return f"{self._width}x{self._height}"
-
- @staticmethod
- def parseSize(string: str) -> "Size":
- parts = string.split("x")
- if len(parts) == 2:
- return Size(int(parts[0]), int(parts[1]))
- raise ValueError(f"Invalid size: {string}")
-
- def __eq__(self, other):
- return self.equals(other)
-
- def __hash__(self):
- return self.hashCode()
-
- def __repr__(self):
- return self.toString()
-
-
-class SizeF(Stub):
- """SizeF — 浮点数尺寸"""
-
- def __init__(self, width: float, height: float):
- super().__init__()
- self._width = width
- self._height = height
-
- def getWidth(self) -> float:
- return self._width
-
- def getHeight(self) -> float:
- return self._height
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, SizeF):
- return False
- return abs(self._width - other._width) < 0.001 and abs(self._height - other._height) < 0.001
-
- def hashCode(self) -> int:
- return hash((self._width, self._height))
-
- def toString(self) -> str:
- return f"{self._width:.1f}x{self._height:.1f}"
-
- @staticmethod
- def parseSizeF(string: str) -> "SizeF":
- parts = string.split("x")
- if len(parts) == 2:
- return SizeF(float(parts[0]), float(parts[1]))
- raise ValueError(f"Invalid size: {string}")
-
- def __eq__(self, other):
- return self.equals(other)
-
- def __hash__(self):
- return self.hashCode()
-
- def __repr__(self):
- return self.toString()
-
-
-# ═══════════════════════════════════════════════════════════════
-# StateSet
-# ═══════════════════════════════════════════════════════════════
-
-class StateSet(Stub):
- """StateSet — 状态集合"""
-
- VIEW_STATE_WINDOW_FOCUSED = 1
- VIEW_STATE_SELECTED = 1 << 1
- VIEW_STATE_FOCUSED = 1 << 2
- VIEW_STATE_ENABLED = 1 << 3
- VIEW_STATE_PRESSED = 1 << 4
- VIEW_STATE_ACTIVATED = 1 << 5
- VIEW_STATE_ACCELERATED = 1 << 6
- VIEW_STATE_HOVERED = 1 << 7
- VIEW_STATE_DRAG_CAN_ACCEPT = 1 << 8
- VIEW_STATE_DRAG_HOVERED = 1 << 9
-
- WILD_CARD = 0x00000000
-
- @staticmethod
- def isWildCard(state_spec_or_mask: Any) -> bool:
- if isinstance(state_spec_or_mask, list):
- return len(state_spec_or_mask) == 0
- return state_spec_or_mask == StateSet.WILD_CARD
-
- @staticmethod
- def trimStateSet(states: List[int], new_size: int) -> List[int]:
- return states[:new_size]
-
- @staticmethod
- def dump(states: List[int]) -> str:
- if not states:
- return "[]"
- return "[" + ", ".join(str(s) for s in states) + "]"
-
-
-# ═══════════════════════════════════════════════════════════════
-# MathUtils
-# ═══════════════════════════════════════════════════════════════
-
-class MathUtils(Stub):
- """MathUtils — 数学工具"""
-
- DEG_TO_RAD = math.pi / 180.0
- RAD_TO_DEG = 180.0 / math.pi
-
- @staticmethod
- def abs(v: float) -> float:
- return abs(v)
-
- @staticmethod
- def constrain(amount: float, low: float, high: float) -> float:
- return max(low, min(high, amount))
-
- @staticmethod
- def constrainInt(amount: int, low: int, high: int) -> int:
- return max(low, min(high, amount))
-
- @staticmethod
- def lerp(start: float, stop: float, amount: float) -> float:
- return start + (stop - start) * amount
-
- @staticmethod
- def lerpInv(a: float, b: float, value: float) -> float:
- if a != b:
- return (value - a) / (b - a)
- return 0.0
-
- @staticmethod
- def norm(start: float, stop: float, value: float) -> float:
- return MathUtils.lerpInv(start, stop, value)
-
- @staticmethod
- def map(min_start: float, min_stop: float, max_start: float, max_stop: float, value: float) -> float:
- return max_start + (value - min_start) * (max_stop - max_start) / (min_stop - min_start)
-
- @staticmethod
- def dist(x1: float, y1: float, x2: float, y2: float) -> float:
- return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
-
- @staticmethod
- def max(var1: float, var2: float) -> float:
- return max(var1, var2)
-
- @staticmethod
- def min(var1: float, var2: float) -> float:
- return min(var1, var2)
-
- @staticmethod
- def degrees(radians: float) -> float:
- return math.degrees(radians)
-
- @staticmethod
- def radians(degrees: float) -> float:
- return math.radians(degrees)
-
- @staticmethod
- def exp(a: float) -> float:
- return math.exp(a)
-
- @staticmethod
- def log(a: float) -> float:
- return math.log(a)
-
- @staticmethod
- def pow(a: float, b: float) -> float:
- return a ** b
-
- @staticmethod
- def sqrt(a: float) -> float:
- return math.sqrt(a)
-
- @staticmethod
- def sin(angle: float) -> float:
- return math.sin(angle)
-
- @staticmethod
- def cos(angle: float) -> float:
- return math.cos(angle)
-
- @staticmethod
- def tan(angle: float) -> float:
- return math.tan(angle)
-
- @staticmethod
- def atan2(a: float, b: float) -> float:
- return math.atan2(a, b)
-
- @staticmethod
- def random() -> float:
- import random
- return random.random()
-
- @staticmethod
- def isNaN(v: float) -> bool:
- return math.isnan(v)
-
- @staticmethod
- def nanToZero(value: float) -> float:
- return 0.0 if math.isnan(value) else value
-
-
-# ═══════════════════════════════════════════════════════════════
-# Pattern (re)
-# ═══════════════════════════════════════════════════════════════
-
-class Pattern(Stub):
- """Pattern — 正则表达式模式"""
-
- CASE_INSENSITIVE = 2
- MULTILINE = 8
- DOTALL = 32
- UNICODE_CASE = 64
- CANON_EQ = 128
- UNIX_LINES = 1
- LITERAL = 16
- COMMENTS = 4
-
- def __init__(self, pattern: str, flags: int = 0):
- super().__init__()
- self._pattern_str = pattern
- self._flags = flags
- re_flags = 0
- if flags & self.CASE_INSENSITIVE:
- re_flags |= _re.IGNORECASE
- if flags & self.MULTILINE:
- re_flags |= _re.MULTILINE
- if flags & self.DOTALL:
- re_flags |= _re.DOTALL
- if flags & self.UNICODE_CASE:
- re_flags |= _re.UNICODE
- if flags & self.UNIX_LINES:
- pass # no re equivalent
- self._compiled = _re.compile(pattern, re_flags)
-
- @staticmethod
- def compile(pattern: str, flags: int = 0) -> "Pattern":
- return Pattern(pattern, flags)
-
- def matcher(self, input_str: str) -> "Matcher":
- return Matcher(self._compiled, input_str)
-
- def split(self, input_str: str, limit: int = 0) -> List[str]:
- if limit < 0:
- return self._compiled.split(input_str, maxsplit=0)
- return self._compiled.split(input_str, maxsplit=limit - 1 if limit > 0 else 0)
-
- def pattern(self) -> str:
- return self._pattern_str
-
- def flags(self) -> int:
- return self._flags
-
- @staticmethod
- def matches(regex: str, input_str: str) -> bool:
- return bool(_re.fullmatch(regex, input_str))
-
- @staticmethod
- def quote(s: str) -> str:
- return _re.escape(s)
-
- def toString(self) -> str:
- return self._pattern_str
-
-
-class Matcher(Stub):
- """Matcher — 正则匹配器"""
-
- def __init__(self, compiled_pattern: "Pattern", input_str: str):
- super().__init__()
- self._pattern = compiled_pattern
- self._input = input_str
- self._region_start = 0
- self._region_end = len(input_str)
- self._match: Optional[Any] = None
-
- def matches(self) -> bool:
- self._match = self._pattern.fullmatch(self._input,
- self._region_start, self._region_end)
- return self._match is not None
-
- def find(self, start: int = 0) -> bool:
- self._match = self._pattern.search(self._input, start or self._region_start,
- self._region_end)
- return self._match is not None
-
- def lookingAt(self) -> bool:
- self._match = self._pattern.match(self._input, self._region_start,
- self._region_end)
- return self._match is not None
-
- def group(self, group: int = 0) -> Optional[str]:
- if self._match:
- return self._match.group(group)
- return None
-
- def groupCount(self) -> int:
- if self._match:
- return len(self._match.groups())
- return 0
-
- def start(self, group: int = 0) -> int:
- if self._match:
- return self._match.start(group)
- return -1
-
- def end(self, group: int = 0) -> int:
- if self._match:
- return self._match.end(group)
- return -1
-
- def replaceAll(self, replacement: str) -> str:
- return self._pattern.sub(replacement, self._input)
-
- def replaceFirst(self, replacement: str) -> str:
- return self._pattern.sub(replacement, self._input, count=1)
-
- def region(self, start: int, end: int) -> "Matcher":
- self._region_start = start
- self._region_end = end
- return self
-
- def regionStart(self) -> int:
- return self._region_start
-
- def regionEnd(self) -> int:
- return self._region_end
-
- def reset(self, input_str: Optional[str] = None) -> "Matcher":
- if input_str is not None:
- self._input = input_str
- self._match = None
- return self
-
- def hitEnd(self) -> bool:
- return False
-
- def requireEnd(self) -> bool:
- return False
-
- def usePattern(self, new_pattern: "Pattern") -> "Matcher":
- self._pattern = new_pattern
- return self
-
- def appendReplacement(self, sb: Any, replacement: str):
- pass
-
- def appendTail(self, sb: Any):
- pass
-
- def toString(self) -> str:
- return f"Matcher({self._pattern.pattern()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TYPED_VALUE 常量
-# ═══════════════════════════════════════════════════════════════
-
-TYPED_VALUE = TypedValue # 别名
-
-
-# ═══════════════════════════════════════════════════════════════
-# Pair 反向兼容 (android.util.Pair)
-# ═══════════════════════════════════════════════════════════════
-
-# Pair 已在上面定义
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Log",
- "SparseArray",
- "SparseIntArray",
- "SparseBooleanArray",
- "LruCache",
- "DisplayMetrics",
- "TypedValue",
- "Pair",
- "Size",
- "SizeF",
- "StateSet",
- "MathUtils",
- "Pattern",
- "Matcher",
- "TYPED_VALUE",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/uwb.py b/android_pyapi/android/uwb.py
deleted file mode 100644
index 5b9cde9..0000000
--- a/android_pyapi/android/uwb.py
+++ /dev/null
@@ -1,420 +0,0 @@
-"""
-Android uwb 组件 — UwbManager, RangingResult, RangingParameters, UwbAddress 等
-方法签名完全对齐 Android SDK (UWB API)
-"""
-
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# UwbConstants
-# ═══════════════════════════════════════════════════════════════
-
-class UwbConstants(Stub):
- """UwbConstants — UWB 常量"""
-
- STATUS_OK = 0
- STATUS_FAILURE = 1
- STATUS_INVALID_PARAMETERS = 2
- STATUS_SESSION_DOES_NOT_EXIST = 3
- STATUS_MAX_RANGING_ROUND_RETRY = 4
- STATUS_RANGING_TX_FAILED = 5
- STATUS_SESSION_STATE_CHANGE_EXCEPTION = 6
- STATUS_UNKNOWN_ERROR = 255
-
- CONFIG_ID_0 = 0
- CONFIG_ID_1 = 1
- CONFIG_ID_2 = 2
- CONFIG_ID_3 = 3
-
- MEASUREMENT_REPORT_TYPE_DEFERRED = 0
- MEASUREMENT_REPORT_TYPE_NTF = 1
-
- RANGING_UPDATE_RATE_AUTO = 0
- RANGING_UPDATE_RATE_FREQUENCY_1_HZ = 1
- RANGING_UPDATE_RATE_FREQUENCY_2_HZ = 2
- RANGING_UPDATE_RATE_FREQUENCY_5_HZ = 5
- RANGING_UPDATE_RATE_FREQUENCY_10_HZ = 10
- RANGING_UPDATE_RATE_FREQUENCY_20_HZ = 20
- RANGING_UPDATE_RATE_FREQUENCY_100_HZ = 100
- RANGING_UPDATE_RATE_FREQUENCY_250_HZ = 250
-
-
-# ═══════════════════════════════════════════════════════════════
-# UwbAddress
-# ═══════════════════════════════════════════════════════════════
-
-class UwbAddress(Stub):
- """UwbAddress — UWB 地址"""
-
- SHORT_MAC_ADDRESS = 0
- EXTENDED_MAC_ADDRESS = 1
-
- def __init__(self, address: bytes = b"", type_: int = SHORT_MAC_ADDRESS):
- super().__init__()
- self._address = address
- self._type = type_
-
- def getAddress(self) -> bytes:
- return self._address
-
- def getType(self) -> int:
- return self._type
-
- def toString(self) -> str:
- return f"UwbAddress(type={self._type}, addr={self._address.hex()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AngleOfArrival
-# ═══════════════════════════════════════════════════════════════
-
-class AngleOfArrival(Stub):
- """AngleOfArrival — 到达角"""
-
- STATUS_SUCCESS = 0
- STATUS_FAILURE = 1
-
- def __init__(self, azimuth: float = 0.0, elevation: float = 0.0,
- azimuthConfidence: float = 0.0, elevationConfidence: float = 0.0,
- status: int = STATUS_FAILURE):
- super().__init__()
- self._azimuth = azimuth
- self._elevation = elevation
- self._azimuth_confidence = azimuthConfidence
- self._elevation_confidence = elevationConfidence
- self._status = status
-
- def getAzimuth(self) -> float:
- return self._azimuth
-
- def getElevation(self) -> float:
- return self._elevation
-
- def getAzimuthConfidence(self) -> float:
- return self._azimuth_confidence
-
- def getElevationConfidence(self) -> float:
- return self._elevation_confidence
-
-
-# ═══════════════════════════════════════════════════════════════
-# DistanceMeasurement
-# ═══════════════════════════════════════════════════════════════
-
-class DistanceMeasurement(Stub):
- """DistanceMeasurement — 距离测量"""
-
- STATUS_SUCCESS = 0
- STATUS_FAILURE = 1
-
- def __init__(self, meters: float = 0.0, confidence: float = 0.0,
- standardDeviation: float = 0.0, status: int = STATUS_FAILURE):
- super().__init__()
- self._meters = meters
- self._confidence = confidence
- self._standard_deviation = standardDeviation
- self._status = status
-
- def getMeters(self) -> float:
- return self._meters
-
- def getConfidence(self) -> float:
- return self._confidence
-
- def getStandardDeviation(self) -> float:
- return self._standard_deviation
-
-
-# ═══════════════════════════════════════════════════════════════
-# RangingResult
-# ═══════════════════════════════════════════════════════════════
-
-class RangingResult(Stub):
- """RangingResult — 测距结果"""
-
- def __init__(self, uwbDevice: Any = None, remoteDevice: Any = None,
- status: int = 0, nofRounds: int = 0, nofMeasurements: int = 0,
- elapsedRealtimeNanos: int = 0,
- distanceMeasurement: Optional[DistanceMeasurement] = None,
- angleOfArrival: Optional[AngleOfArrival] = None,
- rssi: float = -90.0):
- super().__init__()
- self._uwb_device = uwbDevice
- self._remote_device = remoteDevice
- self._status = status
- self._nof_rounds = nofRounds
- self._nof_measurements = nofMeasurements
- self._elapsed_realtime_nanos = elapsedRealtimeNanos
- self._distance_measurement = distanceMeasurement
- self._angle_of_arrival = angleOfArrival
- self._rssi = rssi
- self._distance_reported = distanceMeasurement is not None
- self._aoa_reported = angleOfArrival is not None
-
- def getUwbDevice(self) -> Any:
- return self._uwb_device
-
- def getRemoteDevice(self) -> Any:
- return self._remote_device
-
- def getStatus(self) -> int:
- return self._status
-
- def getNofRounds(self) -> int:
- return self._nof_rounds
-
- def getNofMeasurements(self) -> int:
- return self._nof_measurements
-
- def getElapsedRealtimeNanos(self) -> int:
- return self._elapsed_realtime_nanos
-
- def getDistanceMeasurement(self) -> Optional[DistanceMeasurement]:
- return self._distance_measurement
-
- def getAngleOfArrival(self) -> Optional[AngleOfArrival]:
- return self._angle_of_arrival
-
- def getAngleOfArrivalAzimuth(self) -> float:
- if self._angle_of_arrival:
- return self._angle_of_arrival.getAzimuth()
- return 0.0
-
- def getAngleOfArrivalElevation(self) -> float:
- if self._angle_of_arrival:
- return self._angle_of_arrival.getElevation()
- return 0.0
-
- def getAngleOfArrivalAzimuthConfidence(self) -> float:
- if self._angle_of_arrival:
- return self._angle_of_arrival.getAzimuthConfidence()
- return 0.0
-
- def getAngleOfArrivalElevationConfidence(self) -> float:
- if self._angle_of_arrival:
- return self._angle_of_arrival.getElevationConfidence()
- return 0.0
-
- def getRssi(self) -> float:
- return self._rssi
-
- def isDistanceMeasurementReported(self) -> bool:
- return self._distance_reported
-
- def isAngleOfArrivalReported(self) -> bool:
- return self._aoa_reported
-
-
-# ═══════════════════════════════════════════════════════════════
-# RangingParameters
-# ═══════════════════════════════════════════════════════════════
-
-class RangingParameters(Stub):
- """RangingParameters — 测距参数"""
-
- class Builder(Stub):
- """RangingParameters.Builder — 测距参数构建器"""
-
- def __init__(self):
- super().__init__()
- self._uwb_config_id = 0
- self._session_id = 0
- self._sub_session_id = 0
- self._ranging_update_rate = 1
- self._slot_duration = 0
- self._measurement_report_type = 0
- self._number_of_controlee = 1
- self._destination_addresses: List[UwbAddress] = []
- self._device_configs: List[Any] = []
- self._vendor_specific_data: List[Any] = []
-
- def setUwbConfigId(self, configId: int) -> "RangingParameters.Builder":
- self._uwb_config_id = configId
- return self
-
- def setSessionId(self, sessionId: int) -> "RangingParameters.Builder":
- self._session_id = sessionId
- return self
-
- def setSubSessionId(self, subSessionId: int) -> "RangingParameters.Builder":
- self._sub_session_id = subSessionId
- return self
-
- def setRangingUpdateRate(self, rate: int) -> "RangingParameters.Builder":
- self._ranging_update_rate = rate
- return self
-
- def setSlotDuration(self, duration: int) -> "RangingParameters.Builder":
- self._slot_duration = duration
- return self
-
- def setMeasurementReportType(self, reportType: int) -> "RangingParameters.Builder":
- self._measurement_report_type = reportType
- return self
-
- def setNumberOfControlee(self, count: int) -> "RangingParameters.Builder":
- self._number_of_controlee = count
- return self
-
- def setDestinationAddresses(self, addrs: List[UwbAddress]) -> "RangingParameters.Builder":
- self._destination_addresses = addrs
- return self
-
- def setDeviceConfigs(self, configs: List[Any]) -> "RangingParameters.Builder":
- self._device_configs = configs
- return self
-
- def setVendorSpecificData(self, data: List[Any]) -> "RangingParameters.Builder":
- self._vendor_specific_data = data
- return self
-
- def build(self) -> "RangingParameters":
- rp = RangingParameters()
- rp._uwb_config_id = self._uwb_config_id
- rp._session_id = self._session_id
- rp._sub_session_id = self._sub_session_id
- rp._ranging_update_rate = self._ranging_update_rate
- rp._slot_duration = self._slot_duration
- rp._measurement_report_type = self._measurement_report_type
- rp._number_of_controlee = self._number_of_controlee
- rp._destination_addresses = self._destination_addresses
- rp._device_configs = self._device_configs
- rp._vendor_specific_data = self._vendor_specific_data
- return rp
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# UwbConfiguration / RangingConfig (stubs)
-# ═══════════════════════════════════════════════════════════════
-
-class UwbConfiguration(Stub):
- """UwbConfiguration — UWB 配置"""
-
- def __init__(self):
- super().__init__()
-
-
-class RangingConfig(Stub):
- """RangingConfig — 测距配置"""
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# RangingSession
-# ═══════════════════════════════════════════════════════════════
-
-class RangingSession(Stub):
- """RangingSession — 测距会话"""
-
- def __init__(self):
- super().__init__()
- self._open = False
-
- def open(self):
- self._open = True
-
- def close(self):
- self._open = False
-
- def reconfigure(self, params: RangingParameters):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# UwbManager
-# ═══════════════════════════════════════════════════════════════
-
-class UwbManager(Stub):
- """UwbManager — UWB 管理器"""
-
- # ═══════════════════════════════════════════════════════════
- # UwbCallback
- # ═══════════════════════════════════════════════════════════
-
- class UwbCallback(Stub):
- """UwbManager.UwbCallback — UWB 回调"""
-
- def onRangingResult(self, sessionId: int, result: RangingResult):
- pass
-
- def onRangingFailure(self, sessionId: int, reason: int):
- pass
-
- def onControleeResult(self, sessionId: int, status: int):
- pass
-
- _instance: Optional["UwbManager"] = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance(context: Any = None) -> "UwbManager":
- if UwbManager._instance is None:
- UwbManager._instance = UwbManager()
- return UwbManager._instance
-
- def open(self, sessionId: int) -> RangingSession:
- session = RangingSession()
- session.open()
- return session
-
- def close(self, sessionId: int):
- pass
-
- def range(self, sessionId: int, params: RangingParameters,
- callback: UwbCallback):
- if callback:
- result = RangingResult(
- status=UwbConstants.STATUS_OK,
- distanceMeasurement=DistanceMeasurement(
- meters=1.5, confidence=0.8,
- standardDeviation=0.1, status=DistanceMeasurement.STATUS_SUCCESS
- ),
- rssi=-65.0
- )
- callback.onRangingResult(sessionId, result)
-
- def stopRange(self, sessionId: int):
- pass
-
- def addControlee(self, sessionId: int, address: UwbAddress):
- pass
-
- def removeControlee(self, sessionId: int, address: UwbAddress):
- pass
-
- def setMeasurementData(self, sessionId: int, data: bytes):
- pass
-
- def sendMeasurementData(self, sessionId: int, data: bytes):
- pass
-
- def getUwbDevice(self) -> Any:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "UwbManager",
- "UwbConstants",
- "UwbAddress",
- "AngleOfArrival",
- "DistanceMeasurement",
- "RangingResult",
- "RangingParameters",
- "UwbConfiguration",
- "RangingConfig",
- "RangingSession",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/view.py b/android_pyapi/android/view.py
deleted file mode 100644
index 5e0b481..0000000
--- a/android_pyapi/android/view.py
+++ /dev/null
@@ -1,4207 +0,0 @@
-"""
-Android View 组件 — View, ViewGroup, MotionEvent, KeyEvent, GestureDetector 等
-方法签名完全对齐 Android SDK
-"""
-
-import math
-import time
-import weakref
-from typing import Any, Callable, Dict, List, Optional, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError, android_context, HAS_PYAUTOGUI
-
-try:
- from .._linux_impl import IS_LINUX, LinuxDisplay, LinuxUIAutomation, HAS_XDOTOOL
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# Gravity
-# ═══════════════════════════════════════════════════════════════
-
-class Gravity:
- """Gravity — 布局重力常量"""
- NO_GRAVITY = 0x0000
- TOP = 0x0030
- BOTTOM = 0x0050
- LEFT = 0x0003
- RIGHT = 0x0005
- CENTER = 0x0011
- CENTER_HORIZONTAL = 0x0001
- CENTER_VERTICAL = 0x0010
- FILL = 0x0077
- FILL_HORIZONTAL = 0x0007
- FILL_VERTICAL = 0x0070
- CLIP_HORIZONTAL = 0x0008
- CLIP_VERTICAL = 0x0080
- START = 0x00800001
- END = 0x00800005
- RELATIVE_LAYOUT_DIRECTION = 0x00800000
-
- @staticmethod
- def getAbsoluteGravity(gravity: int, layout_direction: int) -> int:
- from ..os import View
- if layout_direction == View.LAYOUT_DIRECTION_RTL:
- if gravity & Gravity.START:
- gravity = (gravity & ~Gravity.START) | Gravity.RIGHT
- if gravity & Gravity.END:
- gravity = (gravity & ~Gravity.END) | Gravity.LEFT
- else:
- if gravity & Gravity.START:
- gravity = (gravity & ~Gravity.START) | Gravity.LEFT
- if gravity & Gravity.END:
- gravity = (gravity & ~Gravity.END) | Gravity.RIGHT
- return gravity
-
- @staticmethod
- def apply(gravity: int, w: int, h: int, container: "Rect") -> int:
- return 0
-
-
-Rect = None
-
-
-def _set_rect_class():
- global Rect
- if Rect is None:
- class _Rect:
- def __init__(self, l=0, t=0, r=0, b=0):
- self.left = l
- self.top = t
- self.right = r
- self.bottom = b
- def width(self): return self.right - self.left
- def height(self): return self.bottom - self.top
- def set(self, l, t, r, b):
- self.left, self.top, self.right, self.bottom = l, t, r, b
- def isEmpty(self): return self.width() <= 0 or self.height() <= 0
- def toString(self): return f"Rect({self.left}, {self.top} - {self.right}, {self.bottom})"
- Rect = _Rect
-
-
-_set_rect_class()
-
-
-# ═══════════════════════════════════════════════════════════════
-# View
-# ═══════════════════════════════════════════════════════════════
-
-class View(Stub):
- """View — 所有 UI 组件的基类"""
-
- # 可见性常量
- VISIBLE = 0
- INVISIBLE = 4
- GONE = 8
-
- # 测量常量
- MEASURED_SIZE_STATE_MASK = 0xFF000000
- MEASURED_STATE_MASK = 0xFF000000
- MEASURED_HEIGHT_STATE_SHIFT = 16
- MEASURED_WIDTH_STATE_SHIFT = 0
-
- # 测量模式
- EXACTLY = 0x40000000
- AT_MOST = 0x80000000 # -2147483648
- UNSPECIFIED = 0
-
- # 滚动轴
- SCROLL_AXIS_NONE = 0
- SCROLL_AXIS_HORIZONTAL = 1
- SCROLL_AXIS_VERTICAL = 2
-
- # 布局方向
- LAYOUT_DIRECTION_LTR = 0
- LAYOUT_DIRECTION_RTL = 1
-
- # 绘制缓存
- DRAWING_CACHE_QUALITY_LOW = 0x00040000
- DRAWING_CACHE_QUALITY_HIGH = 0x00080000
- DRAWING_CACHE_QUALITY_AUTO = 0
-
- # 焦点方向
- FOCUS_BACKWARD = 0x00000001
- FOCUS_FORWARD = 0x00000002
- FOCUS_LEFT = 0x00000011
- FOCUS_UP = 0x00000021
- FOCUS_RIGHT = 0x00000042
- FOCUS_DOWN = 0x00000082
-
- # Keep screen on
- KEEP_SCREEN_ON = 0x02000000
-
- # 状态
- STATUS_BAR_HIDDEN = 0x00000001
- STATUS_BAR_VISIBLE = 0x00000000
- NAVIGATION_BAR_HIDDEN = 0x00000002
- NAVIGATION_BAR_VISIBLE = 0x00000000
-
- # 系统UI可见性
- SYSTEM_UI_FLAG_VISIBLE = 0
- SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001
- SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002
- SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004
- SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100
- SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200
- SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400
- SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800
- SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000
-
- _next_id = 0x10000000
- _id_lock = None
-
- def __init__(self, context=None):
- super().__init__()
- if context is None:
- context = android_context
- self._context = context
- self._id = View.NO_ID
- self._tag: Any = None
- self._layout_params: Optional["ViewGroup.LayoutParams"] = None
- self._visibility = View.VISIBLE
- self._enabled = True
- self._clickable = False
- self._focusable = False
- self._selected = False
- self._activated = False
- self._x: float = 0.0
- self._y: float = 0.0
- self._translation_x: float = 0.0
- self._translation_y: float = 0.0
- self._rotation: float = 0.0
- self._scale_x: float = 1.0
- self._scale_y: float = 1.0
- self._alpha: float = 1.0
- self._pivot_x: float = 0.0
- self._pivot_y: float = 0.0
- self._measured_width: int = 0
- self._measured_height: int = 0
- self._left: int = 0
- self._top: int = 0
- self._right: int = 0
- self._bottom: int = 0
- self._padding_left: int = 0
- self._padding_top: int = 0
- self._padding_right: int = 0
- self._padding_bottom: int = 0
- self._parent: Optional["ViewGroup"] = None
- self._background_color: Optional[int] = None
- self._background_drawable: Any = None
- self._background_resource: int = 0
- self._on_click_listener: Optional[Callable] = None
- self._on_long_click_listener: Optional[Callable] = None
- self._on_touch_listener: Optional[Callable] = None
- self._on_key_listener: Optional[Callable] = None
- self._callbacks: Dict[Any, Tuple[Callable, float]] = {}
- self._scroll_x: int = 0
- self._scroll_y: int = 0
- self._will_not_draw = False
- self._layer_type = View.LAYER_TYPE_NONE
- self._layout_direction = View.LAYOUT_DIRECTION_LTR
- self._min_width: int = 0
- self._min_height: int = 0
- self._elevation: float = 0.0
- self._clickable = False
- self._long_clickable = False
- self._context_clickable = False
- self._children: List["View"] = []
-
- # ─── 常量 ──────────────────────────────────────────────────
-
- NO_ID = -1
- DRAWING_CACHE_QUALITY_LOW = 0x00040000
- DRAWING_CACHE_QUALITY_HIGH = 0x00080000
- DRAWING_CACHE_QUALITY_AUTO = 0
- LAYER_TYPE_NONE = 0
- LAYER_TYPE_SOFTWARE = 1
- LAYER_TYPE_HARDWARE = 2
- FADING_EDGE_NONE = 0
- FADING_EDGE_HORIZONTAL = 0x00001000
- FADING_EDGE_VERTICAL = 0x00002000
- OVER_SCROLL_ALWAYS = 0
- OVER_SCROLL_IF_CONTENT_SCROLLS = 1
- OVER_SCROLL_NEVER = 2
-
- # ─── id / tag ──────────────────────────────────────────────
-
- def setId(self, id_: int):
- self._id = id_
-
- def getId(self) -> int:
- return self._id
-
- def setTag(self, tag: Any):
- self._tag = tag
-
- def getTag(self) -> Any:
- return self._tag
-
- # ─── layout params ─────────────────────────────────────────
-
- def setLayoutParams(self, params: "ViewGroup.LayoutParams"):
- self._layout_params = params
-
- def getLayoutParams(self) -> Optional["ViewGroup.LayoutParams"]:
- return self._layout_params
-
- # ─── visibility ────────────────────────────────────────────
-
- def setVisibility(self, visibility: int):
- self._visibility = visibility
-
- def getVisibility(self) -> int:
- return self._visibility
-
- def isShown(self) -> bool:
- return self._visibility == View.VISIBLE
-
- # ─── position / size ───────────────────────────────────────
-
- def getX(self) -> float:
- return self._x
-
- def setX(self, x: float):
- self._x = x
-
- def getY(self) -> float:
- return self._y
-
- def setY(self, y: float):
- self._y = y
-
- def getWidth(self) -> int:
- return self._right - self._left
-
- def getHeight(self) -> int:
- return self._bottom - self._top
-
- def getLeft(self) -> int:
- return self._left
-
- def getTop(self) -> int:
- return self._top
-
- def getRight(self) -> int:
- return self._right
-
- def getBottom(self) -> int:
- return self._bottom
-
- def getMeasuredWidth(self) -> int:
- return self._measured_width
-
- def getMeasuredHeight(self) -> int:
- return self._measured_height
-
- def setFrame(self, left: int, top: int, right: int, bottom: int) -> bool:
- changed = (left != self._left or top != self._top or
- right != self._right or bottom != self._bottom)
- self._left, self._top, self._right, self._bottom = left, top, right, bottom
- return changed
-
- def layout(self, l: int, t: int, r: int, b: int):
- old_l, old_t, old_r, old_b = self._left, self._top, self._right, self._bottom
- changed = self.setFrame(l, t, r, b)
- if changed:
- self.onLayout(changed, l - old_l, t - old_t, r - old_r, b - old_b)
-
- def onLayout(self, changed: bool, left: int, top: int, right: int, bottom: int):
- pass
-
- def measure(self, width_measure_spec: int, height_measure_spec: int):
- self.onMeasure(width_measure_spec, height_measure_spec)
-
- def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
- w = View.getDefaultSize(self.getSuggestedMinimumWidth(), width_measure_spec)
- h = View.getDefaultSize(self.getSuggestedMinimumHeight(), height_measure_spec)
- self.setMeasuredDimension(w, h)
-
- def setMeasuredDimension(self, measured_width: int, measured_height: int):
- self._measured_width = measured_width
- self._measured_height = measured_height
-
- def getSuggestedMinimumWidth(self) -> int:
- return self._min_width
-
- def getSuggestedMinimumHeight(self) -> int:
- return self._min_height
-
- def getMinimumWidth(self) -> int:
- return self._min_width
-
- def getMinimumHeight(self) -> int:
- return self._min_height
-
- def setMinimumWidth(self, min_w: int):
- self._min_width = min_w
-
- def setMinimumHeight(self, min_h: int):
- self._min_height = min_h
-
- def draw(self, canvas: Any):
- self.onDraw(canvas)
-
- def onDraw(self, canvas: Any):
- pass
-
- # ─── listeners ─────────────────────────────────────────────
-
- def setOnClickListener(self, listener: Optional[Callable]):
- self._on_click_listener = listener
-
- def setOnLongClickListener(self, listener: Optional[Callable]) -> None:
- self._on_long_click_listener = listener
-
- def setOnTouchListener(self, listener: Optional[Callable]) -> None:
- self._on_touch_listener = listener
-
- def setOnKeyListener(self, listener: Optional[Callable]) -> None:
- self._on_key_listener = listener
-
- def callOnClick(self) -> bool:
- if self._on_click_listener:
- self._on_click_listener(self)
- return True
- return False
-
- def performClick(self) -> bool:
- return self.callOnClick()
-
- def screenshot(self, path=None):
- """截屏"""
- if _USE_LINUX:
- return LinuxDisplay.screenshot(path)
- return None
-
- def performLongClick(self) -> bool:
- if self._on_long_click_listener:
- self._on_long_click_listener(self)
- return True
- return False
-
- # ─── post / delayed ────────────────────────────────────────
-
- def post(self, action: Callable) -> bool:
- action()
- return True
-
- def postDelayed(self, action: Callable, delay_millis: int) -> bool:
- import threading
- timer = threading.Timer(delay_millis / 1000.0, action)
- timer.daemon = True
- timer.start()
- self._callbacks[action] = (action, time.time() + delay_millis / 1000.0)
- return True
-
- def removeCallbacks(self, action: Optional[Callable] = None):
- if action is None:
- self._callbacks.clear()
- else:
- self._callbacks.pop(action, None)
-
- # ─── invalidate / requestLayout ────────────────────────────
-
- def invalidate(self):
- pass
-
- def requestLayout(self):
- pass
-
- def requestFocus(self, direction: int = FOCUS_FORWARD) -> bool:
- if self._visibility != View.VISIBLE or not self._enabled:
- return False
- return True
-
- # ─── padding ───────────────────────────────────────────────
-
- def setPadding(self, left: int, top: int, right: int, bottom: int):
- self._padding_left = left
- self._padding_top = top
- self._padding_right = right
- self._padding_bottom = bottom
-
- def getPaddingLeft(self) -> int:
- return self._padding_left
-
- def getPaddingTop(self) -> int:
- return self._padding_top
-
- def getPaddingRight(self) -> int:
- return self._padding_right
-
- def getPaddingBottom(self) -> int:
- return self._padding_bottom
-
- def getPaddingStart(self) -> int:
- return self._padding_left
-
- def getPaddingEnd(self) -> int:
- return self._padding_right
-
- # ─── background ────────────────────────────────────────────
-
- def setBackgroundColor(self, color: int):
- self._background_color = color
- self._background_drawable = None
-
- def setBackground(self, background: Any):
- self._background_drawable = background
-
- def setBackgroundDrawable(self, background: Any):
- self._background_drawable = background
-
- def setBackgroundResource(self, resid: int):
- self._background_resource = resid
-
- def getBackground(self) -> Any:
- return self._background_drawable
-
- # ─── transform properties ──────────────────────────────────
-
- def setAlpha(self, alpha: float):
- self._alpha = alpha
-
- def getAlpha(self) -> float:
- return self._alpha
-
- def setRotation(self, rotation: float):
- self._rotation = rotation
-
- def getRotation(self) -> float:
- return self._rotation
-
- def setScaleX(self, scale_x: float):
- self._scale_x = scale_x
-
- def getScaleX(self) -> float:
- return self._scale_x
-
- def setScaleY(self, scale_y: float):
- self._scale_y = scale_y
-
- def getScaleY(self) -> float:
- return self._scale_y
-
- def setTranslationX(self, translation_x: float):
- self._translation_x = translation_x
-
- def getTranslationX(self) -> float:
- return self._translation_x
-
- def setTranslationY(self, translation_y: float):
- self._translation_y = translation_y
-
- def getTranslationY(self) -> float:
- return self._translation_y
-
- def getPivotX(self) -> float:
- return self._pivot_x
-
- def setPivotX(self, pivot_x: float):
- self._pivot_x = pivot_x
-
- def getPivotY(self) -> float:
- return self._pivot_y
-
- def setPivotY(self, pivot_y: float):
- self._pivot_y = pivot_y
-
- def setElevation(self, elevation: float):
- self._elevation = elevation
-
- def getElevation(self) -> float:
- return self._elevation
-
- def animate(self) -> "ViewPropertyAnimator":
- return ViewPropertyAnimator(self)
-
- # ─── parent / root ─────────────────────────────────────────
-
- def getParent(self) -> Optional["ViewParent"]:
- return self._parent
-
- def getRootView(self) -> "View":
- v = self
- while v._parent is not None:
- v = v._parent
- return v
-
- # ─── hierarchy ─────────────────────────────────────────────
-
- def findViewById(self, id_: int) -> Optional["View"]:
- if self._id == id_:
- return self
- if hasattr(self, "_children"):
- for child in self._children:
- result = child.findViewById(id_)
- if result is not None:
- return result
- return None
-
- def bringToFront(self):
- if self._parent is not None:
- self._parent.bringChildToFront(self)
-
- # ─── enable / focusable / clickable ────────────────────────
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setFocusable(self, focusable: bool):
- self._focusable = focusable
-
- def isFocusable(self) -> bool:
- return self._focusable
-
- def setClickable(self, clickable: bool):
- self._clickable = clickable
-
- def isClickable(self) -> bool:
- return self._clickable
-
- def setLongClickable(self, long_clickable: bool):
- self._long_clickable = long_clickable
-
- def isLongClickable(self) -> bool:
- return self._long_clickable
-
- def setContextClickable(self, context_clickable: bool):
- self._context_clickable = context_clickable
-
- def isContextClickable(self) -> bool:
- return self._context_clickable
-
- def setSelected(self, selected: bool):
- self._selected = selected
-
- def isSelected(self) -> bool:
- return self._selected
-
- def setActivated(self, activated: bool):
- self._activated = activated
-
- def isActivated(self) -> bool:
- return self._activated
-
- # ─── context / resources ───────────────────────────────────
-
- def getContext(self):
- return self._context
-
- def getResources(self):
- if hasattr(self._context, "getResources"):
- return self._context.getResources()
- return None
-
- # ─── scroll ────────────────────────────────────────────────
-
- def setScrollX(self, value: int):
- self._scroll_x = value
-
- def setScrollY(self, value: int):
- self._scroll_y = value
-
- def getScrollX(self) -> int:
- return self._scroll_x
-
- def getScrollY(self) -> int:
- return self._scroll_y
-
- def scrollTo(self, x: int, y: int):
- self._scroll_x = x
- self._scroll_y = y
-
- def scrollBy(self, x: int, y: int):
- self._scroll_x += x
- self._scroll_y += y
-
- def computeScroll(self):
- pass
-
- # ─── drawing / layer ───────────────────────────────────────
-
- def setWillNotDraw(self, will_not_draw: bool):
- self._will_not_draw = will_not_draw
-
- def willNotDraw(self) -> bool:
- return self._will_not_draw
-
- def setLayerType(self, layer_type: int, paint: Any = None):
- self._layer_type = layer_type
-
- def getLayerType(self) -> int:
- return self._layer_type
-
- def buildLayer(self):
- pass
-
- def setDrawingCacheQuality(self, quality: int):
- pass
-
- def getDrawingCacheQuality(self) -> int:
- return View.DRAWING_CACHE_QUALITY_AUTO
-
- def getDrawingCache(self, auto_scale: bool = True) -> Any:
- return None
-
- def buildDrawingCache(self, auto_scale: bool = True):
- pass
-
- def destroyDrawingCache(self):
- pass
-
- # ─── layout direction ──────────────────────────────────────
-
- def setLayoutDirection(self, layout_direction: int):
- self._layout_direction = layout_direction
-
- def getLayoutDirection(self) -> int:
- return self._layout_direction
-
- def setTextDirection(self, text_direction: int):
- pass
-
- def getTextDirection(self) -> int:
- return 0
-
- def setTextAlignment(self, text_alignment: int):
- pass
-
- def getTextAlignment(self) -> int:
- return 0
-
- # ─── hit / focus ───────────────────────────────────────────
-
- def onTouchEvent(self, event: "MotionEvent") -> bool:
- return self._clickable or self._long_clickable
-
- def onTrackballEvent(self, event: "MotionEvent") -> bool:
- return False
-
- def onKeyDown(self, key_code: int, event: "KeyEvent") -> bool:
- return False
-
- def onKeyUp(self, key_code: int, event: "KeyEvent") -> bool:
- return False
-
- def onKeyLongPress(self, key_code: int, event: "KeyEvent") -> bool:
- return False
-
- def onKeyMultiple(self, key_code: int, repeat_count: int, event: "KeyEvent") -> bool:
- return False
-
- def dispatchTouchEvent(self, event: "MotionEvent") -> bool:
- if self._on_touch_listener is not None:
- handled = self._on_touch_listener(self, event)
- if handled:
- return True
- return self.onTouchEvent(event)
-
- def dispatchKeyEvent(self, event: "KeyEvent") -> bool:
- if self._on_key_listener is not None:
- handled = self._on_key_listener(self, event.getKeyCode(), event)
- if handled:
- return True
- if event.getAction() == KeyEvent.ACTION_DOWN:
- return self.onKeyDown(event.getKeyCode(), event)
- elif event.getAction() == KeyEvent.ACTION_UP:
- return self.onKeyUp(event.getKeyCode(), event)
- return False
-
- def dispatchGenericMotionEvent(self, event: "MotionEvent") -> bool:
- return False
-
- def hasFocus(self) -> bool:
- return False
-
- def isFocused(self) -> bool:
- return self.hasFocus()
-
- def clearFocus(self):
- pass
-
- def onWindowFocusChanged(self, has_window_focus: bool):
- pass
-
- def hasWindowFocus(self) -> bool:
- return True
-
- def getWindowToken(self) -> Any:
- return None
-
- def getWindowVisibility(self) -> int:
- return View.VISIBLE
-
- def getWindowAttachCount(self) -> int:
- return 1
-
- def onAttachedToWindow(self):
- pass
-
- def onDetachedFromWindow(self):
- pass
-
- def isAttachedToWindow(self) -> bool:
- return self._parent is not None
-
- # ─── Haptic ────────────────────────────────────────────────
-
- def performHapticFeedback(self, feedback_constant: int) -> bool:
- return False
-
- HapticFeedbackConstants = None
-
- # ─── static helpers ────────────────────────────────────────
-
- @staticmethod
- def generateViewId() -> int:
- View._next_id += 1
- return View._next_id
-
- @staticmethod
- def getDefaultSize(size: int, measure_spec: int) -> int:
- spec_mode = View.MeasureSpec.getMode(measure_spec)
- spec_size = View.MeasureSpec.getSize(measure_spec)
- if spec_mode == View.UNSPECIFIED:
- return size
- else:
- return spec_size
-
- @staticmethod
- def combineMeasuredStates(cur_state: int, new_state: int) -> int:
- return cur_state | new_state
-
- @staticmethod
- def resolveSize(size: int, measure_spec: int) -> int:
- return View.getDefaultSize(size, measure_spec)
-
- @staticmethod
- def resolveSizeAndState(size: int, measure_spec: int, child_measured_state: int) -> int:
- result = View.resolveSize(size, measure_spec)
- return result | (child_measured_state & View.MEASURED_STATE_MASK)
-
- @staticmethod
- def inflate(context, resource, root):
- return View(context)
-
- # ─── 事件处理 (扩展) ───────────────────────────────────────
-
- def onGenericMotionEvent(self, event) -> bool:
- return False
-
- def onHoverEvent(self, event) -> bool:
- return False
-
- def onDragEvent(self, event) -> bool:
- return False
-
- def onSizeChanged(self, w, h, oldw, oldh):
- pass
-
- def onFocusChanged(self, gainFocus, direction, previouslyFocusedRect):
- pass
-
- def onScrollChanged(self, l, t, oldl, oldt):
- pass
-
- def onVisibilityChanged(self, changedView, visibility):
- pass
-
- # ─── 监听器设置 (扩展) ─────────────────────────────────────
-
- def setOnGenericMotionListener(self, listener):
- self._on_generic_motion_listener = listener
- return self
-
- def setOnHoverListener(self, listener):
- self._on_hover_listener = listener
- return self
-
- def setOnDragListener(self, listener):
- self._on_drag_listener = listener
- return self
-
- def setOnFocusChangeListener(self, listener):
- self._on_focus_change_listener = listener
- return self
-
- def setOnContextClickListener(self, listener):
- self._on_context_click_listener = listener
- return self
-
- def addOnLayoutChangeListener(self, listener):
- if not hasattr(self, '_layout_change_listeners'):
- self._layout_change_listeners = []
- self._layout_change_listeners.append(listener)
-
- def removeOnLayoutChangeListener(self, listener):
- if hasattr(self, '_layout_change_listeners'):
- try:
- self._layout_change_listeners.remove(listener)
- except ValueError:
- pass
-
- def setOnApplyWindowInsetsListener(self, listener):
- self._on_apply_window_insets_listener = listener
- return self
-
- # ─── 位置和尺寸 (扩展) ─────────────────────────────────────
-
- def getLocationOnScreen(self, location):
- location[0] = self._left if hasattr(self, '_left') else 0
- location[1] = self._top if hasattr(self, '_top') else 0
-
- def getLocationInWindow(self, location):
- self.getLocationOnScreen(location)
-
- def offsetLeftAndRight(self, offset):
- if hasattr(self, '_left'):
- self._left += offset
-
- def offsetTopAndBottom(self, offset):
- if hasattr(self, '_top'):
- self._top += offset
-
- def getHitRect(self, out_rect):
- out_rect.left = self._left if hasattr(self, '_left') else 0
- out_rect.top = self._top if hasattr(self, '_top') else 0
- out_rect.right = out_rect.left + (self._width if hasattr(self, '_width') else 0)
- out_rect.bottom = out_rect.top + (self._height if hasattr(self, '_height') else 0)
-
- def getDrawingRect(self, out_rect):
- out_rect.left = 0
- out_rect.top = 0
- out_rect.right = self._width if hasattr(self, '_width') else 0
- out_rect.bottom = self._height if hasattr(self, '_height') else 0
-
- # ─── 其他扩展方法 ──────────────────────────────────────────
-
- def setTooltipText(self, text):
- self._tooltip_text = text
-
- def getTooltipText(self):
- return getattr(self, '_tooltip_text', None)
-
- def setTranslationZ(self, translationZ):
- self._translation_z = translationZ
-
- def getTranslationZ(self):
- return getattr(self, '_translation_z', 0.0)
-
- def setZ(self, z):
- self._z = z
-
- def getZ(self):
- return getattr(self, '_z', 0.0)
-
- def setTransitionName(self, name):
- self._transition_name = name
-
- def getTransitionName(self):
- return getattr(self, '_transition_name', None)
-
- def setClipToOutline(self, clipToOutline):
- self._clip_to_outline = clipToOutline
-
- def getClipToOutline(self):
- return getattr(self, '_clip_to_outline', False)
-
- def setFitsSystemWindows(self, fitSystemWindows):
- self._fits_system_windows = fitSystemWindows
-
- def getFitsSystemWindows(self):
- return getattr(self, '_fits_system_windows', False)
-
- def playSoundEffect(self, soundConstant):
- pass
-
- def setSaveEnabled(self, enabled):
- self._save_enabled = enabled
-
- def isSaveEnabled(self):
- return getattr(self, '_save_enabled', True)
-
- def setSystemUiVisibility(self, visibility):
- self._system_ui_visibility = visibility
-
- def getSystemUiVisibility(self):
- return getattr(self, '_system_ui_visibility', 0)
-
- def requestApplyInsets(self):
- pass
-
- def onApplyWindowInsets(self, insets):
- return insets
-
- def setOnCreateContextMenuListener(self, listener):
- self._on_create_context_menu_listener = listener
- return self
-
- def getBaseline(self):
- return -1
-
- def setFocusableInTouchMode(self, focusable):
- self._focusable_in_touch_mode = focusable
-
- def isFocusableInTouchMode(self):
- return getattr(self, '_focusable_in_touch_mode', False)
-
- def setRotationX(self, rotationX):
- self._rotation_x = rotationX
-
- def getRotationX(self):
- return getattr(self, '_rotation_x', 0.0)
-
- def setRotationY(self, rotationY):
- self._rotation_y = rotationY
-
- def getRotationY(self):
- return getattr(self, '_rotation_y', 0.0)
-
- def setCameraDistance(self, distance):
- self._camera_distance = distance
-
- def getCameraDistance(self):
- return getattr(self, '_camera_distance', 0.0)
-
- def setForeground(self, foreground):
- self._foreground = foreground
-
- def getForeground(self):
- return getattr(self, '_foreground', None)
-
- def setBackgroundTintList(self, tint):
- self._background_tint = tint
-
- def setBackgroundTintMode(self, tintMode):
- self._background_tint_mode = tintMode
-
- def setScrollbarFadingEnabled(self, fadeScrollbars):
- self._fade_scrollbars = fadeScrollbars
-
- def isScrollbarFadingEnabled(self):
- return getattr(self, '_fade_scrollbars', True)
-
- def setVerticalScrollBarEnabled(self, enabled):
- self._vertical_scrollbar = enabled
-
- def isVerticalScrollBarEnabled(self):
- return getattr(self, '_vertical_scrollbar', True)
-
- def setHorizontalScrollBarEnabled(self, enabled):
- self._horizontal_scrollbar = enabled
-
- def isHorizontalScrollBarEnabled(self):
- return getattr(self, '_horizontal_scrollbar', True)
-
- def setLabelFor(self, id):
- self._label_for = id
-
- def getLabelFor(self):
- return getattr(self, '_label_for', 0)
-
- def cancelLongPress(self):
- pass
-
- def setPaddingRelative(self, start, top, end, bottom):
- self._padding_start = start
- self._padding_top = top
- self._padding_end = end
- self._padding_bottom = bottom
-
- def setSoundEffectsEnabled(self, soundEffectsEnabled):
- self._sound_effects = soundEffectsEnabled
-
- def isSoundEffectsEnabled(self):
- return getattr(self, '_sound_effects', True)
-
- def setHapticFeedbackEnabled(self, hapticFeedbackEnabled):
- self._haptic_feedback = hapticFeedbackEnabled
-
- def isHapticFeedbackEnabled(self):
- return getattr(self, '_haptic_feedback', True)
-
- def refreshDrawableState(self):
- pass
-
- def getDrawableState(self):
- return []
-
- def requestRectangleOnScreen(self, rectangle):
- return False
-
- def setAllCaps(self, allCaps):
- self._all_caps = allCaps
-
-
-class MeasureSpec:
- """MeasureSpec — 测量规格包装"""
- EXACTLY = View.EXACTLY
- AT_MOST = 0x80000000 # -2147483648
- UNSPECIFIED = 0
- MODE_SHIFT = 30
- MODE_MASK = 0xC0000000
-
- @staticmethod
- def makeMeasureSpec(size: int, mode: int) -> int:
- return (size & ~MeasureSpec.MODE_MASK) | (mode & MeasureSpec.MODE_MASK)
-
- @staticmethod
- def getMode(measure_spec: int) -> int:
- return measure_spec & MeasureSpec.MODE_MASK
-
- @staticmethod
- def getSize(measure_spec: int) -> int:
- return measure_spec & ~MeasureSpec.MODE_MASK
-
- @staticmethod
- def toString(measure_spec: int) -> str:
- mode = MeasureSpec.getMode(measure_spec)
- size = MeasureSpec.getSize(measure_spec)
- mode_str = "UNSPECIFIED"
- if mode == MeasureSpec.EXACTLY:
- mode_str = "EXACTLY"
- elif mode == MeasureSpec.AT_MOST:
- mode_str = "AT_MOST"
- return f"MeasureSpec: {mode_str} {size}"
-
-
-View.MeasureSpec = MeasureSpec
-
-
-class ViewPropertyAnimator:
- """ViewPropertyAnimator — View 属性动画"""
-
- def __init__(self, view: View):
- self._view = view
- self._duration: int = 300
- self._interpolator: Any = None
-
- def setDuration(self, duration: int) -> "ViewPropertyAnimator":
- self._duration = duration
- return self
-
- def alpha(self, value: float) -> "ViewPropertyAnimator":
- self._view.setAlpha(value)
- return self
-
- def translationX(self, value: float) -> "ViewPropertyAnimator":
- self._view.setTranslationX(value)
- return self
-
- def translationY(self, value: float) -> "ViewPropertyAnimator":
- self._view.setTranslationY(value)
- return self
-
- def rotation(self, value: float) -> "ViewPropertyAnimator":
- self._view.setRotation(value)
- return self
-
- def scaleX(self, value: float) -> "ViewPropertyAnimator":
- self._view.setScaleX(value)
- return self
-
- def scaleY(self, value: float) -> "ViewPropertyAnimator":
- self._view.setScaleY(value)
- return self
-
- def x(self, value: float) -> "ViewPropertyAnimator":
- self._view.setX(value)
- return self
-
- def y(self, value: float) -> "ViewPropertyAnimator":
- self._view.setY(value)
- return self
-
- def start(self):
- pass
-
- def cancel(self):
- pass
-
- def setInterpolator(self, interpolator: Any) -> "ViewPropertyAnimator":
- self._interpolator = interpolator
- return self
-
- def withStartAction(self, runnable: Callable) -> "ViewPropertyAnimator":
- return self
-
- def withEndAction(self, runnable: Callable) -> "ViewPropertyAnimator":
- return self
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewParent / ViewManager
-# ═══════════════════════════════════════════════════════════════
-
-class ViewParent(Stub):
- """ViewParent — 视图父接口"""
-
- def requestLayout(self):
- pass
-
- def invalidateChild(self, child: View, r: Any):
- pass
-
- def requestChildFocus(self, child: View, focused: View):
- pass
-
- def clearChildFocus(self, child: View):
- pass
-
- def getParent(self) -> Optional["ViewParent"]:
- return None
-
- def bringChildToFront(self, child: View):
- pass
-
- def focusSearch(self, child: View, direction: int) -> Optional[View]:
- return None
-
- def requestChildRectangleOnScreen(self, child: View, rectangle: Any, immediate: bool) -> bool:
- return False
-
- def getChildVisibleRect(self, child: View, r: Any, offset: Any) -> bool:
- return False
-
- def requestTransparentRegion(self, child: View):
- pass
-
- def onStartNestedScroll(self, child: View, target: View, nested_scroll_axes: int) -> bool:
- return False
-
- def onStopNestedScroll(self, target: View):
- pass
-
- def onNestedScroll(self, target: View, dx_consumed: int, dy_consumed: int,
- dx_unconsumed: int, dy_unconsumed: int):
- pass
-
- def onNestedPreScroll(self, target: View, dx: int, dy: int, consumed: List[int]):
- pass
-
- def onNestedFling(self, target: View, velocity_x: float, velocity_y: float, consumed: bool) -> bool:
- return False
-
- def onNestedPreFling(self, target: View, velocity_x: float, velocity_y: float) -> bool:
- return False
-
- def isNestedScrollingEnabled(self) -> bool:
- return False
-
- def setNestedScrollingEnabled(self, enabled: bool):
- pass
-
- def notifySubtreeAccessibilityStateChanged(self, child: View, source: View, change_type: int):
- pass
-
-
-class ViewManager(Stub):
- """ViewManager — 视图管理接口"""
-
- def addView(self, view: View, params: "ViewGroup.LayoutParams"):
- pass
-
- def updateViewLayout(self, view: View, params: "ViewGroup.LayoutParams"):
- pass
-
- def removeView(self, view: View):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewGroup
-# ═══════════════════════════════════════════════════════════════
-
-class ViewGroup(View, ViewParent, ViewManager):
- """ViewGroup — 可包含子视图的容器"""
-
- CLIP_TO_PADDING_MASK = 0x00000001
- CLIP_CHILDREN_MASK = 0x00000002
- FLAG_CLIP_CHILDREN = 0x00000001
- FLAG_CLIP_TO_PADDING = 0x00000002
- FLAG_USE_CHILD_DRAWING_ORDER = 0x00000400
-
- def __init__(self, context=None):
- super().__init__(context)
- self._children: List[View] = []
- self._clip_children = True
- self._clip_to_padding = True
- self._layout_mode = 0
- self._child_drawing_order_reversed = False
- self._persistent_drawing_cache = False
- self._always_drawn_with_cache = True
- self._animate_on_set_layout = True
- self._add_stateset = True
- self._layout_animations = False
-
- # ─── child management ──────────────────────────────────────
-
- def addView(self, child: View, index: Optional[int] = -1,
- params: Optional["ViewGroup.LayoutParams"] = None):
- """addView — 支持 addView(child), addView(child, params), addView(child, index), addView(child, index, params)"""
- # 智能 参数分派:第二个参数可能是 index(int) 或 params(LayoutParams)
- if isinstance(index, ViewGroup.LayoutParams):
- params = index
- index = -1
- if params is None:
- params = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT)
- if index < 0 or index >= len(self._children):
- self._children.append(child)
- else:
- self._children.insert(index, child)
- child._parent = self
- child.setLayoutParams(params)
- child.onAttachedToWindow()
-
- def removeView(self, view: View):
- if view in self._children:
- self._children.remove(view)
- view._parent = None
- view.onDetachedFromWindow()
-
- def removeViewAt(self, index: int):
- if 0 <= index < len(self._children):
- self.removeView(self._children[index])
-
- def removeAllViews(self):
- for child in list(self._children):
- child._parent = None
- child.onDetachedFromWindow()
- self._children.clear()
-
- def getChildCount(self) -> int:
- return len(self._children)
-
- def getChildAt(self, index: int) -> Optional[View]:
- if 0 <= index < len(self._children):
- return self._children[index]
- return None
-
- def indexOfChild(self, child: View) -> int:
- try:
- return self._children.index(child)
- except ValueError:
- return -1
-
- def bringChildToFront(self, child: View):
- if child in self._children:
- self._children.remove(child)
- self._children.append(child)
-
- def requestChildFocus(self, child: View, focused: View):
- pass
-
- def onInterceptTouchEvent(self, event: "MotionEvent") -> bool:
- return False
-
- def onInterceptHoverEvent(self, event: "MotionEvent") -> bool:
- return False
-
- def addChildrenForAccessibility(self, children: List[View]):
- for child in self._children:
- children.append(child)
-
- def setClipChildren(self, clip_children: bool):
- self._clip_children = clip_children
-
- def getClipChildren(self) -> bool:
- return self._clip_children
-
- def setClipToPadding(self, clip_to_padding: bool):
- self._clip_to_padding = clip_to_padding
-
- def getClipToPadding(self) -> bool:
- return self._clip_to_padding
-
- def setLayoutAnimation(self, layout_animation: Any):
- pass
-
- def getLayoutAnimation(self) -> Any:
- return None
-
- def setLayoutMode(self, layout_mode: int):
- self._layout_mode = layout_mode
-
- def getLayoutMode(self) -> int:
- return self._layout_mode
-
- def setPersistentDrawingCache(self, drawing_cache_to_keep: int):
- self._persistent_drawing_cache = bool(drawing_cache_to_keep)
-
- def setAddStatesFromChildren(self, add_states: bool):
- self._add_stateset = add_states
-
- def addStatesFromChildren(self) -> bool:
- return self._add_stateset
-
- def setChildDrawingOrderCallback(self, callback: Any):
- pass
-
- def setChildrenDrawingOrderEnabled(self, enabled: bool):
- self._child_drawing_order_reversed = enabled
-
- def isChildrenDrawingOrderEnabled(self) -> bool:
- return self._child_drawing_order_reversed
-
- def setChildrenDrawnWithCacheEnabled(self, enabled: bool):
- self._always_drawn_with_cache = enabled
-
- def isChildrenDrawnWithCacheEnabled(self) -> bool:
- return self._always_drawn_with_cache
-
- def setMotionEventSplittingEnabled(self, split: bool):
- pass
-
- def isMotionEventSplittingEnabled(self) -> bool:
- return True
-
- # ─── layout transition ────────────────────────────────────
-
- def setLayoutTransition(self, transition: Any):
- self._layout_transition = transition
-
- def getLayoutTransition(self) -> Any:
- return getattr(self, '_layout_transition', None)
-
- # ─── focus / touch blocking ───────────────────────────────
-
- def setTouchscreenBlocksFocus(self, blocks: bool):
- self._touchscreen_blocks_focus = blocks
-
- def isTouchscreenBlocksFocus(self) -> bool:
- return getattr(self, '_touchscreen_blocks_focus', False)
-
- # ─── child visible rect ───────────────────────────────────
-
- def getChildVisibleRect(self, child: View, r: Any, offset: Any) -> bool:
- if r is not None and hasattr(r, 'set'):
- r.set(child.getLeft(), child.getTop(),
- child.getRight(), child.getBottom())
- if offset is not None and hasattr(offset, 'set'):
- offset.set(0, 0)
- return True
-
- def setTransitionGroup(self, is_transition_group: bool):
- pass
-
- def isTransitionGroup(self) -> bool:
- return False
-
- def startLayoutAnimation(self):
- pass
-
- def scheduleLayoutAnimation(self):
- pass
-
- def gatherTransparentRegion(self, region: Any) -> bool:
- return False
-
- def requestTransparentRegion(self, child: View):
- pass
-
- def onChildVisibilityChanged(self, child: View, old_visibility: int, new_visibility: int):
- pass
-
- def focusSearch(self, focused: View, direction: int) -> Optional[View]:
- return None
-
- def focusableViewAvailable(self, v: View):
- pass
-
- def showContextMenuForChild(self, original_view: View) -> bool:
- return False
-
- def createContextMenu(self, menu: Any):
- pass
-
- def showContextMenu(self) -> bool:
- return False
-
- def startActionModeForChild(self, original_view: View, action_mode: Any) -> Optional[Any]:
- return None
-
- # ─── LayoutParams ──────────────────────────────────────────
-
- class LayoutParams:
- """ViewGroup.LayoutParams — 布局参数"""
-
- MATCH_PARENT = -1
- WRAP_CONTENT = -2
-
- def __init__(self, width: int = WRAP_CONTENT, height: int = WRAP_CONTENT):
- self.width = width
- self.height = height
-
- @staticmethod
- def getSize(size: int) -> int:
- return size
-
- # ─── MarginLayoutParams ────────────────────────────────────
-
- class MarginLayoutParams(LayoutParams):
- """ViewGroup.MarginLayoutParams — 带边距的布局参数"""
-
- def __init__(self, width: int = -2, height: int = -2):
- super().__init__(width, height)
- self.leftMargin = 0
- self.topMargin = 0
- self.rightMargin = 0
- self.bottomMargin = 0
- self.startMargin = 0
- self.endMargin = 0
-
- def setMargins(self, left: int, top: int, right: int, bottom: int):
- self.leftMargin = left
- self.topMargin = top
- self.rightMargin = right
- self.bottomMargin = bottom
-
- def getMarginLeft(self) -> int:
- return self.leftMargin
-
- def getMarginTop(self) -> int:
- return self.topMargin
-
- def getMarginRight(self) -> int:
- return self.rightMargin
-
- def getMarginBottom(self) -> int:
- return self.bottomMargin
-
- def getMarginStart(self) -> int:
- return self.startMargin if self.startMargin != 0 else self.leftMargin
-
- def getMarginEnd(self) -> int:
- return self.endMargin if self.endMargin != 0 else self.rightMargin
-
- def setMarginStart(self, start: int):
- self.startMargin = start
-
- def setMarginEnd(self, end: int):
- self.endMargin = end
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowManager
-# ═══════════════════════════════════════════════════════════════
-
-class WindowManager(ViewManager):
- """WindowManager — 窗口管理器"""
-
- class LayoutParams(ViewGroup.LayoutParams):
- """WindowManager.LayoutParams — 窗口布局参数"""
-
- # 窗口类型
- TYPE_FIRST_APPLICATION = 1
- TYPE_APPLICATION = 2
- TYPE_APPLICATION_STARTING = 3
- TYPE_APPLICATION_PANEL = 1000
- TYPE_APPLICATION_MEDIA = 1001
- TYPE_APPLICATION_SUB_PANEL = 1002
- TYPE_APPLICATION_ATTACHED_DIALOG = 1003
- TYPE_APPLICATION_OVERLAY = 1004
-
- # 标志位
- FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001
- FLAG_DIM_BEHIND = 0x00000002
- FLAG_BLUR_BEHIND = 0x00000004
- FLAG_NOT_FOCUSABLE = 0x00000008
- FLAG_NOT_TOUCHABLE = 0x00000010
- FLAG_NOT_TOUCH_MODAL = 0x00000020
- FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040
- FLAG_KEEP_SCREEN_ON = 0x00000080
- FLAG_LAYOUT_IN_SCREEN = 0x00000100
- FLAG_LAYOUT_NO_LIMITS = 0x00000200
- FLAG_FULLSCREEN = 0x00000400
- FLAG_FORCE_NOT_FULLSCREEN = 0x00000800
- FLAG_DITHER = 0x00001000
- FLAG_SECURE = 0x00002000
- FLAG_SCALED = 0x00004000
- FLAG_IGNORE_CHEEK_PRESSES = 0x00008000
- FLAG_LAYOUT_INSET_DECOR = 0x00010000
- FLAG_ALT_FOCUSABLE_IM = 0x00020000
- FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000
- FLAG_SHOW_WHEN_LOCKED = 0x00080000
- FLAG_SHOW_WALLPAPER = 0x00100000
- FLAG_TURN_SCREEN_ON = 0x00200000
- FLAG_DISMISS_KEYGUARD = 0x00400000
- FLAG_SPLIT_TOUCH = 0x00800000
- FLAG_HARDWARE_ACCELERATED = 0x01000000
- FLAG_LOCAL_FOCUS_MODE = 0x02000000
- FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x04000000
- FLAG_TRANSLUCENT_STATUS = 0x04000000
- FLAG_TRANSLUCENT_NAVIGATION = 0x08000000
-
- # 软输入模式
- SOFT_INPUT_STATE_UNSPECIFIED = 0
- SOFT_INPUT_STATE_UNCHANGED = 1
- SOFT_INPUT_STATE_HIDDEN = 2
- SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3
- SOFT_INPUT_STATE_VISIBLE = 4
- SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5
- SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00
- SOFT_INPUT_ADJUST_RESIZE = 0x10
- SOFT_INPUT_ADJUST_PAN = 0x20
- SOFT_INPUT_ADJUST_NOTHING = 0x30
- SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100
-
- # 屏幕方向
- SCREEN_ORIENTATION_UNSPECIFIED = -1
- SCREEN_ORIENTATION_LANDSCAPE = 0
- SCREEN_ORIENTATION_PORTRAIT = 1
- SCREEN_ORIENTATION_USER = 2
- SCREEN_ORIENTATION_BEHIND = 3
- SCREEN_ORIENTATION_SENSOR = 4
- SCREEN_ORIENTATION_NOSENSOR = 5
- SCREEN_ORIENTATION_SENSOR_LANDSCAPE = 6
- SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7
- SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8
- SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9
- SCREEN_ORIENTATION_FULL_SENSOR = 10
- SCREEN_ORIENTATION_USER_LANDSCAPE = 11
- SCREEN_ORIENTATION_USER_PORTRAIT = 12
- SCREEN_ORIENTATION_FULL_USER = 13
- SCREEN_ORIENTATION_LOCKED = 14
-
- # 重力
- gravity = Gravity.NO_GRAVITY
- x = 0
- y = 0
- horizontalMargin = 0.0
- verticalMargin = 0.0
-
- def __init__(self, w: int = ViewGroup.LayoutParams.WRAP_CONTENT,
- h: int = ViewGroup.LayoutParams.WRAP_CONTENT):
- super().__init__(w, h)
- self.type = WindowManager.LayoutParams.TYPE_APPLICATION
- self.flags = 0
- self.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
- self.screenOrientation = WindowManager.LayoutParams.SCREEN_ORIENTATION_UNSPECIFIED
- self.gravity = Gravity.NO_GRAVITY
- self.x = 0
- self.y = 0
- self.token: Any = None
- self.windowAnimations: int = 0
- self.packageName: str = ""
- self.screenBrightness = -1.0
- self.buttonBrightness = -1.0
- self.rotationAnimation = 0
- self.preferredDisplayModeId = 0
- self.colorMode = 0
- self.format = -1
-
- def __init__(self):
- super().__init__()
- self._views: Dict[View, WindowManager.LayoutParams] = {}
-
- def addView(self, view: View, params: LayoutParams):
- self._views[view] = params
-
- def updateViewLayout(self, view: View, params: LayoutParams):
- if view in self._views:
- self._views[view] = params
-
- def removeView(self, view: View):
- self._views.pop(view, None)
-
- def removeViewImmediate(self, view: View):
- self._views.pop(view, None)
-
- def getDefaultDisplay(self) -> "Display":
- return Display()
-
-
-# ═══════════════════════════════════════════════════════════════
-# MotionEvent
-# ═══════════════════════════════════════════════════════════════
-
-class MotionEvent(Stub):
- """MotionEvent — 触摸事件"""
-
- # 动作常量
- ACTION_DOWN = 0
- ACTION_UP = 1
- ACTION_MOVE = 2
- ACTION_CANCEL = 3
- ACTION_OUTSIDE = 4
- ACTION_POINTER_DOWN = 5
- ACTION_POINTER_UP = 6
- ACTION_HOVER_MOVE = 7
- ACTION_HOVER_ENTER = 8
- ACTION_HOVER_EXIT = 9
- ACTION_SCROLL = 11
- ACTION_BUTTON_PRESS = 12
- ACTION_BUTTON_RELEASE = 13
-
- # 动作掩码
- ACTION_MASK = 0xFF
- ACTION_POINTER_INDEX_MASK = 0xFF00
- ACTION_POINTER_INDEX_SHIFT = 8
-
- # 按钮
- BUTTON_PRIMARY = 1
- BUTTON_SECONDARY = 2
- BUTTON_TERTIARY = 4
- BUTTON_BACK = 8
- BUTTON_FORWARD = 16
- BUTTON_STYLUS_PRIMARY = 32
- BUTTON_STYLUS_SECONDARY = 64
-
- # 边缘
- EDGE_LEFT = 1
- EDGE_TOP = 2
- EDGE_RIGHT = 4
- EDGE_BOTTOM = 8
-
- # 坐标分类
- AXIS_X = 0
- AXIS_Y = 1
- AXIS_PRESSURE = 2
- AXIS_SIZE = 3
- AXIS_TOUCH_MAJOR = 4
- AXIS_TOUCH_MINOR = 5
- AXIS_TOOL_MAJOR = 6
- AXIS_TOOL_MINOR = 7
- AXIS_ORIENTATION = 8
- AXIS_VSCROLL = 9
- AXIS_HSCROLL = 10
- AXIS_Z = 11
- AXIS_RX = 12
- AXIS_RY = 13
- AXIS_RZ = 14
- AXIS_HAT_X = 15
- AXIS_HAT_Y = 16
- AXIS_LTRIGGER = 17
- AXIS_RTRIGGER = 18
- AXIS_THROTTLE = 19
- AXIS_RUDDER = 20
- AXIS_WHEEL = 21
- AXIS_GAS = 22
- AXIS_BRAKE = 23
- AXIS_DISTANCE = 24
- AXIS_TILT = 25
- AXIS_SCROLL = 26
- AXIS_RELATIVE_X = 27
- AXIS_RELATIVE_Y = 28
- AXIS_GENERIC_1 = 32
- AXIS_GENERIC_2 = 33
- AXIS_GENERIC_3 = 34
- AXIS_GENERIC_4 = 35
- AXIS_GENERIC_5 = 36
- AXIS_GENERIC_6 = 37
- AXIS_GENERIC_7 = 38
- AXIS_GENERIC_8 = 39
- AXIS_GENERIC_9 = 40
- AXIS_GENERIC_10 = 41
- AXIS_GENERIC_11 = 42
- AXIS_GENERIC_12 = 43
- AXIS_GENERIC_13 = 44
- AXIS_GENERIC_14 = 45
- AXIS_GENERIC_15 = 46
- AXIS_GENERIC_16 = 47
-
- # 输入类型
- TOOL_TYPE_UNKNOWN = 0
- TOOL_TYPE_FINGER = 1
- TOOL_TYPE_STYLUS = 2
- TOOL_TYPE_MOUSE = 3
- TOOL_TYPE_ERASER = 4
-
- INVALID_POINTER_ID = -1
-
- def __init__(self, action: int = 0, x: float = 0.0, y: float = 0.0,
- event_time: int = 0, pointer_count: int = 1,
- meta_state: int = 0, button_state: int = 0):
- super().__init__()
- self._action = action
- self._x = x
- self._y = y
- self._raw_x = x
- self._raw_y = y
- self._event_time = event_time if event_time else int(time.time() * 1000)
- self._down_time = self._event_time
- self._pointer_count = pointer_count
- self._meta_state = meta_state
- self._button_state = button_state
- self._pointers: List[Dict] = []
- for i in range(pointer_count):
- self._pointers.append({
- "id": i,
- "x": x,
- "y": y,
- "pressure": 1.0,
- "size": 0.5,
- "tool_type": MotionEvent.TOOL_TYPE_FINGER,
- })
-
- @classmethod
- def obtain(cls, down_time: int, event_time: int, action: int,
- x: float, y: float, meta_state: int = 0) -> "MotionEvent":
- return cls(action=action, x=x, y=y, event_time=event_time)
-
- @classmethod
- def obtainNoHistory(cls, me: "MotionEvent") -> "MotionEvent":
- return cls(action=me._action, x=me._x, y=me._y,
- event_time=me._event_time, pointer_count=me._pointer_count)
-
- def recycle(self):
- pass
-
- def getAction(self) -> int:
- return self._action
-
- def getActionMasked(self) -> int:
- return self._action & MotionEvent.ACTION_MASK
-
- def getActionIndex(self) -> int:
- return (self._action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT
-
- def getX(self, pointer_index: int = 0) -> float:
- if 0 <= pointer_index < len(self._pointers):
- return self._pointers[pointer_index]["x"]
- return self._x
-
- def getY(self, pointer_index: int = 0) -> float:
- if 0 <= pointer_index < len(self._pointers):
- return self._pointers[pointer_index]["y"]
- return self._y
-
- def getRawX(self) -> float:
- return self._raw_x
-
- def getRawY(self) -> float:
- return self._raw_y
-
- def getPointerCount(self) -> int:
- return self._pointer_count
-
- def getPointerId(self, pointer_index: int) -> int:
- if 0 <= pointer_index < len(self._pointers):
- return self._pointers[pointer_index]["id"]
- return pointer_index
-
- def findPointerIndex(self, pointer_id: int) -> int:
- for i, p in enumerate(self._pointers):
- if p["id"] == pointer_id:
- return i
- return -1
-
- def getPressure(self, pointer_index: int = 0) -> float:
- if 0 <= pointer_index < len(self._pointers):
- return self._pointers[pointer_index]["pressure"]
- return 1.0
-
- def getSize(self, pointer_index: int = 0) -> float:
- if 0 <= pointer_index < len(self._pointers):
- return self._pointers[pointer_index]["size"]
- return 0.5
-
- def getEventTime(self) -> int:
- return self._event_time
-
- def getDownTime(self) -> int:
- return self._down_time
-
- def getMetaState(self) -> int:
- return self._meta_state
-
- def getButtonState(self) -> int:
- return self._button_state
-
- def getToolType(self, pointer_index: int = 0) -> int:
- if 0 <= pointer_index < len(self._pointers):
- return self._pointers[pointer_index]["tool_type"]
- return MotionEvent.TOOL_TYPE_FINGER
-
- def setLocation(self, x: float, y: float):
- self._x = x
- self._y = y
-
- def offsetLocation(self, dx: float, dy: float):
- self._x += dx
- self._y += dy
-
- def transform(self, matrix: Any):
- pass
-
- def isLongPress(self) -> bool:
- return (self._event_time - self._down_time) > 500
-
- def getHistoricalSize(self, pos: int, pointer: int = 0) -> float:
- return 0.5
-
- # ─── historical coordinates ───────────────────────────────
-
- def getHistorySize(self) -> int:
- return len(getattr(self, '_history', []))
-
- def getHistoricalX(self, pointer_index: int = 0, pos: int = 0) -> float:
- history = getattr(self, '_history', [])
- if 0 <= pos < len(history):
- return history[pos].get('x', self.getX(pointer_index))
- return self.getX(pointer_index)
-
- def getHistoricalY(self, pointer_index: int = 0, pos: int = 0) -> float:
- history = getattr(self, '_history', [])
- if 0 <= pos < len(history):
- return history[pos].get('y', self.getY(pointer_index))
- return self.getY(pointer_index)
-
- def getHistoricalPressure(self, pointer_index: int = 0, pos: int = 0) -> float:
- history = getattr(self, '_history', [])
- if 0 <= pos < len(history):
- return history[pos].get('pressure', 1.0)
- return 1.0
-
- def getHistoricalEventTime(self, pos: int = 0) -> int:
- history = getattr(self, '_history', [])
- if 0 <= pos < len(history):
- return history[pos].get('event_time', self._event_time)
- return self._event_time
-
- # ─── edge flags ───────────────────────────────────────────
-
- def getEdgeFlags(self) -> int:
- return getattr(self, '_edge_flags', 0)
-
- def setEdgeFlags(self, edge_flags: int):
- self._edge_flags = edge_flags
-
- # ─── action mutation ──────────────────────────────────────
-
- def setAction(self, action: int):
- self._action = action
-
- # ─── batch ────────────────────────────────────────────────
-
- def addBatch(self, event_time: int, x: float, y: float,
- pressure: float = 1.0, size: float = 0.5,
- meta_state: int = 0):
- if not hasattr(self, '_history'):
- self._history = []
- self._history.append({
- 'event_time': self._event_time,
- 'x': self._x,
- 'y': self._y,
- 'pressure': self.getPressure(0),
- 'size': self.getSize(0),
- 'meta_state': self._meta_state,
- })
- self._x = x
- self._y = y
- self._raw_x = x
- self._raw_y = y
- self._event_time = event_time
- self._meta_state = meta_state
- if self._pointers:
- self._pointers[0]['x'] = x
- self._pointers[0]['y'] = y
- self._pointers[0]['pressure'] = pressure
- self._pointers[0]['size'] = size
-
-
-# ═══════════════════════════════════════════════════════════════
-# KeyEvent
-# ═══════════════════════════════════════════════════════════════
-
-class KeyEvent(Stub):
- """KeyEvent — 按键事件"""
-
- # 动作
- ACTION_DOWN = 0
- ACTION_UP = 1
- ACTION_MULTIPLE = 2
-
- # 键码
- KEYCODE_UNKNOWN = 0
- KEYCODE_SOFT_LEFT = 1
- KEYCODE_SOFT_RIGHT = 2
- KEYCODE_HOME = 3
- KEYCODE_BACK = 4
- KEYCODE_CALL = 5
- KEYCODE_ENDCALL = 6
- KEYCODE_0 = 7
- KEYCODE_1 = 8
- KEYCODE_2 = 9
- KEYCODE_3 = 10
- KEYCODE_4 = 11
- KEYCODE_5 = 12
- KEYCODE_6 = 13
- KEYCODE_7 = 14
- KEYCODE_8 = 15
- KEYCODE_9 = 16
- KEYCODE_STAR = 17
- KEYCODE_POUND = 18
- KEYCODE_DPAD_UP = 19
- KEYCODE_DPAD_DOWN = 20
- KEYCODE_DPAD_LEFT = 21
- KEYCODE_DPAD_RIGHT = 22
- KEYCODE_DPAD_CENTER = 23
- KEYCODE_VOLUME_UP = 24
- KEYCODE_VOLUME_DOWN = 25
- KEYCODE_POWER = 26
- KEYCODE_CAMERA = 27
- KEYCODE_CLEAR = 28
- KEYCODE_A = 29
- KEYCODE_B = 30
- KEYCODE_C = 31
- KEYCODE_D = 32
- KEYCODE_E = 33
- KEYCODE_F = 34
- KEYCODE_G = 35
- KEYCODE_H = 36
- KEYCODE_I = 37
- KEYCODE_J = 38
- KEYCODE_K = 39
- KEYCODE_L = 40
- KEYCODE_M = 41
- KEYCODE_N = 42
- KEYCODE_O = 43
- KEYCODE_P = 44
- KEYCODE_Q = 45
- KEYCODE_R = 46
- KEYCODE_S = 47
- KEYCODE_T = 48
- KEYCODE_U = 49
- KEYCODE_V = 50
- KEYCODE_W = 51
- KEYCODE_X = 52
- KEYCODE_Y = 53
- KEYCODE_Z = 54
- KEYCODE_COMMA = 55
- KEYCODE_PERIOD = 56
- KEYCODE_ALT_LEFT = 57
- KEYCODE_ALT_RIGHT = 58
- KEYCODE_SHIFT_LEFT = 59
- KEYCODE_SHIFT_RIGHT = 60
- KEYCODE_TAB = 61
- KEYCODE_SPACE = 62
- KEYCODE_SYM = 63
- KEYCODE_EXPLORER = 64
- KEYCODE_ENVELOPE = 65
- KEYCODE_ENTER = 66
- KEYCODE_DEL = 67
- KEYCODE_GRAVE = 68
- KEYCODE_MINUS = 69
- KEYCODE_EQUALS = 70
- KEYCODE_LEFT_BRACKET = 71
- KEYCODE_RIGHT_BRACKET = 72
- KEYCODE_BACKSLASH = 73
- KEYCODE_SEMICOLON = 74
- KEYCODE_APOSTROPHE = 75
- KEYCODE_SLASH = 76
- KEYCODE_AT = 77
- KEYCODE_NUM = 78
- KEYCODE_HEADSETHOOK = 79
- KEYCODE_FOCUS = 80
- KEYCODE_PLUS = 81
- KEYCODE_MENU = 82
- KEYCODE_NOTIFICATION = 83
- KEYCODE_SEARCH = 84
- KEYCODE_MEDIA_PLAY_PAUSE = 85
- KEYCODE_MEDIA_STOP = 86
- KEYCODE_MEDIA_NEXT = 87
- KEYCODE_MEDIA_PREVIOUS = 88
- KEYCODE_MEDIA_REWIND = 89
- KEYCODE_MEDIA_FAST_FORWARD = 90
- KEYCODE_MUTE = 91
- KEYCODE_PAGE_UP = 92
- KEYCODE_PAGE_DOWN = 93
- KEYCODE_PICTSYMBOLS = 94
- KEYCODE_SWITCH_CHARSET = 95
- KEYCODE_BUTTON_A = 96
- KEYCODE_BUTTON_B = 97
- KEYCODE_BUTTON_C = 98
- KEYCODE_BUTTON_X = 99
- KEYCODE_BUTTON_Y = 100
- KEYCODE_BUTTON_Z = 101
- KEYCODE_BUTTON_L1 = 102
- KEYCODE_BUTTON_R1 = 103
- KEYCODE_BUTTON_L2 = 104
- KEYCODE_BUTTON_R2 = 105
- KEYCODE_BUTTON_THUMBL = 106
- KEYCODE_BUTTON_THUMBR = 107
- KEYCODE_BUTTON_START = 108
- KEYCODE_BUTTON_SELECT = 109
- KEYCODE_BUTTON_MODE = 110
- KEYCODE_ESCAPE = 111
- KEYCODE_FORWARD_DEL = 112
- KEYCODE_CTRL_LEFT = 113
- KEYCODE_CTRL_RIGHT = 114
- KEYCODE_CAPS_LOCK = 115
- KEYCODE_SCROLL_LOCK = 116
- KEYCODE_META_LEFT = 117
- KEYCODE_META_RIGHT = 118
- KEYCODE_FUNCTION = 119
- KEYCODE_SYSRQ = 120
- KEYCODE_BREAK = 121
- KEYCODE_MOVE_HOME = 122
- KEYCODE_MOVE_END = 123
- KEYCODE_INSERT = 124
- KEYCODE_FORWARD = 125
- KEYCODE_MEDIA_PLAY = 126
- KEYCODE_MEDIA_PAUSE = 127
- KEYCODE_MEDIA_CLOSE = 128
- KEYCODE_MEDIA_EJECT = 129
- KEYCODE_MEDIA_RECORD = 130
- KEYCODE_F1 = 131
- KEYCODE_F2 = 132
- KEYCODE_F3 = 133
- KEYCODE_F4 = 134
- KEYCODE_F5 = 135
- KEYCODE_F6 = 136
- KEYCODE_F7 = 137
- KEYCODE_F8 = 138
- KEYCODE_F9 = 139
- KEYCODE_F10 = 140
- KEYCODE_F11 = 141
- KEYCODE_F12 = 142
- KEYCODE_NUM_LOCK = 143
- KEYCODE_NUMPAD_0 = 144
- KEYCODE_NUMPAD_1 = 145
- KEYCODE_NUMPAD_2 = 146
- KEYCODE_NUMPAD_3 = 147
- KEYCODE_NUMPAD_4 = 148
- KEYCODE_NUMPAD_5 = 149
- KEYCODE_NUMPAD_6 = 150
- KEYCODE_NUMPAD_7 = 151
- KEYCODE_NUMPAD_8 = 152
- KEYCODE_NUMPAD_9 = 153
- KEYCODE_NUMPAD_DIVIDE = 154
- KEYCODE_NUMPAD_MULTIPLY = 155
- KEYCODE_NUMPAD_SUBTRACT = 156
- KEYCODE_NUMPAD_ADD = 157
- KEYCODE_NUMPAD_DOT = 158
- KEYCODE_NUMPAD_COMMA = 159
- KEYCODE_NUMPAD_ENTER = 160
- KEYCODE_NUMPAD_EQUALS = 161
- KEYCODE_NUMPAD_LEFT_PAREN = 162
- KEYCODE_NUMPAD_RIGHT_PAREN = 163
- KEYCODE_META_CTRL_LEFT = 164
- KEYCODE_META_CTRL_RIGHT = 165
- KEYCODE_META_ALT_LEFT = 166
- KEYCODE_META_ALT_RIGHT = 167
- KEYCODE_META_SHIFT_LEFT = 168
- KEYCODE_META_SHIFT_RIGHT = 169
- KEYCODE_META_SYM = 170
-
- # 元键掩码
- META_ALT_ON = 0x02
- META_ALT_LEFT_ON = 0x10
- META_ALT_RIGHT_ON = 0x20
- META_SHIFT_ON = 0x01
- META_SHIFT_LEFT_ON = 0x40
- META_SHIFT_RIGHT_ON = 0x80
- META_SYM_ON = 0x04
- META_FUNCTION_ON = 0x08
- META_CTRL_ON = 0x1000
- META_CTRL_LEFT_ON = 0x2000
- META_CTRL_RIGHT_ON = 0x4000
- META_META_ON = 0x10000
- META_META_LEFT_ON = 0x20000
- META_META_RIGHT_ON = 0x40000
- META_CAPS_LOCK_ON = 0x100000
- META_NUM_LOCK_ON = 0x200000
- META_SCROLL_LOCK_ON = 0x400000
-
- def __init__(self, action: int = ACTION_DOWN, key_code: int = KEYCODE_UNKNOWN,
- repeat_count: int = 0, event_time: int = 0,
- meta_state: int = 0):
- super().__init__()
- self._action = action
- self._key_code = key_code
- self._repeat_count = repeat_count
- self._event_time = event_time if event_time else int(time.time() * 1000)
- self._down_time = self._event_time
- self._meta_state = meta_state
- self._device_id = 0
- self._source = 0x101 # InputDevice.SOURCE_KEYBOARD
- self._flags = 0
- self._display_id = 0
-
- getAction = lambda self: self._action
- getKeyCode = lambda self: self._key_code
- getRepeatCount = lambda self: self._repeat_count
- getEventTime = lambda self: self._event_time
- getDownTime = lambda self: self._down_time
- getMetaState = lambda self: self._meta_state
- getDeviceId = lambda self: self._device_id
- getSource = lambda self: self._source
- getFlags = lambda self: self._flags
- getDisplayId = lambda self: self._display_id
-
- def isLongPress(self) -> bool:
- return self._repeat_count > 0
-
- def dispatch(self, receiver: View, on_receive: Callable) -> bool:
- return on_receive(receiver, self)
-
- def isAltPressed(self) -> bool:
- return bool(self._meta_state & KeyEvent.META_ALT_ON)
-
- def isShiftPressed(self) -> bool:
- return bool(self._meta_state & KeyEvent.META_SHIFT_ON)
-
- def isCtrlPressed(self) -> bool:
- return bool(self._meta_state & KeyEvent.META_CTRL_ON)
-
- def isMetaPressed(self) -> bool:
- return bool(self._meta_state & KeyEvent.META_META_ON)
-
- def isSymPressed(self) -> bool:
- return bool(self._meta_state & KeyEvent.META_SYM_ON)
-
- def isFunctionPressed(self) -> bool:
- return bool(self._meta_state & KeyEvent.META_FUNCTION_ON)
-
- def isCapsLockOn(self) -> bool:
- return bool(self._meta_state & KeyEvent.META_CAPS_LOCK_ON)
-
- def isNumLockOn(self) -> bool:
- return bool(self._meta_state & KeyEvent.META_NUM_LOCK_ON)
-
- def isScrollLockOn(self) -> bool:
- return bool(self._meta_state & KeyEvent.META_SCROLL_LOCK_ON)
-
- @staticmethod
- def changeTimeRepeat(event: "KeyEvent", event_time: int, repeat_count: int) -> "KeyEvent":
- return KeyEvent(
- action=event._action,
- key_code=event._key_code,
- repeat_count=repeat_count,
- event_time=event_time,
- meta_state=event._meta_state,
- )
-
- @staticmethod
- def changeAction(event: "KeyEvent", action: int) -> "KeyEvent":
- return KeyEvent(
- action=action,
- key_code=event._key_code,
- repeat_count=event._repeat_count,
- event_time=event._event_time,
- meta_state=event._meta_state,
- )
-
- def getCharacters(self):
- return getattr(self, '_characters', None)
-
- def isSystem(self):
- return False
-
- def isPrintingKey(self):
- return False
-
- def isModifierKey(self, keyCode):
- return keyCode in (KEYCODE_SHIFT_LEFT, KEYCODE_SHIFT_RIGHT, KEYCODE_ALT_LEFT, KEYCODE_ALT_RIGHT, KEYCODE_CTRL_LEFT, KEYCODE_CTRL_RIGHT, KEYCODE_META_LEFT, KEYCODE_META_RIGHT)
-
- def startTracking(self):
- self._tracking = True
-
- def isTracking(self):
- return getattr(self, '_tracking', False)
-
- @staticmethod
- def keyCodeToString(keyCode):
- return f"KEYCODE_{keyCode}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureDetector
-# ═══════════════════════════════════════════════════════════════
-
-class GestureDetector(Stub):
- """GestureDetector — 手势检测器"""
-
- class SimpleOnGestureListener:
- """SimpleOnGestureListener — 简单手势监听器"""
-
- def onDown(self, e: MotionEvent) -> bool:
- return False
-
- def onShowPress(self, e: MotionEvent):
- pass
-
- def onSingleTapUp(self, e: MotionEvent) -> bool:
- return False
-
- def onScroll(self, e1: MotionEvent, e2: MotionEvent,
- distance_x: float, distance_y: float) -> bool:
- return False
-
- def onLongPress(self, e: MotionEvent):
- pass
-
- def onFling(self, e1: MotionEvent, e2: MotionEvent,
- velocity_x: float, velocity_y: float) -> bool:
- return False
-
- def onSingleTapConfirmed(self, e: MotionEvent) -> bool:
- return False
-
- def onDoubleTap(self, e: MotionEvent) -> bool:
- return False
-
- def onDoubleTapEvent(self, e: MotionEvent) -> bool:
- return False
-
- def onContextClick(self, e: MotionEvent) -> bool:
- return False
-
- class OnGestureListener:
- def onDown(self, e: MotionEvent) -> bool:
- return False
- def onShowPress(self, e: MotionEvent):
- pass
- def onSingleTapUp(self, e: MotionEvent) -> bool:
- return False
- def onScroll(self, e1: MotionEvent, e2: MotionEvent,
- distance_x: float, distance_y: float) -> bool:
- return False
- def onLongPress(self, e: MotionEvent):
- pass
- def onFling(self, e1: MotionEvent, e2: MotionEvent,
- velocity_x: float, velocity_y: float) -> bool:
- return False
-
- class OnDoubleTapListener:
- def onSingleTapConfirmed(self, e: MotionEvent) -> bool:
- return False
- def onDoubleTap(self, e: MotionEvent) -> bool:
- return False
- def onDoubleTapEvent(self, e: MotionEvent) -> bool:
- return False
-
- def __init__(self, context=None, listener: Optional["GestureDetector.OnGestureListener"] = None,
- handler: Any = None):
- super().__init__()
- self._listener = listener
- self._double_tap_listener: Optional["GestureDetector.OnDoubleTapListener"] = None
- self._is_longpress_enabled = True
- self._context = context
- self._current_down_event: Optional[MotionEvent] = None
- self._previous_down_event: Optional[MotionEvent] = None
- self._in_long_press = False
- self._long_press_timeout = 500
- self._touch_slop = 8
-
- def setOnDoubleTapListener(self, listener: Optional["GestureDetector.OnDoubleTapListener"]):
- self._double_tap_listener = listener
-
- def setIsLongpressEnabled(self, enabled: bool):
- self._is_longpress_enabled = enabled
-
- def isLongpressEnabled(self) -> bool:
- return self._is_longpress_enabled
-
- def onTouchEvent(self, ev: MotionEvent) -> bool:
- action = ev.getAction()
- if action == MotionEvent.ACTION_DOWN:
- self._in_long_press = False
- self._current_down_event = ev
- if self._listener:
- return self._listener.onDown(ev)
- elif action == MotionEvent.ACTION_MOVE:
- pass
- elif action == MotionEvent.ACTION_UP:
- if self._listener:
- return self._listener.onSingleTapUp(ev)
- elif action == MotionEvent.ACTION_CANCEL:
- pass
- return False
-
- def setContextClickListener(self, listener: Callable):
- pass
-
- def setContextClickable(self, context_clickable: bool):
- pass
-
- def isContextClickable(self) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScaleGestureDetector
-# ═══════════════════════════════════════════════════════════════
-
-class ScaleGestureDetector(Stub):
- """ScaleGestureDetector — 缩放手势检测器"""
-
- class SimpleOnScaleGestureListener:
- """SimpleOnScaleGestureListener — 简单缩放手势监听器"""
-
- def onScaleBegin(self, detector: "ScaleGestureDetector") -> bool:
- return True
-
- def onScale(self, detector: "ScaleGestureDetector") -> bool:
- return False
-
- def onScaleEnd(self, detector: "ScaleGestureDetector"):
- pass
-
- class OnScaleGestureListener:
- def onScaleBegin(self, detector: "ScaleGestureDetector") -> bool:
- return True
- def onScale(self, detector: "ScaleGestureDetector") -> bool:
- return False
- def onScaleEnd(self, detector: "ScaleGestureDetector"):
- pass
-
- def __init__(self, context=None, listener: Optional[OnScaleGestureListener] = None):
- super().__init__()
- self._listener = listener
- self._scale_factor = 1.0
- self._current_span = 0.0
- self._current_span_x = 0.0
- self._current_span_y = 0.0
- self._focus_x = 0.0
- self._focus_y = 0.0
- self._previous_span = 0.0
- self._time_delta = 0
- self._in_progress = False
-
- def getScaleFactor(self) -> float:
- return self._scale_factor
-
- def getCurrentSpan(self) -> float:
- return self._current_span
-
- def getCurrentSpanX(self) -> float:
- return self._current_span_x
-
- def getCurrentSpanY(self) -> float:
- return self._current_span_y
-
- def getPreviousSpan(self) -> float:
- return self._previous_span
-
- def getPreviousSpanX(self) -> float:
- return self._current_span_x
-
- def getPreviousSpanY(self) -> float:
- return self._current_span_y
-
- def getFocusX(self) -> float:
- return self._focus_x
-
- def getFocusY(self) -> float:
- return self._focus_y
-
- def getTimeDelta(self) -> int:
- return self._time_delta
-
- def getEventTime(self) -> int:
- return int(time.time() * 1000)
-
- def isInProgress(self) -> bool:
- return self._in_progress
-
- def onTouchEvent(self, event: MotionEvent) -> bool:
- action = event.getActionMasked()
- if action == MotionEvent.ACTION_DOWN:
- self._in_progress = False
- elif action == MotionEvent.ACTION_POINTER_DOWN:
- if event.getPointerCount() >= 2:
- self._in_progress = True
- x1, y1 = event.getX(0), event.getY(0)
- x2, y2 = event.getX(1), event.getY(1)
- self._current_span = math.hypot(x2 - x1, y2 - y1)
- self._focus_x = (x1 + x2) / 2.0
- self._focus_y = (y1 + y2) / 2.0
- if self._listener:
- self._listener.onScaleBegin(self)
- return True
- elif action == MotionEvent.ACTION_MOVE:
- if self._in_progress and event.getPointerCount() >= 2:
- x1, y1 = event.getX(0), event.getY(0)
- x2, y2 = event.getX(1), event.getY(1)
- new_span = math.hypot(x2 - x1, y2 - y1)
- self._previous_span = self._current_span
- self._current_span = new_span
- if self._previous_span > 0:
- self._scale_factor = self._current_span / self._previous_span
- self._focus_x = (x1 + x2) / 2.0
- self._focus_y = (y1 + y2) / 2.0
- if self._listener:
- self._listener.onScale(self)
- return True
- elif action in (MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL):
- if self._in_progress and self._listener:
- self._listener.onScaleEnd(self)
- self._in_progress = False
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# VelocityTracker
-# ═══════════════════════════════════════════════════════════════
-
-class VelocityTracker(Stub):
- """VelocityTracker — 速度追踪器"""
-
- def __init__(self):
- super().__init__()
- self._movements: List[Tuple[float, float, float]] = [] # (x, y, time)
- self._x_velocity: float = 0.0
- self._y_velocity: float = 0.0
-
- @staticmethod
- def obtain() -> "VelocityTracker":
- return VelocityTracker()
-
- @staticmethod
- def obtainUnit(max_units: int, generator_id: int) -> "VelocityTracker":
- return VelocityTracker()
-
- def addMovement(self, event: MotionEvent):
- self._movements.append((event.getRawX(), event.getRawY(),
- event.getEventTime() / 1000.0))
- if len(self._movements) > 100:
- self._movements = self._movements[-50:]
-
- def computeCurrentVelocity(self, units: int, max_velocity: float = float("inf")):
- if len(self._movements) < 2:
- self._x_velocity = 0.0
- self._y_velocity = 0.0
- return
- recent = self._movements[-4:] if len(self._movements) >= 4 else self._movements
- first_x, first_y, first_t = recent[0]
- last_x, last_y, last_t = recent[-1]
- dt = last_t - first_t
- if dt > 0:
- unit_scale = units / 1000.0
- self._x_velocity = (last_x - first_x) / dt * unit_scale
- self._y_velocity = (last_y - first_y) / dt * unit_scale
- self._x_velocity = max(-max_velocity, min(max_velocity, self._x_velocity))
- self._y_velocity = max(-max_velocity, min(max_velocity, self._y_velocity))
- else:
- self._x_velocity = 0.0
- self._y_velocity = 0.0
-
- def getXVelocity(self, id_: int = -1) -> float:
- return self._x_velocity
-
- def getYVelocity(self, id_: int = -1) -> float:
- return self._y_velocity
-
- def recycle(self):
- self._movements.clear()
- self._x_velocity = 0.0
- self._y_velocity = 0.0
-
- def clear(self):
- self._movements.clear()
-
- def getEstimator(self) -> Any:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# DragEvent
-# ═══════════════════════════════════════════════════════════════
-
-class DragEvent(Stub):
- """DragEvent — 拖放事件"""
-
- ACTION_DRAG_STARTED = 1
- ACTION_DRAG_LOCATION = 2
- ACTION_DROP = 3
- ACTION_DRAG_ENTERED = 4
- ACTION_DRAG_EXITED = 5
- ACTION_DRAG_ENDED = 6
-
- def __init__(self, action: int = 0, x: float = 0.0, y: float = 0.0,
- clip_data: Any = None, result: bool = False):
- super().__init__()
- self._action = action
- self._x = x
- self._y = y
- self._clip_data = clip_data
- self._result = result
- self._local_state: Any = None
-
- def getAction(self) -> int:
- return self._action
-
- def getX(self) -> float:
- return self._x
-
- def getY(self) -> float:
- return self._y
-
- def getClipData(self) -> Any:
- return self._clip_data
-
- def getResult(self) -> bool:
- return self._result
-
- def getLocalState(self) -> Any:
- return self._local_state
-
- def setLocalState(self, state: Any):
- self._local_state = state
-
- def toString(self) -> str:
- action_names = {
- 1: "ACTION_DRAG_STARTED",
- 2: "ACTION_DRAG_LOCATION",
- 3: "ACTION_DROP",
- 4: "ACTION_DRAG_ENTERED",
- 5: "ACTION_DRAG_EXITED",
- 6: "ACTION_DRAG_ENDED",
- }
- name = action_names.get(self._action, f"UNKNOWN({self._action})")
- return f"DragEvent(action={name}, x={self._x}, y={self._y})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityDelegate
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityDelegate(Stub):
- """AccessibilityDelegate — 辅助功能委托"""
-
- def sendAccessibilityEvent(self, host: View, event_type: int):
- pass
-
- def sendAccessibilityEventUnchecked(self, host: View, event: Any):
- pass
-
- def dispatchPopulateAccessibilityEvent(self, host: View, event: Any) -> bool:
- return False
-
- def onPopulateAccessibilityEvent(self, host: View, event: Any):
- pass
-
- def onInitializeAccessibilityEvent(self, host: View, event: Any):
- pass
-
- def onInitializeAccessibilityNodeInfo(self, host: View, info: Any):
- pass
-
- def onRequestSendAccessibilityEvent(self, host: ViewGroup, child: View, event: Any) -> bool:
- return True
-
- def getAccessibilityNodeProvider(self, host: View) -> Optional[Any]:
- return None
-
- def performAccessibilityAction(self, host: View, action: int, arguments: Any) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewTreeObserver
-# ═══════════════════════════════════════════════════════════════
-
-class ViewTreeObserver(Stub):
- """ViewTreeObserver — 视图树观察者"""
-
- class OnGlobalLayoutListener:
- def onGlobalLayout(self):
- pass
-
- class OnGlobalFocusChangeListener:
- def onGlobalFocusChanged(self, old_focus: View, new_focus: View):
- pass
-
- class OnScrollChangedListener:
- def onScrollChanged(self):
- pass
-
- class OnTouchModeChangeListener:
- def onTouchModeChanged(self, is_in_touch_mode: bool):
- pass
-
- class OnWindowAttachListener:
- def onWindowAttached(self):
- pass
- def onWindowDetached(self):
- pass
-
- class OnWindowFocusChangeListener:
- def onWindowFocusChanged(self, has_focus: bool):
- pass
-
- class OnDrawListener:
- def onDraw(self):
- pass
-
- class OnPreDrawListener:
- def onPreDraw(self) -> bool:
- return True
-
- class OnWindowShownListener:
- def onWindowShown(self):
- pass
-
- def __init__(self):
- super().__init__()
- self._global_layout_listeners: List[ViewTreeObserver.OnGlobalLayoutListener] = []
- self._scroll_changed_listeners: List[ViewTreeObserver.OnScrollChangedListener] = []
- self._pre_draw_listeners: List[ViewTreeObserver.OnPreDrawListener] = []
- self._draw_listeners: List[ViewTreeObserver.OnDrawListener] = []
- self._touch_mode_listeners: List[ViewTreeObserver.OnTouchModeChangeListener] = []
- self._window_focus_listeners: List[ViewTreeObserver.OnWindowFocusChangeListener] = []
- self._window_attach_listeners: List[ViewTreeObserver.OnWindowAttachListener] = []
- self._alive = True
-
- def addOnGlobalLayoutListener(self, listener: OnGlobalLayoutListener):
- self._global_layout_listeners.append(listener)
-
- def removeOnGlobalLayoutListener(self, listener: OnGlobalLayoutListener):
- if listener in self._global_layout_listeners:
- self._global_layout_listeners.remove(listener)
-
- def addOnScrollChangedListener(self, listener: OnScrollChangedListener):
- self._scroll_changed_listeners.append(listener)
-
- def removeOnScrollChangedListener(self, listener: OnScrollChangedListener):
- if listener in self._scroll_changed_listeners:
- self._scroll_changed_listeners.remove(listener)
-
- def addOnPreDrawListener(self, listener: OnPreDrawListener):
- self._pre_draw_listeners.append(listener)
-
- def removeOnPreDrawListener(self, listener: OnPreDrawListener):
- if listener in self._pre_draw_listeners:
- self._pre_draw_listeners.remove(listener)
-
- def addOnDrawListener(self, listener: OnDrawListener):
- self._draw_listeners.append(listener)
-
- def removeOnDrawListener(self, listener: OnDrawListener):
- if listener in self._draw_listeners:
- self._draw_listeners.remove(listener)
-
- def addOnGlobalFocusChangeListener(self, listener: OnGlobalFocusChangeListener):
- pass
-
- def removeOnGlobalFocusChangeListener(self, listener: OnGlobalFocusChangeListener):
- pass
-
- def addOnTouchModeChangeListener(self, listener: OnTouchModeChangeListener):
- self._touch_mode_listeners.append(listener)
-
- def removeOnTouchModeChangeListener(self, listener: OnTouchModeChangeListener):
- if listener in self._touch_mode_listeners:
- self._touch_mode_listeners.remove(listener)
-
- def addOnWindowAttachListener(self, listener: OnWindowAttachListener):
- self._window_attach_listeners.append(listener)
-
- def removeOnWindowAttachListener(self, listener: OnWindowAttachListener):
- if listener in self._window_attach_listeners:
- self._window_attach_listeners.remove(listener)
-
- def addOnWindowFocusChangeListener(self, listener: OnWindowFocusChangeListener):
- self._window_focus_listeners.append(listener)
-
- def removeOnWindowFocusChangeListener(self, listener: OnWindowFocusChangeListener):
- if listener in self._window_focus_listeners:
- self._window_focus_listeners.remove(listener)
-
- def addOnWindowShownListener(self, listener: OnWindowShownListener):
- pass
-
- def removeOnWindowShownListener(self, listener: OnWindowShownListener):
- pass
-
- def dispatchOnGlobalLayout(self):
- for listener in list(self._global_layout_listeners):
- listener.onGlobalLayout()
-
- def dispatchOnScrollChanged(self):
- for listener in list(self._scroll_changed_listeners):
- listener.onScrollChanged()
-
- def isAlive(self) -> bool:
- return self._alive
-
- def kill(self):
- self._alive = False
- self._global_layout_listeners.clear()
- self._scroll_changed_listeners.clear()
- self._pre_draw_listeners.clear()
- self._draw_listeners.clear()
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class ViewConfiguration(Stub):
- """ViewConfiguration — 视图配置常量"""
-
- def __init__(self, context=None):
- super().__init__()
- if context is None:
- context = android_context
- self._context = context
-
- @staticmethod
- def get(context=None) -> "ViewConfiguration":
- return ViewConfiguration(context)
-
- @staticmethod
- def getLongPressTimeout() -> int:
- return 500
-
- @staticmethod
- def getTapTimeout() -> int:
- return 100
-
- @staticmethod
- def getJumpTapTimeout() -> int:
- return 500
-
- @staticmethod
- def getDoubleTapTimeout() -> int:
- return 300
-
- @staticmethod
- def getEdgeSlop() -> int:
- return 12
-
- @staticmethod
- def getTouchSlop() -> int:
- return 8
-
- @staticmethod
- def getScaledTouchSlop(self) -> int:
- return 8
-
- @staticmethod
- def getScaledEdgeSlop(self) -> int:
- return 12
-
- @staticmethod
- def getScaledFadingEdgeLength(self) -> int:
- return 12
-
- @staticmethod
- def getScaledMinimumFlingVelocity(self) -> int:
- return 50
-
- @staticmethod
- def getScaledMaximumFlingVelocity(self) -> int:
- return 8000
-
- @staticmethod
- def getScaledPagingTouchSlop(self) -> int:
- return 16
-
- @staticmethod
- def getScaledOverflingDistance(self) -> int:
- return 32
-
- @staticmethod
- def getScaledOverscrollDistance(self) -> int:
- return 32
-
- @staticmethod
- def getScaledScrollFactor(self) -> int:
- return 64
-
- @staticmethod
- def getScrollFriction() -> float:
- return 0.015
-
- @staticmethod
- def getMaximumDrawingCacheSize() -> int:
- return 480 * 800 * 4
-
- @staticmethod
- def getWindowTouchSlop() -> int:
- return 16
-
- @staticmethod
- def getGlobalActionKeySlop() -> int:
- return 12
-
- def getScaledWindowTouchSlop(self) -> int:
- return 16
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurfaceView
-# ═══════════════════════════════════════════════════════════════
-
-class SurfaceView(View):
- """SurfaceView — 表面视图,用于直接绘制"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._surface = Surface()
- self._surface_holder = SurfaceHolder()
-
- def getHolder(self) -> "SurfaceHolder":
- return self._surface_holder
-
- def getSurfaceControl(self) -> Any:
- return None
-
- def setVisibility(self, visibility: int):
- super().setVisibility(visibility)
-
- def setSecure(self, is_secure: bool):
- pass
-
- def setZOrderMediaOverlay(self, is_media_overlay: bool):
- pass
-
- def setZOrderOnTop(self, on_top: bool):
- pass
-
- def gatherTransparentRegion(self, region: Any) -> bool:
- return False
-
- def draw(self, canvas: Any):
- pass
-
-
-class SurfaceHolder(Stub):
- """SurfaceHolder — Surface 持有者"""
-
- class Callback:
- def surfaceCreated(self, holder: "SurfaceHolder"):
- pass
- def surfaceChanged(self, holder: "SurfaceHolder", format: int, width: int, height: int):
- pass
- def surfaceDestroyed(self, holder: "SurfaceHolder"):
- pass
-
- class Callback2(Callback):
- def surfaceRedrawNeeded(self, holder: "SurfaceHolder"):
- pass
-
- SURFACE_TYPE_NORMAL = 0
- SURFACE_TYPE_HARDWARE = 1
- SURFACE_TYPE_GPU = 2
- SURFACE_TYPE_PUSH_BUFFERS = 3
-
- def __init__(self):
- super().__init__()
- self._surface = Surface()
- self._callbacks: List[SurfaceHolder.Callback] = []
- self._type = SurfaceHolder.SURFACE_TYPE_NORMAL
- self._fixed_size: Optional[Tuple[int, int]] = None
- self._format = -1
-
- def getSurface(self) -> "Surface":
- return self._surface
-
- def addCallback(self, callback: Callback):
- self._callbacks.append(callback)
-
- def removeCallback(self, callback: Callback):
- if callback in self._callbacks:
- self._callbacks.remove(callback)
-
- def isCreating(self) -> bool:
- return False
-
- def setType(self, type_: int):
- self._type = type_
-
- def setFixedSize(self, width: int, height: int):
- self._fixed_size = (width, height)
-
- def setSizeFromLayout(self):
- self._fixed_size = None
-
- def setFormat(self, format: int):
- self._format = format
-
- def lockCanvas(self, *args):
- """锁定画布并返回 Canvas 对象"""
- if hasattr(self, '_surface') and self._surface:
- from .graphics import Canvas, Bitmap
- if hasattr(self._surface, '_bitmap') and self._surface._bitmap:
- return Canvas(self._surface._bitmap)
- from .graphics import Canvas, Bitmap
- return Canvas(Bitmap(100, 100))
-
- def unlockCanvasAndPost(self, canvas):
- """解锁画布并提交"""
- pass # 桌面环境无需实际提交
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextureView
-# ═══════════════════════════════════════════════════════════════
-
-class TextureView(View):
- """TextureView — 纹理视图"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._surface_texture = SurfaceTexture()
- self._layer = None
- self._update_listener: Optional[Callable] = None
- self._surface_texture_listener: Optional[Callable] = None
-
- class SurfaceTextureListener:
- def onSurfaceTextureAvailable(self, surface: "SurfaceTexture", width: int, height: int):
- pass
- def onSurfaceTextureSizeChanged(self, surface: "SurfaceTexture", width: int, height: int):
- pass
- def onSurfaceTextureDestroyed(self, surface: "SurfaceTexture") -> bool:
- return True
- def onSurfaceTextureUpdated(self, surface: "SurfaceTexture"):
- pass
-
- def isOpaque(self) -> bool:
- return False
-
- def setOpaque(self, opaque: bool):
- pass
-
- def getSurfaceTexture(self) -> "SurfaceTexture":
- return self._surface_texture
-
- def setSurfaceTexture(self, surface_texture: "SurfaceTexture"):
- self._surface_texture = surface_texture
-
- def setSurfaceTextureListener(self, listener: SurfaceTextureListener):
- self._surface_texture_listener = listener
-
- def getSurfaceTextureListener(self) -> Optional[SurfaceTextureListener]:
- return self._surface_texture_listener
-
- def buildLayer(self):
- pass
-
- def setLayerPaint(self, paint: Any):
- pass
-
- def getLayerPaint(self) -> Any:
- return None
-
- def setTransform(self, transform: Any):
- pass
-
- def getTransform(self, transform: Any) -> Any:
- return transform
-
- def draw(self, canvas: Any):
- pass
-
- def lockCanvas(self) -> Any:
- return None
-
- def unlockCanvasAndPost(self, canvas: Any):
- pass
-
-
-class SurfaceTexture(Stub):
- """SurfaceTexture — 表面纹理"""
-
- def __init__(self, tex_name: int = 0, allow_legacy: bool = True):
- super().__init__()
- self._tex_name = tex_name
- self._timestamp = 0
- self._frame_available_listener: Optional[Callable] = None
- self._default_buffer_size: Optional[Tuple[int, int]] = None
-
- def setOnFrameAvailableListener(self, listener: Callable, handler: Any = None):
- self._frame_available_listener = listener
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def updateTexImage(self):
- pass
-
- def release(self):
- pass
-
- def setDefaultBufferSize(self, width: int, height: int):
- self._default_buffer_size = (width, height)
-
- def getTransformMatrix(self, mtx: List[float]):
- for i in range(16):
- mtx[i] = 1.0 if i % 5 == 0 else 0.0
-
-
-# ═══════════════════════════════════════════════════════════════
-# MenuInflater
-# ═══════════════════════════════════════════════════════════════
-
-class MenuInflater(Stub):
- """MenuInflater — 菜单填充器(桌面环境桩实现)"""
-
- def __init__(self, context=None):
- super().__init__()
- self._context = context
-
- def inflate(self, menu_res: int, menu: Any):
- return menu
-
- def toString(self) -> str:
- return f"MenuInflater@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Window
-# ═══════════════════════════════════════════════════════════════
-
-class Window(Stub):
- """Window — 抽象窗口基类"""
-
- # 特性ID
- FEATURES_DEFAULT = -1
- FEATURE_OPTIONS_PANEL = 0
- FEATURE_NO_TITLE = 1
- FEATURE_PROGRESS = 2
- FEATURE_LEFT_ICON = 3
- FEATURE_RIGHT_ICON = 4
- FEATURE_INDETERMINATE_PROGRESS = 5
- FEATURE_CONTEXT_MENU = 6
- FEATURE_CUSTOM_TITLE = 7
- FEATURE_ACTION_BAR = 8
- FEATURE_ACTION_BAR_OVERLAY = 9
- FEATURE_ACTION_MODE_OVERLAY = 10
- FEATURE_SWIPE_TO_DISMISS = 11
- FEATURE_CONTENT_TRANSITIONS = 12
- FEATURE_WATCH = 13
-
- # 本地特性
- ID_ANDROID_CONTENT = 0x01020002
-
- DECOR_CAPTION_SHORTCUT_DURATION_MS = 1000
-
- # 标志
- NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME = "navigationBarBackground"
- STATUS_BAR_BACKGROUND_TRANSITION_NAME = "statusBarBackground"
-
- def __init__(self, context=None):
- super().__init__()
- if context is None:
- context = android_context
- self._context = context
- self._features: Dict[int, bool] = {}
- self._title: str = ""
- self._decor_view: Optional[View] = None
- self._callback: Optional["Window.Callback"] = None
- self._window_manager: Optional[WindowManager] = None
- self._soft_input_mode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
- self._flags: Dict[int, bool] = {}
- self._container: Optional[Window] = None
- self._local_features: List[int] = []
-
- class Callback:
- def dispatchKeyEvent(self, event: KeyEvent) -> bool:
- return False
- def dispatchTouchEvent(self, event: MotionEvent) -> bool:
- return False
- def dispatchTrackballEvent(self, event: MotionEvent) -> bool:
- return False
- def dispatchGenericMotionEvent(self, event: MotionEvent) -> bool:
- return False
- def dispatchPopulateAccessibilityEvent(self, event: Any) -> bool:
- return False
- def onCreatePanelView(self, feature_id: int) -> Optional[View]:
- return None
- def onCreatePanelMenu(self, feature_id: int, menu: Any) -> bool:
- return False
- def onPreparePanel(self, feature_id: int, view: View, menu: Any) -> bool:
- return False
- def onMenuOpened(self, feature_id: int, menu: Any):
- pass
- def onMenuItemSelected(self, feature_id: int, item: Any) -> bool:
- return False
- def onWindowAttributesChanged(self, attrs: Any):
- pass
- def onContentChanged(self):
- pass
- def onWindowFocusChanged(self, has_focus: bool):
- pass
- def onAttachedToWindow(self):
- pass
- def onDetachedFromWindow(self):
- pass
- def onPanelClosed(self, feature_id: int, menu: Any):
- pass
- def onSearchRequested(self) -> bool:
- return False
- def onSearchRequested(self, search_event: Any) -> bool:
- return False
- def onActionModeStarted(self, mode: Any):
- pass
- def onActionModeFinished(self, mode: Any):
- pass
- def onWindowStartingActionMode(self, callback: Any) -> Optional[Any]:
- return None
- def onWindowStartingActionMode(self, callback: Any, type_: int) -> Optional[Any]:
- return None
-
- def setContentView(self, layout_res_id: int):
- pass
-
- def setContentView(self, view: View):
- pass
-
- def setContentView(self, view: View, params: ViewGroup.LayoutParams):
- pass
-
- def addContentView(self, view: View, params: ViewGroup.LayoutParams):
- pass
-
- def setTitle(self, title: str):
- self._title = title
-
- def getTitle(self) -> str:
- return self._title
-
- def setFeatureInt(self, feature_id: int, value: int):
- self._features[feature_id] = True
-
- def requestFeature(self, feature_id: int) -> bool:
- self._features[feature_id] = True
- return True
-
- def hasFeature(self, feature_id: int) -> bool:
- return self._features.get(feature_id, False)
-
- def setFlags(self, flags: int, mask: int):
- for flag_bit in range(32):
- if mask & (1 << flag_bit):
- self._flags[1 << flag_bit] = bool(flags & (1 << flag_bit))
-
- def addFlags(self, flags: int):
- for flag_bit in range(32):
- if flags & (1 << flag_bit):
- self._flags[1 << flag_bit] = True
-
- def clearFlags(self, flags: int):
- for flag_bit in range(32):
- if flags & (1 << flag_bit):
- self._flags[1 << flag_bit] = False
-
- def setSoftInputMode(self, soft_input_mode: int):
- self._soft_input_mode = soft_input_mode
-
- def getSoftInputMode(self) -> int:
- return self._soft_input_mode
-
- def setLayout(self, width: int, height: int):
- pass
-
- def findViewById(self, id_: int) -> Optional[View]:
- if self._decor_view:
- return self._decor_view.findViewById(id_)
- return None
-
- def getDecorView(self) -> Optional[View]:
- return self._decor_view
-
- def setDecorView(self, view: View):
- self._decor_view = view
-
- def getWindowManager(self) -> Optional[WindowManager]:
- return self._window_manager
-
- def setWindowManager(self, wm: WindowManager, app_token: Any = None, app_name: str = ""):
- self._window_manager = wm
-
- def setCallback(self, callback: Callback):
- self._callback = callback
-
- def getCallback(self) -> Optional[Callback]:
- return self._callback
-
- def superDispatchTouchEvent(self, event: MotionEvent) -> bool:
- if self._decor_view:
- return self._decor_view.dispatchTouchEvent(event)
- return False
-
- def superDispatchKeyEvent(self, event: KeyEvent) -> bool:
- if self._decor_view:
- return self._decor_view.dispatchKeyEvent(event)
- return False
-
- def superDispatchTrackballEvent(self, event: MotionEvent) -> bool:
- return False
-
- def superDispatchGenericMotionEvent(self, event: MotionEvent) -> bool:
- return False
-
- def takeSurface(self, callback: Any):
- pass
-
- def takeInputQueue(self, callback: Any):
- pass
-
- def isActive(self) -> bool:
- return True
-
- def isFloating(self) -> bool:
- return False
-
- def setBackgroundDrawable(self, drawable: Any):
- pass
-
- def setBackgroundDrawableResource(self, res_id: int):
- pass
-
- def setDimAmount(self, amount: float):
- pass
-
- def getLayoutInflater(self):
- return None
-
- def setWindowAnimations(self, res_id: int):
- pass
-
- def getWindowStyle(self) -> Any:
- return None
-
- def setContainer(self, container: "Window"):
- self._container = container
-
- def getContainer(self) -> Optional["Window"]:
- return self._container
-
- def setLocalFeatures(self, local_features: int):
- pass
-
- def makeActive(self):
- pass
-
- def getContext(self):
- return self._context
-
- def getAttributes(self) -> WindowManager.LayoutParams:
- params = WindowManager.LayoutParams()
- params.softInputMode = self._soft_input_mode
- return params
-
- def setAttributes(self, attrs: WindowManager.LayoutParams):
- pass
-
- def reconfigure(self, attrs: WindowManager.LayoutParams):
- pass
-
- def onConfigurationChanged(self, new_config: Any):
- pass
-
- def getCurrentFocus(self) -> Optional[View]:
- return None
-
- def getVolumeControlStream(self) -> int:
- return -1
-
- def setVolumeControlStream(self, stream_type: int):
- pass
-
- def getMediaController(self) -> Any:
- return None
-
- def setMediaController(self, controller: Any):
- pass
-
- def openGlEsVersion(self) -> int:
- return 2
-
- def isShortcutKey(self, key_code: int, event: KeyEvent) -> bool:
- return False
-
- def setStatusBarColor(self, color: int):
- pass
-
- def setNavigationBarColor(self, color: int):
- pass
-
- def setStatusBarVisibility(self, visible: bool):
- pass
-
- def setNavigationBarVisibility(self, visible: bool):
- pass
-
- def getStatusBarColor(self) -> int:
- return 0
-
- def getNavigationBarColor(self) -> int:
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowInsets
-# ═══════════════════════════════════════════════════════════════
-
-class WindowInsets(Stub):
- """WindowInsets — 窗口插入区域"""
-
- def __init__(self, left: int = 0, top: int = 0, right: int = 0, bottom: int = 0):
- super().__init__()
- self._system_window_insets = Rect(left, top, right, bottom)
- self._stable_insets = Rect(0, 0, 0, 0)
- self._display_cutout_insets = Rect(0, 0, 0, 0)
- self._consumed = False
-
- def getSystemWindowInsetLeft(self) -> int:
- return self._system_window_insets.left
-
- def getSystemWindowInsetTop(self) -> int:
- return self._system_window_insets.top
-
- def getSystemWindowInsetRight(self) -> int:
- return self._system_window_insets.right
-
- def getSystemWindowInsetBottom(self) -> int:
- return self._system_window_insets.bottom
-
- def getSystemWindowInsets(self) -> Rect:
- return self._system_window_insets
-
- def getStableInsetTop(self) -> int:
- return self._stable_insets.top
-
- def getStableInsetLeft(self) -> int:
- return self._stable_insets.left
-
- def getStableInsetRight(self) -> int:
- return self._stable_insets.right
-
- def getStableInsetBottom(self) -> int:
- return self._stable_insets.bottom
-
- def getDisplayCutoutInsets(self) -> Rect:
- return self._display_cutout_insets
-
- def consumeDisplayCutout(self) -> "WindowInsets":
- return WindowInsets()
-
- def consumeSystemWindowInsets(self) -> "WindowInsets":
- return WindowInsets()
-
- def replaceSystemWindowInsets(self, left: int, top: int, right: int, bottom: int) -> "WindowInsets":
- new_ins = WindowInsets(left, top, right, bottom)
- new_ins._stable_insets = self._stable_insets
- return new_ins
-
- def isConsumed(self) -> bool:
- return self._consumed
-
- def hasSystemWindowInsets(self) -> bool:
- return (self._system_window_insets.left > 0 or self._system_window_insets.top > 0 or
- self._system_window_insets.right > 0 or self._system_window_insets.bottom > 0)
-
- def hasInsets(self) -> bool:
- return self.hasSystemWindowInsets()
-
- def isRound(self) -> bool:
- return False
-
- def getDisplayCutout(self) -> Any:
- return None
-
- def consumeStableInsets(self) -> "WindowInsets":
- return WindowInsets()
-
- def toString(self) -> str:
- return f"WindowInsets(system={self._system_window_insets})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowInsetsController
-# ═══════════════════════════════════════════════════════════════
-
-class WindowInsetsController(Stub):
- """WindowInsetsController — 窗口插入控制器"""
-
- BEHAVIOR_SHOW_BARS_BY_TOUCH = 0
- BEHAVIOR_SHOW_BARS_BY_SWIPE = 1
- BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2
-
- APPEARANCE_OPAQUE_STATUS_BARS = 0x00000001
- APPEARANCE_OPAQUE_NAVIGATION_BARS = 0x00000002
- APPEARANCE_LOW_PROFILE_BARS = 0x00000004
- APPEARANCE_LIGHT_STATUS_BARS = 0x00000008
- APPEARANCE_LIGHT_NAVIGATION_BARS = 0x00000010
-
- def __init__(self):
- super().__init__()
- self._appearance = 0
- self._behavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH
-
- def show(self, types: int):
- pass
-
- def hide(self, types: int):
- pass
-
- def setSystemBarsAppearance(self, appearance: int, mask: int):
- self._appearance = (self._appearance & ~mask) | (appearance & mask)
-
- def getSystemBarsAppearance(self) -> int:
- return self._appearance
-
- def setSystemBarsBehavior(self, behavior: int):
- self._behavior = behavior
-
- def getSystemBarsBehavior(self) -> int:
- return self._behavior
-
- def setAnimationsDisabled(self, disabled: bool):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Display
-# ═══════════════════════════════════════════════════════════════
-
-class Display(Stub):
- """Display — 显示信息"""
-
- DEFAULT_DISPLAY = 0
-
- ROTATION_0 = 0
- ROTATION_90 = 1
- ROTATION_180 = 2
- ROTATION_270 = 3
-
- FLAG_PRESENTATION = 0x00000008
- FLAG_PRIVATE = 0x00000004
- FLAG_SECURE = 0x00000002
- FLAG_SUPPORTS_PROTECTED_BUFFERS = 0x00000001
- STATE_DOZE = 3
- STATE_DOZE_SUSPEND = 4
- STATE_OFF = 1
- STATE_ON = 2
- STATE_UNKNOWN = 0
-
- def __init__(self, display_id: int = DEFAULT_DISPLAY):
- super().__init__()
- self._display_id = display_id
- self._width = 1080
- self._height = 1920
- self._rotation = Display.ROTATION_0
- self._refresh_rate = 60.0
- self._density = 2.0
- self._density_dpi = 320
- self._state = Display.STATE_ON
- self._flags = 0
- self._name = "Built-in Screen"
-
- def getDisplayId(self) -> int:
- return self._display_id
-
- def getWidth(self) -> int:
- if _USE_LINUX:
- return LinuxDisplay.get_screen_size()[0]
- return self._width
-
- def getHeight(self) -> int:
- if _USE_LINUX:
- return LinuxDisplay.get_screen_size()[1]
- return self._height
-
- def getRotation(self) -> int:
- return self._rotation
-
- def getRefreshRate(self) -> float:
- return self._refresh_rate
-
- def getName(self) -> str:
- return self._name
-
- def getState(self) -> int:
- return self._state
-
- def getFlags(self) -> int:
- return self._flags
-
- def isHdr(self) -> bool:
- return False
-
- def isWideColorGamut(self) -> bool:
- return False
-
- def getSize(self, out_size: Any = None):
- if out_size is not None:
- out_size.width = self._width
- out_size.height = self._height
- return None
-
- def getRealSize(self, out_size: Any = None):
- if out_size is not None:
- out_size.width = self._width
- out_size.height = self._height
- return None
-
- def getMetrics(self, metrics: Any = None):
- if metrics is not None:
- metrics.widthPixels = self._width
- metrics.heightPixels = self._height
- metrics.density = self._density
- metrics.densityDpi = self._density_dpi
- metrics.scaledDensity = self._density
- metrics.xdpi = 320.0
- metrics.ydpi = 320.0
- return None
-
- def getRealMetrics(self, metrics: Any = None):
- return self.getMetrics(metrics)
-
- def getOrientation(self) -> int:
- return self._rotation
-
- def getDisplayAdjustments(self) -> Any:
- return None
-
- def getPixelFormat(self) -> int:
- return 1 # RGBA_8888
-
- def isValid(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"Display({self._display_id}, {self._width}x{self._height})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Surface
-# ═══════════════════════════════════════════════════════════════
-
-class Surface(Stub):
- """Surface — 表面,用于绘制"""
-
- ROTATION_0 = 0
- ROTATION_90 = 1
- ROTATION_180 = 2
- ROTATION_270 = 3
-
- CHANGE_FRAME_RATE_ALWAYS = 1
- CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0
-
- def __init__(self, surface_control: Any = None):
- super().__init__()
- self._is_valid = True
- self._is_locked = False
- self._width = 1080
- self._height = 1920
- self._hardware_accelerated = False
-
- def isValid(self) -> bool:
- return self._is_valid
-
- def isConsumerRunningBehind(self) -> bool:
- return False
-
- def lockCanvas(self, dirty_rect: Any = None) -> Any:
- if not self._is_valid:
- return None
- self._is_locked = True
- return None # 返回空 Canvas
-
- def lockHardwareCanvas(self) -> Any:
- if not self._is_valid:
- return None
- self._is_locked = True
- self._hardware_accelerated = True
- return None
-
- def unlockCanvasAndPost(self, canvas: Any):
- self._is_locked = False
-
- def getSurfaceControl(self) -> Any:
- return None
-
- def release(self):
- self._is_valid = False
- self._is_locked = False
-
- def destroy(self):
- self.release()
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def setFrameRate(self, frame_rate: float, compatibility: int):
- pass
-
- def toString(self) -> str:
- return f"Surface(valid={self._is_valid}, {self._width}x{self._height})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Choreographer
-# ═══════════════════════════════════════════════════════════════
-
-class Choreographer(Stub):
- """Choreographer — 帧渲染协调器"""
-
- CALLBACK_INPUT = 0
- CALLBACK_ANIMATION = 1
- CALLBACK_INSETS_ANIMATION = 2
- CALLBACK_TRAVERSAL = 3
- CALLBACK_COMMIT = 4
-
- _instance: Optional["Choreographer"] = None
-
- class FrameCallback:
- def doFrame(self, frame_time_nanos: int):
- pass
-
- class FrameTimeline:
- pass
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance() -> "Choreographer":
- if Choreographer._instance is None:
- Choreographer._instance = Choreographer()
- return Choreographer._instance
-
- def postFrameCallback(self, callback: "FrameCallback"):
- callback.doFrame(int(time.time() * 1_000_000_000))
-
- def postFrameCallbackDelayed(self, callback: "FrameCallback", delay_millis: int):
- callback.doFrame(int((time.time() + delay_millis / 1000.0) * 1_000_000_000))
-
- def removeFrameCallback(self, callback: "FrameCallback"):
- pass
-
- def postCallback(self, callback_type: int, action: Callable, token: Any):
- action()
-
- def postCallbackDelayed(self, callback_type: int, action: Callable, token: Any, delay_millis: int):
- import threading
- timer = threading.Timer(delay_millis / 1000.0, action)
- timer.daemon = True
- timer.start()
-
- def removeCallbacks(self, callback_type: int, action: Callable, token: Any):
- pass
-
- def getFrameTimeNanos(self) -> int:
- return int(time.time() * 1_000_000_000)
-
- def getLastFrameTimeNanos(self) -> int:
- return int(time.time() * 1_000_000_000) - 16_666_666
-
-
-# ═══════════════════════════════════════════════════════════════
-# ActionMode
-# ═══════════════════════════════════════════════════════════════
-
-class ActionMode(Stub):
- """ActionMode — 操作模式"""
-
- TYPE_FLOATING = 1
- TYPE_PRIMARY = 0
- TYPE_TOOLBAR = 2
-
- class Callback:
- def onCreateActionMode(self, mode: "ActionMode", menu: Any) -> bool:
- return False
- def onPrepareActionMode(self, mode: "ActionMode", menu: Any) -> bool:
- return False
- def onActionItemClicked(self, mode: "ActionMode", item: Any) -> bool:
- return False
- def onDestroyActionMode(self, mode: "ActionMode"):
- pass
-
- class Callback2(Callback):
- def onGetContentRect(self, mode: "ActionMode", view: View, out_rect: Any):
- pass
-
- def __init__(self):
- super().__init__()
- self._tag: Any = None
- self._title: str = ""
- self._subtitle: str = ""
- self._title_optional_hint: str = ""
- self._subtitle_optional_hint: str = ""
- self._type = ActionMode.TYPE_PRIMARY
- self._menu: Any = None
-
- def setTitle(self, title: str):
- self._title = title
-
- def getTitle(self) -> str:
- return self._title
-
- def setSubtitle(self, subtitle: str):
- self._subtitle = subtitle
-
- def getSubtitle(self) -> str:
- return self._subtitle
-
- def setTitleOptionalHint(self, hint: bool):
- self._title_optional_hint = hint
-
- def getTitleOptionalHint(self) -> bool:
- return bool(self._title_optional_hint)
-
- def setTag(self, tag: Any):
- self._tag = tag
-
- def getTag(self) -> Any:
- return self._tag
-
- def getMenu(self):
- return self._menu
-
- def setType(self, type_: int):
- self._type = type_
-
- def getType(self) -> int:
- return self._type
-
- def invalidate(self):
- pass
-
- def invalidateContentRect(self):
- pass
-
- def finish(self):
- pass
-
- def getCustomView(self) -> Optional[View]:
- return None
-
- def setCustomView(self, view: View):
- pass
-
- def setImageDrawable(self, drawable: Any):
- pass
-
- def getMenuInflater(self):
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# ContextThemeWrapper
-# ═══════════════════════════════════════════════════════════════
-
-class ContextThemeWrapper(Stub):
- """ContextThemeWrapper — 上下文主题包装器"""
-
- def __init__(self, base: Any = None, theme_res_id: int = 0):
- super().__init__()
- self._base = base if base is not None else android_context
- self._theme_res_id = theme_res_id
- self._theme: Any = None
-
- def attachBaseContext(self, new_base: Any):
- self._base = new_base
-
- def getBaseContext(self):
- return self._base
-
- def setTheme(self, resid: int):
- self._theme_res_id = resid
-
- def getThemeResId(self) -> int:
- return self._theme_res_id
-
- def getTheme(self) -> Any:
- return self._theme
-
- def getResources(self):
- if hasattr(self._base, "getResources"):
- return self._base.getResources()
- return None
-
- def getSystemService(self, name: str) -> Any:
- if hasattr(self._base, "getSystemService"):
- return self._base.getSystemService(name)
- return None
-
- def getPackageName(self) -> str:
- if hasattr(self._base, "getPackageName"):
- return self._base.getPackageName()
- return ""
-
- def getApplicationContext(self):
- return self._base
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewOutlineProvider
-# ═══════════════════════════════════════════════════════════════
-
-class ViewOutlineProvider(Stub):
- """ViewOutlineProvider — 视图轮廓提供者"""
-
- BACKGROUND = None
- BOUNDS = None
- PADDED_BOUNDS = None
-
- def getOutline(self, view: View, outline: Any):
- pass
-
- # 预定义实例
- @staticmethod
- def _init_constants():
- if ViewOutlineProvider.BACKGROUND is None:
- class _Background(ViewOutlineProvider):
- def getOutline(self, view, outline):
- if hasattr(outline, "setRect"):
- outline.setRect(0, 0, view.getWidth(), view.getHeight())
- ViewOutlineProvider.BACKGROUND = _Background()
-
- if ViewOutlineProvider.BOUNDS is None:
- class _Bounds(ViewOutlineProvider):
- def getOutline(self, view, outline):
- if hasattr(outline, "setRect"):
- outline.setRect(0, 0, view.getWidth(), view.getHeight())
- ViewOutlineProvider.BOUNDS = _Bounds()
-
- if ViewOutlineProvider.PADDED_BOUNDS is None:
- class _PaddedBounds(ViewOutlineProvider):
- def getOutline(self, view, outline):
- if hasattr(outline, "setRect"):
- outline.setRect(
- view.getPaddingLeft(), view.getPaddingTop(),
- view.getWidth() - view.getPaddingRight(),
- view.getHeight() - view.getPaddingBottom(),
- )
- ViewOutlineProvider.PADDED_BOUNDS = _PaddedBounds()
-
-
-ViewOutlineProvider._init_constants()
-
-# ═══════════════════════════════════════════════════════════════
-# RenderNode
-# ═══════════════════════════════════════════════════════════════
-
-class RenderNode(Stub):
- """RenderNode — 渲染节点"""
-
- STATUS_DISPLAY_LIST_INFLATED = 1
- STATUS_DISPLAY_LIST_READY = 2
- STATUS_DISPLAY_LIST_PREPARE = 3
- STATUS_DISPLAY_LIST_UNUSED = 0
-
- def __init__(self, name: str = ""):
- super().__init__()
- self._name = name
- self._alpha = 1.0
- self._translation_x = 0.0
- self._translation_y = 0.0
- self._translation_z = 0.0
- self._elevation = 0.0
- self._rotation = 0.0
- self._rotation_x = 0.0
- self._rotation_y = 0.0
- self._scale_x = 1.0
- self._scale_y = 1.0
- self._pivot_x = 0.0
- self._pivot_y = 0.0
- self._left = 0
- self._top = 0
- self._right = 0
- self._bottom = 0
- self._clip_to_bounds = False
- self._clip_bounds: Optional[Rect] = None
- self._has_display_list = False
- self._status = RenderNode.STATUS_DISPLAY_LIST_UNUSED
-
- def setPosition(self, left: int, top: int, right: int, bottom: int) -> bool:
- old_left, old_top, old_right, old_bottom = self._left, self._top, self._right, self._bottom
- self._left, self._top, self._right, self._bottom = left, top, right, bottom
- return (old_left != left or old_top != top or old_right != right or old_bottom != bottom)
-
- def getLeft(self) -> int:
- return self._left
- def getTop(self) -> int:
- return self._top
- def getRight(self) -> int:
- return self._right
- def getBottom(self) -> int:
- return self._bottom
-
- def setAlpha(self, alpha: float) -> bool:
- changed = self._alpha != alpha
- self._alpha = alpha
- return changed
-
- def getAlpha(self) -> float:
- return self._alpha
-
- def setTranslationX(self, tx: float) -> bool:
- changed = self._translation_x != tx
- self._translation_x = tx
- return changed
-
- def getTranslationX(self) -> float:
- return self._translation_x
-
- def setTranslationY(self, ty: float) -> bool:
- changed = self._translation_y != ty
- self._translation_y = ty
- return changed
-
- def getTranslationY(self) -> float:
- return self._translation_y
-
- def setElevation(self, elevation: float) -> bool:
- changed = self._elevation != elevation
- self._elevation = elevation
- return changed
-
- def getElevation(self) -> float:
- return self._elevation
-
- def setRotation(self, rotation: float) -> bool:
- changed = self._rotation != rotation
- self._rotation = rotation
- return changed
-
- def getRotation(self) -> float:
- return self._rotation
-
- def setScaleX(self, scale_x: float) -> bool:
- changed = self._scale_x != scale_x
- self._scale_x = scale_x
- return changed
-
- def getScaleX(self) -> float:
- return self._scale_x
-
- def setScaleY(self, scale_y: float) -> bool:
- changed = self._scale_y != scale_y
- self._scale_y = scale_y
- return changed
-
- def getScaleY(self) -> float:
- return self._scale_y
-
- def setPivotX(self, pivot_x: float) -> bool:
- changed = self._pivot_x != pivot_x
- self._pivot_x = pivot_x
- return changed
-
- def getPivotX(self) -> float:
- return self._pivot_x
-
- def setPivotY(self, pivot_y: float) -> bool:
- changed = self._pivot_y != pivot_y
- self._pivot_y = pivot_y
- return changed
-
- def getPivotY(self) -> float:
- return self._pivot_y
-
- def setClipToBounds(self, clip_to_bounds: bool) -> bool:
- changed = self._clip_to_bounds != clip_to_bounds
- self._clip_to_bounds = clip_to_bounds
- return changed
-
- def getClipToBounds(self) -> bool:
- return self._clip_to_bounds
-
- def setClipBounds(self, clip_rect: Optional[Rect]):
- self._clip_bounds = clip_rect
-
- def getClipBounds(self) -> Optional[Rect]:
- return self._clip_bounds
-
- def setHasDisplayList(self, has_display_list: bool):
- self._has_display_list = has_display_list
-
- def hasDisplayList(self) -> bool:
- return self._has_display_list
-
- def getName(self) -> str:
- return self._name
-
- def discardDisplayList(self):
- self._has_display_list = False
- self._status = RenderNode.STATUS_DISPLAY_LIST_UNUSED
-
- def start(self) -> Any:
- return None
-
- def end(self):
- pass
-
- def offsetLeftAndRight(self, offset: int):
- self._left += offset
- self._right += offset
-
- def offsetTopAndBottom(self, offset: int):
- self._top += offset
- self._bottom += offset
-
- def getMatrix(self, out_matrix: Any):
- pass
-
- def getInverseMatrix(self, out_matrix: Any):
- pass
-
- def useLighting(self) -> bool:
- return False
-
- def setUseLighting(self, use_lighting: bool):
- pass
-
- def setLayerType(self, layer_type: int):
- pass
-
- def getLayerType(self) -> int:
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScrollCaptureCallback
-# ═══════════════════════════════════════════════════════════════
-
-class ScrollCaptureCallback(Stub):
- """ScrollCaptureCallback — 滚动捕获回调"""
-
- def onScrollCaptureSearch(self, l: int, t: int, r: int, b: int) -> Optional[Any]:
- return None
-
- def onScrollCaptureStart(self, session: Any) -> Optional[Any]:
- return None
-
- def onScrollCaptureImageRequest(self, session: Any, request: Any) -> int:
- return 0
-
- def onScrollCaptureEnd(self, session: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# KeyboardShortcutGroup
-# ═══════════════════════════════════════════════════════════════
-
-class KeyboardShortcutGroup(Stub):
- """KeyboardShortcutGroup — 键盘快捷键分组"""
-
- def __init__(self, label: str, items: Optional[List[Any]] = None):
- super().__init__()
- self._label = label
- self._items: List[Any] = items if items is not None else []
- self._system_group = False
-
- def getLabel(self) -> str:
- return self._label
-
- def getItems(self) -> List[Any]:
- return list(self._items)
-
- def addItem(self, item: Any):
- self._items.append(item)
-
- def setSystemGroup(self, is_system: bool):
- self._system_group = is_system
-
- def isSystemGroup(self) -> bool:
- return self._system_group
-
-
-# ═══════════════════════════════════════════════════════════════
-# SoundEffectConstants
-# ═══════════════════════════════════════════════════════════════
-
-class SoundEffectConstants:
- """SoundEffectConstants — 音效常量"""
-
- CLICK = 0
- NAVIGATION_LEFT = 1
- NAVIGATION_UP = 2
- NAVIGATION_RIGHT = 3
- NAVIGATION_DOWN = 4
- NAVIGATION_REPEAT_LEFT = 5
- NAVIGATION_REPEAT_UP = 6
- NAVIGATION_REPEAT_RIGHT = 7
- NAVIGATION_REPEAT_DOWN = 8
-
- @staticmethod
- def getDirectionForNavigation(gravity: int) -> int:
- return SoundEffectConstants.NAVIGATION_UP
-
-
-# ═══════════════════════════════════════════════════════════════
-# FocusFinder
-# ═══════════════════════════════════════════════════════════════
-
-class FocusFinder(Stub):
- """FocusFinder — 焦点查找器"""
-
- _instance: Optional["FocusFinder"] = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def getInstance() -> "FocusFinder":
- if FocusFinder._instance is None:
- FocusFinder._instance = FocusFinder()
- return FocusFinder._instance
-
- def findNextFocus(self, root: ViewGroup, focused: View, direction: int) -> Optional[View]:
- return None
-
- def findNearestTouchable(self, root: ViewGroup, x: int, y: int, direction: int,
- deltas: List[int]) -> Optional[View]:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewGroup override for children list
-# ═══════════════════════════════════════════════════════════════
-
-# Ensure ViewGroup._children is separate from View._children
-ViewGroup._children = [] # Will be overridden in __init__
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "View",
- "ViewGroup",
- "ViewParent",
- "ViewManager",
- "WindowManager",
- "MotionEvent",
- "KeyEvent",
- "GestureDetector",
- "ScaleGestureDetector",
- "VelocityTracker",
- "DragEvent",
- "AccessibilityDelegate",
- "ViewTreeObserver",
- "ViewConfiguration",
- "SurfaceView",
- "TextureView",
- "Window",
- "WindowInsets",
- "WindowInsetsController",
- "Display",
- "Surface",
- "Choreographer",
- "ActionMode",
- "ContextThemeWrapper",
- "Gravity",
- "ViewOutlineProvider",
- "RenderNode",
- "ScrollCaptureCallback",
- "KeyboardShortcutGroup",
- "MeasureSpec",
- "ViewPropertyAnimator",
- "SurfaceHolder",
- "SurfaceTexture",
- "FocusFinder",
- "SoundEffectConstants",
- "Rect",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/view_accessibility.py b/android_pyapi/android/view_accessibility.py
deleted file mode 100644
index 7e306bc..0000000
--- a/android_pyapi/android/view_accessibility.py
+++ /dev/null
@@ -1,1488 +0,0 @@
-"""
-Android View Accessibility 组件 — AccessibilityEvent, AccessibilityNodeInfo,
-AccessibilityService, AccessibilityManager 等
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError, android_context
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityEvent
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityEvent(Stub):
- """AccessibilityEvent — 无障碍事件"""
-
- # 事件类型
- TYPE_VIEW_CLICKED = 0x00000001
- TYPE_VIEW_LONG_CLICKED = 0x00000002
- TYPE_VIEW_SELECTED = 0x00000004
- TYPE_VIEW_FOCUSED = 0x00000008
- TYPE_VIEW_TEXT_CHANGED = 0x00000010
- TYPE_WINDOW_STATE_CHANGED = 0x00000020
- TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040
- TYPE_VIEW_HOVER_ENTER = 0x00000080
- TYPE_VIEW_HOVER_EXIT = 0x00000100
- TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200
- TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400
- TYPE_WINDOW_CONTENT_CHANGED = 0x00000800
- TYPE_VIEW_SCROLLED = 0x00001000
- TYPE_VIEW_TEXT_SELECTION_CHANGED = 0x00002000
- TYPE_ANNOUNCEMENT = 0x00004000
- TYPE_VIEW_ACCESSIBILITY_FOCUSED = 0x00008000
- TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 0x00010000
- TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 0x00020000
- TYPE_GESTURE_DETECTION_START = 0x00040000
- TYPE_GESTURE_DETECTION_END = 0x00080000
- TYPE_TOUCH_INTERACTION_START = 0x00100000
- TYPE_TOUCH_INTERACTION_END = 0x00200000
- TYPE_WINDOWS_CHANGED = 0x00400000
- TYPE_VIEW_CONTEXT_CLICKED = 0x00800000
- TYPE_ASSIST_READING_CONTENT = 0x01000000
-
- # 内容变化类型
- CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000001
- CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 0x00000002
- CONTENT_CHANGE_TYPE_SUBTREE = 0x00000004
- CONTENT_CHANGE_TYPE_TEXT = 0x00000010
- CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000000
- CONTENT_CHANGE_TYPE_PANE_TITLE = 0x00000020
- CONTENT_CHANGE_TYPE_DRAG_STARTED = 0x00000040
- CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 0x00000080
- CONTENT_CHANGE_TYPE_DRAG_DROPPED = 0x00000100
- CONTENT_CHANGE_TYPE_CLEAR_FOCUS = 0x00000200
- CONTENT_CHANGE_TYPE_ADDED = 0x00000400
- CONTENT_CHANGE_TYPE_REMOVED = 0x00000800
- CONTENT_CHANGE_TYPE_VISIBILITY_CHANGED = 0x00001000
- CONTENT_CHANGE_TYPE_PANE_APPEARED = 0x00002000
- CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 0x00004000
- CONTENT_CHANGE_TYPE_ERROR = 0x00008000
-
- # 窗口变化类型
- WINDOWS_CHANGE_ADDED = 0x00000001
- WINDOWS_CHANGE_REMOVED = 0x00000002
- WINDOWS_CHANGE_TITLE = 0x00000004
- WINDOWS_CHANGE_BOUNDS = 0x00000008
- WINDOWS_CHANGE_LAYER = 0x00000010
- WINDOWS_CHANGE_ACTIVE = 0x00000020
- WINDOWS_CHANGE_FOCUSED = 0x00000040
- WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED = 0x00000080
- WINDOWS_CHANGE_PARENT = 0x00000100
- WINDOWS_CHANGE_CHILDREN = 0x00000200
- WINDOWS_CHANGE_PIP = 0x00000400
-
- MAX_TEXT_LENGTH = 500
-
- # 预留回收池
- _pool: List["AccessibilityEvent"] = []
- _pool_max = 10
-
- def __init__(self):
- super().__init__()
- self._event_type: int = 0
- self._source: Optional[Any] = None
- self._source_node_id: int = -1
- self._class_name: Optional[str] = None
- self._package_name: Optional[str] = None
- self._content_description: Optional[str] = None
- self._text: List[str] = []
- self._action: int = 0
- self._from_index: int = -1
- self._to_index: int = -1
- self._item_count: int = 0
- self._current_item_index: int = 0
- self._enabled: bool = True
- self._password: bool = False
- self._checked: bool = False
- self._full_package_name: Optional[str] = None
- self._before_text: Optional[str] = None
- self._movement_granularity: int = 0
- self._added_count: int = 0
- self._removed_count: int = 0
- self._content_change_types: int = 0
- self._scroll_delta_x: float = 0.0
- self._scroll_delta_y: float = 0.0
- self._max_scroll_x: float = 0.0
- self._max_scroll_y: float = 0.0
- self._event_time: int = 0
- self._parcelable_data: Dict[str, Any] = {}
- self._record_count: int = 0
-
- @staticmethod
- def obtain(event: Optional["AccessibilityEvent"] = None) -> "AccessibilityEvent":
- if AccessibilityEvent._pool:
- result = AccessibilityEvent._pool.pop()
- else:
- result = AccessibilityEvent()
- if event is not None:
- result._event_type = event._event_type
- result._source = event._source
- result._class_name = event._class_name
- result._package_name = event._package_name
- result._content_description = event._content_description
- result._text = list(event._text)
- result._action = event._action
- return result
-
- def recycle(self):
- self._event_type = 0
- self._source = None
- self._source_node_id = -1
- self._class_name = None
- self._package_name = None
- self._content_description = None
- self._text.clear()
- self._action = 0
- self._from_index = -1
- self._to_index = -1
- self._item_count = 0
- if len(AccessibilityEvent._pool) < AccessibilityEvent._pool_max:
- AccessibilityEvent._pool.append(self)
-
- def getEventType(self) -> int:
- return self._event_type
-
- def setEventType(self, event_type: int):
- self._event_type = event_type
-
- def getSource(self) -> Optional[Any]:
- return self._source
-
- def setSource(self, source: Optional[Any]):
- self._source = source
-
- def getClassName(self) -> Optional[str]:
- return self._class_name
-
- def setClassName(self, class_name: Optional[str]):
- self._class_name = class_name
-
- def getPackageName(self) -> Optional[str]:
- return self._package_name
-
- def setPackageName(self, package_name: Optional[str]):
- self._package_name = package_name
-
- def getContentDescription(self) -> Optional[str]:
- return self._content_description
-
- def setContentDescription(self, content_description: Optional[str]):
- self._content_description = content_description
-
- def getText(self) -> List[str]:
- return list(self._text)
-
- def getAction(self) -> int:
- return self._action
-
- def setAction(self, action: int):
- self._action = action
-
- def setFromIndex(self, from_index: int):
- self._from_index = from_index
-
- def getFromIndex(self) -> int:
- return self._from_index
-
- def setToIndex(self, to_index: int):
- self._to_index = to_index
-
- def getToIndex(self) -> int:
- return self._to_index
-
- def setItemCount(self, item_count: int):
- self._item_count = item_count
-
- def getItemCount(self) -> int:
- return self._item_count
-
- def setCurrentItemIndex(self, index: int):
- self._current_item_index = index
-
- def getCurrentItemIndex(self) -> int:
- return self._current_item_index
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- def isPassword(self) -> bool:
- return self._password
-
- def setPassword(self, password: bool):
- self._password = password
-
- def isChecked(self) -> bool:
- return self._checked
-
- def setChecked(self, checked: bool):
- self._checked = checked
-
- def getBeforeText(self) -> Optional[str]:
- return self._before_text
-
- def setBeforeText(self, before_text: Optional[str]):
- self._before_text = before_text
-
- def getMovementGranularity(self) -> int:
- return self._movement_granularity
-
- def setMovementGranularity(self, granularity: int):
- self._movement_granularity = granularity
-
- def getAddedCount(self) -> int:
- return self._added_count
-
- def setAddedCount(self, added_count: int):
- self._added_count = added_count
-
- def getRemovedCount(self) -> int:
- return self._removed_count
-
- def setRemovedCount(self, removed_count: int):
- self._removed_count = removed_count
-
- def getContentChangeTypes(self) -> int:
- return self._content_change_types
-
- def setContentChangeTypes(self, change_types: int):
- self._content_change_types = change_types
-
- def getScrollDeltaX(self) -> float:
- return self._scroll_delta_x
-
- def setScrollDeltaX(self, delta_x: float):
- self._scroll_delta_x = delta_x
-
- def getScrollDeltaY(self) -> float:
- return self._scroll_delta_y
-
- def setScrollDeltaY(self, delta_y: float):
- self._scroll_delta_y = delta_y
-
- def getMaxScrollX(self) -> float:
- return self._max_scroll_x
-
- def setMaxScrollX(self, max_x: float):
- self._max_scroll_x = max_x
-
- def getMaxScrollY(self) -> float:
- return self._max_scroll_y
-
- def setMaxScrollY(self, max_y: float):
- self._max_scroll_y = max_y
-
- def getEventTime(self) -> int:
- return self._event_time
-
- def setEventTime(self, event_time: int):
- self._event_time = event_time
-
- def getParcelableData(self) -> Any:
- return self._parcelable_data
-
- def setParcelableData(self, data: Any):
- if isinstance(data, dict):
- self._parcelable_data = data
- else:
- self._parcelable_data = {"data": data}
-
- def getRecordCount(self) -> int:
- return self._record_count
-
- def appendRecord(self, record: "AccessibilityRecord"):
- self._record_count += 1
-
- def getRecord(self, index: int) -> Optional["AccessibilityRecord"]:
- return None
-
- def toString(self) -> str:
- return (f"AccessibilityEvent(type={hex(self._event_type)}, "
- f"className={self._class_name}, "
- f"packageName={self._package_name}, "
- f"text={self._text})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityRecord
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityRecord(Stub):
- """AccessibilityRecord — 无障碍记录"""
-
- def __init__(self):
- super().__init__()
- self._source: Optional[Any] = None
- self._source_node_id: int = -1
- self._class_name: Optional[str] = None
- self._package_name: Optional[str] = None
- self._content_description: Optional[str] = None
- self._text: List[str] = []
- self._from_index: int = -1
- self._to_index: int = -1
- self._item_count: int = 0
- self._current_item_index: int = 0
- self._scrollable: bool = False
- self._scroll_x: int = 0
- self._scroll_y: int = 0
- self._max_scroll_x: int = 0
- self._max_scroll_y: int = 0
- self._enabled: bool = True
- self._password: bool = False
- self._checked: bool = False
- self._full_package_name: Optional[str] = None
- self._before_text: Optional[str] = None
- self._removed_count: int = 0
- self._added_count: int = 0
-
- def setSource(self, source: Optional[Any]):
- self._source = source
-
- def getSource(self) -> Optional[Any]:
- return self._source
-
- def setClassName(self, class_name: Optional[str]):
- self._class_name = class_name
-
- def getClassName(self) -> Optional[str]:
- return self._class_name
-
- def setContentDescription(self, content_description: Optional[str]):
- self._content_description = content_description
-
- def getContentDescription(self) -> Optional[str]:
- return self._content_description
-
- def setPackageName(self, package_name: Optional[str]):
- self._package_name = package_name
-
- def getPackageName(self) -> Optional[str]:
- return self._package_name
-
- def getText(self) -> List[str]:
- return list(self._text)
-
- def setFromIndex(self, from_index: int):
- self._from_index = from_index
-
- def getFromIndex(self) -> int:
- return self._from_index
-
- def setToIndex(self, to_index: int):
- self._to_index = to_index
-
- def getToIndex(self) -> int:
- return self._to_index
-
- def setItemCount(self, item_count: int):
- self._item_count = item_count
-
- def getItemCount(self) -> int:
- return self._item_count
-
- def setScrollable(self, scrollable: bool):
- self._scrollable = scrollable
-
- def getScrollable(self) -> bool:
- return self._scrollable
-
- def setScrollX(self, scroll_x: int):
- self._scroll_x = scroll_x
-
- def getScrollX(self) -> int:
- return self._scroll_x
-
- def setScrollY(self, scroll_y: int):
- self._scroll_y = scroll_y
-
- def getScrollY(self) -> int:
- return self._scroll_y
-
- def setMaxScrollX(self, max_scroll_x: int):
- self._max_scroll_x = max_scroll_x
-
- def getMaxScrollX(self) -> int:
- return self._max_scroll_x
-
- def setMaxScrollY(self, max_scroll_y: int):
- self._max_scroll_y = max_scroll_y
-
- def getMaxScrollY(self) -> int:
- return self._max_scroll_y
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- def isPassword(self) -> bool:
- return self._password
-
- def setPassword(self, password: bool):
- self._password = password
-
- def isChecked(self) -> bool:
- return self._checked
-
- def setChecked(self, checked: bool):
- self._checked = checked
-
- def getBeforeText(self) -> Optional[str]:
- return self._before_text
-
- def setBeforeText(self, before_text: Optional[str]):
- self._before_text = before_text
-
- def getAddedCount(self) -> int:
- return self._added_count
-
- def setAddedCount(self, added_count: int):
- self._added_count = added_count
-
- def getRemovedCount(self) -> int:
- return self._removed_count
-
- def setRemovedCount(self, removed_count: int):
- self._removed_count = removed_count
-
- def toString(self) -> str:
- return (f"AccessibilityRecord(className={self._class_name}, "
- f"packageName={self._package_name})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityNodeInfo
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityNodeInfo(Stub):
- """AccessibilityNodeInfo — 无障碍节点信息"""
-
- FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000002
- FLAG_REPORT_VIEW_IDS = 0x00000010
- FLAG_PREFETCH_PREDECESSORS = 0x00000001
- FLAG_PREFETCH_SIBLINGS = 0x00000002
- FLAG_PREFETCH_DESCENDANTS = 0x00000004
-
- ACTION_CLICK = 0x00000010
- ACTION_LONG_CLICK = 0x00000020
- ACTION_FOCUS = 0x00000040
- ACTION_CLEAR_FOCUS = 0x00000080
- ACTION_SELECT = 0x00000100
- ACTION_CLEAR_SELECTION = 0x00000200
- ACTION_ACCESSIBILITY_FOCUS = 0x00000400
- ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000800
- ACTION_SCROLL_FORWARD = 0x00001000
- ACTION_SCROLL_BACKWARD = 0x00002000
- ACTION_SCROLL_TO_POSITION = 0x00004000
- ACTION_SET_SELECTION = 0x00008000
- ACTION_COPY = 0x00010000
- ACTION_PASTE = 0x00020000
- ACTION_CUT = 0x00030000
- ACTION_SET_TEXT = 0x00040000
- ACTION_EXPAND = 0x00080000
- ACTION_COLLAPSE = 0x00100000
- ACTION_DISMISS = 0x00200000
- ACTION_MOVE_WINDOW = 0x00400000
- ACTION_SHOW_ON_SCREEN = 0x00800000
- ACTION_CONTEXT_CLICK = 0x01000000
- ACTION_SCROLL_UP = 0x02000000
- ACTION_SCROLL_DOWN = 0x04000000
- ACTION_SCROLL_LEFT = 0x08000000
- ACTION_SCROLL_RIGHT = 0x10000000
- ACTION_PAGE_UP = 0x20000000
- ACTION_PAGE_DOWN = 0x40000000
- ACTION_PAGE_LEFT = 0x80000000
- ACTION_PAGE_RIGHT = 0x100000000
-
- # 移动粒度
- MOVEMENT_GRANULARITY_CHARACTER = 1
- MOVEMENT_GRANULARITY_WORD = 2
- MOVEMENT_GRANULARITY_LINE = 4
- MOVEMENT_GRANULARITY_PARAGRAPH = 8
- MOVEMENT_GRANULARITY_PAGE = 16
-
- def __init__(self):
- super().__init__()
- self._children: List["AccessibilityNodeInfo"] = []
- self._actions: int = 0
- self._clickable: bool = False
- self._focusable: bool = False
- self._long_clickable: bool = False
- self._scrollable: bool = False
- self._content_description: Optional[str] = None
- self._text: Optional[str] = None
- self._class_name: Optional[str] = None
- self._package_name: Optional[str] = None
- self._parent: Optional["AccessibilityNodeInfo"] = None
- self._view_id: Optional[str] = None
- self._enabled: bool = True
- self._password: bool = False
- self._checked: bool = False
- self._checkable: bool = False
- self._selected: bool = False
- self._focused: bool = False
- self._visible_to_user: bool = True
- self._accessibility_focused: bool = False
- self._can_open_popup: bool = False
- self._dismissable: bool = False
- self._editable: bool = False
- self._multi_line: bool = False
- self._important_for_accessibility: bool = True
- self._pane_title: Optional[str] = None
- self._hint_text: Optional[str] = None
- self._tooltip_text: Optional[str] = None
- self._error: Optional[str] = None
- self._min_text_length: int = -1
- self._max_text_length: int = -1
- self._child_count: int = 0
- self._bounds_in_parent: Optional[Tuple[int, int, int, int]] = None
- self._bounds_in_screen: Optional[Tuple[int, int, int, int]] = None
-
- def findAccessibilityNodeInfosByText(self, text: str) -> List["AccessibilityNodeInfo"]:
- result: List["AccessibilityNodeInfo"] = []
- if self._text and text and text.lower() in self._text.lower():
- result.append(self)
- for child in self._children:
- result.extend(child.findAccessibilityNodeInfosByText(text))
- return result
-
- def findAccessibilityNodeInfosByViewId(self, view_id: str) -> List["AccessibilityNodeInfo"]:
- result: List["AccessibilityNodeInfo"] = []
- if self._view_id == view_id:
- result.append(self)
- for child in self._children:
- result.extend(child.findAccessibilityNodeInfosByViewId(view_id))
- return result
-
- def performAction(self, action: int) -> bool:
- if action & self._actions:
- sys.stderr.write(f"[AccessibilityNodeInfo] performAction: {hex(action)}\n")
- return True
- return False
-
- def setClickable(self, clickable: bool):
- self._clickable = clickable
-
- def isClickable(self) -> bool:
- return self._clickable
-
- def setFocusable(self, focusable: bool):
- self._focusable = focusable
-
- def isFocusable(self) -> bool:
- return self._focusable
-
- def setLongClickable(self, long_clickable: bool):
- self._long_clickable = long_clickable
-
- def isLongClickable(self) -> bool:
- return self._long_clickable
-
- def setScrollable(self, scrollable: bool):
- self._scrollable = scrollable
-
- def isScrollable(self) -> bool:
- return self._scrollable
-
- def setContentDescription(self, content_description: Optional[str]):
- self._content_description = content_description
-
- def getContentDescription(self) -> Optional[str]:
- return self._content_description
-
- def setText(self, text: Optional[str]):
- self._text = text
-
- def getText(self) -> Optional[str]:
- return self._text
-
- def setClassName(self, class_name: Optional[str]):
- self._class_name = class_name
-
- def getClassName(self) -> Optional[str]:
- return self._class_name
-
- def setPackageName(self, package_name: Optional[str]):
- self._package_name = package_name
-
- def getPackageName(self) -> Optional[str]:
- return self._package_name
-
- def getChild(self, index: int) -> Optional["AccessibilityNodeInfo"]:
- if 0 <= index < len(self._children):
- return self._children[index]
- return None
-
- def setParent(self, parent: Optional["AccessibilityNodeInfo"]):
- self._parent = parent
-
- def getParent(self) -> Optional["AccessibilityNodeInfo"]:
- return self._parent
-
- def getChildCount(self) -> int:
- return len(self._children)
-
- def addChild(self, child: "AccessibilityNodeInfo"):
- self._children.append(child)
- child._parent = self
-
- def addAction(self, action: int):
- self._actions |= action
-
- def setActions(self, actions: int):
- self._actions = actions
-
- def getActions(self) -> int:
- return self._actions
-
- def setViewIdResourceName(self, view_id: str):
- self._view_id = view_id
-
- def getViewIdResourceName(self) -> Optional[str]:
- return self._view_id
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool):
- self._enabled = enabled
-
- def isPassword(self) -> bool:
- return self._password
-
- def setPassword(self, password: bool):
- self._password = password
-
- def isChecked(self) -> bool:
- return self._checked
-
- def setChecked(self, checked: bool):
- self._checked = checked
-
- def isCheckable(self) -> bool:
- return self._checkable
-
- def setCheckable(self, checkable: bool):
- self._checkable = checkable
-
- def isSelected(self) -> bool:
- return self._selected
-
- def setSelected(self, selected: bool):
- self._selected = selected
-
- def isFocused(self) -> bool:
- return self._focused
-
- def setFocused(self, focused: bool):
- self._focused = focused
-
- def isVisibleToUser(self) -> bool:
- return self._visible_to_user
-
- def setVisibleToUser(self, visible: bool):
- self._visible_to_user = visible
-
- def isAccessibilityFocused(self) -> bool:
- return self._accessibility_focused
-
- def setAccessibilityFocused(self, focused: bool):
- self._accessibility_focused = focused
-
- def isEditable(self) -> bool:
- return self._editable
-
- def setEditable(self, editable: bool):
- self._editable = editable
-
- def isMultiLine(self) -> bool:
- return self._multi_line
-
- def setMultiLine(self, multi_line: bool):
- self._multi_line = multi_line
-
- def isImportantForAccessibility(self) -> bool:
- return self._important_for_accessibility
-
- def setImportantForAccessibility(self, important: bool):
- self._important_for_accessibility = important
-
- def setPaneTitle(self, pane_title: Optional[str]):
- self._pane_title = pane_title
-
- def getPaneTitle(self) -> Optional[str]:
- return self._pane_title
-
- def setHintText(self, hint_text: Optional[str]):
- self._hint_text = hint_text
-
- def getHintText(self) -> Optional[str]:
- return self._hint_text
-
- def setTooltipText(self, tooltip_text: Optional[str]):
- self._tooltip_text = tooltip_text
-
- def getTooltipText(self) -> Optional[str]:
- return self._tooltip_text
-
- def setError(self, error: Optional[str]):
- self._error = error
-
- def getError(self) -> Optional[str]:
- return self._error
-
- def setBoundsInParent(self, left: int, top: int, right: int, bottom: int):
- self._bounds_in_parent = (left, top, right, bottom)
-
- def getBoundsInParent(self) -> Optional[Tuple[int, int, int, int]]:
- return self._bounds_in_parent
-
- def setBoundsInScreen(self, left: int, top: int, right: int, bottom: int):
- self._bounds_in_screen = (left, top, right, bottom)
-
- def getBoundsInScreen(self) -> Optional[Tuple[int, int, int, int]]:
- return self._bounds_in_screen
-
- def getWindowId(self) -> int:
- return -1
-
- def recycle(self):
- self._children.clear()
- self._parent = None
- self._actions = 0
-
- def toString(self) -> str:
- return (f"AccessibilityNodeInfo(className={self._class_name}, "
- f"text={self._text}, "
- f"contentDescription={self._content_description})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityNodeProvider
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityNodeProvider(Stub):
- """AccessibilityNodeProvider — 无障碍节点提供者"""
-
- HOST_VIEW_ID = -1
-
- def __init__(self):
- super().__init__()
-
- def createAccessibilityNodeInfo(self, virtual_view_id: int) -> AccessibilityNodeInfo:
- raise AndroidOnlyError("AccessibilityNodeProvider.createAccessibilityNodeInfo")
-
- def addExtraDataToAccessibilityNodeInfo(self, virtual_view_id: int,
- info: AccessibilityNodeInfo,
- extra_data_key: str,
- arguments: Optional[Any]):
- pass
-
- def performAction(self, virtual_view_id: int, action: int,
- arguments: Optional[Any]) -> bool:
- return False
-
- def findFocus(self, focus: int) -> Optional[AccessibilityNodeInfo]:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityServiceInfo
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityServiceInfo(Stub):
- """AccessibilityServiceInfo — 无障碍服务信息"""
-
- FEEDBACK_GENERIC = 16
- FEEDBACK_SPOKEN = 1
- FEEDBACK_HAPTIC = 2
- FEEDBACK_AUDIBLE = 4
- FEEDBACK_VISUAL = 8
- FEEDBACK_BRAILLE = 32
- FEEDBACK_ALL_MASK = -1
-
- FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x00000001
- FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000002
- FLAG_REPORT_VIEW_IDS = 0x00000010
- FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020
- FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040
- FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000080
- FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x00000100
- FLAG_REQUEST_SHORTCUT_WARNING_DIALOG = 0x00000200
-
- CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1
- CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2
- CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4
- CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8
- CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16
- CAPABILITY_CAN_PERFORM_GESTURES = 32
-
- def __init__(self):
- super().__init__()
- self.eventTypes: int = 0
- self.feedbackType: int = 0
- self.flags: int = 0
- self.notificationTimeout: int = 0
- self.filterTouchExploration: bool = False
- self.packageNames: Optional[List[str]] = None
- self.descriptionResId: int = 0
- self.description: Optional[str] = None
- self.settingsActivityName: Optional[str] = None
- self.capabilities: int = 0
- self.interactiveUiTimeout: int = 0
- self.nonInteractiveUiTimeout: int = 0
-
- def getCapabilityInfo(self, capability: int) -> Optional[str]:
- cap_map = {
- self.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: "CAN_RETRIEVE_WINDOW_CONTENT",
- self.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: "CAN_REQUEST_TOUCH_EXPLORATION",
- self.CAPABILITY_CAN_CONTROL_MAGNIFICATION: "CAN_CONTROL_MAGNIFICATION",
- self.CAPABILITY_CAN_PERFORM_GESTURES: "CAN_PERFORM_GESTURES",
- }
- return cap_map.get(capability)
-
- def toString(self) -> str:
- return (f"AccessibilityServiceInfo(eventTypes={hex(self.eventTypes)}, "
- f"feedbackType={self.feedbackType}, "
- f"flags={hex(self.flags)})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityWindowInfo
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityWindowInfo(Stub):
- """AccessibilityWindowInfo — 无障碍窗口信息"""
-
- TYPE_APPLICATION = 1
- TYPE_INPUT_METHOD = 2
- TYPE_SYSTEM = 3
- TYPE_ACCESSIBILITY_OVERLAY = 4
- TYPE_SPLIT_SCREEN_DIVIDER = 5
-
- UNDEFINED = -1
- ACTIVE = 0x00000001
- FOCUSED = 0x00000002
- ACCESSIBILITY_FOCUSED = 0x00000004
-
- def __init__(self):
- super().__init__()
- self._type: int = TYPE_SYSTEM
- self._bounds_in_screen: Tuple[int, int, int, int] = (0, 0, 0, 0)
- self._root: Optional[AccessibilityNodeInfo] = None
- self._title: Optional[str] = None
- self._anchor: Optional[Any] = None
- self._parent: Optional["AccessibilityWindowInfo"] = None
- self._children: List["AccessibilityWindowInfo"] = []
- self._id: int = -1
- self._layer: int = 0
- self._active: bool = False
- self._focused: bool = False
- self._accessibility_focused: bool = False
- self._picture_in_picture: bool = False
-
- @staticmethod
- def obtain() -> "AccessibilityWindowInfo":
- return AccessibilityWindowInfo()
-
- def recycle(self):
- self._root = None
- self._children.clear()
- self._parent = None
-
- def getType(self) -> int:
- return self._type
-
- def setType(self, window_type: int):
- self._type = window_type
-
- def getBoundsInScreen(self) -> Tuple[int, int, int, int]:
- return self._bounds_in_screen
-
- def setBoundsInScreen(self, left: int, top: int, right: int, bottom: int):
- self._bounds_in_screen = (left, top, right, bottom)
-
- def getRoot(self) -> Optional[AccessibilityNodeInfo]:
- return self._root
-
- def setRoot(self, root: Optional[AccessibilityNodeInfo]):
- self._root = root
-
- def getTitle(self) -> Optional[str]:
- return self._title
-
- def setTitle(self, title: Optional[str]):
- self._title = title
-
- def getAnchor(self) -> Optional[Any]:
- return self._anchor
-
- def setAnchor(self, anchor: Optional[Any]):
- self._anchor = anchor
-
- def getId(self) -> int:
- return self._id
-
- def setId(self, window_id: int):
- self._id = window_id
-
- def getLayer(self) -> int:
- return self._layer
-
- def setLayer(self, layer: int):
- self._layer = layer
-
- def getParent(self) -> Optional["AccessibilityWindowInfo"]:
- return self._parent
-
- def setParent(self, parent: Optional["AccessibilityWindowInfo"]):
- self._parent = parent
-
- def getChild(self, index: int) -> Optional["AccessibilityWindowInfo"]:
- if 0 <= index < len(self._children):
- return self._children[index]
- return None
-
- def getChildCount(self) -> int:
- return len(self._children)
-
- def addChild(self, child: "AccessibilityWindowInfo"):
- self._children.append(child)
-
- def isActive(self) -> bool:
- return self._active
-
- def setActive(self, active: bool):
- self._active = active
-
- def isFocused(self) -> bool:
- return self._focused
-
- def setFocused(self, focused: bool):
- self._focused = focused
-
- def isAccessibilityFocused(self) -> bool:
- return self._accessibility_focused
-
- def setAccessibilityFocused(self, focused: bool):
- self._accessibility_focused = focused
-
- def isInPictureInPictureMode(self) -> bool:
- return self._picture_in_picture
-
- def setPictureInPictureMode(self, pip: bool):
- self._picture_in_picture = pip
-
- def toString(self) -> str:
- type_names = {1: "APPLICATION", 2: "INPUT_METHOD", 3: "SYSTEM",
- 4: "ACCESSIBILITY_OVERLAY", 5: "SPLIT_SCREEN_DIVIDER"}
- type_name = type_names.get(self._type, "UNKNOWN")
- return f"AccessibilityWindowInfo(id={self._id}, type={type_name}, title={self._title})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityService
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityService(Stub):
- """AccessibilityService — 无障碍服务基类"""
-
- GLOBAL_ACTION_BACK = 1
- GLOBAL_ACTION_HOME = 2
- GLOBAL_ACTION_RECENTS = 3
- GLOBAL_ACTION_NOTIFICATIONS = 4
- GLOBAL_ACTION_QUICK_SETTINGS = 5
- GLOBAL_ACTION_POWER_DIALOG = 6
- GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7
- GLOBAL_ACTION_LOCK_SCREEN = 8
- GLOBAL_ACTION_TAKE_SCREENSHOT = 9
- GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10
- GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 11
- GLOBAL_ACTION_ACCESSIBILITY_BUTTON = 12
- GLOBAL_ACTION_ACCESSIBILITY_BUTTON_CHOOSER = 13
- GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT_CHOOSER = 14
- GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS = 15
-
- def __init__(self):
- super().__init__()
- self._service_info: Optional[AccessibilityServiceInfo] = None
- self._root_node: Optional[AccessibilityNodeInfo] = None
- self._windows: List[AccessibilityWindowInfo] = []
-
- def onAccessibilityEvent(self, event: AccessibilityEvent):
- raise AndroidOnlyError("AccessibilityService.onAccessibilityEvent: not implemented")
-
- def onInterrupt(self):
- raise AndroidOnlyError("AccessibilityService.onInterrupt: not implemented")
-
- def onServiceConnected(self):
- pass
-
- def performGlobalAction(self, action: int) -> bool:
- action_names = {
- self.GLOBAL_ACTION_BACK: "BACK",
- self.GLOBAL_ACTION_HOME: "HOME",
- self.GLOBAL_ACTION_RECENTS: "RECENTS",
- self.GLOBAL_ACTION_NOTIFICATIONS: "NOTIFICATIONS",
- self.GLOBAL_ACTION_QUICK_SETTINGS: "QUICK_SETTINGS",
- }
- sys.stderr.write(f"[AccessibilityService] performGlobalAction: "
- f"{action_names.get(action, hex(action))}\n")
- return True
-
- def getRootInActiveWindow(self) -> Optional[AccessibilityNodeInfo]:
- return self._root_node
-
- def findFocus(self, focus_type: int) -> Optional[AccessibilityNodeInfo]:
- return self._root_node
-
- def getServiceInfo(self) -> Optional[AccessibilityServiceInfo]:
- return self._service_info
-
- def setServiceInfo(self, info: AccessibilityServiceInfo):
- self._service_info = info
-
- def getWindows(self) -> List[AccessibilityWindowInfo]:
- return list(self._windows)
-
- def getWindowsOnScreen(self) -> List[AccessibilityWindowInfo]:
- return [w for w in self._windows if w.isActive()]
-
- def disableSelf(self):
- sys.stderr.write("[AccessibilityService] disableSelf\n")
-
- def onKeyEvent(self, event: Any) -> bool:
- return False
-
- def onGesture(self, gesture_id: int) -> bool:
- return False
-
- def onMotionEvent(self, event: Any) -> bool:
- return False
-
- def onTouchExplorationStateChanged(self, enabled: bool):
- pass
-
- def onMagnificationChanged(self, region: Any, scale: float):
- pass
-
- def onSoftKeyboardShowModeChanged(self, show_mode: int):
- pass
-
- def dispatchKeyEventToInputMethod(self, event: Any) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityManager
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityManager(Stub):
- """AccessibilityManager — 无障碍管理器"""
-
- def __init__(self):
- super().__init__()
- self._enabled: bool = False
- self._touch_exploration_enabled: bool = False
- self._state_listeners: List[Callable] = []
- self._touch_exploration_listeners: List[Callable] = []
- self._accessibility_service_list: List[AccessibilityServiceInfo] = []
- self._request_preparers: List[Any] = []
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool):
- old = self._enabled
- self._enabled = enabled
- if old != enabled:
- for listener in list(self._state_listeners):
- try:
- listener.onAccessibilityStateChanged(enabled)
- except Exception:
- pass
-
- def isTouchExplorationEnabled(self) -> bool:
- return self._touch_exploration_enabled
-
- def addAccessibilityStateChangeListener(self, listener: Callable) -> bool:
- if listener not in self._state_listeners:
- self._state_listeners.append(listener)
- return True
- return False
-
- def removeAccessibilityStateChangeListener(self, listener: Callable) -> bool:
- if listener in self._state_listeners:
- self._state_listeners.remove(listener)
- return True
- return False
-
- def addTouchExplorationStateChangeListener(self, listener: Callable) -> bool:
- if listener not in self._touch_exploration_listeners:
- self._touch_exploration_listeners.append(listener)
- return True
- return False
-
- def removeTouchExplorationStateChangeListener(self, listener: Callable) -> bool:
- if listener in self._touch_exploration_listeners:
- self._touch_exploration_listeners.remove(listener)
- return True
- return False
-
- def getAccessibilityServiceList(self) -> List[AccessibilityServiceInfo]:
- return list(self._accessibility_service_list)
-
- def addAccessibilityRequestPreparer(self, preparer: Any):
- if preparer not in self._request_preparers:
- self._request_preparers.append(preparer)
-
- def removeAccessibilityRequestPreparer(self, preparer: Any):
- if preparer in self._request_preparers:
- self._request_preparers.remove(preparer)
-
- def sendAccessibilityEvent(self, event: AccessibilityEvent):
- sys.stderr.write(f"[AccessibilityManager] sendEvent: type={hex(event.getEventType())}\n")
-
- def interrupt(self):
- sys.stderr.write("[AccessibilityManager] interrupt\n")
-
- def getEnabledAccessibilityServiceList(self, feedback_type_flags: int) -> List[AccessibilityServiceInfo]:
- return [s for s in self._accessibility_service_list
- if s.feedbackType & feedback_type_flags]
-
- def getInstalledAccessibilityServiceList(self) -> List[AccessibilityServiceInfo]:
- return list(self._accessibility_service_list)
-
- def addAccessibilityStateChangeListener(self, listener: Callable) -> bool:
- if listener not in self._state_listeners:
- self._state_listeners.append(listener)
- return True
- return False
-
- def removeAccessibilityStateChangeListener(self, listener: Callable) -> bool:
- if listener in self._state_listeners:
- self._state_listeners.remove(listener)
- return True
- return False
-
- def toString(self) -> str:
- return f"AccessibilityManager(enabled={self._enabled})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CaptioningManager
-# ═══════════════════════════════════════════════════════════════
-
-class CaptioningManager(Stub):
- """CaptioningManager — 字幕管理器"""
-
- class CaptionStyle(Stub):
- """CaptionStyle — 字幕样式"""
-
- EDGE_TYPE_NONE = 0
- EDGE_TYPE_OUTLINE = 1
- EDGE_TYPE_DROP_SHADOW = 2
- EDGE_TYPE_RAISED = 3
- EDGE_TYPE_DEPRESSED = 4
-
- def __init__(self):
- super().__init__()
- self._foreground_color: int = 0xFFFFFFFF
- self._background_color: int = 0xFF000000
- self._edge_color: int = 0xFF000000
- self._edge_type: int = EDGE_TYPE_NONE
- self._typeface: Optional[Any] = None
- self._font_scale: float = 1.0
- self._window_color: int = 0xFF000000
-
- @staticmethod
- def getCustomStyle(css: Any) -> "CaptioningManager.CaptionStyle":
- return CaptioningManager.CaptionStyle()
-
- def getForegroundColor(self) -> int:
- return self._foreground_color
-
- def getBackgroundColor(self) -> int:
- return self._background_color
-
- def getEdgeColor(self) -> int:
- return self._edge_color
-
- def getEdgeType(self) -> int:
- return self._edge_type
-
- def getTypeface(self) -> Optional[Any]:
- return self._typeface
-
- def hasForegroundColor(self) -> bool:
- return True
-
- def hasBackgroundColor(self) -> bool:
- return True
-
- def hasEdgeColor(self) -> bool:
- return True
-
- def hasEdgeType(self) -> bool:
- return True
-
- def hasWindowColor(self) -> bool:
- return True
-
- def getWindowColor(self) -> int:
- return self._window_color
-
- def __init__(self):
- super().__init__()
- self._enabled: bool = False
- self._locale: Optional[str] = None
- self._font_scale: float = 1.0
- self._user_style: Optional["CaptioningManager.CaptionStyle"] = None
-
- def isCaptioningEnabled(self) -> bool:
- return self._enabled
-
- def getLocale(self) -> Optional[str]:
- return self._locale
-
- def getFontScale(self) -> float:
- return self._font_scale
-
- def getUserStyle(self) -> "CaptioningManager.CaptionStyle":
- if self._user_style is None:
- self._user_style = CaptioningManager.CaptionStyle()
- return self._user_style
-
- def addCaptioningChangeListener(self, listener: Any):
- pass
-
- def removeCaptioningChangeListener(self, listener: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityServiceGestureResult
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityServiceGestureResult(Stub):
- """AccessibilityServiceGestureResult — 手势结果"""
-
- def __init__(self, completed: bool):
- super().__init__()
- self._completed: bool = completed
-
- def isCompleted(self) -> bool:
- return self._completed
-
-
-# ═══════════════════════════════════════════════════════════════
-# TouchExplorationStateChangeListener
-# ═══════════════════════════════════════════════════════════════
-
-class TouchExplorationStateChangeListener(Stub):
- """TouchExplorationStateChangeListener — 触摸探索状态变更监听器"""
-
- def onTouchExplorationStateChanged(self, enabled: bool):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityButtonController
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityButtonController(Stub):
- """AccessibilityButtonController — 无障碍按钮控制器"""
-
- class AccessibilityButtonCallback(Stub):
- """AccessibilityButtonCallback — 无障碍按钮回调"""
-
- def onAvailabilityChanged(self, available: bool):
- pass
-
- def onClicked(self, controller: "AccessibilityButtonController"):
- pass
-
- def __init__(self):
- super().__init__()
- self._callback: Optional["AccessibilityButtonController.AccessibilityButtonCallback"] = None
-
- def isAccessibilityButtonAvailable(self) -> bool:
- return False
-
- def registerAccessibilityButtonCallback(self, callback: "AccessibilityButtonController.AccessibilityButtonCallback"):
- self._callback = callback
-
- def unregisterAccessibilityButtonCallback(self, callback: "AccessibilityButtonController.AccessibilityButtonCallback"):
- if self._callback == callback:
- self._callback = None
-
- def performAccessibilityButtonAction(self) -> bool:
- if self._callback:
- self._callback.onClicked(self)
- return True
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityButtonControllerCallback
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityButtonControllerCallback(Stub):
- """AccessibilityButtonControllerCallback — 别名"""
-
- def onAvailabilityChanged(self, available: bool):
- pass
-
- def onClicked(self, controller: AccessibilityButtonController):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# MagnificationConfig
-# ═══════════════════════════════════════════════════════════════
-
-class MagnificationConfig(Stub):
- """MagnificationConfig — 放大配置"""
-
- SCALE = 0
- CENTER_X = 1
- CENTER_Y = 2
- ALL = -1
-
- def __init__(self):
- super().__init__()
- self._scale: float = 1.0
- self._center_x: float = 0.0
- self._center_y: float = 0.0
- self._mode: int = 0
- self._frame_left: float = 0.0
- self._frame_top: float = 0.0
- self._frame_right: float = 0.0
- self._frame_bottom: float = 0.0
-
- def getScale(self) -> float:
- return self._scale
-
- def setScale(self, scale: float):
- self._scale = scale
-
- def getCenterX(self) -> float:
- return self._center_x
-
- def setCenterX(self, center_x: float):
- self._center_x = center_x
-
- def getCenterY(self) -> float:
- return self._center_y
-
- def setCenterY(self, center_y: float):
- self._center_y = center_y
-
- def getMode(self) -> int:
- return self._mode
-
- def setMode(self, mode: int):
- self._mode = mode
-
- def toString(self) -> str:
- return (f"MagnificationConfig(scale={self._scale}, "
- f"center=({self._center_x}, {self._center_y}))")
-
-
-# ═══════════════════════════════════════════════════════════════
-# MagnificationController
-# ═══════════════════════════════════════════════════════════════
-
-class MagnificationController(Stub):
- """MagnificationController — 放大控制器"""
-
- class OnMagnificationChangedListener(Stub):
- def onMagnificationChanged(self, controller: "MagnificationController",
- region: Any, scale: float, center_x: float, center_y: float):
- pass
-
- def __init__(self):
- super().__init__()
- self._listeners: List["MagnificationController.OnMagnificationChangedListener"] = []
- self._scale: float = 1.0
- self._center_x: float = 0.0
- self._center_y: float = 0.0
- self._magnification_region: Any = None
-
- def getScale(self) -> float:
- return self._scale
-
- def getCenterX(self) -> float:
- return self._center_x
-
- def getCenterY(self) -> float:
- return self._center_y
-
- def getMagnificationRegion(self) -> Any:
- return self._magnification_region
-
- def setScale(self, scale: float, animate: bool = False) -> bool:
- self._scale = scale
- self._notifyListeners()
- return True
-
- def setCenter(self, center_x: float, center_y: float, animate: bool = False) -> bool:
- self._center_x = center_x
- self._center_y = center_y
- self._notifyListeners()
- return True
-
- def addListener(self, listener: "MagnificationController.OnMagnificationChangedListener"):
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeListener(self, listener: "MagnificationController.OnMagnificationChangedListener"):
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def _notifyListeners(self):
- for listener in list(self._listeners):
- try:
- listener.onMagnificationChanged(self, self._magnification_region,
- self._scale, self._center_x, self._center_y)
- except Exception:
- pass
-
- def isMagnifying(self) -> bool:
- return abs(self._scale - 1.0) > 0.01
-
- def reset(self, animate: bool = False) -> bool:
- if self.isMagnifying():
- self._scale = 1.0
- self._center_x = 0.0
- self._center_y = 0.0
- self._notifyListeners()
- return True
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "AccessibilityEvent", "AccessibilityRecord",
- "AccessibilityNodeInfo", "AccessibilityNodeProvider",
- "AccessibilityService", "AccessibilityServiceInfo",
- "AccessibilityWindowInfo",
- "CaptioningManager",
- "AccessibilityManager",
- "AccessibilityServiceGestureResult",
- "TouchExplorationStateChangeListener",
- "AccessibilityButtonController",
- "AccessibilityButtonControllerCallback",
- "MagnificationConfig",
- "MagnificationController",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/view_accessibility_ext.py b/android_pyapi/android/view_accessibility_ext.py
deleted file mode 100644
index 0e725a5..0000000
--- a/android_pyapi/android/view_accessibility_ext.py
+++ /dev/null
@@ -1,744 +0,0 @@
-"""
-Android View Accessibility 扩展组件
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import time
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# 无障碍事件常量
-# ═══════════════════════════════════════════════════════════════
-
-TYPE_VIEW_CLICKED = 0x00000001
-TYPE_VIEW_LONG_CLICKED = 0x00000002
-TYPE_VIEW_SELECTED = 0x00000004
-TYPE_VIEW_FOCUSED = 0x00000008
-TYPE_VIEW_TEXT_CHANGED = 0x00000010
-TYPE_WINDOW_STATE_CHANGED = 0x00000020
-TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040
-TYPE_VIEW_HOVER_ENTER = 0x00000080
-TYPE_VIEW_HOVER_EXIT = 0x00000100
-TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200
-TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400
-TYPE_WINDOW_CONTENT_CHANGED = 0x00000800
-TYPE_VIEW_SCROLLED = 0x00001000
-TYPE_VIEW_TEXT_SELECTION_CHANGED = 0x00002000
-TYPE_ANNOUNCEMENT = 0x00004000
-TYPE_VIEW_ACCESSIBILITY_FOCUSED = 0x00008000
-TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 0x00010000
-TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 0x00020000
-TYPE_GESTURE_DETECTION_START = 0x00040000
-TYPE_GESTURE_DETECTION_END = 0x00080000
-TYPE_TOUCH_INTERACTION_START = 0x00100000
-TYPE_TOUCH_INTERACTION_END = 0x00200000
-TYPE_WINDOWS_CHANGED = 0x00400000
-TYPE_VIEW_CONTEXT_CLICKED = 0x00800000
-TYPE_ASSIST_READING_CONTEXT = 0x01000000
-
-CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000001
-CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 0x00000002
-CONTENT_CHANGE_TYPE_SUBTREE = 0x00000004
-CONTENT_CHANGE_TYPE_TEXT = 0x00000008
-CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000010
-
-WINDOWS_CHANGE_ADDED = 0x00000001
-WINDOWS_CHANGE_REMOVED = 0x00000002
-WINDOWS_CHANGE_TITLE = 0x00000004
-WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED = 0x00000008
-WINDOWS_CHANGE_ACTIVE = 0x00000010
-WINDOWS_CHANGE_PARENT = 0x00000020
-WINDOWS_CHANGE_CHILDREN = 0x00000040
-WINDOWS_CHANGE_BOUNDS = 0x00000080
-WINDOWS_CHANGE_LAYER = 0x00000100
-
-WINDOW_TYPE_ACCESSIBILITY_OVERLAY = 4
-WINDOW_TYPE_APPLICATION = 1
-WINDOW_TYPE_INPUT_METHOD = 2
-WINDOW_TYPE_SPLIT_SCREEN_DIVIDER = 5
-WINDOW_TYPE_SYSTEM = 3
-
-FLAG_REPORT_VIEW_IDS = 0x10
-FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x80
-FLAG_REQUEST_FILTER_KEY_EVENTS = 0x20
-FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x40
-FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x08
-FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x02
-FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x100
-
-CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1
-CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2
-CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4
-CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8
-
-CAPTIONING_TYPE_UNKNOWN = -1
-CAPTIONING_TYPE_FEATURE = 0
-CAPTIONING_TYPE_COUNTRY = 1
-CAPTIONING_TYPE_SPOKEN = 2
-CAPTIONING_TYPE_UNKNOWN_CHARACTER = 3
-CAPTIONING_TYPE_MUSIC = 4
-CAPTIONING_TYPE_SFX = 5
-CAPTIONING_TYPE_VOICE = 6
-
-CAPTIONING_PRESET_INVALID = -1
-CAPTIONING_PRESET_CUSTOM = 0
-CAPTIONING_PRESET_WHITE_ON_BLACK = 1
-CAPTIONING_PRESET_BLACK_ON_WHITE = 2
-CAPTIONING_PRESET_YELLOW_ON_BLACK = 3
-CAPTIONING_PRESET_YELLOW_ON_BLUE = 4
-CAPTIONING_PRESET_CUSTOM_BLACK_ON_WHITE = 5
-CAPTIONING_PRESET_CUSTOM_WHITE_ON_BLACK = 6
-CAPTIONING_PRESET_CUSTOM_YELLOW_ON_BLACK = 7
-CAPTIONING_PRESET_CUSTOM_YELLOW_ON_BLUE = 8
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityEvent
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityRecord(Stub):
- """AccessibilityRecord — 无障碍记录"""
-
- def __init__(self):
- super().__init__()
- self._source_view: Optional[Any] = None
- self._source_node_id: int = -1
- self._source_window_id: int = -1
- self._event_time: int = 0
- self._package_name: Optional[str] = None
- self._class_name: Optional[str] = None
- self._text: List[str] = []
- self._content_description: Optional[str] = None
- self._item_count: int = -1
- self._current_item_index: int = -1
- self._from_index: int = -1
- self._to_index: int = -1
- self._scrollable: bool = False
- self._password: bool = False
- self._checked: bool = False
- self._enabled: bool = True
- self._clickable: bool = False
- self._focusable: bool = False
- self._focused: bool = False
- self._long_clickable: bool = False
- self._selected: bool = False
- self._pass_through: bool = False
- self._before_text: Optional[str] = None
- self._removed_count: int = 0
- self._added_count: int = 0
- self._max_scroll_x: int = -1
- self._max_scroll_y: int = -1
- self._scroll_x: int = -1
- self._scroll_y: int = -1
-
- def setSource(self, view: Any) -> None:
- self._source_view = view
-
- def getSource(self) -> Optional[Any]:
- return self._source_view
-
- def setSourceNodeId(self, node_id: int) -> None:
- self._source_node_id = node_id
-
- def getSourceNodeId(self) -> int:
- return self._source_node_id
-
- def setWindowId(self, window_id: int) -> None:
- self._source_window_id = window_id
-
- def getWindowId(self) -> int:
- return self._source_window_id
-
- def setEventTime(self, time: int) -> None:
- self._event_time = time
-
- def getEventTime(self) -> int:
- return self._event_time if self._event_time else int(time.time() * 1000)
-
- def setPackageName(self, name: str) -> None:
- self._package_name = name
-
- def getPackageName(self) -> Optional[str]:
- return self._package_name
-
- def setClassName(self, name: str) -> None:
- self._class_name = name
-
- def getClassName(self) -> Optional[str]:
- return self._class_name
-
- def setText(self, text: List[str]) -> None:
- self._text = list(text)
-
- def getText(self) -> List[str]:
- return list(self._text)
-
- def setContentDescription(self, desc: str) -> None:
- self._content_description = desc
-
- def getContentDescription(self) -> Optional[str]:
- return self._content_description
-
- def setItemCount(self, count: int) -> None:
- self._item_count = count
-
- def getItemCount(self) -> int:
- return self._item_count
-
- def setCurrentItemIndex(self, index: int) -> None:
- self._current_item_index = index
-
- def getCurrentItemIndex(self) -> int:
- return self._current_item_index
-
- def setFromIndex(self, index: int) -> None:
- self._from_index = index
-
- def getFromIndex(self) -> int:
- return self._from_index
-
- def setToIndex(self, index: int) -> None:
- self._to_index = index
-
- def getToIndex(self) -> int:
- return self._to_index
-
- def setScrollable(self, scrollable: bool) -> None:
- self._scrollable = scrollable
-
- def isScrollable(self) -> bool:
- return self._scrollable
-
- def setPassword(self, password: bool) -> None:
- self._password = password
-
- def isPassword(self) -> bool:
- return self._password
-
- def setChecked(self, checked: bool) -> None:
- self._checked = checked
-
- def isChecked(self) -> bool:
- return self._checked
-
- def setEnabled(self, enabled: bool) -> None:
- self._enabled = enabled
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setClickable(self, clickable: bool) -> None:
- self._clickable = clickable
-
- def isClickable(self) -> bool:
- return self._clickable
-
- def setFocusable(self, focusable: bool) -> None:
- self._focusable = focusable
-
- def isFocusable(self) -> bool:
- return self._focusable
-
- def setFocused(self, focused: bool) -> None:
- self._focused = focused
-
- def isFocused(self) -> bool:
- return self._focused
-
- def setLongClickable(self, long_clickable: bool) -> None:
- self._long_clickable = long_clickable
-
- def isLongClickable(self) -> bool:
- return self._long_clickable
-
- def setSelected(self, selected: bool) -> None:
- self._selected = selected
-
- def isSelected(self) -> bool:
- return self._selected
-
- def setBeforeText(self, text: str) -> None:
- self._before_text = text
-
- def getBeforeText(self) -> Optional[str]:
- return self._before_text
-
- def setRemovedCount(self, count: int) -> None:
- self._removed_count = count
-
- def getRemovedCount(self) -> int:
- return self._removed_count
-
- def setAddedCount(self, count: int) -> None:
- self._added_count = count
-
- def getAddedCount(self) -> int:
- return self._added_count
-
- def setMaxScrollX(self, max_x: int) -> None:
- self._max_scroll_x = max_x
-
- def getMaxScrollX(self) -> int:
- return self._max_scroll_x
-
- def setMaxScrollY(self, max_y: int) -> None:
- self._max_scroll_y = max_y
-
- def getMaxScrollY(self) -> int:
- return self._max_scroll_y
-
- def setScrollX(self, x: int) -> None:
- self._scroll_x = x
-
- def getScrollX(self) -> int:
- return self._scroll_x
-
- def setScrollY(self, y: int) -> None:
- self._scroll_y = y
-
- def getScrollY(self) -> int:
- return self._scroll_y
-
- def toString(self) -> str:
- return (f"AccessibilityRecord(class={self._class_name}, "
- f"text={self._text})")
-
-
-class AccessibilityEvent(AccessibilityRecord):
- """AccessibilityEvent — 无障碍事件"""
-
- INVALID_POSITION = -1
- MAX_TEXT_LENGTH = 500
-
- def __init__(self, event_type: int = 0):
- super().__init__()
- self._event_type = event_type
- self._event_type_int = event_type
- self._movement_granularity: int = 0
- self._action: int = 0
- self._content_change_types: int = 0
- self._window_changes: int = 0
-
- @staticmethod
- def obtain(event_type: int = 0) -> "AccessibilityEvent":
- return AccessibilityEvent(event_type)
-
- @staticmethod
- def obtain(event: "AccessibilityEvent") -> "AccessibilityEvent":
- e = AccessibilityEvent(event.getEventType())
- return e
-
- def getEventType(self) -> int:
- return self._event_type
-
- def setEventType(self, event_type: int) -> None:
- self._event_type = event_type
-
- def setMovementGranularity(self, granularity: int) -> None:
- self._movement_granularity = granularity
-
- def getMovementGranularity(self) -> int:
- return self._movement_granularity
-
- def setAction(self, action: int) -> None:
- self._action = action
-
- def getAction(self) -> int:
- return self._action
-
- def setContentChangeTypes(self, types: int) -> None:
- self._content_change_types = types
-
- def getContentChangeTypes(self) -> int:
- return self._content_change_types
-
- def setWindowChanges(self, changes: int) -> None:
- self._window_changes = changes
-
- def getWindowChanges(self) -> int:
- return self._window_changes
-
- def recycle(self) -> None:
- pass
-
- def toString(self) -> str:
- return f"AccessibilityEvent(type={self._event_type})"
-
-
-class AccessibilityWindowInfo(Stub):
- """AccessibilityWindowInfo — 无障碍窗口信息"""
-
- TYPE_ACCESSIBILITY_OVERLAY = WINDOW_TYPE_ACCESSIBILITY_OVERLAY
- TYPE_APPLICATION = WINDOW_TYPE_APPLICATION
- TYPE_INPUT_METHOD = WINDOW_TYPE_INPUT_METHOD
- TYPE_SPLIT_SCREEN_DIVIDER = WINDOW_TYPE_SPLIT_SCREEN_DIVIDER
- TYPE_SYSTEM = WINDOW_TYPE_SYSTEM
-
- UNDEFINED = -1
- ACTIVE = 0
- INACTIVE = 1
-
- def __init__(self):
- super().__init__()
- self._type: int = self.TYPE_APPLICATION
- self._id: int = -1
- self._layer: int = 0
- self._is_active = False
- self._is_focused = False
- self._is_accessibility_focused = False
- self._title: Optional[str] = None
- self._root: Optional[Any] = None
- self._parent: Optional["AccessibilityWindowInfo"] = None
- self._bounds: Tuple[int, int, int, int] = (0, 0, 0, 0)
- self._anchor: Optional[Any] = None
- self._picture_in_picture = False
- self._first_child: Optional["AccessibilityWindowInfo"] = None
- self._last_child: Optional["AccessibilityWindowInfo"] = None
- self._child_count: int = 0
-
- def getType(self) -> int:
- return self._type
-
- def setType(self, type_val: int) -> None:
- self._type = type_val
-
- def getId(self) -> int:
- return self._id
-
- def setId(self, id_val: int) -> None:
- self._id = id_val
-
- def setLayer(self, layer: int) -> None:
- self._layer = layer
-
- def getLayer(self) -> int:
- return self._layer
-
- def isActive(self) -> bool:
- return self._is_active
-
- def setActive(self, active: bool) -> None:
- self._is_active = active
-
- def isFocused(self) -> bool:
- return self._is_focused
-
- def setFocused(self, focused: bool) -> None:
- self._is_focused = focused
-
- def isAccessibilityFocused(self) -> bool:
- return self._is_accessibility_focused
-
- def setAccessibilityFocused(self, focused: bool) -> None:
- self._is_accessibility_focused = focused
-
- def getTitle(self) -> Optional[str]:
- return self._title
-
- def setTitle(self, title: str) -> None:
- self._title = title
-
- def setBoundsInScreen(self, bounds: Tuple[int, int, int, int]) -> None:
- self._bounds = bounds
-
- def getBoundsInScreen(self) -> Tuple[int, int, int, int]:
- return self._bounds
-
- def setAnchorId(self, anchor: Any) -> None:
- self._anchor = anchor
-
- def getAnchorId(self) -> Optional[Any]:
- return self._anchor
-
- def isInPictureInPictureMode(self) -> bool:
- return self._picture_in_picture
-
- def setPictureInPictureMode(self, pip: bool) -> None:
- self._picture_in_picture = pip
-
- def getRoot(self) -> Optional[Any]:
- return self._root
-
- def setRoot(self, root: Any) -> None:
- self._root = root
-
- def getParent(self) -> Optional["AccessibilityWindowInfo"]:
- return self._parent
-
- def getChild(self, index: int) -> Optional["AccessibilityWindowInfo"]:
- if index == 0:
- return self._first_child
- return None
-
- def getChildCount(self) -> int:
- return self._child_count
-
- @staticmethod
- def obtain() -> "AccessibilityWindowInfo":
- return AccessibilityWindowInfo()
-
- @staticmethod
- def obtain(info: "AccessibilityWindowInfo") -> "AccessibilityWindowInfo":
- return AccessibilityWindowInfo()
-
- def recycle(self) -> None:
- pass
-
- def toString(self) -> str:
- types = {1: "APPLICATION", 2: "INPUT_METHOD", 3: "SYSTEM", 4: "OVERLAY"}
- return (f"AccessibilityWindowInfo(type={types.get(self._type, 'UNKNOWN')}, "
- f"id={self._id})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccessibilityManager 扩展
-# ═══════════════════════════════════════════════════════════════
-
-class AccessibilityManager(Stub):
- """AccessibilityManager — 无障碍管理器扩展"""
-
- FLAG_REPORT_VIEW_IDS = FLAG_REPORT_VIEW_IDS
- FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
- FLAG_REQUEST_FILTER_KEY_EVENTS = FLAG_REQUEST_FILTER_KEY_EVENTS
- FLAG_REQUEST_TOUCH_EXPLORATION_MODE = FLAG_REQUEST_TOUCH_EXPLORATION_MODE
- FLAG_RETRIEVE_INTERACTIVE_WINDOWS = FLAG_RETRIEVE_INTERACTIVE_WINDOWS
- FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
- FLAG_REQUEST_ACCESSIBILITY_BUTTON = FLAG_REQUEST_ACCESSIBILITY_BUTTON
-
- class AccessibilityStateChangeListener(Stub):
- """AccessibilityManager.AccessibilityStateChangeListener"""
- def onAccessibilityStateChanged(self, enabled: bool) -> None:
- pass
-
- class TouchExplorationStateChangeListener(Stub):
- """AccessibilityManager.TouchExplorationStateChangeListener"""
- def onTouchExplorationStateChanged(self, enabled: bool) -> None:
- pass
-
- class HighTextContrastChangeListener(Stub):
- def onHighTextContrastStateChanged(self, enabled: bool) -> None:
- pass
-
- def __init__(self):
- super().__init__()
- self._enabled = False
- self._touch_exploration_enabled = False
- self._high_text_contrast_enabled = False
- self._state_listeners: List[AccessibilityStateChangeListener] = []
- self._touch_listeners: List[TouchExplorationStateChangeListener] = []
- self._contrast_listeners: List[Any] = []
- self._accessibility_button_available = False
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool) -> None:
- old = self._enabled
- self._enabled = enabled
- if old != enabled:
- for listener in list(self._state_listeners):
- listener.onAccessibilityStateChanged(enabled)
-
- def isTouchExplorationEnabled(self) -> bool:
- return self._touch_exploration_enabled
-
- def setTouchExplorationEnabled(self, enabled: bool) -> None:
- old = self._touch_exploration_enabled
- self._touch_exploration_enabled = enabled
- if old != enabled:
- for listener in list(self._touch_listeners):
- listener.onTouchExplorationStateChanged(enabled)
-
- def isHighTextContrastEnabled(self) -> bool:
- return self._high_text_contrast_enabled
-
- def addAccessibilityStateChangeListener(self, listener: AccessibilityStateChangeListener) -> None:
- if listener not in self._state_listeners:
- self._state_listeners.append(listener)
-
- def removeAccessibilityStateChangeListener(self, listener: AccessibilityStateChangeListener) -> None:
- if listener in self._state_listeners:
- self._state_listeners.remove(listener)
-
- def addTouchExplorationStateChangeListener(self, listener: TouchExplorationStateChangeListener) -> None:
- if listener not in self._touch_listeners:
- self._touch_listeners.append(listener)
-
- def removeTouchExplorationStateChangeListener(self, listener: TouchExplorationStateChangeListener) -> None:
- if listener in self._touch_listeners:
- self._touch_listeners.remove(listener)
-
- def addHighTextContrastStateChangeListener(self, listener: Any) -> None:
- if listener not in self._contrast_listeners:
- self._contrast_listeners.append(listener)
-
- def removeHighTextContrastStateChangeListener(self, listener: Any) -> None:
- if listener in self._contrast_listeners:
- self._contrast_listeners.remove(listener)
-
- def setAccessibilityButtonAvailable(self, available: bool) -> None:
- self._accessibility_button_available = available
-
- def isAccessibilityButtonAvailable(self) -> bool:
- return self._accessibility_button_available
-
- def sendAccessibilityEvent(self, event: AccessibilityEvent) -> None:
- pass
-
- def interrupt(self) -> None:
- pass
-
- def getInstalledAccessibilityServiceList(self) -> List[Any]:
- return []
-
- def getEnabledAccessibilityServiceList(self) -> List[Any]:
- return []
-
- def toString(self) -> str:
- return (f"AccessibilityManager(enabled={self._enabled}, "
- f"touchExploration={self._touch_exploration_enabled})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CaptioningManager
-# ═══════════════════════════════════════════════════════════════
-
-class CaptioningManager(Stub):
- """CaptioningManager — 字幕管理"""
-
- CAPTIONING_TYPE_UNKNOWN = CAPTIONING_TYPE_UNKNOWN
- CAPTIONING_TYPE_FEATURE = CAPTIONING_TYPE_FEATURE
- CAPTIONING_TYPE_COUNTRY = CAPTIONING_TYPE_COUNTRY
- CAPTIONING_TYPE_SPOKEN = CAPTIONING_TYPE_SPOKEN
- CAPTIONING_TYPE_UNKNOWN_CHARACTER = CAPTIONING_TYPE_UNKNOWN_CHARACTER
- CAPTIONING_TYPE_MUSIC = CAPTIONING_TYPE_MUSIC
- CAPTIONING_TYPE_SFX = CAPTIONING_TYPE_SFX
- CAPTIONING_TYPE_VOICE = CAPTIONING_TYPE_VOICE
-
- class CaptionStyle(Stub):
- """CaptioningManager.CaptionStyle — 字幕风格"""
-
- EDGE_TYPE_NONE = 0
- EDGE_TYPE_OUTLINE = 1
- EDGE_TYPE_DROP_SHADOW = 2
- EDGE_TYPE_RAISED = 3
- EDGE_TYPE_DEPRESSED = 4
-
- PRESET_CUSTOM = CAPTIONING_PRESET_CUSTOM
- PRESET_WHITE_ON_BLACK = CAPTIONING_PRESET_WHITE_ON_BLACK
- PRESET_BLACK_ON_WHITE = CAPTIONING_PRESET_BLACK_ON_WHITE
- PRESET_YELLOW_ON_BLACK = CAPTIONING_PRESET_YELLOW_ON_BLACK
- PRESET_YELLOW_ON_BLUE = CAPTIONING_PRESET_YELLOW_ON_BLUE
-
- def __init__(self):
- super().__init__()
- self._foreground_color: int = 0xFFFFFFFF
- self._background_color: int = 0xFF000000
- self._edge_color: int = 0xFF000000
- self._edge_type: int = self.EDGE_TYPE_NONE
- self._window_color: int = 0xFF000000
- self._foreground_size: int = 1
- self._preset: int = CAPTIONING_PRESET_WHITE_ON_BLACK
-
- def getForegroundColor(self) -> int:
- return self._foreground_color
-
- def getBackgroundColor(self) -> int:
- return self._background_color
-
- def getEdgeColor(self) -> int:
- return self._edge_color
-
- def getEdgeType(self) -> int:
- return self._edge_type
-
- def getWindowColor(self) -> int:
- return self._window_color
-
- def getForegroundSize(self) -> int:
- return self._foreground_size
-
- def getPreset(self) -> int:
- return self._preset
-
- def hasBackgroundColor(self) -> bool:
- return (self._background_color >> 24) > 0
-
- def hasForegroundColor(self) -> bool:
- return (self._foreground_color >> 24) > 0
-
- def hasEdgeType(self) -> bool:
- return self._edge_type != self.EDGE_TYPE_NONE
-
- def hasWindowColor(self) -> bool:
- return (self._window_color >> 24) > 0
-
- @staticmethod
- def getCustomStyle(style_id: int) -> "CaptioningManager.CaptionStyle":
- return CaptioningManager.CaptionStyle()
-
- @staticmethod
- def getPresetStyle(preset: int) -> "CaptioningManager.CaptionStyle":
- return CaptioningManager.CaptionStyle()
-
- def applyStyle(self, style: "CaptioningManager.CaptionStyle") -> None:
- pass
-
- def toString(self) -> str:
- return f"CaptionStyle(preset={self._preset})"
-
- class CaptioningChangeListener(Stub):
- """CaptioningManager.CaptioningChangeListener"""
-
- def onEnabledChanged(self, enabled: bool) -> None:
- pass
-
- def onUserStyleChanged(self, style: "CaptioningManager.CaptionStyle") -> None:
- pass
-
- def onLocaleChanged(self, locale: Any) -> None:
- pass
-
- def onFontScaleChanged(self, scale: float) -> None:
- pass
-
- def __init__(self):
- super().__init__()
- self._enabled = False
- self._user_style: Optional[CaptioningManager.CaptionStyle] = None
- self._font_scale: float = 1.0
- self._locale: Optional[Any] = None
- self._listeners: List[CaptioningManager.CaptioningChangeListener] = []
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def getFontScale(self) -> float:
- return self._font_scale
-
- def getLocale(self) -> Optional[Any]:
- return self._locale
-
- def getUserStyle(self) -> CaptionStyle:
- return self._user_style or CaptioningManager.CaptionStyle()
-
- def addCaptioningChangeListener(self, listener: CaptioningChangeListener) -> None:
- if listener not in self._listeners:
- self._listeners.append(listener)
-
- def removeCaptioningChangeListener(self, listener: CaptioningChangeListener) -> None:
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def toString(self) -> str:
- return f"CaptioningManager(enabled={self._enabled})"
-
-
-IllegalArgumentException = type("IllegalStateException", (RuntimeException,), {})
\ No newline at end of file
diff --git a/android_pyapi/android/view_animation.py b/android_pyapi/android/view_animation.py
deleted file mode 100644
index 1c703ea..0000000
--- a/android_pyapi/android/view_animation.py
+++ /dev/null
@@ -1,935 +0,0 @@
-"""
-Android View Animation 组件 — Animation, AnimationSet, Interpolators,
-AnimationUtils, Transformation 等
-方法签名完全对齐 Android SDK
-"""
-
-import math
-import sys
-import time
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError, android_context
-
-
-# ═══════════════════════════════════════════════════════════════
-# Interpolator
-# ═══════════════════════════════════════════════════════════════
-
-class Interpolator(Stub):
- """Interpolator — 插值器接口"""
-
- def getInterpolation(self, input: float) -> float:
- return input
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccelerateInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class AccelerateInterpolator(Interpolator):
- """AccelerateInterpolator — 加速插值器(先慢后快)"""
-
- def __init__(self, factor: float = 1.0):
- super().__init__()
- self._factor = factor
- self._double_factor = 2.0 * factor
-
- def getInterpolation(self, input: float) -> float:
- if self._factor == 1.0:
- return input * input
- return input ** (self._double_factor)
-
-
-# ═══════════════════════════════════════════════════════════════
-# DecelerateInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class DecelerateInterpolator(Interpolator):
- """DecelerateInterpolator — 减速插值器(先快后慢)"""
-
- def __init__(self, factor: float = 1.0):
- super().__init__()
- self._factor = factor
-
- def getInterpolation(self, input: float) -> float:
- if self._factor == 1.0:
- return 1.0 - (1.0 - input) * (1.0 - input)
- return 1.0 - (1.0 - input) ** (2.0 * self._factor)
-
-
-# ═══════════════════════════════════════════════════════════════
-# AccelerateDecelerateInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class AccelerateDecelerateInterpolator(Interpolator):
- """AccelerateDecelerateInterpolator — 加速减速插值器"""
-
- def getInterpolation(self, input: float) -> float:
- return float(math.cos((input + 1) * math.pi) / 2.0 + 0.5)
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinearInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class LinearInterpolator(Interpolator):
- """LinearInterpolator — 线性插值器"""
-
- def getInterpolation(self, input: float) -> float:
- return input
-
-
-# ═══════════════════════════════════════════════════════════════
-# OvershootInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class OvershootInterpolator(Interpolator):
- """OvershootInterpolator — 超出插值器(越过目标再回弹)"""
-
- def __init__(self, tension: float = 2.0):
- super().__init__()
- self._tension = tension
-
- def getInterpolation(self, input: float) -> float:
- input -= 1.0
- return input * input * ((self._tension + 1) * input + self._tension) + 1.0
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnticipateInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class AnticipateInterpolator(Interpolator):
- """AnticipateInterpolator — 预判插值器(先反向后正向前进)"""
-
- def __init__(self, tension: float = 2.0):
- super().__init__()
- self._tension = tension
-
- def getInterpolation(self, input: float) -> float:
- return input * input * ((self._tension + 1) * input - self._tension)
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnticipateOvershootInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class AnticipateOvershootInterpolator(Interpolator):
- """AnticipateOvershootInterpolator — 预判超出插值器"""
-
- def __init__(self, tension: float = 2.0, extra_tension: float = 1.5):
- super().__init__()
- self._tension = tension
- self._extra_tension = extra_tension
-
- def getInterpolation(self, input: float) -> float:
- if input < 0.5:
- t = input * 2.0
- return 0.5 * t * t * ((self._tension + 1) * t - self._tension)
- else:
- t = input * 2.0 - 2.0
- return 0.5 * (t * t * ((self._tension + 1) * t + self._tension) + 2.0)
-
-
-# ═══════════════════════════════════════════════════════════════
-# BounceInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class BounceInterpolator(Interpolator):
- """BounceInterpolator — 弹跳插值器"""
-
- @staticmethod
- def _bounce(t: float) -> float:
- t2 = t * t
- return t2 * 8.0
-
- def getInterpolation(self, input: float) -> float:
- if input < 0.3535:
- return BounceInterpolator._bounce(input)
- elif input < 0.7408:
- return BounceInterpolator._bounce(input - 0.54719) + 0.7
- elif input < 0.9644:
- return BounceInterpolator._bounce(input - 0.8526) + 0.9
- else:
- return BounceInterpolator._bounce(input - 1.0435) + 0.95
-
-
-# ═══════════════════════════════════════════════════════════════
-# CycleInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class CycleInterpolator(Interpolator):
- """CycleInterpolator — 周期插值器(正弦循环)"""
-
- def __init__(self, cycles: float = 1.0):
- super().__init__()
- self._cycles = cycles
-
- def getInterpolation(self, input: float) -> float:
- return float(math.sin(2.0 * math.pi * self._cycles * input))
-
-
-# ═══════════════════════════════════════════════════════════════
-# PathInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class PathInterpolator(Interpolator):
- """PathInterpolator — 路径插值器"""
-
- def __init__(self, control_x1: float = 0.0, control_y1: float = 0.0,
- control_x2: float = 1.0, control_y2: float = 1.0):
- super().__init__()
- self._control_x1 = control_x1
- self._control_y1 = control_y1
- self._control_x2 = control_x2
- self._control_y2 = control_y2
-
- def getInterpolation(self, input: float) -> float:
- return self._cubic_bezier(input)
-
- def _cubic_bezier(self, t: float) -> float:
- u = 1.0 - t
- return (3.0 * u * u * t * self._control_y1 +
- 3.0 * u * t * t * self._control_y2 +
- t * t * t)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Transformation
-# ═══════════════════════════════════════════════════════════════
-
-class Transformation(Stub):
- """Transformation — 动画变换矩阵"""
-
- TYPE_IDENTITY = 0
- TYPE_ALPHA = 1
- TYPE_BOTH = 2
-
- def __init__(self):
- super().__init__()
- self._alpha: float = 1.0
- self._matrix: Any = None # 占位,实际 Android 为 Matrix 对象
- self._transformation_type: int = Transformation.TYPE_IDENTITY
-
- def getAlpha(self) -> float:
- return self._alpha
-
- def setAlpha(self, alpha: float):
- self._alpha = alpha
-
- def getMatrix(self) -> Any:
- return self._matrix
-
- def setMatrix(self, matrix: Any):
- self._matrix = matrix
-
- def setTransformationType(self, transformation_type: int):
- self._transformation_type = transformation_type
-
- def getTransformationType(self) -> int:
- return self._transformation_type
-
- def clear(self):
- self._alpha = 1.0
- self._matrix = None
- self._transformation_type = Transformation.TYPE_IDENTITY
-
- def compose(self, other: "Transformation"):
- if other is None:
- return
- self._alpha *= other._alpha
- if self._matrix is None:
- self._matrix = other._matrix
- elif other._matrix is not None:
- pass # 占位:矩阵乘法
- self._transformation_type = max(self._transformation_type,
- other._transformation_type)
-
- def toString(self) -> str:
- return (f"Transformation(alpha={self._alpha}, "
- f"type={self._transformation_type})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# Animation
-# ═══════════════════════════════════════════════════════════════
-
-class Animation(Stub):
- """Animation — 动画基类"""
-
- INFINITE = -1
- RESTART = 1
- REVERSE = 2
-
- ABSOLUTE = 0
- RELATIVE_TO_SELF = 1
- RELATIVE_TO_PARENT = 2
-
- START_ON_FIRST_FRAME = -1
-
- class AnimationListener(Stub):
- """AnimationListener — 动画监听器"""
-
- def onAnimationStart(self, animation: "Animation"):
- pass
-
- def onAnimationEnd(self, animation: "Animation"):
- pass
-
- def onAnimationRepeat(self, animation: "Animation"):
- pass
-
- def __init__(self):
- super().__init__()
- self._duration: int = 0
- self._start_offset: int = 0
- self._repeat_count: int = 0
- self._repeat_mode: int = Animation.RESTART
- self._fill_before: bool = False
- self._fill_after: bool = False
- self._fill_enabled: bool = False
- self._z_adjustment: int = 0
- self._interpolator: Optional[Interpolator] = None
- self._listener: Optional["Animation.AnimationListener"] = None
- self._start_time: Optional[int] = None
- self._started: bool = False
- self._ended: bool = False
- self._cycle: float = 0.0
- self._current_repeat: int = 0
- self._initialized: bool = False
- self._scale_factor: float = 1.0
- self._paused: bool = False
- self._more: bool = True
-
- def start(self):
- self._start_time = self._current_time_millis()
- self._started = True
- self._ended = False
- self._current_repeat = 0
- self._more = True
- if self._listener:
- self._listener.onAnimationStart(self)
-
- def startNow(self):
- self.start()
-
- def cancel(self):
- self._ended = True
- self._more = False
-
- def reset(self):
- self._start_time = None
- self._started = False
- self._ended = False
- self._current_repeat = 0
- self._cycle = 0.0
- self._more = True
- self._initialized = False
-
- def setDuration(self, duration_millis: int):
- self._duration = duration_millis
-
- def getDuration(self) -> int:
- return self._duration
-
- def setStartOffset(self, start_offset: int):
- self._start_offset = start_offset
-
- def getStartOffset(self) -> int:
- return self._start_offset
-
- def setRepeatCount(self, repeat_count: int):
- self._repeat_count = repeat_count
-
- def getRepeatCount(self) -> int:
- return self._repeat_count
-
- def setRepeatMode(self, repeat_mode: int):
- self._repeat_mode = repeat_mode
-
- def getRepeatMode(self) -> int:
- return self._repeat_mode
-
- def setInterpolator(self, interpolator: Optional[Interpolator]):
- self._interpolator = interpolator
-
- def getInterpolator(self) -> Optional[Interpolator]:
- return self._interpolator
-
- def setAnimationListener(self, listener: "Animation.AnimationListener"):
- self._listener = listener
-
- def getAnimationListener(self) -> Optional["Animation.AnimationListener"]:
- return self._listener
-
- def getTransformation(self, current_time: int,
- out_transformation: Transformation) -> bool:
- if self._start_time is None:
- self._start_time = current_time
-
- elapsed = current_time - self._start_time - self._start_offset
- if elapsed < 0:
- out_transformation.clear()
- return True
-
- duration = self._duration
- if duration == 0:
- duration = 1
-
- normalized = elapsed / duration
-
- if normalized >= 1.0:
- if self._current_repeat < self._repeat_count or self._repeat_count == self.INFINITE:
- if self._repeat_mode == Animation.REVERSE:
- normalized = 0.0
- else:
- normalized = 0.0
- self._current_repeat += 1
- if self._listener:
- self._listener.onAnimationRepeat(self)
- else:
- normalized = 1.0
- self._ended = True
- self._more = False
- self._apply_transformation(1.0, out_transformation)
- if self._listener:
- self._listener.onAnimationEnd(self)
- return False
-
- if normalized > 1.0:
- normalized = 1.0
-
- if self._interpolator:
- interpolated = self._interpolator.getInterpolation(normalized)
- else:
- interpolated = normalized
-
- self._cycle = normalized
- self._apply_transformation(interpolated, out_transformation)
- return self._more
-
- def _apply_transformation(self, interpolated_time: float, t: Transformation):
- pass
-
- def hasEnded(self) -> bool:
- return self._ended
-
- def hasStarted(self) -> bool:
- return self._started
-
- def setFillBefore(self, fill_before: bool):
- self._fill_before = fill_before
-
- def getFillBefore(self) -> bool:
- return self._fill_before
-
- def setFillAfter(self, fill_after: bool):
- self._fill_after = fill_after
-
- def getFillAfter(self) -> bool:
- return self._fill_after
-
- def setFillEnabled(self, fill_enabled: bool):
- self._fill_enabled = fill_enabled
-
- def getFillEnabled(self) -> bool:
- return self._fill_enabled
-
- def setZAdjustment(self, z_adjustment: int):
- self._z_adjustment = z_adjustment
-
- def getZAdjustment(self) -> int:
- return self._z_adjustment
-
- def willChangeBounds(self) -> bool:
- return True
-
- def willChangeTransformationMatrix(self) -> bool:
- return True
-
- def initialize(self, width: int, height: int, parent_width: int, parent_height: int):
- self._initialized = True
-
- def restrictDuration(self, duration_millis: int):
- if self._duration > duration_millis:
- self._duration = duration_millis
-
- def scaleCurrentDuration(self, scale: float):
- self._duration = int(self._duration * scale)
-
- @staticmethod
- def _current_time_millis() -> int:
- return int(time.time() * 1000)
-
- def toString(self) -> str:
- return (f"Animation(duration={self._duration}, "
- f"repeatCount={self._repeat_count}, "
- f"started={self._started})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# AlphaAnimation
-# ═══════════════════════════════════════════════════════════════
-
-class AlphaAnimation(Animation):
- """AlphaAnimation — 透明度动画"""
-
- def __init__(self, from_alpha: float, to_alpha: float):
- super().__init__()
- self._from_alpha = from_alpha
- self._to_alpha = to_alpha
-
- def _apply_transformation(self, interpolated_time: float, t: Transformation):
- alpha = self._from_alpha + (self._to_alpha - self._from_alpha) * interpolated_time
- t.setAlpha(alpha)
-
- def getFromAlpha(self) -> float:
- return self._from_alpha
-
- def getToAlpha(self) -> float:
- return self._to_alpha
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScaleAnimation
-# ═══════════════════════════════════════════════════════════════
-
-class ScaleAnimation(Animation):
- """ScaleAnimation — 缩放动画"""
-
- def __init__(self, from_x: float, to_x: float, from_y: float, to_y: float,
- pivot_x: float = 0.0, pivot_y: float = 0.0,
- pivot_x_type: int = Animation.ABSOLUTE,
- pivot_y_type: int = Animation.ABSOLUTE):
- super().__init__()
- self._from_x = from_x
- self._to_x = to_x
- self._from_y = from_y
- self._to_y = to_y
- self._pivot_x = pivot_x
- self._pivot_y = pivot_y
- self._pivot_x_type = pivot_x_type
- self._pivot_y_type = pivot_y_type
-
- def _apply_transformation(self, interpolated_time: float, t: Transformation):
- sx = self._from_x + (self._to_x - self._from_x) * interpolated_time
- sy = self._from_y + (self._to_y - self._from_y) * interpolated_time
- # 占位:Matrix 的缩放操作
- if t.getMatrix() is not None:
- pass
-
- def getFromX(self) -> float:
- return self._from_x
-
- def getToX(self) -> float:
- return self._to_x
-
- def getFromY(self) -> float:
- return self._from_y
-
- def getToY(self) -> float:
- return self._to_y
-
- def getPivotX(self) -> float:
- return self._pivot_x
-
- def getPivotY(self) -> float:
- return self._pivot_y
-
-
-# ═══════════════════════════════════════════════════════════════
-# TranslateAnimation
-# ═══════════════════════════════════════════════════════════════
-
-class TranslateAnimation(Animation):
- """TranslateAnimation — 平移动画"""
-
- def __init__(self, from_x: float, to_x: float, from_y: float, to_y: float,
- from_x_type: int = Animation.ABSOLUTE,
- to_x_type: int = Animation.ABSOLUTE,
- from_y_type: int = Animation.ABSOLUTE,
- to_y_type: int = Animation.ABSOLUTE):
- super().__init__()
- self._from_x = from_x
- self._to_x = to_x
- self._from_y = from_y
- self._to_y = to_y
- self._from_x_type = from_x_type
- self._to_x_type = to_x_type
- self._from_y_type = from_y_type
- self._to_y_type = to_y_type
-
- def _apply_transformation(self, interpolated_time: float, t: Transformation):
- dx = self._from_x + (self._to_x - self._from_x) * interpolated_time
- dy = self._from_y + (self._to_y - self._from_y) * interpolated_time
- if t.getMatrix() is not None:
- pass
-
- def getFromX(self) -> float:
- return self._from_x
-
- def getToX(self) -> float:
- return self._to_x
-
- def getFromY(self) -> float:
- return self._from_y
-
- def getToY(self) -> float:
- return self._to_y
-
-
-# ═══════════════════════════════════════════════════════════════
-# RotateAnimation
-# ═══════════════════════════════════════════════════════════════
-
-class RotateAnimation(Animation):
- """RotateAnimation — 旋转动画"""
-
- def __init__(self, from_degrees: float, to_degrees: float,
- pivot_x: float = 0.0, pivot_y: float = 0.0,
- pivot_x_type: int = Animation.ABSOLUTE,
- pivot_y_type: int = Animation.ABSOLUTE):
- super().__init__()
- self._from_degrees = from_degrees
- self._to_degrees = to_degrees
- self._pivot_x = pivot_x
- self._pivot_y = pivot_y
- self._pivot_x_type = pivot_x_type
- self._pivot_y_type = pivot_y_type
-
- def _apply_transformation(self, interpolated_time: float, t: Transformation):
- degrees = self._from_degrees + (self._to_degrees - self._from_degrees) * interpolated_time
- if t.getMatrix() is not None:
- pass
-
- def getFromDegrees(self) -> float:
- return self._from_degrees
-
- def getToDegrees(self) -> float:
- return self._to_degrees
-
- def getPivotX(self) -> float:
- return self._pivot_x
-
- def getPivotY(self) -> float:
- return self._pivot_y
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimationSet
-# ═══════════════════════════════════════════════════════════════
-
-class AnimationSet(Animation):
- """AnimationSet — 动画集合"""
-
- def __init__(self, share_interpolator: bool = True):
- super().__init__()
- self._share_interpolator = share_interpolator
- self._animations: List[Animation] = []
-
- def addAnimation(self, animation: Animation):
- self._animations.append(animation)
- if self._share_interpolator and self._interpolator:
- animation.setInterpolator(self._interpolator)
-
- def getAnimations(self) -> List[Animation]:
- return list(self._animations)
-
- def setDuration(self, duration_millis: int):
- super().setDuration(duration_millis)
- for anim in self._animations:
- anim.setDuration(duration_millis)
-
- def setFillAfter(self, fill_after: bool):
- super().setFillAfter(fill_after)
- for anim in self._animations:
- anim.setFillAfter(fill_after)
-
- def setFillBefore(self, fill_before: bool):
- super().setFillBefore(fill_before)
- for anim in self._animations:
- anim.setFillBefore(fill_before)
-
- def setRepeatMode(self, repeat_mode: int):
- super().setRepeatMode(repeat_mode)
- for anim in self._animations:
- anim.setRepeatMode(repeat_mode)
-
- def setRepeatCount(self, repeat_count: int):
- super().setRepeatCount(repeat_count)
- for anim in self._animations:
- anim.setRepeatCount(repeat_count)
-
- def setStartOffset(self, start_offset: int):
- super().setStartOffset(start_offset)
- for anim in self._animations:
- anim.setStartOffset(start_offset)
-
- def setInterpolator(self, interpolator: Optional[Interpolator]):
- super().setInterpolator(interpolator)
- if self._share_interpolator:
- for anim in self._animations:
- anim.setInterpolator(interpolator)
-
- def start(self):
- super().start()
- for anim in self._animations:
- anim.start()
-
- def reset(self):
- super().reset()
- for anim in self._animations:
- anim.reset()
-
- def cancel(self):
- super().cancel()
- for anim in self._animations:
- anim.cancel()
-
- def getTransformation(self, current_time: int,
- out_transformation: Transformation) -> bool:
- more = False
- for anim in self._animations:
- local_t = Transformation()
- if anim.getTransformation(current_time, local_t):
- more = True
- out_transformation.compose(local_t)
- return more
-
- def initialize(self, width: int, height: int, parent_width: int, parent_height: int):
- super().initialize(width, height, parent_width, parent_height)
- for anim in self._animations:
- anim.initialize(width, height, parent_width, parent_height)
-
- def willChangeBounds(self) -> bool:
- for anim in self._animations:
- if anim.willChangeBounds():
- return True
- return False
-
- def willChangeTransformationMatrix(self) -> bool:
- for anim in self._animations:
- if anim.willChangeTransformationMatrix():
- return True
- return False
-
- def getAnimations(self) -> List[Animation]:
- return list(self._animations)
-
- def restrictDuration(self, duration_millis: int):
- super().restrictDuration(duration_millis)
- for anim in self._animations:
- anim.restrictDuration(duration_millis)
-
- def scaleCurrentDuration(self, scale: float):
- super().scaleCurrentDuration(scale)
- for anim in self._animations:
- anim.scaleCurrentDuration(scale)
-
-
-# ═══════════════════════════════════════════════════════════════
-# Animation.AnimationListener (已定义在 Animation 类中)
-# ═══════════════════════════════════════════════════════════════
-
-# Animation.AnimationListener is defined inside the Animation class above
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimationUtils
-# ═══════════════════════════════════════════════════════════════
-
-class AnimationUtils(Stub):
- """AnimationUtils — 动画工具类"""
-
- @staticmethod
- def loadAnimation(context: Any, id: int) -> Animation:
- """加载动画资源(占位实现)"""
- sys.stderr.write(f"[AnimationUtils] loadAnimation: id={id}\n")
- return Animation()
-
- @staticmethod
- def makeInAnimation(context: Any, from_left: bool) -> Animation:
- """创建进入动画"""
- anim = AlphaAnimation(0.0, 1.0)
- anim.setDuration(300)
- return anim
-
- @staticmethod
- def makeOutAnimation(context: Any, to_left: bool) -> Animation:
- """创建退出动画"""
- anim = AlphaAnimation(1.0, 0.0)
- anim.setDuration(300)
- return anim
-
- @staticmethod
- def makeInChildBottomAnimation(context: Any) -> Animation:
- """创建子视图从底部进入动画"""
- anim = TranslateAnimation(0, 0, 1.0, 0.0,
- from_x_type=Animation.RELATIVE_TO_SELF,
- to_x_type=Animation.RELATIVE_TO_SELF,
- from_y_type=Animation.RELATIVE_TO_SELF,
- to_y_type=Animation.RELATIVE_TO_SELF)
- anim.setDuration(300)
- return anim
-
- @staticmethod
- def currentAnimationTimeMillis() -> int:
- return int(time.time() * 1000)
-
-
-# ═══════════════════════════════════════════════════════════════
-# LayoutAnimationController
-# ═══════════════════════════════════════════════════════════════
-
-class LayoutAnimationController(Stub):
- """LayoutAnimationController — 布局动画控制器"""
-
- ORDER_NORMAL = 0
- ORDER_REVERSE = 1
- ORDER_RANDOM = 2
-
- def __init__(self, animation: Optional[Animation] = None):
- super().__init__()
- self._animation: Optional[Animation] = animation
- self._delay: float = 0.5
- self._order: int = LayoutAnimationController.ORDER_NORMAL
- self._initialized: bool = False
- self._max_delay: int = 0
-
- def setAnimation(self, animation: Animation):
- self._animation = animation
-
- def getAnimation(self) -> Optional[Animation]:
- return self._animation
-
- def setOrder(self, order: int):
- self._order = order
-
- def getOrder(self) -> int:
- return self._order
-
- def setDelay(self, delay: float):
- self._delay = delay
-
- def getDelay(self) -> float:
- return self._delay
-
- def getDelayForView(self, view: Any) -> int:
- if self._order == LayoutAnimationController.ORDER_NORMAL:
- return 0
- elif self._order == LayoutAnimationController.ORDER_REVERSE:
- return 0
- elif self._order == LayoutAnimationController.ORDER_RANDOM:
- import random
- return int(random.random() * self._max_delay)
- return 0
-
- def willOverlap(self) -> bool:
- return self._delay < 1.0
-
- def start(self):
- self._initialized = True
-
- def isDone(self) -> bool:
- return True
-
- def getAnimationForView(self, view: Any) -> Optional[Animation]:
- return self._animation
-
- def setInitialized(self, initialized: bool):
- self._initialized = initialized
-
-
-# ═══════════════════════════════════════════════════════════════
-# GridLayoutAnimationController
-# ═══════════════════════════════════════════════════════════════
-
-class GridLayoutAnimationController(LayoutAnimationController):
- """GridLayoutAnimationController — 网格布局动画控制器"""
-
- DIRECTION_LEFT_TO_RIGHT = 0x0
- DIRECTION_RIGHT_TO_LEFT = 0x1
- DIRECTION_TOP_TO_BOTTOM = 0x2
- DIRECTION_BOTTOM_TO_TOP = 0x3
- DIRECTION_HORIZONTAL_MASK = 0x1
- DIRECTION_VERTICAL_MASK = 0x2
-
- def __init__(self, animation: Optional[Animation] = None):
- super().__init__(animation)
- self._column_delay: float = 0.5
- self._row_delay: float = 0.5
- self._direction: int = GridLayoutAnimationController.DIRECTION_LEFT_TO_RIGHT
- self._columns: int = 1
- self._rows: int = 1
-
- def setColumnDelay(self, column_delay: float):
- self._column_delay = column_delay
-
- def getColumnDelay(self) -> float:
- return self._column_delay
-
- def setRowDelay(self, row_delay: float):
- self._row_delay = row_delay
-
- def getRowDelay(self) -> float:
- return self._row_delay
-
- def setDirection(self, direction: int):
- self._direction = direction
-
- def getDirection(self) -> int:
- return self._direction
-
- def setColumns(self, columns: int):
- self._columns = columns
-
- def getColumns(self) -> int:
- return self._columns
-
- def setRows(self, rows: int):
- self._rows = rows
-
- def getRows(self) -> int:
- return self._rows
-
- def getDelayForView(self, view: Any) -> int:
- duration = 0
- if self._animation:
- duration = self._animation.getDuration()
- return int(duration * self._column_delay)
-
- def willOverlap(self) -> bool:
- return self._column_delay < 1.0 or self._row_delay < 1.0
-
- def getAnimationForView(self, view: Any) -> Optional[Animation]:
- return self._animation
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "Animation",
- "AnimationSet",
- "AlphaAnimation",
- "ScaleAnimation",
- "TranslateAnimation",
- "RotateAnimation",
- "AnimationUtils",
- "Interpolator",
- "AccelerateInterpolator",
- "DecelerateInterpolator",
- "AccelerateDecelerateInterpolator",
- "LinearInterpolator",
- "OvershootInterpolator",
- "AnticipateInterpolator",
- "AnticipateOvershootInterpolator",
- "BounceInterpolator",
- "CycleInterpolator",
- "PathInterpolator",
- "Transformation",
- "LayoutAnimationController",
- "GridLayoutAnimationController",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/view_animator.py b/android_pyapi/android/view_animator.py
deleted file mode 100644
index b7a3816..0000000
--- a/android_pyapi/android/view_animator.py
+++ /dev/null
@@ -1,887 +0,0 @@
-"""
-Android View Animator 组件 — LayoutAnimationController, AnimationUtils,
-AnimationSet, Interpolator 系列, RotateAnimation, ScaleAnimation,
-TranslateAnimation, AlphaAnimation, GridLayoutAnimationController 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import time
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-__all__ = [
- "LayoutAnimationController", "AnimationUtils", "AnimationSet",
- "AnimationScale", "AnimationInterpolator", "CycleInterpolator",
- "AccelerateInterpolator", "DecelerateInterpolator",
- "AccelerateDecelerateInterpolator", "AnticipateInterpolator",
- "OvershootInterpolator", "AnticipateOvershootInterpolator",
- "BounceInterpolator", "LinearInterpolator", "PathInterpolator",
- "RotateAnimation", "ScaleAnimation", "TranslateAnimation",
- "AlphaAnimation", "AnimationDescription",
- "GridLayoutAnimationController",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 常量
-# ═══════════════════════════════════════════════════════════════
-
-INFINITE = -1
-RESTART = 1
-REVERSE = 2
-
-ZORDER_NORMAL = 0
-ZORDER_TOP = 1
-ZORDER_BOTTOM = -1
-
-RELATIVE_TO_SELF = 0
-RELATIVE_TO_PARENT = 1
-
-FILL_AFTER = 1
-FILL_BEFORE = 2
-FILL_BOTH = 3
-
-START_ON_FIRST_FRAME = 4
-ABSOLUTE_TO_SELF = 8
-
-ANIMATION_STARTED = 0
-ANIMATION_RUNNING = 1
-ANIMATION_FILLED = 2
-ANIMATION_ENDED = 3
-ANIMATION_CANCELLED = 4
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimationInterpolator
-# ═══════════════════════════════════════════════════════════════
-
-class AnimationInterpolator(Stub):
- """AnimationInterpolator — 动画插值器基类"""
-
- def getInterpolation(self, input: float) -> float:
- return input
-
- def toString(self) -> str:
- return f"{self.__class__.__name__}@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-class LinearInterpolator(AnimationInterpolator):
- """LinearInterpolator — 线性插值器"""
-
- def getInterpolation(self, input: float) -> float:
- return input
-
- def toString(self) -> str:
- return "LinearInterpolator"
-
-
-class AccelerateInterpolator(AnimationInterpolator):
- """AccelerateInterpolator — 加速插值器"""
-
- def __init__(self, factor: float = 1.0):
- super().__init__()
- self._factor = factor
- self._double_factor = 2.0 * factor
-
- def getInterpolation(self, input: float) -> float:
- if self._factor == 1.0:
- return input * input
- return pow(input, self._double_factor)
-
- def toString(self) -> str:
- return f"AccelerateInterpolator(factor={self._factor})"
-
-
-class DecelerateInterpolator(AnimationInterpolator):
- """DecelerateInterpolator — 减速插值器"""
-
- def __init__(self, factor: float = 1.0):
- super().__init__()
- self._factor = factor
-
- def getInterpolation(self, input: float) -> float:
- if self._factor == 1.0:
- return 1.0 - (1.0 - input) * (1.0 - input)
- return 1.0 - pow(1.0 - input, 2.0 * self._factor)
-
- def toString(self) -> str:
- return f"DecelerateInterpolator(factor={self._factor})"
-
-
-class AccelerateDecelerateInterpolator(AnimationInterpolator):
- """AccelerateDecelerateInterpolator — 加速减速插值器"""
-
- def getInterpolation(self, input: float) -> float:
- return float(math.cos((input + 1.0) * math.pi) / 2.0 + 0.5)
-
- def toString(self) -> str:
- return "AccelerateDecelerateInterpolator"
-
-
-class AnticipateInterpolator(AnimationInterpolator):
- """AnticipateInterpolator — 预期插值器"""
-
- def __init__(self, tension: float = 2.0):
- super().__init__()
- self._tension = tension
-
- def getInterpolation(self, input: float) -> float:
- return input * input * ((self._tension + 1.0) * input - self._tension)
-
- def toString(self) -> str:
- return f"AnticipateInterpolator(tension={self._tension})"
-
-
-class OvershootInterpolator(AnimationInterpolator):
- """OvershootInterpolator — 超调插值器"""
-
- def __init__(self, tension: float = 2.0):
- super().__init__()
- self._tension = tension
-
- def getInterpolation(self, input: float) -> float:
- x = input - 1.0
- return x * x * ((self._tension + 1.0) * x + self._tension) + 1.0
-
- def toString(self) -> str:
- return f"OvershootInterpolator(tension={self._tension})"
-
-
-class AnticipateOvershootInterpolator(AnimationInterpolator):
- """AnticipateOvershootInterpolator — 预期超调插值器"""
-
- def __init__(self, tension: float = 2.0, extraTension: float = 1.5):
- super().__init__()
- self._tension = tension
- self._extra_tension = extraTension
-
- def getInterpolation(self, input: float) -> float:
- if input < 0.5:
- x = 2.0 * input
- return 0.5 * x * x * ((self._tension + 1.0) * x - self._tension)
- else:
- x = 2.0 * input - 2.0
- t = self._tension * self._extra_tension
- return 0.5 * (x * x * ((t + 1.0) * x + t) + 2.0)
-
- def toString(self) -> str:
- return f"AnticipateOvershootInterpolator(tension={self._tension})"
-
-
-class BounceInterpolator(AnimationInterpolator):
- """BounceInterpolator — 弹跳插值器"""
-
- def getInterpolation(self, input: float) -> float:
- x = input
- for i in range(4):
- duration = pow(2.0, -i) * 0.6
- if x < duration:
- scale = 0.5 / duration
- return scale * x * (duration - x) * 8.0 + (1.0 - 1.0 / pow(2.0, i))
- x -= duration
- return 0.0
-
- def toString(self) -> str:
- return "BounceInterpolator"
-
-
-class CycleInterpolator(AnimationInterpolator):
- """CycleInterpolator — 周期插值器"""
-
- def __init__(self, cycles: float = 1.0):
- super().__init__()
- self._cycles = cycles
-
- def getInterpolation(self, input: float) -> float:
- return float(math.sin(2.0 * math.pi * self._cycles * input))
-
- def toString(self) -> str:
- return f"CycleInterpolator(cycles={self._cycles})"
-
-
-class PathInterpolator(AnimationInterpolator):
- """PathInterpolator — 路径插值器"""
-
- def __init__(self, controlX1: float = 0.0, controlY1: float = 0.0,
- controlX2: float = 1.0, controlY2: float = 1.0):
- super().__init__()
- self._cx1 = controlX1
- self._cy1 = controlY1
- self._cx2 = controlX2
- self._cy2 = controlY2
-
- def getInterpolation(self, input: float) -> float:
- t = input
- return (1.0 - t) * (1.0 - t) * (1.0 - t) * 0.0 + \
- 3.0 * (1.0 - t) * (1.0 - t) * t * self._cy1 + \
- 3.0 * (1.0 - t) * t * t * self._cy2 + \
- t * t * t * 1.0
-
- def toString(self) -> str:
- return f"PathInterpolator({self._cx1}, {self._cy1}, {self._cx2}, {self._cy2})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimationScale
-# ═══════════════════════════════════════════════════════════════
-
-class AnimationScale(Stub):
- """AnimationScale — 动画缩放比例"""
-
- def __init__(self, scale: float = 1.0):
- super().__init__()
- self._scale = scale
-
- def getScale(self) -> float:
- return self._scale
-
- def setScale(self, scale: float):
- self._scale = max(0.0, scale)
-
- def toString(self) -> str:
- return f"AnimationScale(scale={self._scale})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimationSet
-# ═══════════════════════════════════════════════════════════════
-
-class AnimationSet(Stub):
- """AnimationSet — 动画集合"""
-
- def __init__(self, shareInterpolator: bool = True):
- super().__init__()
- self._share_interpolator = shareInterpolator
- self._animations: List[Any] = []
- self._interpolator: Optional[AnimationInterpolator] = None
- self._duration: int = 0
- self._fill_after = False
- self._fill_before = False
- self._repeat_count = 0
- self._repeat_mode = RESTART
- self._start_offset = 0
- self._start_time = -1
-
- def addAnimation(self, animation: Any):
- self._animations.append(animation)
-
- def getAnimations(self) -> List[Any]:
- return list(self._animations)
-
- def setDuration(self, duration: int):
- self._duration = duration
- for anim in self._animations:
- if hasattr(anim, 'setDuration'):
- anim.setDuration(duration)
-
- def getDuration(self) -> int:
- return self._duration
-
- def setInterpolator(self, interpolator: AnimationInterpolator):
- self._interpolator = interpolator
- if self._share_interpolator:
- for anim in self._animations:
- if hasattr(anim, 'setInterpolator'):
- anim.setInterpolator(interpolator)
-
- def getInterpolator(self) -> Optional[AnimationInterpolator]:
- return self._interpolator
-
- def setFillAfter(self, fill: bool):
- self._fill_after = fill
-
- def isFillAfter(self) -> bool:
- return self._fill_after
-
- def setFillBefore(self, fill: bool):
- self._fill_before = fill
-
- def isFillBefore(self) -> bool:
- return self._fill_before
-
- def setRepeatCount(self, count: int):
- self._repeat_count = count
-
- def getRepeatCount(self) -> int:
- return self._repeat_count
-
- def setRepeatMode(self, mode: int):
- self._repeat_mode = mode
-
- def getRepeatMode(self) -> int:
- return self._repeat_mode
-
- def setStartOffset(self, offset: int):
- self._start_offset = offset
-
- def getStartOffset(self) -> int:
- return self._start_offset
-
- def start(self):
- self._start_time = int(time.time() * 1000)
-
- def cancel(self):
- self._start_time = -1
-
- def isRunning(self) -> bool:
- return self._start_time >= 0
-
- def hasStarted(self) -> bool:
- return self._start_time >= 0
-
- def toString(self) -> str:
- return f"AnimationSet(animations={len(self._animations)}, duration={self._duration})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimationDescription
-# ═══════════════════════════════════════════════════════════════
-
-class AnimationDescription(Stub):
- """AnimationDescription — 动画描述"""
-
- def __init__(self, name: str = "", duration: int = 300,
- interpolator: Optional[AnimationInterpolator] = None,
- fillAfter: bool = False, repeatCount: int = 0):
- super().__init__()
- self._name = name
- self._duration = duration
- self._interpolator = interpolator or LinearInterpolator()
- self._fill_after = fillAfter
- self._repeat_count = repeatCount
-
- def getName(self) -> str:
- return self._name
-
- def getDuration(self) -> int:
- return self._duration
-
- def getInterpolator(self) -> AnimationInterpolator:
- return self._interpolator
-
- def isFillAfter(self) -> bool:
- return self._fill_after
-
- def getRepeatCount(self) -> int:
- return self._repeat_count
-
- def toString(self) -> str:
- return f"AnimationDescription(name={self._name}, duration={self._duration})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RotateAnimation
-# ═══════════════════════════════════════════════════════════════
-
-class RotateAnimation(Stub):
- """RotateAnimation — 旋转动画"""
-
- def __init__(self, fromDegrees: float = 0.0, toDegrees: float = 360.0,
- pivotX: float = 0.0, pivotY: float = 0.0,
- pivotXType: int = RELATIVE_TO_SELF,
- pivotYType: int = RELATIVE_TO_SELF):
- super().__init__()
- self._from_degrees = fromDegrees
- self._to_degrees = toDegrees
- self._pivot_x = pivotX
- self._pivot_y = pivotY
- self._pivot_x_type = pivotXType
- self._pivot_y_type = pivotYType
- self._duration = 300
- self._interpolator: Optional[AnimationInterpolator] = None
- self._repeat_count = 0
- self._repeat_mode = RESTART
- self._fill_after = False
- self._fill_before = False
- self._start_offset = 0
- self._start_time = -1
-
- def getFromDegrees(self) -> float:
- return self._from_degrees
-
- def getToDegrees(self) -> float:
- return self._to_degrees
-
- def getPivotX(self) -> float:
- return self._pivot_x
-
- def getPivotY(self) -> float:
- return self._pivot_y
-
- def getPivotXType(self) -> int:
- return self._pivot_x_type
-
- def getPivotYType(self) -> int:
- return self._pivot_y_type
-
- def setDuration(self, duration: int):
- self._duration = duration
-
- def getDuration(self) -> int:
- return self._duration
-
- def setInterpolator(self, interpolator: AnimationInterpolator):
- self._interpolator = interpolator
-
- def getInterpolator(self) -> Optional[AnimationInterpolator]:
- return self._interpolator
-
- def setRepeatCount(self, count: int):
- self._repeat_count = count
-
- def getRepeatCount(self) -> int:
- return self._repeat_count
-
- def setRepeatMode(self, mode: int):
- self._repeat_mode = mode
-
- def getRepeatMode(self) -> int:
- return self._repeat_mode
-
- def setFillAfter(self, fill: bool):
- self._fill_after = fill
-
- def isFillAfter(self) -> bool:
- return self._fill_after
-
- def setFillBefore(self, fill: bool):
- self._fill_before = fill
-
- def isFillBefore(self) -> bool:
- return self._fill_before
-
- def setStartOffset(self, offset: int):
- self._start_offset = offset
-
- def start(self):
- self._start_time = int(time.time() * 1000)
-
- def cancel(self):
- self._start_time = -1
-
- def toString(self) -> str:
- return (f"RotateAnimation(from={self._from_degrees}, to={self._to_degrees}, "
- f"duration={self._duration})")
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScaleAnimation
-# ═══════════════════════════════════════════════════════════════
-
-class ScaleAnimation(Stub):
- """ScaleAnimation — 缩放动画"""
-
- def __init__(self, fromX: float = 0.0, toX: float = 1.0,
- fromY: float = 0.0, toY: float = 1.0,
- pivotX: float = 0.0, pivotY: float = 0.0,
- pivotXType: int = RELATIVE_TO_SELF,
- pivotYType: int = RELATIVE_TO_SELF):
- super().__init__()
- self._from_x = fromX
- self._to_x = toX
- self._from_y = fromY
- self._to_y = toY
- self._pivot_x = pivotX
- self._pivot_y = pivotY
- self._pivot_x_type = pivotXType
- self._pivot_y_type = pivotYType
- self._duration = 300
- self._interpolator: Optional[AnimationInterpolator] = None
- self._repeat_count = 0
- self._fill_after = False
- self._start_time = -1
-
- def getFromX(self) -> float:
- return self._from_x
-
- def getToX(self) -> float:
- return self._to_x
-
- def getFromY(self) -> float:
- return self._from_y
-
- def getToY(self) -> float:
- return self._to_y
-
- def getPivotX(self) -> float:
- return self._pivot_x
-
- def getPivotY(self) -> float:
- return self._pivot_y
-
- def setDuration(self, duration: int):
- self._duration = duration
-
- def getDuration(self) -> int:
- return self._duration
-
- def setInterpolator(self, interpolator: AnimationInterpolator):
- self._interpolator = interpolator
-
- def getInterpolator(self) -> Optional[AnimationInterpolator]:
- return self._interpolator
-
- def setRepeatCount(self, count: int):
- self._repeat_count = count
-
- def setFillAfter(self, fill: bool):
- self._fill_after = fill
-
- def start(self):
- self._start_time = int(time.time() * 1000)
-
- def cancel(self):
- self._start_time = -1
-
- def toString(self) -> str:
- return (f"ScaleAnimation(x={self._from_x}->{self._to_x}, "
- f"y={self._from_y}->{self._to_y})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# TranslateAnimation (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class TranslateAnimation(Stub):
- """TranslateAnimation — 位移动画 (完整版)"""
-
- def __init__(self, fromX: float = 0.0, toX: float = 0.0,
- fromY: float = 0.0, toY: float = 0.0,
- fromXType: int = RELATIVE_TO_SELF,
- toXType: int = RELATIVE_TO_SELF,
- fromYType: int = RELATIVE_TO_SELF,
- toYType: int = RELATIVE_TO_SELF):
- super().__init__()
- self._from_x = fromX
- self._to_x = toX
- self._from_y = fromY
- self._to_y = toY
- self._from_x_type = fromXType
- self._to_x_type = toXType
- self._from_y_type = fromYType
- self._to_y_type = toYType
- self._duration = 300
- self._interpolator: Optional[AnimationInterpolator] = None
- self._repeat_count = 0
- self._fill_after = False
- self._start_time = -1
-
- def getFromX(self) -> float:
- return self._from_x
-
- def getToX(self) -> float:
- return self._to_x
-
- def getFromY(self) -> float:
- return self._from_y
-
- def getToY(self) -> float:
- return self._to_y
-
- def setDuration(self, duration: int):
- self._duration = duration
-
- def getDuration(self) -> int:
- return self._duration
-
- def setInterpolator(self, interpolator: AnimationInterpolator):
- self._interpolator = interpolator
-
- def setRepeatCount(self, count: int):
- self._repeat_count = count
-
- def setFillAfter(self, fill: bool):
- self._fill_after = fill
-
- def start(self):
- self._start_time = int(time.time() * 1000)
-
- def cancel(self):
- self._start_time = -1
-
- def hasStarted(self) -> bool:
- return self._start_time >= 0
-
- def toString(self) -> str:
- return (f"TranslateAnimation(x={self._from_x}->{self._to_x}, "
- f"y={self._from_y}->{self._to_y})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# AlphaAnimation (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class AlphaAnimation(Stub):
- """AlphaAnimation — 透明度动画 (完整版)"""
-
- def __init__(self, fromAlpha: float = 0.0, toAlpha: float = 1.0):
- super().__init__()
- self._from_alpha = fromAlpha
- self._to_alpha = toAlpha
- self._duration = 300
- self._interpolator: Optional[AnimationInterpolator] = None
- self._repeat_count = 0
- self._fill_after = False
- self._start_time = -1
-
- def getFromAlpha(self) -> float:
- return self._from_alpha
-
- def getToAlpha(self) -> float:
- return self._to_alpha
-
- def setDuration(self, duration: int):
- self._duration = duration
-
- def getDuration(self) -> int:
- return self._duration
-
- def setInterpolator(self, interpolator: AnimationInterpolator):
- self._interpolator = interpolator
-
- def getInterpolator(self) -> Optional[AnimationInterpolator]:
- return self._interpolator
-
- def setRepeatCount(self, count: int):
- self._repeat_count = count
-
- def setFillAfter(self, fill: bool):
- self._fill_after = fill
-
- def start(self):
- self._start_time = int(time.time() * 1000)
-
- def cancel(self):
- self._start_time = -1
-
- def hasStarted(self) -> bool:
- return self._start_time >= 0
-
- def toString(self) -> str:
- return f"AlphaAnimation(from={self._from_alpha}, to={self._to_alpha})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LayoutAnimationController
-# ═══════════════════════════════════════════════════════════════
-
-class LayoutAnimationController(Stub):
- """LayoutAnimationController — 布局动画控制器"""
-
- ORDER_NORMAL = 0
- ORDER_REVERSE = 1
- ORDER_RANDOM = 2
-
- def __init__(self, animation: Optional[AnimationDescription] = None,
- delay: float = 0.5, order: int = ORDER_NORMAL):
- super().__init__()
- self._animation = animation
- self._delay = delay
- self._order = order
- self._interpolator: Optional[AnimationInterpolator] = None
-
- def getAnimation(self) -> Optional[AnimationDescription]:
- return self._animation
-
- def setAnimation(self, animation: AnimationDescription):
- self._animation = animation
-
- def getDelay(self) -> float:
- return self._delay
-
- def setDelay(self, delay: float):
- self._delay = delay
-
- def getOrder(self) -> int:
- return self._order
-
- def setOrder(self, order: int):
- self._order = order
-
- def setInterpolator(self, interpolator: AnimationInterpolator):
- self._interpolator = interpolator
-
- def getInterpolator(self) -> Optional[AnimationInterpolator]:
- return self._interpolator
-
- def isEnabled(self) -> bool:
- return self._animation is not None
-
- def toString(self) -> str:
- return f"LayoutAnimationController(delay={self._delay})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# GridLayoutAnimationController
-# ═══════════════════════════════════════════════════════════════
-
-class GridLayoutAnimationController(LayoutAnimationController):
- """GridLayoutAnimationController — 网格布局动画控制器"""
-
- DIRECTION_LEFT_TO_RIGHT = 0
- DIRECTION_RIGHT_TO_LEFT = 1
- DIRECTION_TOP_TO_BOTTOM = 2
- DIRECTION_BOTTOM_TO_TOP = 3
-
- DIRECTION_HORIZONTAL_MASK = 1
- DIRECTION_VERTICAL_MASK = 2
-
- PRIORITY_NONE = 0
- PRIORITY_COLUMN = 1
- PRIORITY_ROW = 2
-
- def __init__(self, animation: Optional[AnimationDescription] = None,
- columnDelay: float = 0.5, rowDelay: float = 0.5,
- direction: int = DIRECTION_LEFT_TO_RIGHT,
- directionPriority: int = PRIORITY_NONE):
- super().__init__(animation=animation, delay=0.5)
- self._column_delay = columnDelay
- self._row_delay = rowDelay
- self._direction = direction
- self._direction_priority = directionPriority
-
- def getColumnDelay(self) -> float:
- return self._column_delay
-
- def setColumnDelay(self, delay: float):
- self._column_delay = delay
-
- def getRowDelay(self) -> float:
- return self._row_delay
-
- def setRowDelay(self, delay: float):
- self._row_delay = delay
-
- def getDirection(self) -> int:
- return self._direction
-
- def setDirection(self, direction: int):
- self._direction = direction
-
- def getDirectionPriority(self) -> int:
- return self._direction_priority
-
- def setDirectionPriority(self, priority: int):
- self._direction_priority = priority
-
- def toString(self) -> str:
- return f"GridLayoutAnimationController(colDelay={self._column_delay})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnimationUtils
-# ═══════════════════════════════════════════════════════════════
-
-class AnimationUtils(Stub):
- """AnimationUtils — 动画工具类"""
-
- @staticmethod
- def currentAnimationTimeMillis() -> int:
- return int(time.time() * 1000)
-
- @staticmethod
- def loadAnimation(context: Any, id: int) -> Optional[AnimationDescription]:
- return None
-
- @staticmethod
- def loadInterpolator(context: Any, id: int) -> Optional[AnimationInterpolator]:
- return None
-
- @staticmethod
- def makeInAnimation(context: Any, fromLeft: bool = True) -> TranslateAnimation:
- x = -1.0 if fromLeft else 1.0
- anim = TranslateAnimation(fromX=x, toX=0.0, fromXType=RELATIVE_TO_PARENT,
- toXType=RELATIVE_TO_PARENT)
- anim.setDuration(300)
- anim.setInterpolator(DecelerateInterpolator())
- return anim
-
- @staticmethod
- def makeOutAnimation(context: Any, toRight: bool = True) -> TranslateAnimation:
- x = 1.0 if toRight else -1.0
- anim = TranslateAnimation(fromX=0.0, toX=x, fromXType=RELATIVE_TO_PARENT,
- toXType=RELATIVE_TO_PARENT)
- anim.setDuration(300)
- anim.setInterpolator(AccelerateInterpolator())
- return anim
-
- @staticmethod
- def makeInChildBottomAnimation(context: Any) -> TranslateAnimation:
- anim = TranslateAnimation(fromX=0.0, toX=0.0,
- fromY=1.0, toY=0.0,
- fromYType=RELATIVE_TO_PARENT,
- toYType=RELATIVE_TO_PARENT)
- anim.setDuration(300)
- anim.setInterpolator(DecelerateInterpolator())
- return anim
-
- @staticmethod
- def createScaleUpAnimation(context: Any) -> ScaleAnimation:
- anim = ScaleAnimation(fromX=0.0, toX=1.0, fromY=0.0, toY=1.0,
- pivotX=0.5, pivotY=0.5,
- pivotXType=RELATIVE_TO_SELF,
- pivotYType=RELATIVE_TO_SELF)
- anim.setDuration(300)
- anim.setInterpolator(AccelerateDecelerateInterpolator())
- return anim
-
- @staticmethod
- def createShrinkDownAnimation(context: Any) -> ScaleAnimation:
- anim = ScaleAnimation(fromX=1.0, toX=0.0, fromY=1.0, toY=0.0,
- pivotX=0.5, pivotY=0.5,
- pivotXType=RELATIVE_TO_SELF,
- pivotYType=RELATIVE_TO_SELF)
- anim.setDuration(300)
- anim.setInterpolator(AccelerateDecelerateInterpolator())
- return anim
-
- @staticmethod
- def createFadeInAnimation(context: Any) -> AlphaAnimation:
- anim = AlphaAnimation(fromAlpha=0.0, toAlpha=1.0)
- anim.setDuration(300)
- return anim
-
- @staticmethod
- def createFadeOutAnimation(context: Any) -> AlphaAnimation:
- anim = AlphaAnimation(fromAlpha=1.0, toAlpha=0.0)
- anim.setDuration(300)
- return anim
-
- @staticmethod
- def createRotateAnimation(context: Any, fromDeg: float = 0.0,
- toDeg: float = 360.0) -> RotateAnimation:
- anim = RotateAnimation(fromDegrees=fromDeg, toDegrees=toDeg,
- pivotX=0.5, pivotY=0.5)
- anim.setDuration(500)
- return anim
-
- def toString(self) -> str:
- return "AnimationUtils"
\ No newline at end of file
diff --git a/android_pyapi/android/view_autofill.py b/android_pyapi/android/view_autofill.py
deleted file mode 100644
index b721ea9..0000000
--- a/android_pyapi/android/view_autofill.py
+++ /dev/null
@@ -1,313 +0,0 @@
-"""
-Android view.autofill 组件 — AutofillManager, AutofillValue, AutofillId 等
-方法签名完全对齐 Android SDK
-"""
-
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# AutofillManager
-# ═══════════════════════════════════════════════════════════════
-
-class AutofillManager(Stub):
- """AutofillManager — 自动填充管理器"""
-
- # ═══════════════════════════════════════════════════════════
- # AutofillCallback
- # ═══════════════════════════════════════════════════════════
-
- class AutofillCallback(Stub):
- """AutofillManager.AutofillCallback — 自动填充回调"""
-
- def onAutofillEvent(self, view: Any, event: int):
- pass
-
- def onAutofillUnavailableEvent(self, event: int):
- pass
-
- def onAuthenticationShowing(self):
- pass
-
- def __init__(self):
- super().__init__()
- self._enabled = False
- self._callbacks: List[AutofillManager.AutofillCallback] = []
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def hasEnabledAutofillServices(self) -> bool:
- return False
-
- def isAutofillSupported(self) -> bool:
- return False
-
- def disableAutofillServices(self):
- self._enabled = False
-
- def notifyValueChanged(self, view: Any):
- pass
-
- def commit(self):
- pass
-
- def cancel(self):
- pass
-
- def requestAutofill(self, view: Any):
- pass
-
- def getAutofillServiceComponentName(self) -> Any:
- return None
-
- def getAutofillServiceLabel(self) -> str:
- return ""
-
- def getAvailableFieldClassificationAlgorithms(self) -> List[str]:
- return []
-
- def getDefaultFieldClassificationAlgorithm(self) -> Optional[str]:
- return None
-
- def getFillEventHistory(self) -> Optional["FillEventHistory"]:
- return None
-
- def onAuthenticationResult(self, authenticationResult: Any):
- pass
-
- def onAuthenticationFailed(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# AutofillValue
-# ═══════════════════════════════════════════════════════════════
-
-class AutofillValue(Stub):
- """AutofillValue — 自动填充值"""
-
- def __init__(self):
- super().__init__()
- self._text_value: Optional[str] = None
- self._date_value: Optional[int] = None
- self._toggle_value: Optional[bool] = None
- self._list_value: Optional[int] = None
- self._is_text = False
- self._is_date = False
- self._is_toggle = False
- self._is_list = False
-
- @staticmethod
- def forText(value: str) -> "AutofillValue":
- v = AutofillValue()
- v._text_value = value
- v._is_text = True
- return v
-
- @staticmethod
- def forDate(value: int) -> "AutofillValue":
- v = AutofillValue()
- v._date_value = value
- v._is_date = True
- return v
-
- @staticmethod
- def forToggle(value: bool) -> "AutofillValue":
- v = AutofillValue()
- v._toggle_value = value
- v._is_toggle = True
- return v
-
- @staticmethod
- def forList(value: int) -> "AutofillValue":
- v = AutofillValue()
- v._list_value = value
- v._is_list = True
- return v
-
- def getTextValue(self) -> Optional[str]:
- return self._text_value
-
- def getDateValue(self) -> Optional[int]:
- return self._date_value
-
- def getToggleValue(self) -> Optional[bool]:
- return self._toggle_value
-
- def getListValue(self) -> Optional[int]:
- return self._list_value
-
- def isText(self) -> bool:
- return self._is_text
-
- def isDate(self) -> bool:
- return self._is_date
-
- def isToggle(self) -> bool:
- return self._is_toggle
-
- def isList(self) -> bool:
- return self._is_list
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AutofillValue):
- return False
- return (self._text_value == other._text_value
- and self._date_value == other._date_value
- and self._toggle_value == other._toggle_value
- and self._list_value == other._list_value)
-
- def hashCode(self) -> int:
- return hash((self._text_value, self._date_value,
- self._toggle_value, self._list_value)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- if self._is_text:
- return f"AutofillValue(text={self._text_value})"
- if self._is_date:
- return f"AutofillValue(date={self._date_value})"
- if self._is_toggle:
- return f"AutofillValue(toggle={self._toggle_value})"
- if self._is_list:
- return f"AutofillValue(list={self._list_value})"
- return "AutofillValue(empty)"
-
-
-# ═══════════════════════════════════════════════════════════════
-# AutofillId
-# ═══════════════════════════════════════════════════════════════
-
-class AutofillId(Stub):
- """AutofillId — 自动填充 ID"""
-
- FLAG_AUTOFILL_SESSION_SUPPORTS_INDEXING = 1
- FLAG_AUTOFILL_SESSION_SUPPORTS_AUGMENTED_AUTOFILL = 2
-
- def __init__(self, viewId: int = 0, sessionId: int = 0,
- virtualChildId: int = -1, virtualIntId: int = -1):
- super().__init__()
- self._view_id = viewId
- self._session_id = sessionId
- self._virtual_child_id = virtualChildId
- self._virtual_int_id = virtualIntId
-
- def getViewId(self) -> int:
- return self._view_id
-
- def getSessionId(self) -> int:
- return self._session_id
-
- def getVirtualChildId(self) -> int:
- return self._virtual_child_id
-
- def getVirtualIntId(self) -> int:
- return self._virtual_int_id
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, AutofillId):
- return False
- return (self._view_id == other._view_id
- and self._session_id == other._session_id
- and self._virtual_child_id == other._virtual_child_id)
-
- def hashCode(self) -> int:
- return hash((self._view_id, self._session_id,
- self._virtual_child_id)) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return f"AutofillId(viewId={self._view_id}, sessionId={self._session_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FillEventHistory
-# ═══════════════════════════════════════════════════════════════
-
-class FillEventHistory(Stub):
- """FillEventHistory — 填充事件历史"""
-
- def __init__(self):
- super().__init__()
- self._events: List[Any] = []
- self._client_state: Any = None
-
- def getEvents(self) -> List[Any]:
- return self._events
-
- def getClientState(self) -> Any:
- return self._client_state
-
-
-# ═══════════════════════════════════════════════════════════════
-# FillContext
-# ═══════════════════════════════════════════════════════════════
-
-class FillContext(Stub):
- """FillContext — 填充上下文"""
-
- def __init__(self, requestId: int = 0, autofillId: Optional[AutofillId] = None,
- focusedId: Optional[AutofillId] = None,
- focusedVirtualId: int = -1, extras: Any = None,
- autofillValue: Optional[AutofillValue] = None,
- visibility: Optional[int] = None,
- options: Optional[List[Any]] = None):
- super().__init__()
- self._request_id = requestId
- self._autofill_id = autofillId
- self._focused_id = focusedId
- self._focused_virtual_id = focusedVirtualId
- self._extras = extras
- self._autofill_value = autofillValue
- self._visibility = visibility
- self._options = options
-
- def getRequestId(self) -> int:
- return self._request_id
-
- def getAutofillId(self) -> Optional[AutofillId]:
- return self._autofill_id
-
- def getFocusedId(self) -> Optional[AutofillId]:
- return self._focused_id
-
- def getFocusedVirtualId(self) -> int:
- return self._focused_virtual_id
-
- def getExtras(self) -> Any:
- return self._extras
-
- def getAutofillValue(self) -> Optional[AutofillValue]:
- return self._autofill_value
-
- def getVisibility(self) -> Optional[int]:
- return self._visibility
-
- def getOptions(self) -> Optional[List[Any]]:
- return self._options
-
-
-# ═══════════════════════════════════════════════════════════════
-# AugmentedAutofillManager (stub)
-# ═══════════════════════════════════════════════════════════════
-
-class AugmentedAutofillManager(Stub):
- """AugmentedAutofillManager — 增强自动填充管理器"""
-
- def __init__(self):
- super().__init__()
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "AutofillManager",
- "AutofillValue",
- "AutofillId",
- "FillEventHistory",
- "FillContext",
- "AugmentedAutofillManager",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/view_dragndrop.py b/android_pyapi/android/view_dragndrop.py
deleted file mode 100644
index 8a20ef6..0000000
--- a/android_pyapi/android/view_dragndrop.py
+++ /dev/null
@@ -1,248 +0,0 @@
-"""
-Android DragAndDrop 组件 — DragAndDropPermissions, ClipData, ClipDescription
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# MIME 类型常量
-# ═══════════════════════════════════════════════════════════════
-
-MIMETYPE_TEXT_PLAIN = "text/plain"
-MIMETYPE_TEXT_HTML = "text/html"
-MIMETYPE_TEXT_URILIST = "text/uri-list"
-MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"
-MIMETYPE_IMAGE_PNG = "image/png"
-MIMETYPE_IMAGE_JPEG = "image/jpeg"
-MIMETYPE_IMAGE_GIF = "image/gif"
-MIMETYPE_IMAGE_WEBP = "image/webp"
-MIMETYPE_IMAGE_BMP = "image/bmp"
-MIMETYPE_VIDEO_MP4 = "video/mp4"
-MIMETYPE_VIDEO_3GP = "video/3gpp"
-MIMETYPE_AUDIO_MP3 = "audio/mpeg"
-MIMETYPE_AUDIO_AAC = "audio/mp4a-latm"
-MIMETYPE_APPLICATION_PDF = "application/pdf"
-MIMETYPE_APPLICATION_ZIP = "application/zip"
-MIMETYPE_APPLICATION_JSON = "application/json"
-MIMETYPE_APPLICATION_XML = "application/xml"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ClipDescription
-# ═══════════════════════════════════════════════════════════════
-
-class ClipDescription(Stub):
- """ClipDescription — 剪贴板数据描述"""
-
- MIMETYPE_TEXT_PLAIN = MIMETYPE_TEXT_PLAIN
- MIMETYPE_TEXT_HTML = MIMETYPE_TEXT_HTML
- MIMETYPE_TEXT_URILIST = MIMETYPE_TEXT_URILIST
- MIMETYPE_TEXT_INTENT = MIMETYPE_TEXT_INTENT
-
- def __init__(self, label: str, mime_types: List[str]):
- super().__init__()
- self._label = label
- self._mime_types: List[str] = list(mime_types)
- self._extras: Optional[Any] = None
- self._timestamp: int = 0
-
- @staticmethod
- def compareMimeTypes(mime_type1: str, mime_type2: str) -> bool:
- """比较两个 MIME 类型是否匹配"""
- if mime_type1 == mime_type2:
- return True
- if mime_type1 == "*/*" or mime_type2 == "*/*":
- return True
- t1 = mime_type1.split("/")[0] if "/" in mime_type1 else ""
- t2 = mime_type2.split("/")[0] if "/" in mime_type2 else ""
- if t1 and t1 == t2:
- if mime_type1.endswith("/*") or mime_type2.endswith("/*"):
- return True
- return False
-
- def getLabel(self) -> str:
- return self._label
-
- def getMimeType(self, index: int) -> str:
- if 0 <= index < len(self._mime_types):
- return self._mime_types[index]
- return ""
-
- def getMimeTypeCount(self) -> int:
- return len(self._mime_types)
-
- def hasMimeType(self, mime_type: str) -> bool:
- for mt in self._mime_types:
- if ClipDescription.compareMimeTypes(mt, mime_type):
- return True
- return False
-
- def filterMimeTypes(self, mime_type: str) -> List[str]:
- result = []
- for mt in self._mime_types:
- if ClipDescription.compareMimeTypes(mt, mime_type):
- result.append(mt)
- return result
-
- def setExtras(self, extras: Any) -> None:
- self._extras = extras
-
- def getExtras(self) -> Optional[Any]:
- return self._extras
-
- def getTimestamp(self) -> int:
- return self._timestamp
-
- def setTimestamp(self, ts: int) -> None:
- self._timestamp = ts
-
- def toString(self) -> str:
- return (f"ClipDescription(label={self._label}, "
- f"mimeTypes={self._mime_types})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ClipData.Item
-# ═══════════════════════════════════════════════════════════════
-
-class ClipItem(Stub):
- """ClipData.Item — 剪贴板数据项"""
-
- def __init__(self, text: Optional[str] = None,
- intent: Optional[Any] = None,
- uri: Optional[str] = None,
- html_text: Optional[str] = None):
- super().__init__()
- self._text = text
- self._intent = intent
- self._uri = uri
- self._html_text = html_text
-
- def getText(self) -> Optional[str]:
- return self._text
-
- def getIntent(self) -> Optional[Any]:
- return self._intent
-
- def getUri(self) -> Optional[str]:
- return self._uri
-
- def getHtmlText(self) -> Optional[str]:
- return self._html_text
-
- def coerceToText(self, context: Any) -> str:
- if self._text:
- return self._text
- if self._uri:
- return str(self._uri)
- if self._intent:
- return str(self._intent)
- return ""
-
- def coerceToHtmlText(self, context: Any) -> Optional[str]:
- return self._html_text
-
- def coerceToStyledText(self, context: Any) -> Optional[str]:
- return self.coerceToText(context)
-
- def toString(self) -> str:
- return (f"ClipData.Item(text={self._text}, "
- f"uri={self._uri})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ClipData
-# ═══════════════════════════════════════════════════════════════
-
-class ClipData(Stub):
- """ClipData — 剪贴板数据"""
-
- Item = ClipItem
-
- def __init__(self, description: ClipDescription, item: ClipItem):
- super().__init__()
- self._description = description
- self._items: List[ClipItem] = [item]
-
- @staticmethod
- def newPlainText(label: str, text: str) -> "ClipData":
- desc = ClipDescription(label, [MIMETYPE_TEXT_PLAIN])
- item = ClipItem(text=text)
- return ClipData(desc, item)
-
- @staticmethod
- def newHtmlText(label: str, text: str, html_text: str) -> "ClipData":
- desc = ClipDescription(label, [MIMETYPE_TEXT_HTML, MIMETYPE_TEXT_PLAIN])
- item = ClipItem(text=text, html_text=html_text)
- return ClipData(desc, item)
-
- @staticmethod
- def newIntent(label: str, intent: Any) -> "ClipData":
- desc = ClipDescription(label, [MIMETYPE_TEXT_INTENT])
- item = ClipItem(intent=intent)
- return ClipData(desc, item)
-
- @staticmethod
- def newUri(cr: Any, label: str, uri: str) -> "ClipData":
- mime_type = MIMETYPE_TEXT_URILIST
- desc = ClipDescription(label, [mime_type])
- item = ClipItem(uri=uri)
- return ClipData(desc, item)
-
- @staticmethod
- def newRawUri(label: str, uri: str) -> "ClipData":
- desc = ClipDescription(label, [MIMETYPE_TEXT_URILIST])
- item = ClipItem(uri=uri)
- return ClipData(desc, item)
-
- def getDescription(self) -> ClipDescription:
- return self._description
-
- def addItem(self, item: ClipItem) -> None:
- self._items.append(item)
-
- def getItemAt(self, index: int) -> Optional[ClipItem]:
- if 0 <= index < len(self._items):
- return self._items[index]
- return None
-
- def getItemCount(self) -> int:
- return len(self._items)
-
- def toString(self) -> str:
- return (f"ClipData(desc={self._description}, "
- f"items={len(self._items)})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# DragAndDropPermissions
-# ═══════════════════════════════════════════════════════════════
-
-class DragAndDropPermissions(Stub):
- """DragAndDropPermissions — 拖放权限"""
-
- def __init__(self):
- super().__init__()
- self._granted_uris: List[str] = []
- self._released = False
-
- def release(self) -> None:
- self._released = True
- self._granted_uris.clear()
-
- def isReleased(self) -> bool:
- return self._released
-
- def getGrantedUris(self) -> List[str]:
- return list(self._granted_uris)
-
- def toString(self) -> str:
- return (f"DragAndDropPermissions(uris={len(self._granted_uris)}, "
- f"released={self._released})")
\ No newline at end of file
diff --git a/android_pyapi/android/view_ext.py b/android_pyapi/android/view_ext.py
deleted file mode 100644
index c942ad1..0000000
--- a/android_pyapi/android/view_ext.py
+++ /dev/null
@@ -1,2520 +0,0 @@
-"""
-Android View 扩展组件 — ViewOutlineProvider, ViewPropertyAnimator, ViewStructure 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import time
-import weakref
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-from .view import KeyEvent as _BaseKeyEvent
-from .view import ViewGroup as _BaseViewGroup
-from .view import View as _BaseView
-from .view import ViewOutlineProvider as _BaseViewOutlineProvider
-from .view import ViewPropertyAnimator as _BaseViewPropertyAnimator
-from .view import ViewTreeObserver as _BaseViewTreeObserver
-from .view import ViewConfiguration as _BaseViewConfiguration
-from .view import ViewParent as _BaseViewParent
-from .view import WindowInsets as _BaseWindowInsets
-from .view import Display as _BaseDisplay
-from .view import DragEvent as _BaseDragEvent
-from .view import GestureDetector as _BaseGestureDetector
-from .view import ScaleGestureDetector as _BaseScaleGestureDetector
-from .view import SoundEffectConstants as _BaseSoundEffectConstants
-from .view import Surface as _BaseSurface
-from .view import SurfaceView as _BaseSurfaceView
-from .view import TextureView as _BaseTextureView
-from .view import VelocityTracker as _BaseVelocityTracker
-from .view import WindowInsetsController as _BaseWindowInsetsController
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewOutlineProvider
-# ═══════════════════════════════════════════════════════════════
-
-class ViewOutlineProvider(_BaseViewOutlineProvider):
- """ViewOutlineProvider — 视图轮廓提供者 (继承 view.ViewOutlineProvider 的所有方法)"""
-
- BACKGROUND = None
- BOUNDS = None
- PADDED_BOUNDS = None
-
- def __init__(self):
- super().__init__()
-
- def getOutline(self, view: Any, outline: Any) -> None:
- """获取视图轮廓"""
- pass
-
-
-ViewOutlineProvider.BACKGROUND = ViewOutlineProvider()
-ViewOutlineProvider.BOUNDS = ViewOutlineProvider()
-ViewOutlineProvider.PADDED_BOUNDS = ViewOutlineProvider()
-
-
-class Outline(Stub):
- """Outline — 轮廓描述"""
-
- MODE_CONVEX_PATH = 2
- MODE_EMPTY = 0
- MODE_ROUND_RECT = 1
-
- def __init__(self):
- super().__init__()
- self._alpha: float = 1.0
- self._mode: int = self.MODE_EMPTY
- self._rect: Tuple[float, float, float, float] = (0, 0, 0, 0)
- self._radius: float = 0.0
-
- def setAlpha(self, alpha: float) -> None:
- self._alpha = max(0.0, min(1.0, alpha))
-
- def getAlpha(self) -> float:
- return self._alpha
-
- def setEmpty(self) -> None:
- self._mode = self.MODE_EMPTY
-
- def isEmpty(self) -> bool:
- return self._mode == self.MODE_EMPTY
-
- def setRoundRect(self, left: float, top: float, right: float, bottom: float,
- radius: float) -> None:
- self._mode = self.MODE_ROUND_RECT
- self._rect = (left, top, right, bottom)
- self._radius = radius
-
- def setOval(self, left: float, top: float, right: float, bottom: float) -> None:
- self._mode = self.MODE_ROUND_RECT
- self._rect = (left, top, right, bottom)
- self._radius = min(right - left, bottom - top) / 2.0
-
- def setConvexPath(self, path: Any) -> None:
- self._mode = self.MODE_CONVEX_PATH
-
- def getRect(self) -> Optional[Tuple[float, float, float, float]]:
- if self._mode == self.MODE_EMPTY:
- return None
- return self._rect
-
- def getRadius(self) -> float:
- return self._radius
-
- def canClip(self) -> bool:
- return self._mode in (self.MODE_ROUND_RECT, self.MODE_CONVEX_PATH)
-
- def toString(self) -> str:
- return (f"Outline(mode={self._mode}, alpha={self._alpha}, "
- f"radius={self._radius})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewPropertyAnimator
-# ═══════════════════════════════════════════════════════════════
-
-class ViewPropertyAnimator(_BaseViewPropertyAnimator):
- """ViewPropertyAnimator — 视图属性动画器 (继承 view.ViewPropertyAnimator 的所有方法)"""
-
- def __init__(self, view: Any = None):
- super().__init__()
- self._view = weakref.ref(view) if view is not None else None
- self._duration: int = 300
- self._start_delay: int = 0
- self._interpolator: Optional[Any] = None
- self._listener: Optional[Callable] = None
- self._translation_x: Optional[float] = None
- self._translation_y: Optional[float] = None
- self._translation_z: Optional[float] = None
- self._scale_x: Optional[float] = None
- self._scale_y: Optional[float] = None
- self._rotation: Optional[float] = None
- self._rotation_x: Optional[float] = None
- self._rotation_y: Optional[float] = None
- self._alpha: Optional[float] = None
- self._x: Optional[float] = None
- self._y: Optional[float] = None
- self._width: Optional[int] = None
- self._height: Optional[int] = None
- self._running = False
-
- def translationX(self, value: float) -> "ViewPropertyAnimator":
- self._translation_x = value
- return self
-
- def translationY(self, value: float) -> "ViewPropertyAnimator":
- self._translation_y = value
- return self
-
- def translationZ(self, value: float) -> "ViewPropertyAnimator":
- self._translation_z = value
- return self
-
- def rotation(self, value: float) -> "ViewPropertyAnimator":
- self._rotation = value
- return self
-
- def rotationX(self, value: float) -> "ViewPropertyAnimator":
- self._rotation_x = value
- return self
-
- def rotationY(self, value: float) -> "ViewPropertyAnimator":
- self._rotation_y = value
- return self
-
- def scaleX(self, value: float) -> "ViewPropertyAnimator":
- self._scale_x = value
- return self
-
- def scaleY(self, value: float) -> "ViewPropertyAnimator":
- self._scale_y = value
- return self
-
- def alpha(self, value: float) -> "ViewPropertyAnimator":
- self._alpha = max(0.0, min(1.0, value))
- return self
-
- def x(self, value: float) -> "ViewPropertyAnimator":
- self._x = value
- return self
-
- def y(self, value: float) -> "ViewPropertyAnimator":
- self._y = value
- return self
-
- def width(self, value: int) -> "ViewPropertyAnimator":
- self._width = value
- return self
-
- def height(self, value: int) -> "ViewPropertyAnimator":
- self._height = value
- return self
-
- def setDuration(self, duration: int) -> "ViewPropertyAnimator":
- self._duration = max(0, duration)
- return self
-
- def getDuration(self) -> int:
- return self._duration
-
- def setStartDelay(self, delay: int) -> "ViewPropertyAnimator":
- self._start_delay = max(0, delay)
- return self
-
- def getStartDelay(self) -> int:
- return self._start_delay
-
- def setInterpolator(self, interpolator: Any) -> "ViewPropertyAnimator":
- self._interpolator = interpolator
- return self
-
- def setListener(self, listener: Optional[Callable]) -> "ViewPropertyAnimator":
- self._listener = listener
- return self
-
- def withEndAction(self, action: Callable) -> "ViewPropertyAnimator":
- self._end_action = action
- return self
-
- def withStartAction(self, action: Callable) -> "ViewPropertyAnimator":
- self._start_action = action
- return self
-
- def start(self) -> None:
- if self._running:
- return
- self._running = True
- if self._start_action:
- self._start_action()
- if self._listener:
- self._listener.onAnimationStart(self)
- if self._alpha is not None and self._view:
- v = self._view()
- if v:
- v.setAlpha(self._alpha)
- if self._listener:
- self._listener.onAnimationEnd(self)
- if self._end_action:
- self._end_action()
-
- def cancel(self) -> None:
- self._running = False
- if self._listener:
- self._listener.onAnimationCancel(self)
-
- def isRunning(self) -> bool:
- return self._running
-
- def toString(self) -> str:
- return (f"ViewPropertyAnimator(duration={self._duration}, "
- f"running={self._running})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewStructure
-# ═══════════════════════════════════════════════════════════════
-
-class ViewStructure(Stub):
- """ViewStructure — 视图结构(用于 Assist/autofill)"""
-
- def __init__(self):
- super().__init__()
- self._text: Optional[str] = None
- self._hint: Optional[str] = None
- self._className: Optional[str] = None
- self._contentDescription: Optional[str] = None
- self._id: Optional[int] = None
- self._id_package: Optional[str] = None
- self._id_type: Optional[str] = None
- self._id_entry: Optional[str] = None
- self._web_domain: Optional[str] = None
- self._input_type: int = 0
- self._alpha: float = 1.0
- self._elevation: float = 0.0
- self._width: int = 0
- self._height: int = 0
- self._left: int = 0
- self._top: int = 0
- self._scroll_x: int = 0
- self._scroll_y: int = 0
- self._children: List[ViewStructure] = []
- self._html_info: Optional[Any] = None
- self._data_set: Optional[Any] = None
-
- def setText(self, text: str) -> None:
- self._text = text
-
- def getText(self) -> Optional[str]:
- return self._text
-
- def setHint(self, hint: str) -> None:
- self._hint = hint
-
- def getHint(self) -> Optional[str]:
- return self._hint
-
- def setClassName(self, class_name: str) -> None:
- self._className = class_name
-
- def getClassName(self) -> Optional[str]:
- return self._className
-
- def setContentDescription(self, desc: str) -> None:
- self._contentDescription = desc
-
- def getContentDescription(self) -> Optional[str]:
- return self._contentDescription
-
- def setId(self, id_val: int, package: str, type_name: str, entry: str) -> None:
- self._id = id_val
- self._id_package = package
- self._id_type = type_name
- self._id_entry = entry
-
- def getAutoFillId(self) -> Optional[int]:
- return self._id
-
- def setWebDomain(self, domain: str) -> None:
- self._web_domain = domain
-
- def getWebDomain(self) -> Optional[str]:
- return self._web_domain
-
- def setInputType(self, input_type: int) -> None:
- self._input_type = input_type
-
- def getInputType(self) -> int:
- return self._input_type
-
- def setAlpha(self, alpha: float) -> None:
- self._alpha = max(0.0, min(1.0, alpha))
-
- def getAlpha(self) -> float:
- return self._alpha
-
- def setElevation(self, elevation: float) -> None:
- self._elevation = elevation
-
- def getElevation(self) -> float:
- return self._elevation
-
- def setDimensions(self, width: int, height: int) -> None:
- self._width = width
- self._height = height
-
- def setDimens(self, left: int, top: int, scroll_x: int, scroll_y: int) -> None:
- self._left = left
- self._top = top
- self._scroll_x = scroll_x
- self._scroll_y = scroll_y
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getLeft(self) -> int:
- return self._left
-
- def getTop(self) -> int:
- return self._top
-
- def addChild(self, num: int) -> ViewStructure:
- for _ in range(num):
- child = ViewStructure()
- self._children.append(child)
- return self._children[0] if self._children else ViewStructure()
-
- def getChildCount(self) -> int:
- return len(self._children)
-
- def getChildAt(self, index: int) -> Optional[ViewStructure]:
- if 0 <= index < len(self._children):
- return self._children[index]
- return None
-
- def setAutofillHints(self, hints: List[str]) -> None:
- pass
-
- def setAutofillType(self, type_val: int) -> None:
- pass
-
- def setAutofillValue(self, value: Any) -> None:
- pass
-
- def setDataIsSensitive(self, sensitive: bool) -> None:
- pass
-
- def toString(self) -> str:
- return (f"ViewStructure(class={self._className}, "
- f"children={len(self._children)})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewTreeObserver
-# ═══════════════════════════════════════════════════════════════
-
-class ViewTreeObserver(_BaseViewTreeObserver):
- """ViewTreeObserver — 视图树观察者 (继承 view.ViewTreeObserver 的所有方法)"""
-
- def __init__(self):
- super().__init__()
- self._global_layout_listeners: List[Callable] = []
- self._global_focus_listeners: List[Callable] = []
- self._pre_draw_listeners: List[Callable] = []
- self._scroll_listeners: List[Callable] = []
- self._touch_mode_listeners: List[Callable] = []
- self._window_focus_listeners: List[Callable] = []
- self._window_attach_listeners: List[Callable] = []
- self._draw_listeners: List[Callable] = []
- self._lock = threading.Lock()
-
- def addOnGlobalLayoutListener(self, listener: Callable) -> None:
- with self._lock:
- if listener not in self._global_layout_listeners:
- self._global_layout_listeners.append(listener)
-
- def removeOnGlobalLayoutListener(self, listener: Callable) -> None:
- with self._lock:
- if listener in self._global_layout_listeners:
- self._global_layout_listeners.remove(listener)
-
- def addOnGlobalFocusChangeListener(self, listener: Callable) -> None:
- with self._lock:
- if listener not in self._global_focus_listeners:
- self._global_focus_listeners.append(listener)
-
- def removeOnGlobalFocusChangeListener(self, listener: Callable) -> None:
- with self._lock:
- if listener in self._global_focus_listeners:
- self._global_focus_listeners.remove(listener)
-
- def addOnPreDrawListener(self, listener: Callable) -> None:
- with self._lock:
- if listener not in self._pre_draw_listeners:
- self._pre_draw_listeners.append(listener)
-
- def removeOnPreDrawListener(self, listener: Callable) -> None:
- with self._lock:
- if listener in self._pre_draw_listeners:
- self._pre_draw_listeners.remove(listener)
-
- def addOnScrollChangedListener(self, listener: Callable) -> None:
- with self._lock:
- if listener not in self._scroll_listeners:
- self._scroll_listeners.append(listener)
-
- def removeOnScrollChangedListener(self, listener: Callable) -> None:
- with self._lock:
- if listener in self._scroll_listeners:
- self._scroll_listeners.remove(listener)
-
- def addOnTouchModeChangeListener(self, listener: Callable) -> None:
- with self._lock:
- if listener not in self._touch_mode_listeners:
- self._touch_mode_listeners.append(listener)
-
- def removeOnTouchModeChangeListener(self, listener: Callable) -> None:
- with self._lock:
- if listener in self._touch_mode_listeners:
- self._touch_mode_listeners.remove(listener)
-
- def addOnWindowFocusChangeListener(self, listener: Callable) -> None:
- with self._lock:
- if listener not in self._window_focus_listeners:
- self._window_focus_listeners.append(listener)
-
- def removeOnWindowFocusChangeListener(self, listener: Callable) -> None:
- with self._lock:
- if listener in self._window_focus_listeners:
- self._window_focus_listeners.remove(listener)
-
- def addOnWindowAttachListener(self, listener: Callable) -> None:
- with self._lock:
- if listener not in self._window_attach_listeners:
- self._window_attach_listeners.append(listener)
-
- def removeOnWindowAttachListener(self, listener: Callable) -> None:
- with self._lock:
- if listener in self._window_attach_listeners:
- self._window_attach_listeners.remove(listener)
-
- def addOnDrawListener(self, listener: Callable) -> None:
- with self._lock:
- if listener not in self._draw_listeners:
- self._draw_listeners.append(listener)
-
- def removeOnDrawListener(self, listener: Callable) -> None:
- with self._lock:
- if listener in self._draw_listeners:
- self._draw_listeners.remove(listener)
-
- def dispatchOnGlobalLayout(self) -> None:
- with self._lock:
- listeners = list(self._global_layout_listeners)
- for listener in listeners:
- listener()
-
- def isAlive(self) -> bool:
- return True
-
- def toString(self) -> str:
- return (f"ViewTreeObserver(layoutListeners={len(self._global_layout_listeners)}, "
- f"preDrawListeners={len(self._pre_draw_listeners)})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewDebug
-# ═══════════════════════════════════════════════════════════════
-
-class ViewDebug(Stub):
- """ViewDebug — 视图调试工具"""
-
- TRACE_HIERARCHY = 0
- TRACE_CAPTURE = 1
-
- @staticmethod
- def dump(view: Any, out: Any) -> None:
- pass
-
- @staticmethod
- def dumpCapturedView(view: Any, out: Any, prefix: str) -> None:
- pass
-
- @staticmethod
- def trace(view: Any, type_val: int, out: Any) -> None:
- pass
-
- @staticmethod
- def startRecyclerTracing() -> None:
- pass
-
- @staticmethod
- def stopRecyclerTracing() -> None:
- pass
-
- class RecyclerTraceable(Stub):
- def getTraceInfo(self) -> str:
- return ""
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewConfiguration
-# ═══════════════════════════════════════════════════════════════
-
-class ViewConfiguration(_BaseViewConfiguration):
- """ViewConfiguration — 视图配置 (继承 view.ViewConfiguration 的所有方法)"""
-
- def __init__(self):
- super().__init__()
- self._scaled_touch_slop: int = 8
- self._scaled_double_tap_slop: int = 100
- self._scaled_edge_slop: int = 12
- self._scaled_fading_edge_length: int = 12
- self._scaled_minimum_fling_velocity: int = 50
- self._scaled_maximum_fling_velocity: int = 4000
- self._scaled_scroll_bar_size: int = 10
- self._scaled_over_scroll_distance: int = 0
- self._scaled_paging_touch_slop: int = 16
- self._scaled_drawing_cache_size: int = 480
-
- @staticmethod
- def get(context: Any) -> "ViewConfiguration":
- return ViewConfiguration()
-
- def getScaledTouchSlop(self) -> int:
- return self._scaled_touch_slop
-
- def getScaledDoubleTapSlop(self) -> int:
- return self._scaled_double_tap_slop
-
- def getScaledEdgeSlop(self) -> int:
- return self._scaled_edge_slop
-
- def getScaledFadingEdgeLength(self) -> int:
- return self._scaled_fading_edge_length
-
- def getScaledMinimumFlingVelocity(self) -> int:
- return self._scaled_minimum_fling_velocity
-
- def getScaledMaximumFlingVelocity(self) -> int:
- return self._scaled_maximum_fling_velocity
-
- def getScaledScrollBarSize(self) -> int:
- return self._scaled_scroll_bar_size
-
- def getScaledOverScrollDistance(self) -> int:
- return self._scaled_over_scroll_distance
-
- def getScaledPagingTouchSlop(self) -> int:
- return self._scaled_paging_touch_slop
-
- def getScaledDrawingCacheSize(self) -> int:
- return self._scaled_drawing_cache_size
-
- @staticmethod
- def getLongPressTimeout() -> int:
- return 500
-
- @staticmethod
- def getTapTimeout() -> int:
- return 100
-
- @staticmethod
- def getDoubleTapTimeout() -> int:
- return 300
-
- @staticmethod
- def getKeyRepeatTimeout() -> int:
- return 400
-
- @staticmethod
- def getKeyRepeatDelay() -> int:
- return 50
-
- @staticmethod
- def getScrollDefaultDelay() -> int:
- return 40
-
- @staticmethod
- def getScrollFriction() -> float:
- return 0.015
-
- def toString(self) -> str:
- return "ViewConfiguration()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewParent (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class ViewParent(_BaseViewParent):
- """ViewParent — 视图父容器接口扩展 (继承 view.ViewParent 的所有方法)"""
-
- def requestLayout(self) -> None:
- pass
-
- def isLayoutRequested(self) -> bool:
- return False
-
- def requestTransparentRegion(self, child: Any) -> None:
- pass
-
- def invalidateChild(self, child: Any, r: Any) -> None:
- pass
-
- def invalidateChildInParent(self, location: Any, r: Any) -> Optional[Any]:
- return None
-
- def getParent(self) -> Optional["ViewParent"]:
- return None
-
- def requestChildFocus(self, child: Any, focused: Any) -> None:
- pass
-
- def recomputeViewAttributes(self, child: Any) -> None:
- pass
-
- def clearChildFocus(self, child: Any) -> None:
- pass
-
- def getChildVisibleRect(self, child: Any, r: Any, offset: Any) -> bool:
- return True
-
- def createSnapshot(self, out: Any, child: Any) -> None:
- pass
-
- def onStartTemporaryDetach(self) -> None:
- pass
-
- def onFinishTemporaryDetach(self) -> None:
- pass
-
- def bringChildToFront(self, child: Any) -> None:
- pass
-
- def focusSearch(self, child: Any, direction: int) -> Optional[Any]:
- return None
-
- def focusableViewAvailable(self, v: Any) -> None:
- pass
-
- def showContextMenuForChild(self, original_view: Any) -> bool:
- return False
-
- def actionModeStartingForChild(self, original_view: Any) -> Optional[Any]:
- return None
-
- def requestSendAccessibilityEvent(self, child: Any, event: Any) -> bool:
- return True
-
- def childHasTransientStateChanged(self, child: Any, has_state: bool) -> None:
- pass
-
- def requestChildRectangleOnScreen(self, child: Any, rectangle: Any,
- immediate: bool) -> bool:
- return True
-
- def canResolveLayoutDirection(self) -> bool:
- return True
-
- def isLayoutDirectionResolved(self) -> bool:
- return True
-
- def getLayoutDirection(self) -> int:
- return 0
-
- def toString(self) -> str:
- return "ViewParent()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewGroup (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class ViewGroup(_BaseViewGroup):
- """ViewGroup — 视图组扩展 (继承 view.ViewGroup 的所有方法)"""
-
- CLIP_TO_PADDING_MASK = 0
- FOCUS_AFTER = 1
- FOCUS_BEFORE = 2
- FOCUS_BLOCK = 3
-
- LAYOUT_MODE_CLIP_BOUNDS = 0
- LAYOUT_MODE_OPTICAL_BOUNDS = 1
-
- PERSISTENT_NO_CACHE = 0
- PERSISTENT_ANIMATION_CACHE = 1
- PERSISTENT_SCROLLING_CACHE = 2
- PERSISTENT_ALL_CACHES = 3
-
- class LayoutParams(Stub):
- """ViewGroup.LayoutParams — 布局参数"""
-
- FILL_PARENT = -1
- MATCH_PARENT = -1
- WRAP_CONTENT = -2
-
- def __init__(self, width: int = WRAP_CONTENT, height: int = WRAP_CONTENT):
- super().__init__()
- self.width = width
- self.height = height
-
- def resolveLayoutDirection(self, layout_direction: int) -> None:
- pass
-
- def toString(self) -> str:
- return f"LayoutParams({self.width}x{self.height})"
-
- class MarginLayoutParams(LayoutParams):
- """ViewGroup.MarginLayoutParams — 带边距的布局参数"""
-
- def __init__(self, width: int = -2,
- height: int = -2):
- super().__init__(width, height)
- self.leftMargin: int = 0
- self.topMargin: int = 0
- self.rightMargin: int = 0
- self.bottomMargin: int = 0
- self.marginStart: int = 0
- self.marginEnd: int = 0
-
- def setMargins(self, left: int, top: int, right: int, bottom: int) -> None:
- self.leftMargin = left
- self.topMargin = top
- self.rightMargin = right
- self.bottomMargin = bottom
-
- def getMarginLeft(self) -> int:
- return self.leftMargin
-
- def getMarginTop(self) -> int:
- return self.topMargin
-
- def getMarginRight(self) -> int:
- return self.rightMargin
-
- def getMarginBottom(self) -> int:
- return self.bottomMargin
-
- def setMarginStart(self, start: int) -> None:
- self.marginStart = start
-
- def setMarginEnd(self, end: int) -> None:
- self.marginEnd = end
-
- def getMarginStart(self) -> int:
- return self.marginStart
-
- def getMarginEnd(self) -> int:
- return self.marginEnd
-
- def toString(self) -> str:
- return (f"MarginLayoutParams({self.width}x{self.height}, "
- f"margins=({self.leftMargin},{self.topMargin},"
- f"{self.rightMargin},{self.bottomMargin}))")
-
- def __init__(self, context=None):
- super().__init__(context)
- if not hasattr(self, '_children'):
- self._children: List[Any] = []
- if not hasattr(self, '_clip_children'):
- self._clip_children = True
- if not hasattr(self, '_clip_to_padding'):
- self._clip_to_padding = True
- self._layout_mode = self.LAYOUT_MODE_CLIP_BOUNDS
- self._persistent_caching = self.PERSISTENT_NO_CACHE
- self._touch_mode = False
- if not hasattr(self, '_motion_event_splitting'):
- self._motion_event_splitting = True
- self._transient_child: Optional[Any] = None
- self._add_stateset_focus = False
- self._child_drawable_state: Optional[Any] = None
-
- def addView(self, child: Any, index: int = -1) -> None:
- if index < 0 or index >= len(self._children):
- self._children.append(child)
- else:
- self._children.insert(index, child)
-
- def removeView(self, child: Any) -> None:
- if child in self._children:
- self._children.remove(child)
-
- def removeViewAt(self, index: int) -> None:
- if 0 <= index < len(self._children):
- self._children.pop(index)
-
- def removeAllViews(self) -> None:
- self._children.clear()
-
- def getChildCount(self) -> int:
- return len(self._children)
-
- def getChildAt(self, index: int) -> Optional[Any]:
- if 0 <= index < len(self._children):
- return self._children[index]
- return None
-
- def indexOfChild(self, child: Any) -> int:
- try:
- return self._children.index(child)
- except ValueError:
- return -1
-
- def bringChildToFront(self, child: Any) -> None:
- if child in self._children:
- self._children.remove(child)
- self._children.append(child)
-
- def setClipChildren(self, clip: bool) -> None:
- self._clip_children = clip
-
- def getClipChildren(self) -> bool:
- return self._clip_children
-
- def setClipToPadding(self, clip: bool) -> None:
- self._clip_to_padding = clip
-
- def getClipToPadding(self) -> bool:
- return self._clip_to_padding
-
- def setLayoutMode(self, mode: int) -> None:
- self._layout_mode = mode
-
- def getLayoutMode(self) -> int:
- return self._layout_mode
-
- def setPersistentDrawingCache(self, cache: int) -> None:
- self._persistent_caching = cache
-
- def getPersistentDrawingCache(self) -> int:
- return self._persistent_caching
-
- def setAddStatesFromChildren(self, add: bool) -> None:
- self._add_stateset_focus = add
-
- def addStatesFromChildren(self) -> bool:
- return self._add_stateset_focus
-
- def setMotionEventSplittingEnabled(self, split: bool) -> None:
- self._motion_event_splitting = split
-
- def isMotionEventSplittingEnabled(self) -> bool:
- return self._motion_event_splitting
-
- def setTouchMode(self, touch: bool) -> None:
- self._touch_mode = touch
-
- def isTouchMode(self) -> bool:
- return self._touch_mode
-
- def onLayout(self, changed: bool, l: int, t: int, r: int, b: int) -> None:
- pass
-
- def onInterceptTouchEvent(self, ev: Any) -> bool:
- return False
-
- def requestDisallowInterceptTouchEvent(self, disallow: bool) -> None:
- pass
-
- def getChildDrawingOrder(self, child_count: int, i: int) -> int:
- return i
-
- def setChildrenDrawingOrderEnabled(self, enabled: bool) -> None:
- pass
-
- def isChildrenDrawingOrderEnabled(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"ViewGroup(children={len(self._children)})"
-
-
-class ViewGroupOverlay(Stub):
- """ViewGroupOverlay — 视图组覆盖层"""
-
- def __init__(self, host: Any = None):
- super().__init__()
- self._host = host
- self._drawables: List[Any] = []
-
- def add(self, drawable: Any) -> None:
- if drawable not in self._drawables:
- self._drawables.append(drawable)
-
- def remove(self, drawable: Any) -> None:
- if drawable in self._drawables:
- self._drawables.remove(drawable)
-
- def clear(self) -> None:
- self._drawables.clear()
-
- def toString(self) -> str:
- return f"ViewGroupOverlay(size={len(self._drawables)})"
-
-
-class ViewOverlay(Stub):
- """ViewOverlay — 视图覆盖层"""
-
- def __init__(self, host: Any = None):
- super().__init__()
- self._host = host
- self._drawables: List[Any] = []
-
- def add(self, drawable: Any) -> None:
- if drawable not in self._drawables:
- self._drawables.append(drawable)
-
- def remove(self, drawable: Any) -> None:
- if drawable in self._drawables:
- self._drawables.remove(drawable)
-
- def clear(self) -> None:
- self._drawables.clear()
-
- def getHost(self) -> Optional[Any]:
- return self._host
-
- def toString(self) -> str:
- return f"ViewOverlay(size={len(self._drawables)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowInsets / DisplayCutout / Display
-# ═══════════════════════════════════════════════════════════════
-
-class WindowInsets(_BaseWindowInsets):
- """WindowInsets — 窗口插入区域 (继承 view.WindowInsets 的所有方法)"""
-
- def __init__(self):
- super().__init__()
- self._system_window_insets: Tuple[int, int, int, int] = (0, 0, 0, 0)
- self._stable_insets: Tuple[int, int, int, int] = (0, 0, 0, 0)
- self._display_cutout_insets: Tuple[int, int, int, int] = (0, 0, 0, 0)
- self._mandatory_system_gesture_insets: Tuple[int, int, int, int] = (0, 0, 0, 0)
- self._tappable_element_insets: Tuple[int, int, int, int] = (0, 0, 0, 0)
- self._system_gesture_insets: Tuple[int, int, int, int] = (0, 0, 0, 0)
- self._consume_stable = False
- self._consume_system_windows = False
- self._display_cutout: Optional[DisplayCutout] = None
- self._rounded_corners: List[Any] = []
- self._privacy_indicators: Optional[Tuple[int, int, int, int]] = None
-
- def getSystemWindowInsetLeft(self) -> int:
- return self._system_window_insets[0]
-
- def getSystemWindowInsetTop(self) -> int:
- return self._system_window_insets[1]
-
- def getSystemWindowInsetRight(self) -> int:
- return self._system_window_insets[2]
-
- def getSystemWindowInsetBottom(self) -> int:
- return self._system_window_insets[3]
-
- def getSystemWindowInsets(self) -> Tuple[int, int, int, int]:
- return self._system_window_insets
-
- def getStableInsetLeft(self) -> int:
- return self._stable_insets[0]
-
- def getStableInsetTop(self) -> int:
- return self._stable_insets[1]
-
- def getStableInsetRight(self) -> int:
- return self._stable_insets[2]
-
- def getStableInsetBottom(self) -> int:
- return self._stable_insets[3]
-
- def getDisplayCutout(self) -> Optional[DisplayCutout]:
- return self._display_cutout
-
- def getDisplayCutoutInsets(self) -> Tuple[int, int, int, int]:
- return self._display_cutout_insets
-
- def getMandatorySystemGestureInsets(self) -> Tuple[int, int, int, int]:
- return self._mandatory_system_gesture_insets
-
- def getTappableElementInsets(self) -> Tuple[int, int, int, int]:
- return self._tappable_element_insets
-
- def getSystemGestureInsets(self) -> Tuple[int, int, int, int]:
- return self._system_gesture_insets
-
- def consumeSystemWindowInsets(self) -> WindowInsets:
- insets = WindowInsets()
- insets._system_window_insets = (0, 0, 0, 0)
- return insets
-
- def consumeStableInsets(self) -> WindowInsets:
- insets = WindowInsets()
- insets._stable_insets = (0, 0, 0, 0)
- return insets
-
- def isConsumed(self) -> bool:
- return self._consume_system_windows
-
- def hasInsets(self) -> bool:
- return (max(self._system_window_insets) > 0 or
- max(self._stable_insets) > 0)
-
- def hasSystemWindowInsets(self) -> bool:
- return max(self._system_window_insets) > 0
-
- def hasStableInsets(self) -> bool:
- return max(self._stable_insets) > 0
-
- def hasDisplayCutout(self) -> bool:
- return self._display_cutout is not None
-
- def toString(self) -> str:
- return (f"WindowInsets(sys={self._system_window_insets}, "
- f"stable={self._stable_insets})")
-
-
-class DisplayCutout(Stub):
- """DisplayCutout — 屏幕缺口信息"""
-
- def __init__(self):
- super().__init__()
- self._safe_insets: Tuple[int, int, int, int] = (0, 0, 0, 0)
- self._bound_left: Optional[Any] = None
- self._bound_top: Optional[Any] = None
- self._bound_right: Optional[Any] = None
- self._bound_bottom: Optional[Any] = None
- self._waterfall_insets: Tuple[int, int, int, int] = (0, 0, 0, 0)
-
- def getSafeInsetLeft(self) -> int:
- return self._safe_insets[0]
-
- def getSafeInsetTop(self) -> int:
- return self._safe_insets[1]
-
- def getSafeInsetRight(self) -> int:
- return self._safe_insets[2]
-
- def getSafeInsetBottom(self) -> int:
- return self._safe_insets[3]
-
- def getBoundingRectLeft(self) -> Optional[Any]:
- return self._bound_left
-
- def getBoundingRectTop(self) -> Optional[Any]:
- return self._bound_top
-
- def getBoundingRectRight(self) -> Optional[Any]:
- return self._bound_right
-
- def getBoundingRectBottom(self) -> Optional[Any]:
- return self._bound_bottom
-
- def getWaterfallInsets(self) -> Tuple[int, int, int, int]:
- return self._waterfall_insets
-
- def toString(self) -> str:
- return f"DisplayCutout(safe={self._safe_insets})"
-
-
-class Display(_BaseDisplay):
- """Display — 屏幕显示信息 (继承 view.Display 的所有方法)"""
-
- DEFAULT_DISPLAY = 0
- FLAG_PRESENTATION = 1
- FLAG_SECURE = 2
- FLAG_SUPPORTS_PROTECTED_BUFFERS = 4
-
- STATE_OFF = 0
- STATE_ON = 1
- STATE_DOZE = 2
- STATE_DOZE_SUSPEND = 3
- STATE_SUSPENDED = 4
- STATE_UNKNOWN = -1
-
- def __init__(self, display_id: int = DEFAULT_DISPLAY):
- super().__init__()
- self._display_id = display_id
- self._width: int = 1080
- self._height: int = 1920
- self._refresh_rate: float = 60.0
- self._rotation: int = 0
- self._state: int = STATE_ON
- self._name: str = "Internal Display"
- self._flags: int = 0
- self._density: float = 2.0
- self._dpi_x: float = 480.0
- self._dpi_y: float = 480.0
- self._app_width: int = 1080
- self._app_height: int = 1920
- self._smallest_width: int = 1080
- self._largest_width: int = 1920
- self._hdr_capabilities: Optional[Any] = None
- self._mode: Optional[Any] = None
- self._supported_modes: List[Any] = []
-
- def getDisplayId(self) -> int:
- return self._display_id
-
- def getName(self) -> str:
- return self._name
-
- def getFlags(self) -> int:
- return self._flags
-
- def getHeight(self) -> int:
- return self._height
-
- def getWidth(self) -> int:
- return self._width
-
- def getRotation(self) -> int:
- return self._rotation
-
- def getState(self) -> int:
- return self._state
-
- def getRefreshRate(self) -> float:
- return self._refresh_rate
-
- def getDensity(self) -> float:
- return self._density
-
- def getDpiX(self) -> float:
- return self._dpi_x
-
- def getDpiY(self) -> float:
- return self._dpi_y
-
- def getAppWidth(self) -> int:
- return self._app_width
-
- def getAppHeight(self) -> int:
- return self._app_height
-
- def getSmallestWidth(self) -> int:
- return self._smallest_width
-
- def getLargestWidth(self) -> int:
- return self._largest_width
-
- def getSupportedModes(self) -> List[Any]:
- return list(self._supported_modes)
-
- def getMode(self) -> Optional[Any]:
- return self._mode
-
- def isHdr(self) -> bool:
- return False
-
- def getHdrCapabilities(self) -> Optional[Any]:
- return self._hdr_capabilities
-
- def isValid(self) -> bool:
- return True
-
- def toString(self) -> str:
- return (f"Display(id={self._display_id}, "
- f"{self._width}x{self._height}, "
- f"rotation={self._rotation})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# DragEvent / GestureDetector / KeyEvent / KeyCharacterMap
-# ═══════════════════════════════════════════════════════════════
-
-DRAG_EVENT_ACTION_DRAG_STARTED = 1
-DRAG_EVENT_ACTION_DRAG_ENTERED = 2
-DRAG_EVENT_ACTION_DRAG_LOCATION = 3
-DRAG_EVENT_ACTION_DRAG_EXITED = 4
-DRAG_EVENT_ACTION_DROP = 5
-DRAG_EVENT_ACTION_DRAG_ENDED = 6
-
-GESTURE_STATE_NONE = 0
-GESTURE_STATE_STARTED = 1
-GESTURE_STATE_IN_PROGRESS = 2
-GESTURE_STATE_FINISHED = 3
-
-ACTION_DOWN = 0
-ACTION_UP = 1
-ACTION_MOVE = 2
-ACTION_CANCEL = 3
-ACTION_OUTSIDE = 4
-ACTION_POINTER_DOWN = 5
-ACTION_POINTER_UP = 6
-ACTION_HOVER_ENTER = 7
-ACTION_HOVER_EXIT = 8
-ACTION_HOVER_MOVE = 9
-ACTION_SCROLL = 10
-ACTION_POINTER_INDEX_MASK = 0xFF00
-ACTION_POINTER_INDEX_SHIFT = 8
-
-META_ALT_MASK = 2
-META_ALT_LEFT_ON = 16
-META_ALT_RIGHT_ON = 32
-META_ALT_ON = 2
-META_CTRL_MASK = 4096
-META_CTRL_LEFT_ON = 8192
-META_CTRL_RIGHT_ON = 16384
-META_CTRL_ON = 4096
-META_FUNCTION_ON = 8
-META_META_MASK = 65536
-META_META_LEFT_ON = 131072
-META_META_RIGHT_ON = 262144
-META_META_ON = 65536
-META_SHIFT_MASK = 1
-META_SHIFT_LEFT_ON = 64
-META_SHIFT_RIGHT_ON = 128
-META_SHIFT_ON = 1
-META_SYM_ON = 4
-META_CAPS_LOCK_ON = 1048576
-META_NUM_LOCK_ON = 2097152
-META_SCROLL_LOCK_ON = 4194304
-
-KEYCODE_UNKNOWN = 0
-KEYCODE_SOFT_LEFT = 1
-KEYCODE_SOFT_RIGHT = 2
-KEYCODE_HOME = 3
-KEYCODE_BACK = 4
-KEYCODE_CALL = 5
-KEYCODE_ENDCALL = 6
-KEYCODE_0 = 7
-KEYCODE_1 = 8
-KEYCODE_2 = 9
-KEYCODE_3 = 10
-KEYCODE_4 = 11
-KEYCODE_5 = 12
-KEYCODE_6 = 13
-KEYCODE_7 = 14
-KEYCODE_8 = 15
-KEYCODE_9 = 16
-KEYCODE_STAR = 17
-KEYCODE_POUND = 18
-KEYCODE_DPAD_UP = 19
-KEYCODE_DPAD_DOWN = 20
-KEYCODE_DPAD_LEFT = 21
-KEYCODE_DPAD_RIGHT = 22
-KEYCODE_DPAD_CENTER = 23
-KEYCODE_VOLUME_UP = 24
-KEYCODE_VOLUME_DOWN = 25
-KEYCODE_POWER = 26
-KEYCODE_CAMERA = 27
-KEYCODE_CLEAR = 28
-KEYCODE_A = 29
-KEYCODE_B = 30
-KEYCODE_C = 31
-KEYCODE_D = 32
-KEYCODE_E = 33
-KEYCODE_F = 34
-KEYCODE_G = 35
-KEYCODE_H = 36
-KEYCODE_I = 37
-KEYCODE_J = 38
-KEYCODE_K = 39
-KEYCODE_L = 40
-KEYCODE_M = 41
-KEYCODE_N = 42
-KEYCODE_O = 43
-KEYCODE_P = 44
-KEYCODE_Q = 45
-KEYCODE_R = 46
-KEYCODE_S = 47
-KEYCODE_T = 48
-KEYCODE_U = 49
-KEYCODE_V = 50
-KEYCODE_W = 51
-KEYCODE_X = 52
-KEYCODE_Y = 53
-KEYCODE_Z = 54
-KEYCODE_COMMA = 55
-KEYCODE_PERIOD = 56
-KEYCODE_ALT_LEFT = 57
-KEYCODE_ALT_RIGHT = 58
-KEYCODE_SHIFT_LEFT = 59
-KEYCODE_SHIFT_RIGHT = 60
-KEYCODE_TAB = 61
-KEYCODE_SPACE = 62
-KEYCODE_SYM = 63
-KEYCODE_EXPLORER = 64
-KEYCODE_ENVELOPE = 65
-KEYCODE_ENTER = 66
-KEYCODE_DEL = 67
-KEYCODE_GRAVE = 68
-KEYCODE_MINUS = 69
-KEYCODE_EQUALS = 70
-KEYCODE_LEFT_BRACKET = 71
-KEYCODE_RIGHT_BRACKET = 72
-KEYCODE_BACKSLASH = 73
-KEYCODE_SEMICOLON = 74
-KEYCODE_APOSTROPHE = 75
-KEYCODE_SLASH = 76
-KEYCODE_AT = 77
-KEYCODE_NUM = 78
-KEYCODE_HEADSETHOOK = 79
-KEYCODE_FOCUS = 80
-KEYCODE_PLUS = 81
-KEYCODE_MENU = 82
-KEYCODE_NOTIFICATION = 83
-KEYCODE_SEARCH = 84
-KEYCODE_MEDIA_PLAY_PAUSE = 85
-KEYCODE_MEDIA_STOP = 86
-KEYCODE_MEDIA_NEXT = 87
-KEYCODE_MEDIA_PREVIOUS = 88
-KEYCODE_MEDIA_REWIND = 89
-KEYCODE_MEDIA_FAST_FORWARD = 90
-KEYCODE_MUTE = 91
-KEYCODE_PAGE_UP = 92
-KEYCODE_PAGE_DOWN = 93
-KEYCODE_PICTSYMBOLS = 94
-KEYCODE_SWITCH_CHARSET = 95
-KEYCODE_BUTTON_A = 96
-KEYCODE_BUTTON_B = 97
-KEYCODE_BUTTON_C = 98
-KEYCODE_BUTTON_X = 99
-KEYCODE_BUTTON_Y = 100
-KEYCODE_BUTTON_Z = 101
-KEYCODE_BUTTON_L1 = 102
-KEYCODE_BUTTON_R1 = 103
-KEYCODE_BUTTON_L2 = 104
-KEYCODE_BUTTON_R2 = 105
-KEYCODE_BUTTON_THUMBL = 106
-KEYCODE_BUTTON_THUMBR = 107
-KEYCODE_BUTTON_START = 108
-KEYCODE_BUTTON_SELECT = 109
-KEYCODE_BUTTON_MODE = 110
-KEYCODE_ESCAPE = 111
-KEYCODE_FORWARD_DEL = 112
-KEYCODE_CTRL_LEFT = 113
-KEYCODE_CTRL_RIGHT = 114
-KEYCODE_CAPS_LOCK = 115
-KEYCODE_SCROLL_LOCK = 116
-KEYCODE_META_LEFT = 117
-KEYCODE_META_RIGHT = 118
-KEYCODE_FUNCTION = 119
-KEYCODE_SYSRQ = 120
-KEYCODE_BREAK = 121
-KEYCODE_MOVE_HOME = 122
-KEYCODE_MOVE_END = 123
-KEYCODE_INSERT = 124
-KEYCODE_FORWARD = 125
-KEYCODE_MEDIA_PLAY = 126
-KEYCODE_MEDIA_PAUSE = 127
-KEYCODE_MEDIA_CLOSE = 128
-KEYCODE_MEDIA_EJECT = 129
-KEYCODE_MEDIA_RECORD = 130
-KEYCODE_F1 = 131
-KEYCODE_F2 = 132
-KEYCODE_F3 = 133
-KEYCODE_F4 = 134
-KEYCODE_F5 = 135
-KEYCODE_F6 = 136
-KEYCODE_F7 = 137
-KEYCODE_F8 = 138
-KEYCODE_F9 = 139
-KEYCODE_F10 = 140
-KEYCODE_F11 = 141
-KEYCODE_F12 = 142
-KEYCODE_NUM_LOCK = 143
-KEYCODE_NUMPAD_0 = 144
-KEYCODE_NUMPAD_1 = 145
-KEYCODE_NUMPAD_2 = 146
-KEYCODE_NUMPAD_3 = 147
-KEYCODE_NUMPAD_4 = 148
-KEYCODE_NUMPAD_5 = 149
-KEYCODE_NUMPAD_6 = 150
-KEYCODE_NUMPAD_7 = 151
-KEYCODE_NUMPAD_8 = 152
-KEYCODE_NUMPAD_9 = 153
-KEYCODE_NUMPAD_DIVIDE = 154
-KEYCODE_NUMPAD_MULTIPLY = 155
-KEYCODE_NUMPAD_SUBTRACT = 156
-KEYCODE_NUMPAD_ADD = 157
-KEYCODE_NUMPAD_DOT = 158
-KEYCODE_NUMPAD_COMMA = 159
-KEYCODE_NUMPAD_ENTER = 160
-KEYCODE_NUMPAD_EQUALS = 161
-KEYCODE_NUMPAD_LEFT_PAREN = 162
-KEYCODE_NUMPAD_RIGHT_PAREN = 163
-KEYCODE_VOLUME_MUTE = 164
-KEYCODE_INFO = 165
-KEYCODE_CHANNEL_UP = 166
-KEYCODE_CHANNEL_DOWN = 167
-KEYCODE_ZOOM_IN = 168
-KEYCODE_ZOOM_OUT = 169
-
-WINDOW_INSETS_TYPE_SYSTEM_BARS = 0
-WINDOW_INSETS_TYPE_STATUS_BARS = 1
-WINDOW_INSETS_TYPE_NAVIGATION_BARS = 2
-WINDOW_INSETS_TYPE_CAPTION_BAR = 3
-WINDOW_INSETS_TYPE_IME = 4
-WINDOW_INSETS_TYPE_TAPPABLE_ELEMENT = 5
-WINDOW_INSETS_TYPE_MANDATORY_SYSTEM_GESTURES = 6
-WINDOW_INSETS_TYPE_SYSTEM_GESTURES = 7
-WINDOW_INSETS_TYPE_DISPLAY_CUTOUT = 8
-WINDOW_INSETS_TYPE_WATERFALL = 9
-WINDOW_INSETS_TYPE_PRIVACY_INDICATORS = 10
-
-WINDOW_INSETS_ANIMATION_TYPE_NONE = 0
-WINDOW_INSETS_ANIMATION_TYPE_ALPHA = 1
-WINDOW_INSETS_ANIMATION_TYPE_TRANSLATION = 2
-WINDOW_INSETS_ANIMATION_TYPE_ALPHA_AND_TRANSLATION = 3
-
-
-class DragEvent(_BaseDragEvent):
- """DragEvent — 拖放事件 (继承 view.DragEvent 的所有方法)"""
-
- ACTION_DRAG_STARTED = DRAG_EVENT_ACTION_DRAG_STARTED
- ACTION_DRAG_ENTERED = DRAG_EVENT_ACTION_DRAG_ENTERED
- ACTION_DRAG_LOCATION = DRAG_EVENT_ACTION_DRAG_LOCATION
- ACTION_DRAG_EXITED = DRAG_EVENT_ACTION_DRAG_EXITED
- ACTION_DROP = DRAG_EVENT_ACTION_DROP
- ACTION_DRAG_ENDED = DRAG_EVENT_ACTION_DRAG_ENDED
-
- def __init__(self, action: int = 0):
- super().__init__()
- self._action = action
- self._x: float = 0.0
- self._y: float = 0.0
- self._clip_data: Optional[Any] = None
- self._result: Optional[Any] = None
- self._local_state: Optional[Any] = None
- self._drag_surface: Optional[Any] = None
-
- def getAction(self) -> int:
- return self._action
-
- def getX(self) -> float:
- return self._x
-
- def getY(self) -> float:
- return self._y
-
- def getClipData(self) -> Optional[Any]:
- return self._clip_data
-
- def getResult(self) -> Optional[Any]:
- return self._result
-
- def getLocalState(self) -> Optional[Any]:
- return self._local_state
-
- def toString(self) -> str:
- actions = {1: "DRAG_STARTED", 2: "DRAG_ENTERED", 3: "DRAG_LOCATION",
- 4: "DRAG_EXITED", 5: "DROP", 6: "DRAG_ENDED"}
- return f"DragEvent(action={actions.get(self._action, 'UNKNOWN')})"
-
-
-class GestureDetector(_BaseGestureDetector):
- """GestureDetector — 手势检测器 (继承 view.GestureDetector 的所有方法)"""
-
- class SimpleOnGestureListener(Stub):
- """GestureDetector.SimpleOnGestureListener — 简单手势监听器"""
-
- def onDown(self, e: Any) -> bool:
- return False
-
- def onShowPress(self, e: Any) -> None:
- pass
-
- def onSingleTapUp(self, e: Any) -> bool:
- return False
-
- def onSingleTapConfirmed(self, e: Any) -> bool:
- return False
-
- def onDoubleTap(self, e: Any) -> bool:
- return False
-
- def onDoubleTapEvent(self, e: Any) -> bool:
- return False
-
- def onLongPress(self, e: Any) -> None:
- pass
-
- def onScroll(self, e1: Any, e2: Any, distance_x: float, distance_y: float) -> bool:
- return False
-
- def onFling(self, e1: Any, e2: Any, velocity_x: float, velocity_y: float) -> bool:
- return False
-
- def onContextClick(self, e: Any) -> bool:
- return False
-
- class OnGestureListener(Stub):
- def onDown(self, e: Any) -> bool:
- return False
- def onShowPress(self, e: Any) -> None:
- pass
- def onSingleTapUp(self, e: Any) -> bool:
- return False
- def onScroll(self, e1: Any, e2: Any, dx: float, dy: float) -> bool:
- return False
- def onLongPress(self, e: Any) -> None:
- pass
- def onFling(self, e1: Any, e2: Any, vx: float, vy: float) -> bool:
- return False
-
- class OnDoubleTapListener(Stub):
- def onSingleTapConfirmed(self, e: Any) -> bool:
- return False
- def onDoubleTap(self, e: Any) -> bool:
- return False
- def onDoubleTapEvent(self, e: Any) -> bool:
- return False
- def onContextClick(self, e: Any) -> bool:
- return False
-
- def __init__(self, context: Any = None, listener: Optional[Any] = None):
- super().__init__()
- self._listener = listener
- self._double_tap_listener: Optional[Any] = None
- self._is_double_tapping = False
- self._touch_slop: int = 8
- self._double_tap_slop: int = 100
- self._double_tap_timeout: int = 300
- self._longpress_timeout: int = 500
- self._last_tap_x: float = 0
- self._last_tap_y: float = 0
- self._last_tap_time: int = 0
-
- def setOnDoubleTapListener(self, listener: Optional[Any]) -> None:
- self._double_tap_listener = listener
-
- def setContextClickListener(self, listener: Optional[Any]) -> None:
- pass
-
- def setIsLongpressEnabled(self, enabled: bool) -> None:
- pass
-
- def isLongpressEnabled(self) -> bool:
- return True
-
- def onTouchEvent(self, ev: Any) -> bool:
- return True
-
- def toString(self) -> str:
- return f"GestureDetector(listener={'yes' if self._listener else 'no'})"
-
-
-class KeyEvent(_BaseKeyEvent):
- """KeyEvent — 按键事件 (扩展版,继承 view.KeyEvent 的所有常量)"""
-
- ACTION_DOWN = 0
- ACTION_UP = 1
- ACTION_MULTIPLE = 2
-
- FLAG_WOKE_HERE = 1
- FLAG_SOFT_KEYBOARD = 2
- FLAG_KEEP_TOUCH_MODE = 4
- FLAG_FROM_SYSTEM = 8
- FLAG_EDITOR_ACTION = 16
- FLAG_CANCELED = 32
- FLAG_VIRTUAL_HARD_KEY = 64
- FLAG_LONG_PRESS = 128
- FLAG_CANCELED_LONG_PRESS = 256
- FLAG_TRACKING = 512
- FLAG_FALLBACK = 1024
-
- def __init__(self, action: int = ACTION_DOWN, code: int = KEYCODE_UNKNOWN):
- super().__init__()
- self._action = action
- self._code = code
- self._repeat: int = 0
- self._meta_state: int = 0
- self._device_id: int = 0
- self._scan_code: int = 0
- self._flags: int = 0
- self._down_time: int = 0
- self._event_time: int = 0
- self._display_id: int = 0
-
- def getAction(self) -> int:
- return self._action
-
- def getKeyCode(self) -> int:
- return self._code
-
- def getRepeatCount(self) -> int:
- return self._repeat
-
- def getMetaState(self) -> int:
- return self._meta_state
-
- def getDeviceId(self) -> int:
- return self._device_id
-
- def getScanCode(self) -> int:
- return self._scan_code
-
- def getFlags(self) -> int:
- return self._flags
-
- def getDownTime(self) -> int:
- return self._down_time
-
- def getEventTime(self) -> int:
- return self._event_time
-
- def getDisplayId(self) -> int:
- return self._display_id
-
- def isLongPress(self) -> bool:
- return bool(self._flags & self.FLAG_LONG_PRESS)
-
- def isCanceled(self) -> bool:
- return bool(self._flags & self.FLAG_CANCELED)
-
- @staticmethod
- def isModifierKey(key_code: int) -> bool:
- return key_code in (KEYCODE_ALT_LEFT, KEYCODE_ALT_RIGHT,
- KEYCODE_SHIFT_LEFT, KEYCODE_SHIFT_RIGHT,
- KEYCODE_CTRL_LEFT, KEYCODE_CTRL_RIGHT,
- KEYCODE_META_LEFT, KEYCODE_META_RIGHT,
- KEYCODE_SYM, KEYCODE_FUNCTION)
-
- @staticmethod
- def keyCodeFromString(symbolic_name: str) -> int:
- mapping = {
- "KEYCODE_A": KEYCODE_A, "KEYCODE_B": KEYCODE_B,
- "KEYCODE_C": KEYCODE_C, "KEYCODE_D": KEYCODE_D,
- "KEYCODE_E": KEYCODE_E, "KEYCODE_F": KEYCODE_F,
- "KEYCODE_G": KEYCODE_G, "KEYCODE_H": KEYCODE_H,
- "KEYCODE_I": KEYCODE_I, "KEYCODE_J": KEYCODE_J,
- "KEYCODE_K": KEYCODE_K, "KEYCODE_L": KEYCODE_L,
- "KEYCODE_M": KEYCODE_M, "KEYCODE_N": KEYCODE_N,
- "KEYCODE_O": KEYCODE_O, "KEYCODE_P": KEYCODE_P,
- "KEYCODE_Q": KEYCODE_Q, "KEYCODE_R": KEYCODE_R,
- "KEYCODE_S": KEYCODE_S, "KEYCODE_T": KEYCODE_T,
- "KEYCODE_U": KEYCODE_U, "KEYCODE_V": KEYCODE_V,
- "KEYCODE_W": KEYCODE_W, "KEYCODE_X": KEYCODE_X,
- "KEYCODE_Y": KEYCODE_Y, "KEYCODE_Z": KEYCODE_Z,
- "KEYCODE_0": KEYCODE_0, "KEYCODE_1": KEYCODE_1,
- "KEYCODE_2": KEYCODE_2, "KEYCODE_3": KEYCODE_3,
- "KEYCODE_4": KEYCODE_4, "KEYCODE_5": KEYCODE_5,
- "KEYCODE_6": KEYCODE_6, "KEYCODE_7": KEYCODE_7,
- "KEYCODE_8": KEYCODE_8, "KEYCODE_9": KEYCODE_9,
- "KEYCODE_HOME": KEYCODE_HOME, "KEYCODE_BACK": KEYCODE_BACK,
- "KEYCODE_MENU": KEYCODE_MENU, "KEYCODE_SEARCH": KEYCODE_SEARCH,
- "KEYCODE_ENTER": KEYCODE_ENTER, "KEYCODE_DEL": KEYCODE_DEL,
- "KEYCODE_SPACE": KEYCODE_SPACE, "KEYCODE_TAB": KEYCODE_TAB,
- }
- return mapping.get(symbolic_name, KEYCODE_UNKNOWN)
-
- @staticmethod
- def keyCodeToString(key_code: int) -> str:
- reverse = {v: k for k, v in {
- "KEYCODE_A": KEYCODE_A, "KEYCODE_B": KEYCODE_B,
- "KEYCODE_HOME": KEYCODE_HOME, "KEYCODE_BACK": KEYCODE_BACK,
- }.items()}
- return reverse.get(key_code, f"KEYCODE_{key_code}")
-
- def toString(self) -> str:
- return (f"KeyEvent(action={self._action}, code={self._code}, "
- f"repeat={self._repeat})")
-
-
-class KeyCharacterMap(Stub):
- """KeyCharacterMap — 按键字符映射"""
-
- ALPHA = 0
- FULL = 1
- NUMERIC = 2
- PREDICTIVE = 3
- SPECIAL_FUNCTION = 4
- VIRTUAL = 5
-
- BUILT_IN_KEYBOARD = 0
- NUMERIC_MODIFIER_MASK = 1
- MODIFIER_BEHAVIOR_CHORDED = 0
- MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED = 1
-
- def __init__(self):
- super().__init__()
-
- def get(self, key_code: int, meta_state: int) -> int:
- return 0
-
- def getNumber(self, key_code: int) -> int:
- if KEYCODE_0 <= key_code <= KEYCODE_9:
- return ord("0") + (key_code - KEYCODE_0)
- return 0
-
- def getMatch(self, key_code: int, chars: List[int],
- meta_state: int = 0) -> int:
- return 0
-
- def getDisplayLabel(self, key_code: int) -> int:
- return key_code
-
- def getKeyboardType(self) -> int:
- return self.QWERTY
-
- @staticmethod
- def deviceHasKey(key_code: int) -> bool:
- return True
-
- @staticmethod
- def deviceHasKeys(key_codes: List[int]) -> List[bool]:
- return [True] * len(key_codes)
-
- def toString(self) -> str:
- return "KeyCharacterMap()"
-
-
-class KeyDispatcherState(Stub):
- """KeyDispatcherState — 按键调度状态"""
-
- def __init__(self):
- super().__init__()
- self._state: Dict[int, Any] = {}
-
- def reset(self) -> None:
- self._state.clear()
-
- def startTracking(self, event: KeyEvent, target: Any) -> None:
- key = event.getKeyCode()
- self._state[key] = {"target": target, "started": True}
-
- def isTracking(self, event: KeyEvent) -> bool:
- key = event.getKeyCode()
- return key in self._state and self._state[key].get("started", False)
-
- def performedLongPress(self, event: KeyEvent) -> None:
- key = event.getKeyCode()
- if key in self._state:
- self._state[key]["longpress"] = True
-
- def handleUpEvent(self, event: KeyEvent) -> bool:
- key = event.getKeyCode()
- if key in self._state:
- del self._state[key]
- return True
- return False
-
- def toString(self) -> str:
- return f"KeyDispatcherState(tracking={len(self._state)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LayoutInflater / Menu / MenuItem / SubMenu / ContextMenu
-# ═══════════════════════════════════════════════════════════════
-
-class LayoutInflater(Stub):
- """LayoutInflater — 布局填充器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
-
- @staticmethod
- def from_context(context: Any) -> "LayoutInflater":
- return LayoutInflater(context)
-
- def inflate(self, resource: Any, root: Any, attach_to_root: bool = False) -> Optional[Any]:
- return None
-
- def getContext(self) -> Optional[Any]:
- return self._context
-
- def cloneInContext(self, new_context: Any) -> "LayoutInflater":
- return LayoutInflater(new_context)
-
- def setFactory(self, factory: Any) -> None:
- pass
-
- def getFactory(self) -> Optional[Any]:
- return None
-
- def setFactory2(self, factory: Any) -> None:
- pass
-
- def getFactory2(self) -> Optional[Any]:
- return None
-
- def setFilters(self, filters: List[Any]) -> None:
- pass
-
- def toString(self) -> str:
- return f"LayoutInflater(context={self._context})"
-
-
-class Menu(Stub):
- """Menu — 菜单接口"""
-
- FIRST = 1
- NONE = 0
- CATEGORY_MASK = 0xFFFF
- CATEGORY_SHIFT = 16
- FLAG_PERFORM_NO_CLOSE = 1
- FLAG_ALWAYS_PERFORM_CLOSE = 2
- USER_MASK = 0x0000FFFF
- USER_SHIFT = 0
- CATEGORY_CONTAINER = 0x00010000
- CATEGORY_SYSTEM = 0x00020000
- CATEGORY_SECONDARY = 0x00030000
- CATEGORY_ALTERNATIVE = 0x00040000
- CATEGORY_APP = 0x00100000
-
- def add(self, title: str) -> "MenuItem":
- return MenuItem(self, 0, 0, 0, title)
-
- def add(self, group_id: int, item_id: int, order: int, title: str) -> "MenuItem":
- return MenuItem(self, group_id, item_id, order, title)
-
- def addIntentOptions(self, group_id: int, item_id: int, order: int,
- caller: Any, specific: Any, intent: Any,
- flags: int, out_specific_items: List[Any]) -> int:
- return 0
-
- def addSubMenu(self, title: str) -> "SubMenu":
- return SubMenu(self)
-
- def addSubMenu(self, group_id: int, item_id: int, order: int,
- title: str) -> "SubMenu":
- return SubMenu(self)
-
- def clear(self) -> None:
- pass
-
- def removeGroup(self, group_id: int) -> None:
- pass
-
- def removeItem(self, id_val: int) -> None:
- pass
-
- def setGroupCheckable(self, group: int, checkable: bool,
- exclusive: bool) -> None:
- pass
-
- def setGroupEnabled(self, group: int, enabled: bool) -> None:
- pass
-
- def setGroupVisible(self, group: int, visible: bool) -> None:
- pass
-
- def findItem(self, id_val: int) -> Optional["MenuItem"]:
- return None
-
- def size(self) -> int:
- return 0
-
- def getItem(self, index: int) -> "MenuItem":
- return MenuItem(self, 0, 0, 0, "")
-
- def close(self) -> None:
- pass
-
- def performIdentifierAction(self, id_val: int, flags: int) -> bool:
- return True
-
- def performShortcut(self, key_code: int, event: Any, flags: int) -> bool:
- return True
-
- def isShortcutKey(self, key_code: int, event: Any) -> bool:
- return False
-
- def hasVisibleItems(self) -> bool:
- return False
-
- def onMenuAction(self, id_val: int) -> bool:
- return True
-
- def toString(self) -> str:
- return "Menu()"
-
-
-class MenuItem(Stub):
- """MenuItem — 菜单项"""
-
- SHOW_AS_ACTION_ALWAYS = 2
- SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8
- SHOW_AS_ACTION_IF_ROOM = 1
- SHOW_AS_ACTION_NEVER = 0
- SHOW_AS_ACTION_WITH_TEXT = 4
-
- def __init__(self, menu: Menu = None, group_id: int = 0,
- item_id: int = 0, order: int = 0, title: str = ""):
- super().__init__()
- self._menu = menu
- self._item_id = item_id
- self._group_id = group_id
- self._order = order
- self._title = title
- self._title_condensed: Optional[str] = None
- self._icon: Optional[Any] = None
- self._intent: Optional[Any] = None
- self._checked = False
- self._checkable = False
- self._visible = True
- self._enabled = True
- self._action_view: Optional[Any] = None
- self._on_click: Optional[Callable] = None
- self._show_as_action = 0
-
- def getItemId(self) -> int:
- return self._item_id
-
- def getGroupId(self) -> int:
- return self._group_id
-
- def getOrder(self) -> int:
- return self._order
-
- def getTitle(self) -> str:
- return self._title
-
- def setTitle(self, title: str) -> "MenuItem":
- self._title = title
- return self
-
- def getTitleCondensed(self) -> Optional[str]:
- return self._title_condensed
-
- def setTitleCondensed(self, title: str) -> "MenuItem":
- self._title_condensed = title
- return self
-
- def getIcon(self) -> Optional[Any]:
- return self._icon
-
- def setIcon(self, icon: Any) -> "MenuItem":
- self._icon = icon
- return self
-
- def getIntent(self) -> Optional[Any]:
- return self._intent
-
- def setIntent(self, intent: Any) -> "MenuItem":
- self._intent = intent
- return self
-
- def isChecked(self) -> bool:
- return self._checked
-
- def setChecked(self, checked: bool) -> "MenuItem":
- self._checked = checked
- return self
-
- def isCheckable(self) -> bool:
- return self._checkable
-
- def setCheckable(self, checkable: bool) -> "MenuItem":
- self._checkable = checkable
- return self
-
- def isVisible(self) -> bool:
- return self._visible
-
- def setVisible(self, visible: bool) -> "MenuItem":
- self._visible = visible
- return self
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def setEnabled(self, enabled: bool) -> "MenuItem":
- self._enabled = enabled
- return self
-
- def setOnMenuItemClickListener(self, click: Callable) -> "MenuItem":
- self._on_click = click
- return self
-
- def getOnMenuItemClickListener(self) -> Optional[Callable]:
- return self._on_click
-
- def setActionView(self, view: Any) -> "MenuItem":
- self._action_view = view
- return self
-
- def setActionView(self, layout_res_id: int) -> "MenuItem":
- return self
-
- def getActionView(self) -> Optional[Any]:
- return self._action_view
-
- def setShowAsAction(self, action_enum: int) -> None:
- self._show_as_action = action_enum
-
- def getShowAsAction(self) -> int:
- return self._show_as_action
-
- def expandActionView(self) -> bool:
- return True
-
- def collapseActionView(self) -> bool:
- return True
-
- def isActionViewExpanded(self) -> bool:
- return False
-
- def setOnActionExpandListener(self, listener: Any) -> "MenuItem":
- return self
-
- def hasSubMenu(self) -> bool:
- return False
-
- def getSubMenu(self) -> Optional["SubMenu"]:
- return None
-
- def toString(self) -> str:
- return f"MenuItem(id={self._item_id}, title={self._title})"
-
-
-class SubMenu(Menu):
- """SubMenu — 子菜单"""
-
- def __init__(self, parent: Optional[Menu] = None):
- super().__init__()
- self._parent = parent
-
- def setHeaderTitle(self, title: str) -> "SubMenu":
- return self
-
- def setHeaderIcon(self, icon: Any) -> "SubMenu":
- return self
-
- def setHeaderView(self, view: Any) -> "SubMenu":
- return self
-
- def clearHeader(self) -> None:
- pass
-
- def setIcon(self, icon: Any) -> "SubMenu":
- return self
-
- def getItem(self) -> MenuItem:
- return MenuItem(self, 0, 0, 0, "")
-
- def toString(self) -> str:
- return "SubMenu()"
-
-
-class ContextMenu(Menu):
- """ContextMenu — 上下文菜单"""
-
- class ContextMenuInfo(Stub):
- """ContextMenu.ContextMenuInfo — 上下文菜单信息接口"""
- pass
-
- def __init__(self):
- super().__init__()
-
- def setHeaderTitle(self, title: str) -> "ContextMenu":
- return self
-
- def setHeaderIcon(self, icon: Any) -> "ContextMenu":
- return self
-
- def setHeaderView(self, view: Any) -> "ContextMenu":
- return self
-
- def clearHeader(self) -> None:
- pass
-
- def toString(self) -> str:
- return "ContextMenu()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScaleGestureDetector / SoundEffectConstants / Surface / etc.
-# ═══════════════════════════════════════════════════════════════
-
-class ScaleGestureDetector(_BaseScaleGestureDetector):
- """ScaleGestureDetector — 缩放手势检测器 (继承 view.ScaleGestureDetector 的所有方法)"""
-
- class SimpleOnScaleGestureListener(Stub):
- def onScale(self, detector: "ScaleGestureDetector") -> bool:
- return False
- def onScaleBegin(self, detector: "ScaleGestureDetector") -> bool:
- return True
- def onScaleEnd(self, detector: "ScaleGestureDetector") -> None:
- pass
-
- class OnScaleGestureListener(Stub):
- def onScale(self, detector: "ScaleGestureDetector") -> bool:
- return False
- def onScaleBegin(self, detector: "ScaleGestureDetector") -> bool:
- return True
- def onScaleEnd(self, detector: "ScaleGestureDetector") -> None:
- pass
-
- def __init__(self, context: Any = None, listener: Optional[Any] = None):
- super().__init__()
- self._listener = listener
- self._scale_factor: float = 1.0
- self._focus_x: float = 0.0
- self._focus_y: float = 0.0
- self._current_span: float = 0.0
- self._previous_span: float = 0.0
- self._time_delta: int = 0
- self._in_progress = False
- self._quick_scale_enabled = False
-
- def getScaleFactor(self) -> float:
- return self._scale_factor
-
- def getFocusX(self) -> float:
- return self._focus_x
-
- def getFocusY(self) -> float:
- return self._focus_y
-
- def getCurrentSpan(self) -> float:
- return self._current_span
-
- def getPreviousSpan(self) -> float:
- return self._previous_span
-
- def getCurrentSpanX(self) -> float:
- return self._current_span
-
- def getCurrentSpanY(self) -> float:
- return self._current_span
-
- def getPreviousSpanX(self) -> float:
- return self._previous_span
-
- def getPreviousSpanY(self) -> float:
- return self._previous_span
-
- def getTimeDelta(self) -> int:
- return self._time_delta
-
- def getEventTime(self) -> int:
- return 0
-
- def isInProgress(self) -> bool:
- return self._in_progress
-
- def setQuickScaleEnabled(self, enabled: bool) -> None:
- self._quick_scale_enabled = enabled
-
- def isQuickScaleEnabled(self) -> bool:
- return self._quick_scale_enabled
-
- def onTouchEvent(self, ev: Any) -> bool:
- return True
-
- def toString(self) -> str:
- return (f"ScaleGestureDetector(scale={self._scale_factor:.2f}, "
- f"inProgress={self._in_progress})")
-
-
-class SoundEffectConstants(_BaseSoundEffectConstants):
- """SoundEffectConstants — 音效常量 (继承 view.SoundEffectConstants 的所有方法)"""
-
- CLICK = 0
- NAVIGATION_UP = 1
- NAVIGATION_DOWN = 2
- NAVIGATION_LEFT = 3
- NAVIGATION_RIGHT = 4
- NAVIGATION_REPEAT_UP = 5
- NAVIGATION_REPEAT_DOWN = 6
- NAVIGATION_REPEAT_LEFT = 7
- NAVIGATION_REPEAT_RIGHT = 8
-
- @staticmethod
- def getContantForFocusDirection(direction: int) -> int:
- return SoundEffectConstants.NAVIGATION_UP
-
-
-class Surface(_BaseSurface):
- """Surface — 表面 (继承 view.Surface 的所有方法)"""
-
- ROTATION_0 = 0
- ROTATION_90 = 1
- ROTATION_180 = 2
- ROTATION_270 = 3
-
- def __init__(self, surface_control: Optional["SurfaceControl"] = None):
- super().__init__()
- self._surface_control = surface_control
- self._is_valid = True
- self._width: int = 0
- self._height: int = 0
-
- def isValid(self) -> bool:
- return self._is_valid
-
- def lockCanvas(self, dirty_rect: Optional[Any] = None) -> Optional[Any]:
- return None
-
- def unlockCanvasAndPost(self, canvas: Any) -> None:
- pass
-
- def getSurfaceControl(self) -> Optional["SurfaceControl"]:
- return self._surface_control
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def toString(self) -> str:
- return f"Surface(valid={self._is_valid})"
-
-
-class SurfaceControl(Stub):
- """SurfaceControl — 表面控制"""
-
- BUFFER_TRANSFORM_IDENTITY = 0
- BUFFER_TRANSFORM_MIRROR_H = 1
- BUFFER_TRANSFORM_MIRROR_V = 2
- BUFFER_TRANSFORM_ROTATE_90 = 4
- BUFFER_TRANSFORM_ROTATE_180 = 3
- BUFFER_TRANSFORM_ROTATE_270 = 7
-
- def __init__(self):
- super().__init__()
- self._surface: Optional[Surface] = None
- self._visible = False
- self._alpha: float = 1.0
- self._layer: int = 0
-
- def createSurface(self) -> Surface:
- self._surface = Surface(self)
- return self._surface
-
- def setAlpha(self, alpha: float) -> None:
- self._alpha = max(0.0, min(1.0, alpha))
-
- def setLayer(self, layer: int) -> None:
- self._layer = layer
-
- def setVisible(self, visible: bool) -> None:
- self._visible = visible
-
- def release(self) -> None:
- self._surface = None
-
- def toString(self) -> str:
- return f"SurfaceControl(layer={self._layer}, visible={self._visible})"
-
-
-class SurfaceView(_BaseSurfaceView):
- """SurfaceView — 表面视图扩展 (继承 view.SurfaceView 的所有方法)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._surface: Optional[Surface] = None
- self._surface_holder: Optional[Any] = None
- self._callback: Optional[Callable] = None
-
- def getHolder(self) -> Optional[Any]:
- return self._surface_holder
-
- def getSurfaceControl(self) -> Optional[SurfaceControl]:
- return None
-
- def setSecure(self, secure: bool) -> None:
- pass
-
- def setZOrderOnTop(self, on_top: bool) -> None:
- pass
-
- def setZOrderMediaOverlay(self, is_media_overlay: bool) -> None:
- pass
-
- def toString(self) -> str:
- return "SurfaceView()"
-
-
-class TextureView(_BaseTextureView):
- """TextureView — 纹理视图扩展 (继承 view.TextureView 的所有方法)"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._surface_texture: Optional[Any] = None
- self._callback: Optional[Callable] = None
- self._update_listener: Optional[Callable] = None
-
- def getSurfaceTexture(self) -> Optional[Any]:
- return self._surface_texture
-
- def setSurfaceTextureListener(self, listener: Optional[Callable]) -> None:
- self._update_listener = listener
-
- def isAvailable(self) -> bool:
- return self._surface_texture is not None
-
- def setOpaque(self, opaque: bool) -> None:
- pass
-
- def getBitmap(self) -> Optional[Any]:
- return None
-
- def toString(self) -> str:
- return "TextureView()"
-
-
-class TouchDelegate(Stub):
- """TouchDelegate — 触摸委托"""
-
- def __init__(self, bounds: Any, delegate_view: Any):
- super().__init__()
- self._bounds = bounds
- self._delegate_view = delegate_view
- self._touch_slop: int = 8
-
- def onTouchEvent(self, event: Any) -> bool:
- return False
-
- def toString(self) -> str:
- return f"TouchDelegate(delegate={self._delegate_view})"
-
-
-class VelocityTracker(_BaseVelocityTracker):
- """VelocityTracker — 速度追踪器 (继承 view.VelocityTracker 的所有方法)"""
-
- def __init__(self, strategy: str = ""):
- super().__init__()
- self._positions: List[Tuple[float, float, int]] = []
- self._strategy = strategy
-
- @staticmethod
- def obtain(strategy: str = "") -> "VelocityTracker":
- return VelocityTracker(strategy)
-
- def addMovement(self, event: Any) -> None:
- pass
-
- def computeCurrentVelocity(self, units: int, max_velocity: float = 10000.0) -> None:
- pass
-
- def getXVelocity(self) -> float:
- return 0.0
-
- def getYVelocity(self) -> float:
- return 0.0
-
- def getXVelocity(self, id_val: int) -> float:
- return 0.0
-
- def getYVelocity(self, id_val: int) -> float:
- return 0.0
-
- def clear(self) -> None:
- self._positions.clear()
-
- def recycle(self) -> None:
- self._positions.clear()
-
- def toString(self) -> str:
- return f"VelocityTracker(strategy={self._strategy})"
-
-
-class WindowInsetsAnimation(Stub):
- """WindowInsetsAnimation — 窗口插入动画"""
-
- def __init__(self, type_mask: int = 0, interpolated_fraction: float = 0.0):
- super().__init__()
- self._type_mask = type_mask
- self._interpolated_fraction = interpolated_fraction
- self._duration: int = 0
- self._interpolator: Optional[Any] = None
-
- def getTypeMask(self) -> int:
- return self._type_mask
-
- def getInterpolatedFraction(self) -> float:
- return self._interpolated_fraction
-
- def getDurationMillis(self) -> float:
- return float(self._duration)
-
- def setDuration(self, duration: int) -> None:
- self._duration = duration
-
- def setInterpolator(self, interpolator: Any) -> None:
- self._interpolator = interpolator
-
- def getInterpolator(self) -> Optional[Any]:
- return self._interpolator
-
- class Callback(Stub):
- """WindowInsetsAnimation.Callback — 动画回调"""
-
- DISPATCH_MODE_STOP = 0
- DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1
-
- def __init__(self, dispatch_mode: int = DISPATCH_MODE_CONTINUE_ON_SUBTREE):
- super().__init__()
- self._dispatch_mode = dispatch_mode
-
- def onPrepare(self, animation: "WindowInsetsAnimation") -> None:
- pass
-
- def onStart(self, animation: "WindowInsetsAnimation",
- bounds: WindowInsetsAnimation.Bounds) -> None:
- pass
-
- def onProgress(self, insets: WindowInsets,
- running_animations: List["WindowInsetsAnimation"]) -> WindowInsets:
- return insets
-
- def onEnd(self, animation: "WindowInsetsAnimation") -> None:
- pass
-
- class Bounds(Stub):
- """WindowInsetsAnimation.Bounds — 动画边界"""
-
- def __init__(self, lower_bound: WindowInsets, upper_bound: WindowInsets):
- super().__init__()
- self._lower_bound = lower_bound
- self._upper_bound = upper_bound
-
- def getLowerBound(self) -> WindowInsets:
- return self._lower_bound
-
- def getUpperBound(self) -> WindowInsets:
- return self._upper_bound
-
- def inset(self, insets: WindowInsets) -> "Bounds":
- return self
-
- def toString(self) -> str:
- return "WindowInsetsAnimation.Bounds()"
-
- def toString(self) -> str:
- return (f"WindowInsetsAnimation(typeMask={self._type_mask}, "
- f"fraction={self._interpolated_fraction})")
-
-
-class WindowInsetsController(_BaseWindowInsetsController):
- """WindowInsetsController — 窗口插入控制器 (继承 view.WindowInsetsController 的所有方法)"""
-
- APPEARANCE_OPAQUE_STATUS_BARS = 1
- APPEARANCE_OPAQUE_NAVIGATION_BARS = 2
- APPEARANCE_LOW_PROFILE_BARS = 4
- APPEARANCE_LIGHT_STATUS_BARS = 8
- APPEARANCE_LIGHT_NAVIGATION_BARS = 16
- APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS = 32
- APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS = 64
-
- BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 0
- BEHAVIOR_DEFAULT = 1
- BEHAVIOR_SHOW_BARS_BY_TOUCH = 2
- BEHAVIOR_SHOW_BARS_BY_SWIPE = 3
-
- def __init__(self):
- super().__init__()
- self._appearance: int = 0
- self._behavior: int = self.BEHAVIOR_DEFAULT
- self._show_types: int = 0
- self._hide_types: int = 0
-
- def show(self, types: int) -> None:
- self._show_types |= types
-
- def hide(self, types: int) -> None:
- self._hide_types |= types
-
- def setAppearance(self, appearance: int) -> None:
- self._appearance = appearance
-
- def getAppearance(self) -> int:
- return self._appearance
-
- def setBehavior(self, behavior: int) -> None:
- self._behavior = behavior
-
- def getBehavior(self) -> int:
- return self._behavior
-
- def setSystemBarsAppearance(self, appearance: int, mask: int) -> None:
- self._appearance = (self._appearance & ~mask) | (appearance & mask)
-
- def getSystemBarsAppearance(self) -> int:
- return self._appearance
-
- def toString(self) -> str:
- return (f"WindowInsetsController(show={self._show_types}, "
- f"hide={self._hide_types})")
\ No newline at end of file
diff --git a/android_pyapi/android/view_gesture.py b/android_pyapi/android/view_gesture.py
deleted file mode 100644
index e798fdc..0000000
--- a/android_pyapi/android/view_gesture.py
+++ /dev/null
@@ -1,647 +0,0 @@
-"""
-Android View Gesture 扩展组件 — GestureBuilder, GestureLibrary, GestureStore 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import time
-import json
-import os
-import threading
-from typing import Any, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# GesturePoint
-# ═══════════════════════════════════════════════════════════════
-
-class GesturePoint(Stub):
- """GesturePoint — 手势点"""
-
- def __init__(self, x: float = 0.0, y: float = 0.0,
- pressure: float = 1.0, size: float = 1.0,
- timestamp: int = 0):
- super().__init__()
- self.x = x
- self.y = y
- self.pressure = pressure
- self.size = size
- self.timestamp = timestamp or int(time.time() * 1000)
-
- def getX(self) -> float:
- return self.x
-
- def getY(self) -> float:
- return self.y
-
- def getPressure(self) -> float:
- return self.pressure
-
- def getSize(self) -> float:
- return self.size
-
- def getTimestamp(self) -> int:
- return self.timestamp
-
- def distance(self, other: "GesturePoint") -> float:
- dx = self.x - other.x
- dy = self.y - other.y
- return math.sqrt(dx * dx + dy * dy)
-
- def toString(self) -> str:
- return (f"GesturePoint({self.x:.1f}, {self.y:.1f}, "
- f"p={self.pressure:.2f})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureStroke
-# ═══════════════════════════════════════════════════════════════
-
-class GestureStroke(Stub):
- """GestureStroke — 手势笔画"""
-
- def __init__(self, points: Optional[List[GesturePoint]] = None):
- super().__init__()
- self._points: List[GesturePoint] = list(points) if points else []
- self._length: float = -1.0
- self._bounding_box: Optional[Tuple[float, float, float, float]] = None
- self._straightness: Optional[float] = None
- self._lock = threading.Lock()
-
- def getPoints(self) -> List[GesturePoint]:
- return list(self._points)
-
- def getPointCount(self) -> int:
- return len(self._points)
-
- def getLength(self) -> float:
- with self._lock:
- if self._length < 0:
- self._length = self._compute_length()
- return self._length
-
- def _compute_length(self) -> float:
- length = 0.0
- for i in range(1, len(self._points)):
- length += self._points[i].distance(self._points[i - 1])
- return length
-
- def getBoundingBox(self) -> Tuple[float, float, float, float]:
- with self._lock:
- if self._bounding_box is None:
- self._bounding_box = self._compute_bounding_box()
- return self._bounding_box
-
- def _compute_bounding_box(self) -> Tuple[float, float, float, float]:
- if not self._points:
- return (0.0, 0.0, 0.0, 0.0)
- min_x = min(p.x for p in self._points)
- max_x = max(p.x for p in self._points)
- min_y = min(p.y for p in self._points)
- max_y = max(p.y for p in self._points)
- return (min_x, min_y, max_x, max_y)
-
- def getStraightness(self) -> float:
- with self._lock:
- if self._straightness is None:
- self._straightness = self._compute_straightness()
- return self._straightness
-
- def _compute_straightness(self) -> float:
- if len(self._points) < 2:
- return 1.0
- dx = self._points[-1].x - self._points[0].x
- dy = self._points[-1].y - self._points[0].y
- straight_dist = math.sqrt(dx * dx + dy * dy)
- actual_dist = self.getLength()
- if actual_dist == 0:
- return 1.0
- return straight_dist / actual_dist
-
- def computeOrientedBoundingBox(self) -> "OrientedBoundingBox":
- return OrientedBoundingBox.computeFromStroke(self)
-
- def addPoint(self, point: GesturePoint) -> None:
- with self._lock:
- self._points.append(point)
- self._length = -1.0
- self._bounding_box = None
-
- def clear(self) -> None:
- with self._lock:
- self._points.clear()
- self._length = -1.0
- self._bounding_box = None
-
- def toString(self) -> str:
- return f"GestureStroke(points={len(self._points)}, length={self.getLength():.1f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# OrientedBoundingBox
-# ═══════════════════════════════════════════════════════════════
-
-class OrientedBoundingBox(Stub):
- """OrientedBoundingBox — 定向边界框"""
-
- def __init__(self, center_x: float = 0.0, center_y: float = 0.0,
- width: float = 0.0, height: float = 0.0,
- orientation: float = 0.0):
- super().__init__()
- self.centerX = center_x
- self.centerY = center_y
- self.width = width
- self.height = height
- self.orientation = orientation
-
- @staticmethod
- def computeFromStroke(stroke: GestureStroke) -> "OrientedBoundingBox":
- points = stroke.getPoints()
- if len(points) < 2:
- return OrientedBoundingBox()
-
- sum_x = sum(p.x for p in points)
- sum_y = sum(p.y for p in points)
- n = len(points)
- center_x = sum_x / n
- center_y = sum_y / n
-
- variance_x = sum((p.x - center_x) ** 2 for p in points) / n
- variance_y = sum((p.y - center_y) ** 2 for p in points) / n
- covariance = sum((p.x - center_x) * (p.y - center_y) for p in points) / n
-
- if variance_x + variance_y == 0:
- return OrientedBoundingBox(center_x, center_y, 1, 1, 0)
-
- theta = 0.5 * math.atan2(2 * covariance, variance_x - variance_y)
- cos_t = math.cos(theta)
- sin_t = math.sin(theta)
-
- max_proj1 = max_proj2 = float("-inf")
- min_proj1 = min_proj2 = float("inf")
-
- for p in points:
- proj1 = (p.x - center_x) * cos_t + (p.y - center_y) * sin_t
- proj2 = -(p.x - center_x) * sin_t + (p.y - center_y) * cos_t
- max_proj1 = max(max_proj1, proj1)
- min_proj1 = min(min_proj1, proj1)
- max_proj2 = max(max_proj2, proj2)
- min_proj2 = min(min_proj2, proj2)
-
- width = max_proj1 - min_proj1
- height = max_proj2 - min_proj2
- orientation = math.degrees(theta)
-
- return OrientedBoundingBox(center_x, center_y, width, height, orientation)
-
- def getCenterX(self) -> float:
- return self.centerX
-
- def getCenterY(self) -> float:
- return self.centerY
-
- def getWidth(self) -> float:
- return self.width
-
- def getHeight(self) -> float:
- return self.height
-
- def getOrientation(self) -> float:
- return self.orientation
-
- def toString(self) -> str:
- return (f"OrientedBoundingBox(center=({self.centerX:.1f},{self.centerY:.1f}), "
- f"size=({self.width:.1f}x{self.height:.1f}), "
- f"angle={self.orientation:.1f})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureUtils
-# ═══════════════════════════════════════════════════════════════
-
-class GestureUtils(Stub):
- """GestureUtils — 手势工具"""
-
- MINIMUM_STROKE_LENGTH = 50.0
- MAXIMUM_STROKE_LENGTH = 10000.0
-
- @staticmethod
- def spatialSampling(gesture: "Gesture", num_samples: int = 16) -> List[float]:
- """空间采样 — 将手势转换为固定长度的向量"""
- result = []
- strokes = gesture.getStrokes()
- if not strokes:
- return [0.0] * (num_samples * 2)
-
- all_points = []
- for stroke in strokes:
- all_points.extend(stroke.getPoints())
-
- if len(all_points) < 2:
- return [0.0] * (num_samples * 2)
-
- total_length = sum(
- all_points[i].distance(all_points[i - 1])
- for i in range(1, len(all_points))
- )
-
- if total_length == 0:
- return [all_points[0].x, all_points[0].y] * num_samples
-
- step = total_length / (num_samples - 1)
- current_dist = 0.0
- target_dist = 0.0
- result.append(all_points[0].x)
- result.append(all_points[0].y)
-
- for i in range(1, len(all_points)):
- seg_length = all_points[i].distance(all_points[i - 1])
- if seg_length == 0:
- continue
- current_dist += seg_length
- while target_dist < current_dist and len(result) < num_samples * 2:
- ratio = 1.0 - (current_dist - target_dist) / seg_length
- x = all_points[i - 1].x + ratio * (all_points[i].x - all_points[i - 1].x)
- y = all_points[i - 1].y + ratio * (all_points[i].y - all_points[i - 1].y)
- result.append(x)
- result.append(y)
- target_dist += step
-
- while len(result) < num_samples * 2:
- result.append(all_points[-1].x)
- result.append(all_points[-1].y)
-
- return result[:num_samples * 2]
-
- @staticmethod
- def temporalSampling(gesture: "Gesture", num_samples: int = 16) -> List[float]:
- return GestureUtils.spatialSampling(gesture, num_samples)
-
- @staticmethod
- def computeOrientedBoundingBox(stroke: GestureStroke) -> OrientedBoundingBox:
- return OrientedBoundingBox.computeFromStroke(stroke)
-
- @staticmethod
- def normalize(points: List[float]) -> List[float]:
- if not points:
- return []
- xs = points[0::2]
- ys = points[1::2]
- min_x = min(xs)
- max_x = max(xs)
- min_y = min(ys)
- max_y = max(ys)
- range_x = max_x - min_x if max_x != min_x else 1
- range_y = max_y - min_y if max_y != min_y else 1
-
- normalized = []
- for i in range(0, len(points), 2):
- normalized.append((points[i] - min_x) / range_x)
- normalized.append((points[i + 1] - min_y) / range_y)
- return normalized
-
- @staticmethod
- def scale(points: List[float], width: float, height: float) -> List[float]:
- normalized = GestureUtils.normalize(points)
- scaled = []
- for i in range(0, len(normalized), 2):
- scaled.append(normalized[i] * width)
- scaled.append(normalized[i + 1] * height)
- return scaled
-
- @staticmethod
- def totalLength(points: List[float]) -> float:
- length = 0.0
- for i in range(2, len(points), 2):
- dx = points[i] - points[i - 2]
- dy = points[i + 1] - points[i - 1]
- length += math.sqrt(dx * dx + dy * dy)
- return length
-
- @staticmethod
- def cosineDistance(vector1: List[float], vector2: List[float]) -> float:
- if len(vector1) != len(vector2) or not vector1:
- return 1.0
- dot = sum(a * b for a, b in zip(vector1, vector2))
- norm1 = math.sqrt(sum(a * a for a in vector1))
- norm2 = math.sqrt(sum(b * b for b in vector2))
- if norm1 == 0 or norm2 == 0:
- return 1.0
- return 1.0 - dot / (norm1 * norm2)
-
- @staticmethod
- def euclideanDistance(vector1: List[float], vector2: List[float]) -> float:
- if len(vector1) != len(vector2):
- return float("inf")
- return math.sqrt(sum((a - b) ** 2 for a, b in zip(vector1, vector2)))
-
-
-# ═══════════════════════════════════════════════════════════════
-# Gesture
-# ═══════════════════════════════════════════════════════════════
-
-class Gesture(Stub):
- """Gesture — 手势"""
-
- def __init__(self):
- super().__init__()
- self._strokes: List[GestureStroke] = []
- self._id: int = 0
- self._name: str = ""
- self._lock = threading.Lock()
-
- def addStroke(self, stroke: GestureStroke) -> None:
- with self._lock:
- self._strokes.append(stroke)
-
- def getStrokes(self) -> List[GestureStroke]:
- return list(self._strokes)
-
- def getStrokeCount(self) -> int:
- return len(self._strokes)
-
- def getLength(self) -> float:
- total = 0.0
- for stroke in self._strokes:
- total += stroke.getLength()
- return total
-
- def getBoundingBox(self) -> Tuple[float, float, float, float]:
- if not self._strokes:
- return (0, 0, 0, 0)
- min_x = min(s.getBoundingBox()[0] for s in self._strokes)
- min_y = min(s.getBoundingBox()[1] for s in self._strokes)
- max_x = max(s.getBoundingBox()[2] for s in self._strokes)
- max_y = max(s.getBoundingBox()[3] for s in self._strokes)
- return (min_x, min_y, max_x, max_y)
-
- def getID(self) -> int:
- return self._id
-
- def setID(self, id_val: int) -> None:
- self._id = id_val
-
- def getName(self) -> str:
- return self._name
-
- def setName(self, name: str) -> None:
- self._name = name
-
- def toJson(self) -> str:
- data = {
- "id": self._id,
- "name": self._name,
- "strokes": []
- }
- for stroke in self._strokes:
- stroke_data = {
- "points": [
- {"x": p.x, "y": p.y, "pressure": p.pressure,
- "size": p.size, "timestamp": p.timestamp}
- for p in stroke.getPoints()
- ]
- }
- data["strokes"].append(stroke_data)
- return json.dumps(data)
-
- @staticmethod
- def fromJson(json_str: str) -> "Gesture":
- data = json.loads(json_str)
- gesture = Gesture()
- gesture.setID(data.get("id", 0))
- gesture.setName(data.get("name", ""))
- for stroke_data in data.get("strokes", []):
- points = [
- GesturePoint(p["x"], p["y"], p.get("pressure", 1.0),
- p.get("size", 1.0), p.get("timestamp", 0))
- for p in stroke_data.get("points", [])
- ]
- gesture.addStroke(GestureStroke(points))
- return gesture
-
- def toString(self) -> str:
- return f"Gesture(name={self._name}, strokes={len(self._strokes)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Prediction
-# ═══════════════════════════════════════════════════════════════
-
-class Prediction(Stub):
- """Prediction — 手势识别预测结果"""
-
- def __init__(self, name: str = "", score: float = 0.0):
- super().__init__()
- self.name = name
- self.score = score
-
- def getName(self) -> str:
- return self.name
-
- def getScore(self) -> float:
- return self.score
-
- def toString(self) -> str:
- return f"Prediction(name={self.name}, score={self.score:.3f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GestureLibrary / GestureStore
-# ═══════════════════════════════════════════════════════════════
-
-class GestureLibrary(Stub):
- """GestureLibrary — 手势库扩展"""
-
- SEQUENCE_MINIMUM_LENGTH = 2
-
- def __init__(self):
- super().__init__()
- self._gestures: Dict[str, List[Gesture]] = {}
- self._lock = threading.Lock()
-
- def getGestureEntries(self) -> Set[str]:
- with self._lock:
- return set(self._gestures.keys())
-
- def getGestures(self, entry_name: str) -> List[Gesture]:
- with self._lock:
- return list(self._gestures.get(entry_name, []))
-
- def recognize(self, gesture: Gesture) -> List[Prediction]:
- """识别手势,返回预测结果列表"""
- results: List[Prediction] = []
- with self._lock:
- for name, gestures in self._gestures.items():
- for g in gestures:
- score = self._compute_similarity(gesture, g)
- results.append(Prediction(name, score))
- results.sort(key=lambda p: p.score, reverse=True)
- return results[:10]
-
- def _compute_similarity(self, g1: Gesture, g2: Gesture) -> float:
- """计算两个手势之间的相似度 (0.0 - 1.0)"""
- try:
- v1 = GestureUtils.spatialSampling(g1, 16)
- v2 = GestureUtils.spatialSampling(g2, 16)
- distance = GestureUtils.euclideanDistance(v1, v2)
- max_dist = math.sqrt(len(v1))
- similarity = 1.0 - (distance / max_dist)
- return max(0.0, min(1.0, similarity))
- except Exception:
- return 0.0
-
- def addGesture(self, entry_name: str, gesture: Gesture) -> None:
- with self._lock:
- if entry_name not in self._gestures:
- self._gestures[entry_name] = []
- gesture.setName(entry_name)
- self._gestures[entry_name].append(gesture)
-
- def removeGesture(self, entry_name: str, gesture: Gesture) -> None:
- with self._lock:
- if entry_name in self._gestures:
- if gesture in self._gestures[entry_name]:
- self._gestures[entry_name].remove(gesture)
-
- def removeEntry(self, entry_name: str) -> None:
- with self._lock:
- self._gestures.pop(entry_name, None)
-
- def getGestureCount(self) -> int:
- count = 0
- with self._lock:
- for gestures in self._gestures.values():
- count += len(gestures)
- return count
-
- def getEntryCount(self) -> int:
- return len(self._gestures)
-
- def save(self, path: str) -> bool:
- try:
- data = {}
- with self._lock:
- for name, gestures in self._gestures.items():
- data[name] = [g.toJson() for g in gestures]
- with open(path, "w") as f:
- json.dump(data, f)
- return True
- except Exception:
- return False
-
- def load(self, path: str) -> bool:
- try:
- if not os.path.exists(path):
- return False
- with open(path, "r") as f:
- data = json.load(f)
- with self._lock:
- self._gestures.clear()
- for name, gesture_jsons in data.items():
- self._gestures[name] = [
- Gesture.fromJson(gj) for gj in gesture_jsons
- ]
- return True
- except Exception:
- return False
-
- def clear(self) -> None:
- with self._lock:
- self._gestures.clear()
-
- def isReadOnly(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"GestureLibrary(entries={len(self._gestures)})"
-
-
-class GestureStore(GestureLibrary):
- """GestureStore — 手势存储扩展"""
-
- SEQUENCE_TYPE_INVARIANT = 1
- SEQUENCE_TYPE_SENSITIVE = 2
- ORIENTATION_INVARIANT = 1
- ORIENTATION_SENSITIVE = 2
-
- def __init__(self):
- super().__init__()
- self._sequence_type = self.SEQUENCE_TYPE_SENSITIVE
- self._orientation_style = self.ORIENTATION_INVARIANT
-
- def setSequenceType(self, type_val: int) -> None:
- self._sequence_type = type_val
-
- def getSequenceType(self) -> int:
- return self._sequence_type
-
- def setOrientationStyle(self, style: int) -> None:
- self._orientation_style = style
-
- def getOrientationStyle(self) -> int:
- return self._orientation_style
-
- def toString(self) -> str:
- return f"GestureStore(entries={self.getEntryCount()})"
-
-
-class GestureBuilder(Stub):
- """GestureBuilder — 手势构建器"""
-
- MIN_LENGTH = 10.0
- MAX_LENGTH = 500.0
-
- def __init__(self):
- super().__init__()
- self._current_gesture: Optional[Gesture] = None
- self._current_stroke: Optional[GestureStroke] = None
- self._current_points: List[GesturePoint] = []
-
- def newGesture(self) -> Gesture:
- gesture = Gesture()
- self._current_gesture = gesture
- self._current_stroke = None
- self._current_points = []
- return gesture
-
- def startStroke(self, x: float, y: float, pressure: float = 1.0) -> None:
- self._current_points = []
- point = GesturePoint(x, y, pressure, 1.0, int(time.time() * 1000))
- self._current_points.append(point)
-
- def moveStroke(self, x: float, y: float, pressure: float = 1.0) -> None:
- point = GesturePoint(x, y, pressure, 1.0, int(time.time() * 1000))
- self._current_points.append(point)
-
- def endStroke(self) -> GestureStroke:
- stroke = GestureStroke(self._current_points)
- self._current_stroke = stroke
- if self._current_gesture:
- self._current_gesture.addStroke(stroke)
- self._current_points = []
- return stroke
-
- def cancelStroke(self) -> None:
- self._current_points = []
- self._current_stroke = None
-
- def getCurrentGesture(self) -> Optional[Gesture]:
- return self._current_gesture
-
- def getCurrentStroke(self) -> Optional[GestureStroke]:
- return self._current_stroke
-
- def setOrientationStyle(self, style: int) -> None:
- pass
-
- def setSequenceType(self, type_val: int) -> None:
- pass
-
- def toString(self) -> str:
- return (f"GestureBuilder(gesture={'yes' if self._current_gesture else 'no'}, "
- f"strokePoints={len(self._current_points)})")
\ No newline at end of file
diff --git a/android_pyapi/android/view_haptic.py b/android_pyapi/android/view_haptic.py
deleted file mode 100644
index d8b3a81..0000000
--- a/android_pyapi/android/view_haptic.py
+++ /dev/null
@@ -1,381 +0,0 @@
-"""
-Android View Haptic 组件 — HapticFeedbackConstants, View 触觉扩展
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import threading
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# HapticFeedbackConstants
-# ═══════════════════════════════════════════════════════════════
-
-class HapticFeedbackConstants(Stub):
- """HapticFeedbackConstants — 触觉反馈常量"""
-
- LONG_PRESS = 0
- TEXT_HANDLE_MOVE = 12
- VIRTUAL_KEY = 1
- VIRTUAL_KEY_RELEASE = 2
- CLOCK_TICK = 4
- KEYBOARD_PRESS = 3
- KEYBOARD_RELEASE = 13
- KEYBOARD_TAP = 3
- CONFIRM = 5
- REJECT = 6
- GESTURE_START = 7
- GESTURE_END = 8
- EDGE_REJECT = 9
- DRAG_CROSS = 10
- SEGMENT_FREQUENT_TICK = 11
- SEGMENT_TICK = 14
- SEGMENT_TICK_VERY_SMALL = 15
- SEGMENT_TICK_SMALL = 16
- SEGMENT_TICK_MEDIUM = 17
- SEGMENT_TICK_LARGE = 18
- ENTRY_BUMP = 19
- EXIT_BUMP = 20
- REORDER = 21
- CONTEXT_CLICK = 22
-
- FLAG_IGNORE_VIEW_SETTING = 1
- FLAG_IGNORE_GLOBAL_SETTING = 2
-
- _is_enabled = True
- _global_enabled = True
- _lock = threading.Lock()
-
- def __init__(self):
- super().__init__()
-
- @classmethod
- def isEnabled(cls) -> bool:
- with cls._lock:
- return cls._is_enabled and cls._global_enabled
-
- @classmethod
- def setEnabled(cls, enabled: bool) -> None:
- with cls._lock:
- cls._is_enabled = enabled
-
- @classmethod
- def setGlobalEnabled(cls, enabled: bool) -> None:
- with cls._lock:
- cls._global_enabled = enabled
-
- @classmethod
- def isGlobalEnabled(cls) -> bool:
- with cls._lock:
- return cls._global_enabled
-
- @classmethod
- def toString(cls) -> str:
- return (f"HapticFeedbackConstants(enabled={cls._is_enabled}, "
- f"global={cls._global_enabled})")
-
- @classmethod
- def getFeedbackConstantName(cls, feedback_constant: int) -> str:
- names = {
- 0: "LONG_PRESS", 12: "TEXT_HANDLE_MOVE", 1: "VIRTUAL_KEY",
- 2: "VIRTUAL_KEY_RELEASE", 4: "CLOCK_TICK", 3: "KEYBOARD_PRESS",
- 13: "KEYBOARD_RELEASE", 5: "CONFIRM", 6: "REJECT",
- 7: "GESTURE_START", 8: "GESTURE_END", 9: "EDGE_REJECT",
- 10: "DRAG_CROSS", 11: "SEGMENT_FREQUENT_TICK",
- 14: "SEGMENT_TICK", 15: "SEGMENT_TICK_VERY_SMALL",
- 16: "SEGMENT_TICK_SMALL", 17: "SEGMENT_TICK_MEDIUM",
- 18: "SEGMENT_TICK_LARGE", 19: "ENTRY_BUMP", 20: "EXIT_BUMP",
- 21: "REORDER", 22: "CONTEXT_CLICK",
- }
- return names.get(feedback_constant, f"UNKNOWN({feedback_constant})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# View Haptic 方法扩展
-# ═══════════════════════════════════════════════════════════════
-
-class ViewHapticExtensions(Stub):
- """ViewHapticExtensions — 视图触觉扩展方法"""
-
- def __init__(self, view: Any = None):
- super().__init__()
- self._view = view
- self._haptic_enabled = True
- self._haptic_feedback_enabled = True
- self._exclude_gesture_region = False
- self._lock = threading.Lock()
-
- def performHapticFeedback(self, feedback_constant: int,
- flags: int = 0) -> bool:
- """执行触觉反馈"""
- if not self._haptic_enabled:
- return False
- if flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING:
- pass
- if flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING:
- pass
- if not HapticFeedbackConstants.isEnabled():
- return False
- return self._do_haptic(feedback_constant)
-
- def _do_haptic(self, feedback_constant: int) -> bool:
- """实际执行触觉反馈效果 (桌面模拟)"""
- return True
-
- def setHapticFeedbackEnabled(self, enabled: bool) -> None:
- with self._lock:
- self._haptic_feedback_enabled = enabled
-
- def isHapticFeedbackEnabled(self) -> bool:
- return self._haptic_feedback_enabled
-
- def setHapticEnabled(self, enabled: bool) -> None:
- with self._lock:
- self._haptic_enabled = enabled
-
- def isHapticEnabled(self) -> bool:
- return self._haptic_enabled
-
- def setExcludeFromExcludeGestureRegion(self, exclude: bool) -> None:
- self._exclude_gesture_region = exclude
-
- def isExcludedFromExcludeGestureRegion(self) -> bool:
- return self._exclude_gesture_region
-
- def toString(self) -> str:
- return (f"ViewHapticExtensions(enabled={self._haptic_enabled}, "
- f"feedback={self._haptic_feedback_enabled})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# HapticPlayer (触觉播放器)
-# ═══════════════════════════════════════════════════════════════
-
-class HapticPlayer(Stub):
- """HapticPlayer — 触觉播放器"""
-
- PLAY_STATUS_IDLE = 0
- PLAY_STATUS_PLAYING = 1
- PLAY_STATUS_PAUSED = 2
- PLAY_STATUS_STOPPED = 3
-
- def __init__(self):
- super().__init__()
- self._status = self.PLAY_STATUS_IDLE
- self._duration: int = 0
- self._amplitude: float = 1.0
- self._frequency: float = 150.0
- self._on_completion: Optional[Callable] = None
- self._lock = threading.Lock()
-
- def play(self) -> None:
- with self._lock:
- self._status = self.PLAY_STATUS_PLAYING
-
- def pause(self) -> None:
- with self._lock:
- self._status = self.PLAY_STATUS_PAUSED
-
- def stop(self) -> None:
- with self._lock:
- self._status = self.PLAY_STATUS_STOPPED
- if self._on_completion:
- self._on_completion()
-
- def setDuration(self, duration_ms: int) -> None:
- self._duration = max(0, duration_ms)
-
- def getDuration(self) -> int:
- return self._duration
-
- def setAmplitude(self, amplitude: float) -> None:
- self._amplitude = max(0.0, min(1.0, amplitude))
-
- def getAmplitude(self) -> float:
- return self._amplitude
-
- def setFrequency(self, frequency_hz: float) -> None:
- self._frequency = max(20.0, min(1000.0, frequency_hz))
-
- def getFrequency(self) -> float:
- return self._frequency
-
- def setOnCompletionListener(self, listener: Optional[Callable]) -> None:
- self._on_completion = listener
-
- def getStatus(self) -> int:
- return self._status
-
- def isPlaying(self) -> bool:
- return self._status == self.PLAY_STATUS_PLAYING
-
- def toString(self) -> str:
- return (f"HapticPlayer(duration={self._duration}ms, "
- f"amplitude={self._amplitude:.2f}, "
- f"freq={self._frequency:.0f}Hz)")
-
-
-# ═══════════════════════════════════════════════════════════════
-# HapticFeedbackProvider
-# ═══════════════════════════════════════════════════════════════
-
-class HapticFeedbackProvider(Stub):
- """HapticFeedbackProvider — 触觉反馈提供者"""
-
- def __init__(self):
- super().__init__()
- self._players: Dict[int, HapticPlayer] = {}
- self._default_duration: Dict[int, int] = {
- HapticFeedbackConstants.LONG_PRESS: 50,
- HapticFeedbackConstants.VIRTUAL_KEY: 10,
- HapticFeedbackConstants.KEYBOARD_TAP: 5,
- HapticFeedbackConstants.CONFIRM: 30,
- HapticFeedbackConstants.REJECT: 40,
- HapticFeedbackConstants.GESTURE_START: 20,
- HapticFeedbackConstants.GESTURE_END: 15,
- HapticFeedbackConstants.CLOCK_TICK: 5,
- }
- self._enabled = True
-
- def getPlayer(self, feedback_constant: int) -> HapticPlayer:
- if feedback_constant not in self._players:
- player = HapticPlayer()
- duration = self._default_duration.get(feedback_constant, 20)
- player.setDuration(duration)
- self._players[feedback_constant] = player
- return self._players[feedback_constant]
-
- def perform(self, feedback_constant: int, flags: int = 0) -> bool:
- if not self._enabled:
- return False
- player = self.getPlayer(feedback_constant)
- player.play()
- return True
-
- def cancel(self, feedback_constant: int) -> None:
- if feedback_constant in self._players:
- self._players[feedback_constant].stop()
-
- def cancelAll(self) -> None:
- for player in self._players.values():
- player.stop()
-
- def setEnabled(self, enabled: bool) -> None:
- self._enabled = enabled
-
- def isEnabled(self) -> bool:
- return self._enabled
-
- def toString(self) -> str:
- return f"HapticFeedbackProvider(players={len(self._players)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HapticPattern / HapticComposer
-# ═══════════════════════════════════════════════════════════════
-
-class HapticPattern(Stub):
- """HapticPattern — 触觉模式"""
-
- def __init__(self):
- super().__init__()
- self._segments: List[HapticPattern.Segment] = []
-
- class Segment(Stub):
- """HapticPattern.Segment — 触觉片段"""
-
- TYPE_PAUSE = 0
- TYPE_VIBRATION = 1
-
- def __init__(self, type_val: int = TYPE_VIBRATION,
- duration_ms: int = 0, amplitude: float = 1.0):
- super().__init__()
- self._type = type_val
- self._duration = duration_ms
- self._amplitude = amplitude
-
- def getType(self) -> int:
- return self._type
-
- def getDuration(self) -> int:
- return self._duration
-
- def getAmplitude(self) -> float:
- return self._amplitude
-
- def toString(self) -> str:
- return (f"Segment(type={'VIBRATION' if self._type == 1 else 'PAUSE'}, "
- f"duration={self._duration}, amplitude={self._amplitude:.2f})")
-
- def addSegment(self, segment: Segment) -> None:
- self._segments.append(segment)
-
- def addVibration(self, duration_ms: int, amplitude: float = 1.0) -> None:
- self._segments.append(self.Segment(self.Segment.TYPE_VIBRATION, duration_ms, amplitude))
-
- def addPause(self, duration_ms: int) -> None:
- self._segments.append(self.Segment(self.Segment.TYPE_PAUSE, duration_ms, 0.0))
-
- def getSegments(self) -> List[Segment]:
- return list(self._segments)
-
- def getTotalDuration(self) -> int:
- return sum(s.getDuration() for s in self._segments)
-
- def clear(self) -> None:
- self._segments.clear()
-
- def toString(self) -> str:
- return f"HapticPattern(segments={len(self._segments)}, total={self.getTotalDuration()}ms)"
-
-
-class HapticComposer(Stub):
- """HapticComposer — 触觉合成器"""
-
- def __init__(self):
- super().__init__()
- self._pattern = HapticPattern()
-
- def addContinuous(self, duration_ms: int, amplitude: float = 1.0) -> "HapticComposer":
- self._pattern.addVibration(duration_ms, amplitude)
- return self
-
- def addPause(self, duration_ms: int) -> "HapticComposer":
- self._pattern.addPause(duration_ms)
- return self
-
- def addRamp(self, duration_ms: int, start_amplitude: float,
- end_amplitude: float, steps: int = 10) -> "HapticComposer":
- step_duration = duration_ms // max(1, steps)
- for i in range(steps):
- amp = start_amplitude + (end_amplitude - start_amplitude) * (i / max(1, steps - 1))
- self._pattern.addVibration(step_duration, amp)
- return self
-
- def addPulse(self, duration_ms: int, amplitude: float = 1.0,
- count: int = 1, interval_ms: int = 100) -> "HapticComposer":
- for i in range(count):
- if i > 0:
- self._pattern.addPause(interval_ms)
- self._pattern.addVibration(duration_ms, amplitude)
- return self
-
- def addClick(self) -> "HapticComposer":
- return self.addPulse(10, 1.0, 1, 0)
-
- def addTick(self) -> "HapticComposer":
- return self.addPulse(5, 0.5, 1, 0)
-
- def build(self) -> HapticPattern:
- return self._pattern
-
- def reset(self) -> None:
- self._pattern = HapticPattern()
-
- def toString(self) -> str:
- return f"HapticComposer(pattern={self._pattern})"
\ No newline at end of file
diff --git a/android_pyapi/android/view_inputmethod.py b/android_pyapi/android/view_inputmethod.py
deleted file mode 100644
index 4da8dab..0000000
--- a/android_pyapi/android/view_inputmethod.py
+++ /dev/null
@@ -1,859 +0,0 @@
-"""
-Android View InputMethod 组件 — InputMethodManager, EditorInfo,
-InputConnection, ExtractedText 等
-方法签名完全对齐 Android SDK
-"""
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError, android_context
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputMethodManager
-# ═══════════════════════════════════════════════════════════════
-
-class InputMethodManager(Stub):
- """InputMethodManager — 输入法管理器"""
-
- SHOW_IMPLICIT = 0x0001
- SHOW_FORCED = 0x0002
- HIDE_IMPLICIT_ONLY = 0x0001
- HIDE_NOT_ALWAYS = 0x0002
- RESULT_SHOWN = 2
- RESULT_HIDDEN = 3
- RESULT_UNCHANGED_SHOWN = 4
- RESULT_UNCHANGED_HIDDEN = 5
-
- def __init__(self):
- super().__init__()
- self._active: bool = False
- self._current_input_connection: Optional["InputConnection"] = None
- self._is_accepting_text: bool = True
- self._fullscreen_mode: bool = False
- self._cursor_x: int = 0
- self._cursor_y: int = 0
- self._selection_start: int = -1
- self._selection_end: int = -1
- self._composing_start: int = -1
- self._composing_end: int = -1
-
- def showSoftInput(self, view: Any, flags: int,
- result_receiver: Any = None) -> bool:
- self._active = True
- sys.stderr.write(f"[InputMethodManager] showSoftInput: flags={flags}\n")
- return True
-
- def hideSoftInputFromWindow(self, window_token: Any, flags: int,
- result_receiver: Any = None) -> bool:
- self._active = False
- sys.stderr.write(f"[InputMethodManager] hideSoftInputFromWindow: flags={flags}\n")
- return True
-
- def toggleSoftInput(self, show_flags: int, hide_flags: int):
- self._active = not self._active
- sys.stderr.write(f"[InputMethodManager] toggleSoftInput: "
- f"show={show_flags}, hide={hide_flags}\n")
-
- def restartInput(self, view: Any):
- sys.stderr.write("[InputMethodManager] restartInput\n")
-
- def startInput(self, view: Any) -> bool:
- sys.stderr.write("[InputMethodManager] startInput\n")
- return True
-
- def updateSelection(self, view: Any, sel_start: int, sel_end: int,
- composing_start: int, composing_end: int):
- self._selection_start = sel_start
- self._selection_end = sel_end
- self._composing_start = composing_start
- self._composing_end = composing_end
-
- def updateCursorAnchorInfo(self, view: Any, cursor_anchor_info: "CursorAnchorInfo"):
- self._cursor_x = cursor_anchor_info.getInsertionMarkerBaseline()
- self._cursor_y = cursor_anchor_info.getInsertionMarkerTop()
-
- def displayCompletions(self, view: Any, completions: List["CompletionInfo"]):
- sys.stderr.write(f"[InputMethodManager] displayCompletions: "
- f"{len(completions) if completions else 0} items\n")
-
- def sendKeyChar(self, key_char: str):
- sys.stderr.write(f"[InputMethodManager] sendKeyChar: '{key_char}'\n")
-
- def clearMetaKeyStates(self, view: Any, states: int):
- sys.stderr.write(f"[InputMethodManager] clearMetaKeyStates: {states}\n")
-
- def isAcceptingText(self) -> bool:
- return self._is_accepting_text
-
- def isActive(self) -> bool:
- return self._active
-
- def isFullscreenMode(self) -> bool:
- return self._fullscreen_mode
-
- def setFullscreenMode(self, fullscreen: bool):
- self._fullscreen_mode = fullscreen
-
- def getCurrentInputMethodSubtype(self) -> Optional["InputMethodSubtype"]:
- return None
-
- def getShortcutInputMethodsAndSubtypes(self) -> List[Any]:
- return []
-
- def showStatusIcon(self, icon: Any):
- pass
-
- def hideStatusIcon(self):
- pass
-
- def registerSuggestionSpansForNotification(self, spans: List[Any], sender: Any):
- pass
-
- def notifySuggestionPicked(self, suggestion: Any):
- pass
-
- def windowDismissed(self, window_token: Any):
- self._active = False
-
- def toString(self) -> str:
- return f"InputMethodManager(active={self._active})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# EditorInfo
-# ═══════════════════════════════════════════════════════════════
-
-class EditorInfo(Stub):
- """EditorInfo — 编辑器信息"""
-
- TYPE_CLASS_TEXT = 0x0001
- TYPE_CLASS_NUMBER = 0x0002
- TYPE_CLASS_PHONE = 0x0004
- TYPE_CLASS_DATETIME = 0x0008
-
- TYPE_TEXT_VARIATION_NORMAL = 0x0000
- TYPE_TEXT_VARIATION_URI = 0x0010
- TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 0x0020
- TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x0030
- TYPE_TEXT_VARIATION_SHORT_MESSAGE = 0x0040
- TYPE_TEXT_VARIATION_LONG_MESSAGE = 0x0050
- TYPE_TEXT_VARIATION_PERSON_NAME = 0x0060
- TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x0070
- TYPE_TEXT_VARIATION_PASSWORD = 0x0080
- TYPE_TEXT_VARIATION_VISIBLE_PASSWORD = 0x0090
- TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x00A0
- TYPE_TEXT_VARIATION_FILTER = 0x00B0
- TYPE_TEXT_VARIATION_PHONETIC = 0x00C0
- TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS = 0x00D0
- TYPE_TEXT_VARIATION_WEB_PASSWORD = 0x00E0
-
- TYPE_NUMBER_VARIATION_NORMAL = 0x0000
- TYPE_NUMBER_VARIATION_PASSWORD = 0x0010
-
- TYPE_DATETIME_VARIATION_NORMAL = 0x0000
- TYPE_DATETIME_VARIATION_DATE = 0x0010
- TYPE_DATETIME_VARIATION_TIME = 0x0020
-
- TYPE_NULL = 0x0000
-
- IME_ACTION_NONE = 0x0001
- IME_ACTION_GO = 0x0002
- IME_ACTION_SEARCH = 0x0003
- IME_ACTION_SEND = 0x0004
- IME_ACTION_NEXT = 0x0005
- IME_ACTION_DONE = 0x0006
- IME_ACTION_PREVIOUS = 0x0007
-
- IME_FLAG_NO_EXTRACT_UI = 0x10000001
- IME_FLAG_NO_ACCESSORY_ACTION = 0x20000000
- IME_FLAG_NO_ENTER_ACTION = 0x40000000
- IME_FLAG_NAVIGATE_NEXT = 0x08000000
- IME_FLAG_NAVIGATE_PREVIOUS = 0x04000000
- IME_FLAG_NO_FULLSCREEN = 0x02000000
- IME_FLAG_FORCE_ASCII = 0x80000000
-
- IME_MASK_ACTION = 0x000000FF
-
- def __init__(self):
- super().__init__()
- self.inputType: int = EditorInfo.TYPE_CLASS_TEXT
- self.imeOptions: int = EditorInfo.IME_ACTION_NONE
- self.actionLabel: Optional[str] = None
- self.actionId: int = 0
- self.initialSelStart: int = -1
- self.initialSelEnd: int = -1
- self.initialCapsMode: int = 0
- self.hintText: Optional[str] = None
- self.label: Optional[str] = None
- self.packageName: Optional[str] = None
- self.fieldId: int = 0
- self.fieldName: Optional[str] = None
- self.extras: Optional[Any] = None
-
- def toString(self) -> str:
- return (f"EditorInfo(inputType={hex(self.inputType)}, "
- f"imeOptions={hex(self.imeOptions)}, "
- f"actionLabel={self.actionLabel})")
-
- def dump(self, printer: Any, prefix: str):
- sys.stderr.write(f"{prefix}EditorInfo: inputType={hex(self.inputType)}\n")
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputConnection
-# ═══════════════════════════════════════════════════════════════
-
-class InputConnection(Stub):
- """InputConnection — 输入连接接口"""
-
- def __init__(self):
- super().__init__()
- self._text: str = ""
- self._selection_start: int = 0
- self._selection_end: int = 0
- self._composing_start: int = -1
- self._composing_end: int = -1
- self._batch_edit_count: int = 0
-
- def getTextBeforeCursor(self, length: int, flags: int) -> Optional[str]:
- end = self._selection_start
- start = max(0, end - length)
- return self._text[start:end]
-
- def getTextAfterCursor(self, length: int, flags: int) -> Optional[str]:
- start = self._selection_end
- end = min(len(self._text), start + length)
- return self._text[start:end]
-
- def getExtractedText(self, request: "ExtractedTextRequest",
- flags: int) -> Optional["ExtractedText"]:
- result = ExtractedText()
- result.text = self._text
- result.startOffset = 0
- result.selectionStart = self._selection_start
- result.selectionEnd = self._selection_end
- result.flags = 0
- return result
-
- def commitText(self, text: Any, new_cursor_position: int) -> bool:
- if isinstance(text, str):
- committed = text
- else:
- committed = str(text) if text else ""
-
- before = self._text[:self._selection_start]
- after = self._text[self._selection_end:]
- self._text = before + committed + after
-
- if new_cursor_position > 0:
- self._selection_start = len(before) + new_cursor_position - 1
- else:
- self._selection_start = len(before) + len(committed) + new_cursor_position
- self._selection_end = self._selection_start
- self._composing_start = -1
- self._composing_end = -1
- return True
-
- def setComposingText(self, text: Any, new_cursor_position: int) -> bool:
- if self._composing_start < 0:
- self._composing_start = self._selection_start
- self._composing_end = self._selection_end
-
- before = self._text[:self._composing_start]
- after = self._text[self._composing_end:]
-
- if isinstance(text, str):
- composing = text
- else:
- composing = str(text) if text else ""
-
- self._text = before + composing + after
- self._composing_end = self._composing_start + len(composing)
- self._selection_start = self._composing_end + new_cursor_position
- self._selection_end = self._selection_start
- return True
-
- def setSelection(self, start: int, end: int) -> bool:
- self._selection_start = max(0, min(start, len(self._text)))
- self._selection_end = max(0, min(end, len(self._text)))
- return True
-
- def deleteSurroundingText(self, before_length: int, after_length: int) -> bool:
- start = max(0, self._selection_start - before_length)
- end = min(len(self._text), self._selection_end + after_length)
- self._text = self._text[:start] + self._text[end:]
- new_cursor = max(0, self._selection_start - before_length)
- self._selection_start = new_cursor
- self._selection_end = new_cursor
- return True
-
- def commitCompletion(self, completion: "CompletionInfo") -> bool:
- sys.stderr.write(f"[InputConnection] commitCompletion: "
- f"{completion.getText()}\n")
- return True
-
- def commitCorrection(self, correction: "CorrectionInfo") -> bool:
- sys.stderr.write(f"[InputConnection] commitCorrection: "
- f"{correction.getNewText()}\n")
- return True
-
- def getSelectedText(self, flags: int) -> Optional[str]:
- if self._selection_start == self._selection_end:
- return ""
- return self._text[self._selection_start:self._selection_end]
-
- def finishComposingText(self) -> bool:
- self._composing_start = -1
- self._composing_end = -1
- return True
-
- def beginBatchEdit(self) -> bool:
- self._batch_edit_count += 1
- return True
-
- def endBatchEdit(self) -> bool:
- if self._batch_edit_count > 0:
- self._batch_edit_count -= 1
- return True
-
- def sendKeyEvent(self, event: Any) -> bool:
- sys.stderr.write(f"[InputConnection] sendKeyEvent\n")
- return True
-
- def clearMetaKeyStates(self, states: int) -> bool:
- return True
-
- def performEditorAction(self, action_code: int) -> bool:
- sys.stderr.write(f"[InputConnection] performEditorAction: {action_code}\n")
- return True
-
- def performContextMenuAction(self, id: int) -> bool:
- sys.stderr.write(f"[InputConnection] performContextMenuAction: {id}\n")
- return True
-
- def commitContent(self, input_content: "InputContentInfo",
- flags: int, opts: Optional[Any] = None) -> bool:
- sys.stderr.write("[InputConnection] commitContent\n")
- return True
-
- def requestCursorUpdates(self, cursor_update_mode: int) -> bool:
- return True
-
- def closeConnection(self):
- pass
-
- def reportFullscreenMode(self, enabled: bool):
- pass
-
- def getSurroundingText(self, before_length: int, after_length: int,
- flags: int) -> Optional["SurroundingText"]:
- start = max(0, self._selection_start - before_length)
- end = min(len(self._text), self._selection_end + after_length)
- return SurroundingText(
- text=self._text[start:end],
- selection_start=self._selection_start - start,
- selection_end=self._selection_end - start,
- offset=start,
- )
-
- def takeSnapshot(self) -> Optional[Any]:
- """获取输入快照"""
- return None
-
- def setComposingRegion(self, start: int, end: int) -> bool:
- self._composing_start = start
- self._composing_end = end
- return True
-
- def getCursorCapsMode(self, req_modes: int) -> int:
- return 0
-
- def getTextBeforeCursor(self, length: int, flags: int) -> Optional[str]:
- end = self._selection_start
- start = max(0, end - length)
- return self._text[start:end]
-
- def getTextAfterCursor(self, length: int, flags: int) -> Optional[str]:
- start = self._selection_end
- end = min(len(self._text), start + length)
- return self._text[start:end]
-
-
-# ═══════════════════════════════════════════════════════════════
-# ExtractedText
-# ═══════════════════════════════════════════════════════════════
-
-class ExtractedText(Stub):
- """ExtractedText — 提取的文本"""
-
- FLAG_SINGLE_LINE = 0x0001
- FLAG_SELECTING = 0x0002
-
- def __init__(self):
- super().__init__()
- self.text: Optional[str] = None
- self.startOffset: int = 0
- self.partialStartOffset: int = -1
- self.partialEndOffset: int = -1
- self.selectionStart: int = -1
- self.selectionEnd: int = -1
- self.flags: int = 0
-
- def toString(self) -> str:
- return (f"ExtractedText(startOffset={self.startOffset}, "
- f"text={self.text}, "
- f"selection=({self.selectionStart}, {self.selectionEnd}))")
-
-
-# ═══════════════════════════════════════════════════════════════
-# ExtractedTextRequest
-# ═══════════════════════════════════════════════════════════════
-
-class ExtractedTextRequest(Stub):
- """ExtractedTextRequest — 提取文本请求"""
-
- def __init__(self):
- super().__init__()
- self.token: int = 0
- self.flags: int = 0
- self.hintMaxLines: int = 0
- self.hintMaxChars: int = 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputBinding
-# ═══════════════════════════════════════════════════════════════
-
-class InputBinding(Stub):
- """InputBinding — 输入绑定"""
-
- def __init__(self, connection: Optional["InputConnection"] = None,
- uid: int = -1, pid: int = -1,
- private_ime_options: str = ""):
- super().__init__()
- self._connection: Optional["InputConnection"] = connection
- self._uid: int = uid
- self._pid: int = pid
- self._private_ime_options: str = private_ime_options
-
- def getConnection(self) -> Optional["InputConnection"]:
- return self._connection
-
- def getUid(self) -> int:
- return self._uid
-
- def getPid(self) -> int:
- return self._pid
-
- def getPrivateImeOptions(self) -> str:
- return self._private_ime_options
-
- def toString(self) -> str:
- return (f"InputBinding(uid={self._uid}, pid={self._pid}, "
- f"connection={self._connection})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputMethodSubtype
-# ═══════════════════════════════════════════════════════════════
-
-class InputMethodSubtype(Stub):
- """InputMethodSubtype — 输入法子类型"""
-
- SUBTYPE_ID_NONE = -1
-
- def __init__(self, locale: str = "", mode: str = "",
- extra_value: str = "", is_auxiliary: bool = False,
- overrides_ime_theme: bool = False,
- subtype_id: int = SUBTYPE_ID_NONE):
- super().__init__()
- self._locale: str = locale
- self._mode: str = mode
- self._extra_value: str = extra_value
- self._is_auxiliary: bool = is_auxiliary
- self._overrides_ime_theme: bool = overrides_ime_theme
- self._subtype_id: int = subtype_id
- self._display_name_res: int = 0
- self._icon_res: int = 0
-
- def getLocale(self) -> str:
- return self._locale
-
- def getMode(self) -> str:
- return self._mode
-
- def getExtraValue(self) -> str:
- return self._extra_value
-
- def getSubtypeId(self) -> int:
- return self._subtype_id
-
- def containsExtraValueKey(self, key: str) -> bool:
- if not self._extra_value:
- return False
- pairs = self._extra_value.split(",")
- for pair in pairs:
- kv = pair.split("=", 1)
- if len(kv) == 2 and kv[0].strip() == key:
- return True
- return False
-
- def getDisplayName(self, context: Any, package_name: str,
- app_info: Any) -> str:
- return self._locale or self._mode
-
- def isAuxiliary(self) -> bool:
- return self._is_auxiliary
-
- def overridesImeTheme(self) -> bool:
- return self._overrides_ime_theme
-
- def hashCode(self) -> int:
- return hash((self._locale, self._mode, self._extra_value)) & 0x7FFFFFFF
-
- def equals(self, other: Any) -> bool:
- if isinstance(other, InputMethodSubtype):
- return (self._locale == other._locale and
- self._mode == other._mode and
- self._extra_value == other._extra_value)
- return False
-
- def toString(self) -> str:
- return (f"InputMethodSubtype(locale={self._locale}, "
- f"mode={self._mode})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CursorAnchorInfo
-# ═══════════════════════════════════════════════════════════════
-
-class CursorAnchorInfo(Stub):
- """CursorAnchorInfo — 光标锚点信息"""
-
- FLAG_HAS_VISIBLE_REGION = 0x01
- FLAG_IS_RTL = 0x02
-
- def __init__(self):
- super().__init__()
- self._insertion_marker_baseline: float = 0.0
- self._insertion_marker_top: float = 0.0
- self._insertion_marker_bottom: float = 0.0
- self._matrix: Optional[Any] = None
- self._character_bounds: Dict[int, Tuple[float, float, float, float]] = {}
- self._character_bounds_flags: Dict[int, int] = {}
- self._composing_text: Optional[str] = None
- self._composing_text_start: int = -1
-
- def getInsertionMarkerBaseline(self) -> float:
- return self._insertion_marker_baseline
-
- def setInsertionMarkerBaseline(self, baseline: float):
- self._insertion_marker_baseline = baseline
-
- def getInsertionMarkerTop(self) -> float:
- return self._insertion_marker_top
-
- def setInsertionMarkerTop(self, top: float):
- self._insertion_marker_top = top
-
- def getInsertionMarkerBottom(self) -> float:
- return self._insertion_marker_bottom
-
- def setInsertionMarkerBottom(self, bottom: float):
- self._insertion_marker_bottom = bottom
-
- def getMatrix(self) -> Optional[Any]:
- return self._matrix
-
- def setMatrix(self, matrix: Any):
- self._matrix = matrix
-
- def getCharacterBounds(self, index: int) -> Optional[Tuple[float, float, float, float]]:
- return self._character_bounds.get(index)
-
- def setCharacterBounds(self, index: int, left: float, top: float,
- right: float, bottom: float, flags: int):
- self._character_bounds[index] = (left, top, right, bottom)
- self._character_bounds_flags[index] = flags
-
- def getCharacterBoundsFlags(self, index: int) -> int:
- return self._character_bounds_flags.get(index, 0)
-
- def getComposingText(self) -> Optional[str]:
- return self._composing_text
-
- def getComposingTextStart(self) -> int:
- return self._composing_text_start
-
- def toString(self) -> str:
- return (f"CursorAnchorInfo(baseline={self._insertion_marker_baseline}, "
- f"top={self._insertion_marker_top})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# CorrectionInfo
-# ═══════════════════════════════════════════════════════════════
-
-class CorrectionInfo(Stub):
- """CorrectionInfo — 校正信息"""
-
- def __init__(self, old_text: str = "", new_text: str = ""):
- super().__init__()
- self._old_text: str = old_text
- self._new_text: str = new_text
-
- def getOldText(self) -> str:
- return self._old_text
-
- def getNewText(self) -> str:
- return self._new_text
-
- def toString(self) -> str:
- return f"CorrectionInfo('{self._old_text}' -> '{self._new_text}')"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompletionInfo
-# ═══════════════════════════════════════════════════════════════
-
-class CompletionInfo(Stub):
- """CompletionInfo — 补全信息"""
-
- def __init__(self, id: int = 0, position: int = 0,
- text: str = "", label: str = ""):
- super().__init__()
- self._id: int = id
- self._position: int = position
- self._text: str = text
- self._label: str = label
-
- def getId(self) -> int:
- return self._id
-
- def getPosition(self) -> int:
- return self._position
-
- def getText(self) -> str:
- return self._text
-
- def getLabel(self) -> str:
- return self._label
-
- def toString(self) -> str:
- return f"CompletionInfo(id={self._id}, text='{self._text}')"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SurroundingText
-# ═══════════════════════════════════════════════════════════════
-
-class SurroundingText(Stub):
- """SurroundingText — 周围文本"""
-
- def __init__(self, text: str = "", selection_start: int = 0,
- selection_end: int = 0, offset: int = 0):
- super().__init__()
- self._text: str = text
- self._selection_start: int = selection_start
- self._selection_end: int = selection_end
- self._offset: int = offset
-
- def getText(self) -> str:
- return self._text
-
- def getSelectionStart(self) -> int:
- return self._selection_start
-
- def getSelectionEnd(self) -> int:
- return self._selection_end
-
- def getOffset(self) -> int:
- return self._offset
-
- def toString(self) -> str:
- return (f"SurroundingText(text='{self._text}', "
- f"selection=({self._selection_start}, {self._selection_end}), "
- f"offset={self._offset})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputContentInfo
-# ═══════════════════════════════════════════════════════════════
-
-class InputContentInfo(Stub):
- """InputContentInfo — 输入内容信息"""
-
- def __init__(self, uri: Any = None, description: Any = None,
- link_uri: Any = None):
- super().__init__()
- self._uri: Any = uri
- self._description: Any = description
- self._link_uri: Any = link_uri
-
- def getUri(self) -> Any:
- return self._uri
-
- def getDescription(self) -> Any:
- return self._description
-
- def getLinkUri(self) -> Any:
- return self._link_uri
-
- def requestPermission(self):
- pass
-
- def releasePermission(self):
- pass
-
- def toString(self) -> str:
- return (f"InputContentInfo(uri={self._uri}, "
- f"description={self._description})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# InputConnectionWrapper
-# ═══════════════════════════════════════════════════════════════
-
-class InputConnectionWrapper(InputConnection):
- """InputConnectionWrapper — 输入连接包装器"""
-
- def __init__(self, target: InputConnection, mutable: bool = True):
- super().__init__()
- self._target: InputConnection = target
- self._mutable: bool = mutable
-
- def setTarget(self, target: InputConnection):
- if self._mutable:
- self._target = target
-
- def getTarget(self) -> InputConnection:
- return self._target
-
- def getTextBeforeCursor(self, length: int, flags: int) -> Optional[str]:
- return self._target.getTextBeforeCursor(length, flags)
-
- def getTextAfterCursor(self, length: int, flags: int) -> Optional[str]:
- return self._target.getTextAfterCursor(length, flags)
-
- def getSelectedText(self, flags: int) -> Optional[str]:
- return self._target.getSelectedText(flags)
-
- def getSurroundingText(self, before_length: int, after_length: int,
- flags: int) -> Optional["SurroundingText"]:
- return self._target.getSurroundingText(before_length, after_length, flags)
-
- def getCursorCapsMode(self, req_modes: int) -> int:
- return self._target.getCursorCapsMode(req_modes)
-
- def getExtractedText(self, request: "ExtractedTextRequest",
- flags: int) -> Optional["ExtractedText"]:
- return self._target.getExtractedText(request, flags)
-
- def commitText(self, text: Any, new_cursor_position: int) -> bool:
- return self._target.commitText(text, new_cursor_position)
-
- def commitCompletion(self, completion: "CompletionInfo") -> bool:
- return self._target.commitCompletion(completion)
-
- def commitCorrection(self, correction: "CorrectionInfo") -> bool:
- return self._target.commitCorrection(correction)
-
- def commitContent(self, input_content: "InputContentInfo",
- flags: int, opts: Optional[Any] = None) -> bool:
- return self._target.commitContent(input_content, flags, opts)
-
- def setComposingText(self, text: Any, new_cursor_position: int) -> bool:
- return self._target.setComposingText(text, new_cursor_position)
-
- def setComposingRegion(self, start: int, end: int) -> bool:
- return self._target.setComposingRegion(start, end)
-
- def finishComposingText(self) -> bool:
- return self._target.finishComposingText()
-
- def setSelection(self, start: int, end: int) -> bool:
- return self._target.setSelection(start, end)
-
- def performEditorAction(self, action_code: int) -> bool:
- return self._target.performEditorAction(action_code)
-
- def performContextMenuAction(self, id: int) -> bool:
- return self._target.performContextMenuAction(id)
-
- def beginBatchEdit(self) -> bool:
- return self._target.beginBatchEdit()
-
- def endBatchEdit(self) -> bool:
- return self._target.endBatchEdit()
-
- def sendKeyEvent(self, event: Any) -> bool:
- return self._target.sendKeyEvent(event)
-
- def clearMetaKeyStates(self, states: int) -> bool:
- return self._target.clearMetaKeyStates(states)
-
- def deleteSurroundingText(self, before_length: int, after_length: int) -> bool:
- return self._target.deleteSurroundingText(before_length, after_length)
-
- def requestCursorUpdates(self, cursor_update_mode: int) -> bool:
- return self._target.requestCursorUpdates(cursor_update_mode)
-
- def closeConnection(self):
- self._target.closeConnection()
-
- def reportFullscreenMode(self, enabled: bool):
- self._target.reportFullscreenMode(enabled)
-
-
-# ═══════════════════════════════════════════════════════════════
-# BaseInputConnection
-# ═══════════════════════════════════════════════════════════════
-
-class BaseInputConnection(InputConnection):
- """BaseInputConnection — 输入连接基类"""
-
- def __init__(self, view: Any, full_editor: bool = True):
- super().__init__()
- self._view = view
- self._full_editor = full_editor
- self._text: str = ""
- self._selection_start: int = 0
- self._selection_end: int = 0
- self._composing_start: int = -1
- self._composing_end: int = -1
-
- def getEditable(self) -> Optional[Any]:
- return None
-
- def reportFullscreenMode(self, enabled: bool):
- pass
-
- def requestCursorUpdates(self, cursor_update_mode: int) -> bool:
- return self._full_editor
-
- def closeConnection(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "InputMethodManager",
- "EditorInfo",
- "InputConnection",
- "ExtractedText",
- "ExtractedTextRequest",
- "InputBinding",
- "InputMethodSubtype",
- "CursorAnchorInfo",
- "CorrectionInfo",
- "CompletionInfo",
- "SurroundingText",
- "InputContentInfo",
- "InputConnectionWrapper",
- "BaseInputConnection",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/view_textclassifier.py b/android_pyapi/android/view_textclassifier.py
deleted file mode 100644
index dbc19e2..0000000
--- a/android_pyapi/android/view_textclassifier.py
+++ /dev/null
@@ -1,426 +0,0 @@
-"""
-Android view.textclassifier 组件 — TextClassifier, TextClassification, TextLinks, TextSelection 等
-方法签名完全对齐 Android SDK
-"""
-
-import re
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# EntityConfig
-# ═══════════════════════════════════════════════════════════════
-
-class EntityConfig(Stub):
- """EntityConfig — 实体配置"""
-
- class Builder(Stub):
- """EntityConfig.Builder — 实体配置构建器"""
-
- def __init__(self):
- super().__init__()
- self._include_types: Optional[Set[str]] = None
- self._exclude_types: Optional[Set[str]] = None
- self._include_from_textclassifier = True
-
- def includeTypesFromTextClassifier(self) -> "EntityConfig.Builder":
- self._include_from_textclassifier = True
- return self
-
- def excludeTypes(self, varargs: List[str]) -> "EntityConfig.Builder":
- self._exclude_types = set(varargs)
- return self
-
- def includeTypes(self, varargs: List[str]) -> "EntityConfig.Builder":
- self._include_types = set(varargs)
- return self
-
- def build(self) -> "EntityConfig":
- config = EntityConfig()
- config._include_types = self._include_types
- config._exclude_types = self._exclude_types
- config._include_from_textclassifier = self._include_from_textclassifier
- return config
-
- def getEntityTypes(self) -> Optional[List[str]]:
- if self._include_types:
- return list(self._include_types)
- return None
-
- def __init__(self):
- super().__init__()
- self._include_types: Optional[Set[str]] = None
- self._exclude_types: Optional[Set[str]] = None
- self._include_from_textclassifier = True
-
- def getEntityTypes(self) -> Optional[List[str]]:
- if self._include_types:
- return list(self._include_types)
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextClassifier
-# ═══════════════════════════════════════════════════════════════
-
-class TextClassifier(Stub):
- """TextClassifier — 文本分类器"""
-
- TYPE_UNKNOWN = "unknown"
- TYPE_ADDRESS = "address"
- TYPE_DATE = "date"
- TYPE_DATE_TIME = "datetime"
- TYPE_DURATION = "duration"
- TYPE_EMAIL = "email"
- TYPE_FLIGHT_NUMBER = "flight"
- TYPE_IDENTIFIER = "identifier"
- TYPE_LINK = "link"
- TYPE_LIST = "list"
- TYPE_LOCATION = "location"
- TYPE_MEASUREMENT = "measurement"
- TYPE_MONEY = "money"
- TYPE_OTHER = "other"
- TYPE_PERIODIC = "periodic"
- TYPE_PHONE = "phone"
- TYPE_PRODUCT = "product"
- TYPE_RECIPE = "recipe"
- TYPE_TRACK_AIRLINE = "track_airline"
- TYPE_TRACK_FLIGHT = "track_flight"
- TYPE_TRACK_FOOD = "track_food"
- TYPE_TRACK_SPORT = "track_sport"
- TYPE_TRACK_WEATHER = "track_weather"
- TYPE_URL = "url"
- TYPE_VEHICLE = "vehicle"
-
- WIDGET_TYPE_CLIPBOARD = "clipboard"
- WIDGET_TYPE_CUT_COPY = "cutcopy"
- WIDGET_TYPE_EDIT_TEXT = "edittext"
- WIDGET_TYPE_LINKIFY = "linkify"
- WIDGET_TYPE_NOTIFICATION = "notification"
- WIDGET_TYPE_OTHER = "other"
- WIDGET_TYPE_SELECTION = "selection"
- WIDGET_TYPE_TEXT = "text"
- WIDGET_TYPE_UNSELECTED_TEXT = "unselected_text"
-
- # ═══════════════════════════════════════════════════════════
- # Request
- # ═══════════════════════════════════════════════════════════
-
- class Request(Stub):
- """TextClassifier.Request — 分类请求"""
-
- def __init__(self):
- super().__init__()
- self._calling_package_name: Optional[str] = None
- self._text: str = ""
- self._start_index: int = 0
- self._end_index: int = 0
- self._extras: Any = None
- self._default_locales: Any = None
- self._dark_launch_allowed = False
-
- def getCallingPackageName(self) -> Optional[str]:
- return self._calling_package_name
-
- def getText(self) -> str:
- return self._text
-
- def getStartIndex(self) -> int:
- return self._start_index
-
- def getEndIndex(self) -> int:
- return self._end_index
-
- def getExtras(self) -> Any:
- return self._extras
-
- def getDefaultLocales(self) -> Any:
- return self._default_locales
-
- def isDarkLaunchAllowed(self) -> bool:
- return self._dark_launch_allowed
-
- def __init__(self):
- super().__init__()
-
- def classifyText(self, request: Request) -> "TextClassification":
- text = request.getText()
- start = request.getStartIndex()
- end = request.getEndIndex()
- if end > len(text):
- end = len(text)
- selected = text[start:end] if start < end else text
-
- entity_type = TextClassifier.TYPE_UNKNOWN
- confidence = 0.0
-
- # Basic regex-based classification
- if re.match(r'^https?://', selected):
- entity_type = TextClassifier.TYPE_URL
- confidence = 0.95
- elif re.match(r'^[\w.+-]+@[\w-]+\.[\w.-]+$', selected):
- entity_type = TextClassifier.TYPE_EMAIL
- confidence = 0.95
- elif re.match(r'^\+?[\d\s\-\(\)]{7,15}$', selected):
- entity_type = TextClassifier.TYPE_PHONE
- confidence = 0.85
- elif re.match(r'^\d{1,4}[-/]\d{1,2}[-/]\d{1,4}$', selected):
- entity_type = TextClassifier.TYPE_DATE
- confidence = 0.80
- elif re.match(r'^\d{1,2}:\d{2}(\s?[AP]M)?$', selected, re.IGNORECASE):
- entity_type = TextClassifier.TYPE_DATE_TIME
- confidence = 0.80
-
- tc = TextClassification()
- tc._text = selected
- tc._entity_type = entity_type
- tc._confidence_score = confidence
- tc._entity_count = 1
- return tc
-
- def suggestConversationActions(self, request: Request) -> List["ConversationAction"]:
- return []
-
- def detectLanguage(self, text: str) -> "TextClassification":
- tc = TextClassification()
- tc._text = text
- tc._entity_type = TextClassifier.TYPE_UNKNOWN
- return tc
-
- def onSelectionEvent(self, event: Any):
- pass
-
- def onTextChanged(self, text: Any):
- pass
-
- def onTextSelectionAction(self, action: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextClassification
-# ═══════════════════════════════════════════════════════════════
-
-class TextClassification(Stub):
- """TextClassification — 文本分类结果"""
-
- def __init__(self):
- super().__init__()
- self._text: str = ""
- self._entity_type: str = TextClassifier.TYPE_UNKNOWN
- self._confidence_score: float = 0.0
- self._entity_count: int = 0
- self._icon: Any = None
- self._label: str = ""
- self._actions: List[Any] = []
- self._extras: Any = None
- self._id: Optional[str] = None
-
- def getText(self) -> str:
- return self._text
-
- def getEntityCount(self) -> int:
- return self._entity_count
-
- def getEntity(self, index: int) -> Optional[str]:
- if index == 0:
- return self._entity_type
- return None
-
- def getEntityType(self) -> str:
- return self._entity_type
-
- def getConfidenceScore(self, entityType: str) -> float:
- if entityType == self._entity_type:
- return self._confidence_score
- return 0.0
-
- def getIcon(self) -> Any:
- return self._icon
-
- def getLabel(self) -> str:
- return self._label
-
- def getActions(self) -> List[Any]:
- return self._actions
-
- def getExtras(self) -> Any:
- return self._extras
-
- def getId(self) -> Optional[str]:
- return self._id
-
- def toString(self) -> str:
- return f"TextClassification(type={self._entity_type}," \
- f" confidence={self._confidence_score:.2f})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextLinks
-# ═══════════════════════════════════════════════════════════════
-
-class TextLinks(Stub):
- """TextLinks — 文本链接"""
-
- def __init__(self):
- super().__init__()
- self._links: List[Any] = []
- self._extras: Any = None
-
- def getLinks(self) -> List[Any]:
- return self._links
-
- def getEntityCount(self) -> int:
- return len(self._links)
-
- def getEntity(self, index: int) -> Optional[str]:
- if 0 <= index < len(self._links):
- return self._links[index]
- return None
-
- def getEntityType(self) -> str:
- return TextClassifier.TYPE_LINK
-
- def getConfidenceScore(self, entityType: str) -> float:
- return 0.0
-
- def getExtras(self) -> Any:
- return self._extras
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextSelection
-# ═══════════════════════════════════════════════════════════════
-
-class TextSelection(Stub):
- """TextSelection — 文本选择结果"""
-
- def __init__(self):
- super().__init__()
- self._start_index: int = 0
- self._end_index: int = 0
- self._entity_type: str = TextClassifier.TYPE_UNKNOWN
- self._text: str = ""
- self._entity_count: int = 0
- self._confidence_score: float = 0.0
- self._extras: Any = None
- self._id: Optional[str] = None
-
- def getSelectionStartIndex(self) -> int:
- return self._start_index
-
- def getSelectionEndIndex(self) -> int:
- return self._end_index
-
- def getEntityType(self) -> str:
- return self._entity_type
-
- def getText(self) -> str:
- return self._text
-
- def getEntityCount(self) -> int:
- return self._entity_count
-
- def getEntity(self, index: int) -> Optional[str]:
- if index == 0:
- return self._entity_type
- return None
-
- def getConfidenceScore(self, entityType: str) -> float:
- if entityType == self._entity_type:
- return self._confidence_score
- return 0.0
-
- def getExtras(self) -> Any:
- return self._extras
-
- def getId(self) -> Optional[str]:
- return self._id
-
-
-# ═══════════════════════════════════════════════════════════════
-# ConversationAction
-# ═══════════════════════════════════════════════════════════════
-
-class ConversationAction(Stub):
- """ConversationAction — 对话操作"""
-
- TYPE_CALL = "call"
- TYPE_CREATE_REMINDER = "create_reminder"
- TYPE_OPEN_URL = "open_url"
- TYPE_SEND_EMAIL = "send_email"
- TYPE_SEND_SMS = "send_sms"
- TYPE_SHARE_LOCATION = "share_location"
- TYPE_TEXT_REPLY = "text_reply"
- TYPE_VIEW_CALENDAR = "view_calendar"
- TYPE_VIEW_MAP = "view_map"
-
- def __init__(self, text: str = "", confidenceScore: float = 0.0,
- action: str = "", extras: Any = None,
- icon: Any = None, label: str = ""):
- super().__init__()
- self._text = text
- self._confidence_score = confidenceScore
- self._action = action
- self._extras = extras
- self._icon = icon
- self._label = label
-
- def getText(self) -> str:
- return self._text
-
- def getConfidenceScore(self) -> float:
- return self._confidence_score
-
- def getAction(self) -> str:
- return self._action
-
- def getExtras(self) -> Any:
- return self._extras
-
- def getIcon(self) -> Any:
- return self._icon
-
- def getLabel(self) -> str:
- return self._label
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextClassificationContext
-# ═══════════════════════════════════════════════════════════════
-
-class TextClassificationContext(Stub):
- """TextClassificationContext — 文本分类上下文"""
-
- def __init__(self, packageName: str = "", widgetType: str = "",
- widgetVersion: str = ""):
- super().__init__()
- self._package_name = packageName
- self._widget_type = widgetType
- self._widget_version = widgetVersion
-
- def getPackageName(self) -> str:
- return self._package_name
-
- def getWidgetType(self) -> str:
- return self._widget_type
-
- def getWidgetVersion(self) -> str:
- return self._widget_version
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "TextClassifier",
- "TextClassification",
- "TextLinks",
- "TextSelection",
- "ConversationAction",
- "TextClassificationContext",
- "EntityConfig",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/view_textservice.py b/android_pyapi/android/view_textservice.py
deleted file mode 100644
index 1f9eed7..0000000
--- a/android_pyapi/android/view_textservice.py
+++ /dev/null
@@ -1,395 +0,0 @@
-"""
-Android view.textservice 包 — TextServicesManager, SpellCheckerSession,
-SuggestionsInfo, TextInfo, SentenceSuggestionsInfo, SpellCheckerSubtype
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import sys
-from typing import Any, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "TextServicesManager",
- "SpellCheckerSession",
- "SpellCheckerSessionListener",
- "SuggestionsInfo",
- "TextInfo",
- "SentenceSuggestionsInfo",
- "SpellCheckerSubtype",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextServicesManager
-# ═══════════════════════════════════════════════════════════════
-
-class TextServicesManager(Stub):
- """TextServicesManager — 文本服务管理器 (桌面存根)"""
-
- SPELL_CHECKER_SERVICE = "textservices"
- EXTRA_SUBTYPE_ID = "android.intent.extra.SUBTYPE_ID"
- EXTRA_SPELL_CHECKER = "android.intent.extra.SPELL_CHECKER"
- EXTRA_RESULT = "android.intent.extra.RESULT"
-
- _instance: Optional["TextServicesManager"] = None
-
- def __init__(self):
- super().__init__()
- self._enabled_spell_checkers: List[Any] = []
- self._current_spell_checker: Optional[Any] = None
- self._current_subtype: Optional["SpellCheckerSubtype"] = None
- self._spell_checker_enabled = True
-
- @staticmethod
- def getInstance() -> "TextServicesManager":
- """获取实例"""
- if TextServicesManager._instance is None:
- TextServicesManager._instance = TextServicesManager()
- return TextServicesManager._instance
-
- def getSpellCheckerService(self, subtype: Any, language: str) -> Optional[Any]:
- """获取拼写检查器服务"""
- return None
-
- def getCurrentSpellChecker(self) -> Optional[Any]:
- """获取当前拼写检查器"""
- return self._current_spell_checker
-
- def getCurrentSubtype(self) -> Optional["SpellCheckerSubtype"]:
- """获取当前子类型"""
- return self._current_subtype
-
- def getEnabledSpellCheckers(self) -> List[Any]:
- """获取启用的拼写检查器列表"""
- return self._enabled_spell_checkers.copy()
-
- def newSpellCheckerSession(self, locale: Any, listener: "SpellCheckerSessionListener",
- grammar: bool = False) -> Optional["SpellCheckerSession"]:
- """创建新的拼写检查器会话"""
- return SpellCheckerSession(self, locale, listener)
-
- def isSpellCheckerEnabled(self) -> bool:
- """检查拼写检查器是否启用"""
- return self._spell_checker_enabled
-
- def getEnabledSubtypes(self, spell_checker: Any) -> List["SpellCheckerSubtype"]:
- """获取启用的子类型"""
- return []
-
- def setSpellCheckerSubtype(self, subtype: "SpellCheckerSubtype") -> None:
- """设置拼写检查器子类型"""
- self._current_subtype = subtype
-
- def getSpellCheckerSubtype(self, spell_checker: Any, subtype_id: int) -> Optional["SpellCheckerSubtype"]:
- """获取拼写检查器子类型"""
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# SpellCheckerSession
-# ═══════════════════════════════════════════════════════════════
-
-class SpellCheckerSessionListener(Stub):
- """SpellCheckerSessionListener — 拼写检查器会话监听器"""
-
- def __init__(self):
- super().__init__()
-
- def onGetSuggestions(self, results: List["SuggestionsInfo"]) -> None:
- """获取建议回调"""
- pass
-
- def onGetSentenceSuggestions(self, results: List["SentenceSuggestionsInfo"]) -> None:
- """获取句子建议回调"""
- pass
-
-
-class SpellCheckerSession(Stub):
- """SpellCheckerSession — 拼写检查器会话 (桌面存根)"""
-
- def __init__(self, manager: TextServicesManager, locale: Any,
- listener: SpellCheckerSessionListener):
- super().__init__()
- self._manager = manager
- self._locale = locale
- self._listener = listener
- self._disconnected = False
- self._active_subtype: Optional["SpellCheckerSubtype"] = None
- self._subtype_offset = 0
- self._session_locale = str(locale) if locale else ""
-
- def getSpellChecker(self) -> Optional[Any]:
- """获取拼写检查器"""
- return self._manager.getCurrentSpellChecker()
-
- def createSuggestions(self, text_info: "TextInfo", suggestions_limit: int) -> List["SuggestionsInfo"]:
- """创建建议"""
- return []
-
- def getActiveSubtype(self) -> Optional["SpellCheckerSubtype"]:
- """获取活动子类型"""
- return self._active_subtype
-
- def getWordSuggestions(self, text_info: "TextInfo", suggestions_limit: int) -> List["SuggestionsInfo"]:
- """获取单词建议"""
- return []
-
- def cancel(self) -> None:
- """取消"""
- self._disconnected = True
-
- def close(self) -> None:
- """关闭"""
- self._disconnected = True
-
- def onStart(self) -> None:
- """开始"""
- pass
-
- def onStop(self) -> None:
- """停止"""
- pass
-
- def isSessionDisconnected(self) -> bool:
- """检查会话是否断开"""
- return self._disconnected
-
- def getSpellCheckerSessionSubtypeOffset(self) -> int:
- """获取拼写检查器会话子类型偏移"""
- return self._subtype_offset
-
- def setSpellCheckerSessionSubtypeOffset(self, offset: int) -> None:
- """设置拼写检查器会话子类型偏移"""
- self._subtype_offset = offset
-
- def getSpellCheckerSessionLocale(self) -> str:
- """获取拼写检查器会话区域设置"""
- return self._session_locale
-
-
-# ═══════════════════════════════════════════════════════════════
-# SuggestionsInfo
-# ═══════════════════════════════════════════════════════════════
-
-class SuggestionsInfo(Stub):
- """SuggestionsInfo — 建议信息"""
-
- RESULT_ATTR_IN_THE_DICTIONARY = 0x0001
- RESULT_ATTR_LOOKS_LIKE_TYPO = 0x0002
- RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 0x0004
- RESULT_ATTR_RECOMMENDED_SUGGESTION = 0x0008
- RESULT_ATTR_SUGGESTED_WITH_EXPERT_MODE = 0x0010
-
- def __init__(self, suggestions: Optional[List[str]] = None, cookie: int = 0,
- sequence: int = 0, suggestions_attrs: Optional[List[int]] = None):
- super().__init__()
- self._suggestions = suggestions or []
- self._cookie = cookie
- self._sequence = sequence
- self._suggestions_attrs = suggestions_attrs or []
-
- def getSuggestionsCount(self) -> int:
- """获取建议数量"""
- return len(self._suggestions)
-
- def getSuggestionsAt(self, index: int) -> Optional[str]:
- """获取指定索引的建议"""
- if 0 <= index < len(self._suggestions):
- return self._suggestions[index]
- return None
-
- def getCookie(self) -> int:
- """获取 Cookie"""
- return self._cookie
-
- def getSequence(self) -> int:
- """获取序列"""
- return self._sequence
-
- def getSuggestionInfo(self, index: int) -> Tuple[Optional[str], int]:
- """获取建议信息和属性"""
- if 0 <= index < len(self._suggestions):
- attr = self._suggestions_attrs[index] if index < len(self._suggestions_attrs) else 0
- return (self._suggestions[index], attr)
- return (None, 0)
-
- def setCookieAndSequence(self, cookie: int, sequence: int) -> None:
- """设置 Cookie 和序列"""
- self._cookie = cookie
- self._sequence = sequence
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextInfo
-# ═══════════════════════════════════════════════════════════════
-
-class TextInfo(Stub):
- """TextInfo — 文本信息"""
-
- def __init__(self, text: str = "", cookie: int = 0, sequence: int = 0,
- input_start: int = 0, input_end: int = 0, cursor_offset: int = 0):
- super().__init__()
- self._text = text
- self._cookie = cookie
- self._sequence = sequence
- self._input_start = input_start
- self._input_end = input_end
- self._cursor_offset = cursor_offset
-
- def getText(self) -> str:
- """获取文本"""
- return self._text
-
- def getCookie(self) -> int:
- """获取 Cookie"""
- return self._cookie
-
- def getSequence(self) -> int:
- """获取序列"""
- return self._sequence
-
- def getInputStart(self) -> int:
- """获取输入起始位置"""
- return self._input_start
-
- def getInputEnd(self) -> int:
- """获取输入结束位置"""
- return self._input_end
-
- def getCursorOffset(self) -> int:
- """获取光标偏移"""
- return self._cursor_offset
-
- def toString(self) -> str:
- return f"TextInfo(text={self._text}, cookie={self._cookie})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, TextInfo):
- return False
- return (self._text == other._text and self._cookie == other._cookie and
- self._sequence == other._sequence)
-
- def hashCode(self) -> int:
- return hash((self._text, self._cookie, self._sequence)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# SentenceSuggestionsInfo
-# ═══════════════════════════════════════════════════════════════
-
-class SentenceSuggestionsInfo(Stub):
- """SentenceSuggestionsInfo — 句子建议信息"""
-
- def __init__(self, suggestions_infos: Optional[List[SuggestionsInfo]] = None,
- offsets: Optional[List[int]] = None, lengths: Optional[List[int]] = None):
- super().__init__()
- self._suggestions_infos = suggestions_infos or []
- self._offsets = offsets or []
- self._lengths = lengths or []
-
- def getSuggestionsCount(self) -> int:
- """获取建议数量"""
- return len(self._suggestions_infos)
-
- def getSuggestionsAt(self, index: int) -> Optional[SuggestionsInfo]:
- """获取指定索引的建议"""
- if 0 <= index < len(self._suggestions_infos):
- return self._suggestions_infos[index]
- return None
-
- def getOffsetAt(self, index: int) -> int:
- """获取指定索引的偏移"""
- if 0 <= index < len(self._offsets):
- return self._offsets[index]
- return 0
-
- def getLengthAt(self, index: int) -> int:
- """获取指定索引的长度"""
- if 0 <= index < len(self._lengths):
- return self._lengths[index]
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# SpellCheckerSubtype
-# ═══════════════════════════════════════════════════════════════
-
-class SpellCheckerSubtype(Stub):
- """SpellCheckerSubtype — 拼写检查器子类型"""
-
- MODE_ANDROID = "android"
- MODE_DEFAULT = "default"
- SUBTYPE_ID_NONE = -1
-
- def __init__(self, locale: str = "", extra_value: str = "",
- name_override: str = "", subtype_id: int = SUBTYPE_ID_NONE,
- subtype_mode: str = MODE_DEFAULT):
- super().__init__()
- self._locale = locale
- self._extra_value = extra_value
- self._name_override = name_override
- self._subtype_id = subtype_id
- self._subtype_mode = subtype_mode
- self._auto_selected = False
-
- def getLocale(self) -> str:
- """获取区域设置"""
- return self._locale
-
- def containsExtraValue(self, key: str) -> bool:
- """检查是否包含额外值"""
- return key in self._extra_value
-
- def getDisplayName(self, context: Any, package_name: str, type_name: str) -> str:
- """获取显示名称"""
- if self._name_override:
- return self._name_override
- return self._locale
-
- def getExtraValue(self) -> str:
- """获取额外值"""
- return self._extra_value
-
- def hashCode(self) -> int:
- return hash((self._locale, self._extra_value, self._subtype_id)) & 0x7FFFFFFF
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, SpellCheckerSubtype):
- return False
- return (self._locale == other._locale and
- self._extra_value == other._extra_value and
- self._subtype_id == other._subtype_id)
-
- def getNameOverride(self) -> str:
- """获取名称覆盖"""
- return self._name_override
-
- def getSubtypeId(self) -> int:
- """获取子类型 ID"""
- return self._subtype_id
-
- def getSubtypeLocale(self) -> str:
- """获取子类型区域设置"""
- return self._locale
-
- def getSubtypeExtraValue(self) -> str:
- """获取子类型额外值"""
- return self._extra_value
-
- def getSubtypeNameOverride(self) -> str:
- """获取子类型名称覆盖"""
- return self._name_override
-
- def getSubtypeMode(self) -> str:
- """获取子类型模式"""
- return self._subtype_mode
-
- def isAutomaticallySelected(self) -> bool:
- """检查是否自动选择"""
- return self._auto_selected
\ No newline at end of file
diff --git a/android_pyapi/android/view_translation.py b/android_pyapi/android/view_translation.py
deleted file mode 100644
index 2a0c6fd..0000000
--- a/android_pyapi/android/view_translation.py
+++ /dev/null
@@ -1,435 +0,0 @@
-"""
-Android view.translation 组件 — TranslationManager, TranslationRequest, TranslationResponse 等
-方法签名完全对齐 Android SDK
-"""
-
-from typing import Any, Callable, Dict, List, Optional
-
-from .._core import Stub, AndroidOnlyError
-
-
-# ═══════════════════════════════════════════════════════════════
-# TranslationSpec
-# ═══════════════════════════════════════════════════════════════
-
-class TranslationSpec(Stub):
- """TranslationSpec — 翻译规格"""
-
- DATA_TYPE_TEXT = 0
- DATA_TYPE_UI = 1
-
- def __init__(self):
- super().__init__()
- self._locale: Optional[str] = None
- self._data_type = TranslationSpec.DATA_TYPE_TEXT
-
- def setLocale(self, locale: str) -> "TranslationSpec":
- self._locale = locale
- return self
-
- def setDataType(self, dataType: int) -> "TranslationSpec":
- self._data_type = dataType
- return self
-
- def getLocale(self) -> Optional[str]:
- return self._locale
-
- def getDataType(self) -> int:
- return self._data_type
-
-
-# ═══════════════════════════════════════════════════════════════
-# TranslationContext
-# ═══════════════════════════════════════════════════════════════
-
-class TranslationContext(Stub):
- """TranslationContext — 翻译上下文"""
-
- def __init__(self, sourceLocale: str = "", targetLocale: str = "",
- translationFlags: int = 0):
- super().__init__()
- self._source_locale = sourceLocale
- self._target_locale = targetLocale
- self._translation_flags = translationFlags
-
- def getSourceLocale(self) -> str:
- return self._source_locale
-
- def getTargetLocale(self) -> str:
- return self._target_locale
-
- def getTranslationFlags(self) -> int:
- return self._translation_flags
-
-
-# ═══════════════════════════════════════════════════════════════
-# TranslationCapability
-# ═══════════════════════════════════════════════════════════════
-
-class TranslationCapability(Stub):
- """TranslationCapability — 翻译能力"""
-
- STATE_AVAILABLE = 0
- STATE_UNAVAILABLE = 1
- STATE_CAPABLE = 2
- STATE_NOT_CAPABLE = 3
- STATE_DOWNLOADING = 4
- STATE_NOT_ALLOWED = 5
-
- def __init__(self, state: int = STATE_UNAVAILABLE,
- sourceLocale: str = "", targetLocale: str = "",
- uiTranslationEnabled: bool = False,
- textTranslationEnabled: bool = False,
- translationService: str = "desktop"):
- super().__init__()
- self._state = state
- self._source_locale = sourceLocale
- self._target_locale = targetLocale
- self._ui_translation_enabled = uiTranslationEnabled
- self._text_translation_enabled = textTranslationEnabled
- self._translation_service = translationService
-
- def getState(self) -> int:
- return self._state
-
- def getSourceLocale(self) -> str:
- return self._source_locale
-
- def getTargetLocale(self) -> str:
- return self._target_locale
-
- def isUiTranslationEnabled(self) -> bool:
- return self._ui_translation_enabled
-
- def isTextTranslationEnabled(self) -> bool:
- return self._text_translation_enabled
-
- def getTranslationService(self) -> str:
- return self._translation_service
-
-
-# ═══════════════════════════════════════════════════════════════
-# TranslationResult
-# ═══════════════════════════════════════════════════════════════
-
-class TranslationResult(Stub):
- """TranslationResult — 翻译结果"""
-
- def __init__(self, translatedText: str = "", sourceText: str = "",
- translationStatus: int = 0):
- super().__init__()
- self._translated_text = translatedText
- self._source_text = sourceText
- self._translation_status = translationStatus
-
- def getTranslatedText(self) -> str:
- return self._translated_text
-
- def getSourceText(self) -> str:
- return self._source_text
-
- def getTranslationStatus(self) -> int:
- return self._translation_status
-
-
-# ═══════════════════════════════════════════════════════════════
-# TranslationRequest
-# ═══════════════════════════════════════════════════════════════
-
-class TranslationRequest(Stub):
- """TranslationRequest — 翻译请求"""
-
- class Builder(Stub):
- """TranslationRequest.Builder — 翻译请求构建器"""
-
- def __init__(self):
- super().__init__()
- self._source_text: str = ""
- self._source_locale: str = ""
- self._target_locale: str = ""
- self._translation_flags: int = 0
- self._ui_translation_result: Any = None
- self._request_id: int = 0
- self._translation_config: Any = None
-
- def setSourceText(self, text: str) -> "TranslationRequest.Builder":
- self._source_text = text
- return self
-
- def setSourceLocale(self, locale: str) -> "TranslationRequest.Builder":
- self._source_locale = locale
- return self
-
- def setTargetLocale(self, locale: str) -> "TranslationRequest.Builder":
- self._target_locale = locale
- return self
-
- def setTranslationFlags(self, flags: int) -> "TranslationRequest.Builder":
- self._translation_flags = flags
- return self
-
- def setUiTranslationResult(self, result: Any) -> "TranslationRequest.Builder":
- self._ui_translation_result = result
- return self
-
- def setRequestId(self, id: int) -> "TranslationRequest.Builder":
- self._request_id = id
- return self
-
- def setTranslationConfig(self, config: Any) -> "TranslationRequest.Builder":
- self._translation_config = config
- return self
-
- def build(self) -> "TranslationRequest":
- req = TranslationRequest()
- req._source_text = self._source_text
- req._source_locale = self._source_locale
- req._target_locale = self._target_locale
- req._translation_flags = self._translation_flags
- req._ui_translation_result = self._ui_translation_result
- req._request_id = self._request_id
- req._translation_config = self._translation_config
- return req
-
- def __init__(self):
- super().__init__()
- self._source_text: str = ""
- self._source_locale: str = ""
- self._target_locale: str = ""
- self._request_id: int = 0
- self._translation_flags: int = 0
- self._ui_translation_result: Any = None
- self._translation_config: Any = None
-
- def getSourceText(self) -> str:
- return self._source_text
-
- def getSourceLocale(self) -> str:
- return self._source_locale
-
- def getTargetLocale(self) -> str:
- return self._target_locale
-
- def getRequestId(self) -> int:
- return self._request_id
-
- def getTranslationFlags(self) -> int:
- return self._translation_flags
-
-
-# ═══════════════════════════════════════════════════════════════
-# TranslationResponse
-# ═══════════════════════════════════════════════════════════════
-
-class TranslationResponse(Stub):
- """TranslationResponse — 翻译响应"""
-
- class Builder(Stub):
- """TranslationResponse.Builder — 翻译响应构建器"""
-
- def __init__(self):
- super().__init__()
- self._translation_result: Optional[TranslationResult] = None
- self._status: int = 0
-
- def setTranslationResult(self, result: TranslationResult) -> "TranslationResponse.Builder":
- self._translation_result = result
- return self
-
- def setStatus(self, status: int) -> "TranslationResponse.Builder":
- self._status = status
- return self
-
- def build(self) -> "TranslationResponse":
- resp = TranslationResponse()
- resp._translation_result = self._translation_result
- resp._status = self._status
- return resp
-
- def __init__(self):
- super().__init__()
- self._translation_result: Optional[TranslationResult] = None
- self._status: int = 0
-
- def getTranslationResult(self) -> Optional[TranslationResult]:
- return self._translation_result
-
- def getStatus(self) -> int:
- return self._status
-
-
-# ═══════════════════════════════════════════════════════════════
-# Translator
-# ═══════════════════════════════════════════════════════════════
-
-class Translator(Stub):
- """Translator — 翻译器"""
-
- def __init__(self):
- super().__init__()
- self._supported_locales: List[str] = ["en", "zh", "ja", "ko", "fr", "de", "es"]
-
- def translate(self, text: str, sourceLocale: str,
- targetLocale: str) -> str:
- # Basic stub: return original text with a prefix
- if sourceLocale == targetLocale:
- return text
- return f"[{sourceLocale}->{targetLocale}] {text}"
-
- def destroy(self):
- pass
-
- def getSupportedLocales(self) -> List[str]:
- return list(self._supported_locales)
-
-
-# ═══════════════════════════════════════════════════════════════
-# TranslationManager
-# ═══════════════════════════════════════════════════════════════
-
-class TranslationManager(Stub):
- """TranslationManager — 翻译管理器"""
-
- EXTRA_CAPABILITIES_FROM_FRAMEWORK = "android.view.translation.extra.CAPABILITIES_FROM_FRAMEWORK"
- EXTRA_TRANSLATION_REQUEST_RESULT = "android.view.translation.extra.TRANSLATION_REQUEST_RESULT"
-
- def __init__(self):
- super().__init__()
- self._translators: Dict[str, Translator] = {}
-
- def startTranslation(self, request: TranslationRequest) -> TranslationResponse:
- builder = TranslationResponse.Builder()
- try:
- source = request.getSourceLocale()
- target = request.getTargetLocale()
- text = request.getSourceText()
-
- translator = self._get_or_create_translator()
- translated = translator.translate(text, source, target)
-
- result = TranslationResult(
- translatedText=translated,
- sourceText=text,
- translationStatus=0
- )
- builder.setTranslationResult(result)
- builder.setStatus(0)
- except Exception as e:
- builder.setStatus(1)
- return builder.build()
-
- def createOnDeviceTranslation(self) -> Translator:
- translator = Translator()
- return translator
-
- def getTranslationCapabilities(self, sourceLocale: str,
- targetLocale: str) -> List[TranslationCapability]:
- return [
- TranslationCapability(
- state=TranslationCapability.STATE_AVAILABLE,
- sourceLocale=sourceLocale,
- targetLocale=targetLocale,
- textTranslationEnabled=True
- )
- ]
-
- def onTranslationRequest(self, request: TranslationRequest):
- pass
-
- def isTranslationSupported(self) -> bool:
- return True
-
- def isOnDeviceTranslationSupported(self) -> bool:
- return True
-
- def isULTRADeviceSupported(self) -> bool:
- return False
-
- def _get_or_create_translator(self) -> Translator:
- return Translator()
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewTranslation / ViewTranslationRequest / ViewTranslationResponse (stubs)
-# ═══════════════════════════════════════════════════════════════
-
-class ViewTranslation(Stub):
- """ViewTranslation — 视图翻译"""
-
- def __init__(self, autofillId: Any = None, value: str = "",
- translationResult: Optional[TranslationResult] = None):
- super().__init__()
- self._autofill_id = autofillId
- self._value = value
- self._translation_result = translationResult
-
- def getAutofillId(self) -> Any:
- return self._autofill_id
-
- def getValue(self) -> str:
- return self._value
-
- def getTranslationResult(self) -> Optional[TranslationResult]:
- return self._translation_result
-
- def setTranslationResult(self, result: TranslationResult):
- self._translation_result = result
-
-
-class ViewTranslationRequest(Stub):
- """ViewTranslationRequest — 视图翻译请求"""
-
- def __init__(self, autofillId: Any = None, value: str = "",
- requestId: int = 0):
- super().__init__()
- self._autofill_id = autofillId
- self._value = value
- self._request_id = requestId
-
- def getAutofillId(self) -> Any:
- return self._autofill_id
-
- def getValue(self) -> str:
- return self._value
-
- def getRequestId(self) -> int:
- return self._request_id
-
-
-class ViewTranslationResponse(Stub):
- """ViewTranslationResponse — 视图翻译响应"""
-
- def __init__(self, autofillId: Any = None, value: str = "",
- extras: Any = None):
- super().__init__()
- self._autofill_id = autofillId
- self._value = value
- self._extras = extras
-
- def getAutofillId(self) -> Any:
- return self._autofill_id
-
- def getValue(self) -> str:
- return self._value
-
- def getExtras(self) -> Any:
- return self._extras
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "TranslationManager",
- "TranslationRequest",
- "TranslationResponse",
- "TranslationResult",
- "TranslationCapability",
- "Translator",
- "TranslationContext",
- "TranslationSpec",
- "ViewTranslation",
- "ViewTranslationRequest",
- "ViewTranslationResponse",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/view_window.py b/android_pyapi/android/view_window.py
deleted file mode 100644
index fff87e2..0000000
--- a/android_pyapi/android/view_window.py
+++ /dev/null
@@ -1,969 +0,0 @@
-"""
-Android Window 组件 — Window, WindowManager, WindowManager.LayoutParams,
-PhoneWindow, Window.Callback, WindowMetrics, SplashScreen,
-WindowContext, WindowManagerGlobal 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-from typing import Any, Callable, Dict, List, Optional, Tuple
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "Window", "WindowManager", "PhoneWindow", "WindowMetrics",
- "WindowMetricsCalculator", "SplashScreen", "SplashScreenView",
- "SplashScreenManager", "WindowContext", "WindowContextController",
- "WindowHideScrollCaptureTarget", "WindowLayoutBuilder",
- "WindowLayoutObserver", "WindowManagerGlobal", "WindowManagerPolicy",
- "WindowProviderService",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 窗口常量
-# ═══════════════════════════════════════════════════════════════
-
-TYPE_BASE_APPLICATION = 1
-TYPE_APPLICATION = 2
-TYPE_APPLICATION_STARTING = 3
-TYPE_APPLICATION_PANEL = 1000
-TYPE_APPLICATION_MEDIA = 1001
-TYPE_APPLICATION_SUB_PANEL = 1002
-TYPE_APPLICATION_ABOVE_SUB_PANEL = 1003
-TYPE_APPLICATION_ATTACHED_DIALOG = 1004
-TYPE_STATUS_BAR = 2000
-TYPE_SEARCH_BAR = 2001
-TYPE_PHONE = 2002
-TYPE_SYSTEM_ALERT = 2003
-TYPE_KEYGUARD = 2004
-TYPE_TOAST = 2005
-TYPE_SYSTEM_OVERLAY = 2006
-TYPE_PRIORITY_PHONE = 2007
-TYPE_SYSTEM_DIALOG = 2008
-TYPE_KEYGUARD_DIALOG = 2009
-TYPE_SYSTEM_ERROR = 2010
-TYPE_INPUT_METHOD = 2011
-TYPE_INPUT_METHOD_DIALOG = 2012
-TYPE_WALLPAPER = 2013
-TYPE_STATUS_BAR_PANEL = 2014
-TYPE_SECURE_SYSTEM_OVERLAY = 2015
-TYPE_DRAG = 2016
-TYPE_STATUS_BAR_SUBSCEEN = 2017
-TYPE_POINTER = 2018
-TYPE_NAVIGATION_BAR = 2019
-TYPE_VOLUME_OVERLAY = 2020
-TYPE_BOOT_PROGRESS = 2021
-TYPE_NAVIGATION_BAR_PANEL = 2024
-TYPE_APPLICATION_OVERLAY = 2025
-TYPE_UNIVERSE_BACKGROUND = 2026
-TYPE_DISPLAY_OVERLAY = 2027
-TYPE_MAGNIFICATION_OVERLAY = 2028
-TYPE_INPUT_CONSUMER = 2029
-TYPE_ACCESSIBILITY_OVERLAY = 2030
-TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = 2031
-TYPE_NOTIFICATION_SHADE = 2032
-TYPE_STATUS_BAR_ADDITIONAL_INFO = 2033
-TYPE_KEYGUARD_SCRIM = 2034
-
-FLAG_NOT_FOCUSABLE = 0x00000008
-FLAG_NOT_TOUCHABLE = 0x00000010
-FLAG_NOT_TOUCH_MODAL = 0x00000020
-FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040
-FLAG_KEEP_SCREEN_ON = 0x00000080
-FLAG_LAYOUT_IN_SCREEN = 0x00000100
-FLAG_LAYOUT_NO_LIMITS = 0x00000200
-FLAG_FULLSCREEN = 0x00000400
-FLAG_FORCE_NOT_FULLSCREEN = 0x00000800
-FLAG_DITHER = 0x00001000
-FLAG_SECURE = 0x00002000
-FLAG_SCALED = 0x00004000
-FLAG_IGNORE_CHEEK_PRESSES = 0x00008000
-FLAG_LAYOUT_INSET_DECOR = 0x00010000
-FLAG_ALT_FOCUSABLE_IM = 0x00020000
-FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000
-FLAG_SHOW_WHEN_LOCKED = 0x00080000
-FLAG_SHOW_WALLPAPER = 0x00100000
-FLAG_TURN_SCREEN_ON = 0x00200000
-FLAG_DISMISS_KEYGUARD = 0x00400000
-FLAG_SPLIT_TOUCH = 0x01000000
-FLAG_HARDWARE_ACCELERATED = 0x10000000
-FLAG_LOCAL_FOCUS_MODE = 0x10000000
-FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000
-FLAG_TRANSLUCENT_STATUS = 0x04000000
-FLAG_TRANSLUCENT_NAVIGATION = 0x08000000
-FLAG_BLUR_BEHIND = 0x00000004
-FLAG_DIM_BEHIND = 0x00000002
-
-FEATURE_NO_TITLE = 1
-FEATURE_INDETERMINATE_PROGRESS = 5
-FEATURE_PROGRESS = 2
-FEATURE_CUSTOM_TITLE = 7
-FEATURE_LEFT_ICON = 3
-FEATURE_RIGHT_ICON = 4
-FEATURE_ACTION_BAR = 8
-FEATURE_ACTION_BAR_OVERLAY = 9
-FEATURE_ACTION_MODE_OVERLAY = 10
-FEATURE_CONTENT_TRANSITIONS = 12
-FEATURE_ACTIVITY_TRANSITIONS = 13
-
-SOFT_INPUT_ADJUST_NOTHING = 0x00000030
-SOFT_INPUT_ADJUST_PAN = 0x00000020
-SOFT_INPUT_ADJUST_RESIZE = 0x00000010
-SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00000000
-SOFT_INPUT_STATE_ALWAYS_HIDDEN = 0x00000003
-SOFT_INPUT_STATE_ALWAYS_VISIBLE = 0x00000005
-SOFT_INPUT_STATE_HIDDEN = 0x00000002
-SOFT_INPUT_STATE_UNCHANGED = 0x00000001
-SOFT_INPUT_STATE_VISIBLE = 0x00000004
-SOFT_INPUT_MASK_ADJUST = 0x000000F0
-SOFT_INPUT_MASK_STATE = 0x0000000F
-SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x10000000
-
-ROTATION_0 = 0
-ROTATION_90 = 1
-ROTATION_180 = 2
-ROTATION_270 = 3
-
-LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0
-LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1
-LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2
-LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 3
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowManager.LayoutParams
-# ═══════════════════════════════════════════════════════════════
-
-class WindowManager:
- """WindowManager — 窗口管理器接口"""
-
- class LayoutParams(Stub):
- """WindowManager.LayoutParams — 窗口布局参数"""
-
- TYPE_BASE_APPLICATION = TYPE_BASE_APPLICATION
- TYPE_APPLICATION = TYPE_APPLICATION
- TYPE_APPLICATION_PANEL = TYPE_APPLICATION_PANEL
- TYPE_APPLICATION_MEDIA = TYPE_APPLICATION_MEDIA
- TYPE_APPLICATION_SUB_PANEL = TYPE_APPLICATION_SUB_PANEL
- TYPE_STATUS_BAR = TYPE_STATUS_BAR
- TYPE_SYSTEM_ALERT = TYPE_SYSTEM_ALERT
- TYPE_KEYGUARD = TYPE_KEYGUARD
- TYPE_TOAST = TYPE_TOAST
- TYPE_SYSTEM_OVERLAY = TYPE_SYSTEM_OVERLAY
- TYPE_INPUT_METHOD = TYPE_INPUT_METHOD
- TYPE_WALLPAPER = TYPE_WALLPAPER
- TYPE_APPLICATION_OVERLAY = TYPE_APPLICATION_OVERLAY
- TYPE_ACCESSIBILITY_OVERLAY = TYPE_ACCESSIBILITY_OVERLAY
-
- FLAG_NOT_FOCUSABLE = FLAG_NOT_FOCUSABLE
- FLAG_NOT_TOUCHABLE = FLAG_NOT_TOUCHABLE
- FLAG_KEEP_SCREEN_ON = FLAG_KEEP_SCREEN_ON
- FLAG_FULLSCREEN = FLAG_FULLSCREEN
- FLAG_SECURE = FLAG_SECURE
- FLAG_SHOW_WHEN_LOCKED = FLAG_SHOW_WHEN_LOCKED
- FLAG_TURN_SCREEN_ON = FLAG_TURN_SCREEN_ON
- FLAG_DISMISS_KEYGUARD = FLAG_DISMISS_KEYGUARD
- FLAG_TRANSLUCENT_STATUS = FLAG_TRANSLUCENT_STATUS
- FLAG_TRANSLUCENT_NAVIGATION = FLAG_TRANSLUCENT_NAVIGATION
- FLAG_HARDWARE_ACCELERATED = FLAG_HARDWARE_ACCELERATED
- FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
-
- SOFT_INPUT_ADJUST_NOTHING = SOFT_INPUT_ADJUST_NOTHING
- SOFT_INPUT_ADJUST_PAN = SOFT_INPUT_ADJUST_PAN
- SOFT_INPUT_ADJUST_RESIZE = SOFT_INPUT_ADJUST_RESIZE
- SOFT_INPUT_MASK_ADJUST = SOFT_INPUT_MASK_ADJUST
- SOFT_INPUT_MASK_STATE = SOFT_INPUT_MASK_STATE
-
- def __init__(self, w: int = -1, h: int = -1,
- type_: int = TYPE_APPLICATION,
- flags: int = 0, format: int = -1):
- super().__init__()
- self.width = w
- self.height = h
- self.type = type_
- self.flags = flags
- self.format = format
- self.x = 0
- self.y = 0
- self.horizontalMargin = 0.0
- self.verticalMargin = 0.0
- self.alpha = 1.0
- self.dimAmount = 0.0
- self.screenOrientation = ROTATION_0
- self.softInputMode = SOFT_INPUT_ADJUST_NOTHING
- self.gravity = 0
- self.windowAnimations = 0
- self.token: Any = None
- self.packageName: str = ""
- self.title: str = ""
- self.windowManager: Any = None
- self.buttonBrightness = -1.0
- self.screenBrightness = -1.0
- self.rotationAnimation = 0
- self.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
- self.preferredDisplayModeId = 0
- self.colorMode = 0
- self.fitInsetsTypes = 0
- self.fitInsetsSides = 0
- self.wideColorGamut = False
- self.captionMode = 0
-
- def setTitle(self, title: str):
- self.title = title
-
- def getTitle(self) -> str:
- return self.title
-
- def setGravity(self, gravity: int):
- self.gravity = gravity
-
- def getGravity(self) -> int:
- return self.gravity
-
- def setSoftInputMode(self, mode: int):
- self.softInputMode = mode
-
- def getSoftInputMode(self) -> int:
- return self.softInputMode
-
- def setFlags(self, flags: int, mask: int):
- self.flags = (self.flags & ~mask) | (flags & mask)
-
- def getFlags(self) -> int:
- return self.flags
-
- def toString(self) -> str:
- return (f"LayoutParams({self.width}x{self.height}, "
- f"type={self.type}, flags=0x{self.flags:08x})")
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self):
- super().__init__()
-
- def addView(self, view: Any, params: LayoutParams):
- raise AndroidOnlyError("WindowManager.addView() is not available on desktop")
-
- def updateViewLayout(self, view: Any, params: LayoutParams):
- raise AndroidOnlyError("WindowManager.updateViewLayout() is not available on desktop")
-
- def removeView(self, view: Any):
- raise AndroidOnlyError("WindowManager.removeView() is not available on desktop")
-
- def removeViewImmediate(self, view: Any):
- raise AndroidOnlyError("WindowManager.removeViewImmediate() is not available on desktop")
-
- def getDefaultDisplay(self) -> Any:
- return None
-
- def getCurrentWindowMetrics(self) -> "WindowMetrics":
- return WindowMetrics(width=1920, height=1080)
-
- def getMaximumWindowMetrics(self) -> "WindowMetrics":
- return WindowMetrics(width=1920, height=1080)
-
- def toString(self) -> str:
- return "WindowManager"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# Window.Callback
-# ═══════════════════════════════════════════════════════════════
-
-class Window:
- """Window — 窗口基类"""
-
- class Callback(Stub):
- """Window.Callback — 窗口回调"""
-
- def onWindowAttributesChanged(self, attrs: Any):
- pass
-
- def onWindowFocusChanged(self, hasFocus: bool):
- pass
-
- def dispatchKeyEvent(self, event: Any) -> bool:
- return False
-
- def dispatchTouchEvent(self, event: Any) -> bool:
- return False
-
- def dispatchTrackballEvent(self, event: Any) -> bool:
- return False
-
- def dispatchGenericMotionEvent(self, event: Any) -> bool:
- return False
-
- def onContentChanged(self):
- pass
-
- def toString(self) -> str:
- return f"Window.Callback@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- class OnFrameMetricsAvailableListener(Stub):
- """Window.OnFrameMetricsAvailableListener — 帧指标监听器"""
-
- def onFrameMetricsAvailable(self, window: "Window", frameMetrics: Any,
- dropCountSinceLastInvocation: int):
- pass
-
- def toString(self) -> str:
- return f"OnFrameMetricsAvailableListener@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- class OnRestrictedCaptionAreaChangedListener(Stub):
- """Window.OnRestrictedCaptionAreaChangedListener — 受限标题区域变化监听器"""
-
- def onRestrictedCaptionAreaChanged(self, rect: Any):
- pass
-
- def toString(self) -> str:
- return f"OnRestrictedCaptionAreaChangedListener@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._context = context
- self._callback: Optional[Window.Callback] = None
- self._window_manager = WindowManager()
- self._features: Dict[int, bool] = {}
- self._local_features: Dict[int, bool] = {}
- self._decor: Any = None
- self._container: Any = None
- self._attributes = WindowManager.LayoutParams()
- self._is_active = False
-
- def getContext(self) -> Any:
- return self._context
-
- def getCallback(self) -> Optional[Callback]:
- return self._callback
-
- def setCallback(self, callback: Callback):
- self._callback = callback
-
- def getWindowManager(self) -> WindowManager:
- return self._window_manager
-
- def setWindowManager(self, wm: WindowManager, pm: Any, appName: str = ""):
- self._window_manager = wm
-
- def getAttributes(self) -> WindowManager.LayoutParams:
- return self._attributes
-
- def setAttributes(self, attrs: WindowManager.LayoutParams):
- self._attributes = attrs
-
- def addFlags(self, flags: int):
- self._attributes.flags |= flags
-
- def clearFlags(self, flags: int):
- self._attributes.flags &= ~flags
-
- def setFlags(self, flags: int, mask: int):
- self._attributes.setFlags(flags, mask)
-
- def setGravity(self, gravity: int):
- self._attributes.setGravity(gravity)
-
- def setSoftInputMode(self, mode: int):
- self._attributes.setSoftInputMode(mode)
-
- def setTitle(self, title: str):
- self._attributes.setTitle(title)
-
- def setType(self, type_: int):
- self._attributes.type = type_
-
- def setFormat(self, format: int):
- self._attributes.format = format
-
- def setWindowAnimations(self, resId: int):
- self._attributes.windowAnimations = resId
-
- def requestFeature(self, featureId: int) -> bool:
- self._features[featureId] = True
- return True
-
- def hasFeature(self, featureId: int) -> bool:
- return self._features.get(featureId, False)
-
- def isActive(self) -> bool:
- return self._is_active
-
- def setContainer(self, container: Any):
- self._container = container
-
- def getContainer(self) -> Any:
- return self._container
-
- def makeActive(self):
- self._is_active = True
-
- def makeInactive(self):
- self._is_active = False
-
- def getDecorView(self) -> Any:
- return self._decor
-
- def setDecorView(self, view: Any):
- self._decor = view
-
- def injectInputEvent(self, event: Any):
- pass
-
- def superDispatchKeyEvent(self, event: Any) -> bool:
- return False
-
- def superDispatchTouchEvent(self, event: Any) -> bool:
- return False
-
- def superDispatchTrackballEvent(self, event: Any) -> bool:
- return False
-
- def superDispatchGenericMotionEvent(self, event: Any) -> bool:
- return False
-
- def toString(self) -> str:
- return f"Window(active={self._is_active})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# PhoneWindow
-# ═══════════════════════════════════════════════════════════════
-
-class PhoneWindow(Window):
- """PhoneWindow — 电话窗口"""
-
- def __init__(self, context: Any = None):
- super().__init__(context=context)
- self._is_phone = True
- self._status_bar_color = 0
- self._navigation_bar_color = 0
- self._is_status_bar_visible = True
- self._is_navigation_bar_visible = True
-
- def setStatusBarColor(self, color: int):
- self._status_bar_color = color
-
- def getStatusBarColor(self) -> int:
- return self._status_bar_color
-
- def setNavigationBarColor(self, color: int):
- self._navigation_bar_color = color
-
- def getNavigationBarColor(self) -> int:
- return self._navigation_bar_color
-
- def setStatusBarVisibility(self, visible: bool):
- self._is_status_bar_visible = visible
-
- def setNavigationBarVisibility(self, visible: bool):
- self._is_navigation_bar_visible = visible
-
- def isStatusBarVisible(self) -> bool:
- return self._is_status_bar_visible
-
- def isNavigationBarVisible(self) -> bool:
- return self._is_navigation_bar_visible
-
- def toString(self) -> str:
- return f"PhoneWindow(statusBar={self._is_status_bar_visible})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowContentFrameStats / WindowFrameStats
-# ═══════════════════════════════════════════════════════════════
-
-class WindowContentFrameStats(Stub):
- """WindowContentFrameStats — 窗口内容帧统计"""
-
- def __init__(self):
- super().__init__()
- self._frames_count = 0
- self._dropped_count = 0
- self._total_duration_ns = 0
-
- def getFramesCount(self) -> int:
- return self._frames_count
-
- def getDroppedCount(self) -> int:
- return self._dropped_count
-
- def getTotalDurationNanos(self) -> int:
- return self._total_duration_ns
-
- def toString(self) -> str:
- return f"WindowContentFrameStats(frames={self._frames_count}, dropped={self._dropped_count})"
-
-
-class WindowFrameStats(Stub):
- """WindowFrameStats — 窗口帧统计"""
-
- def __init__(self):
- super().__init__()
- self._frames_count = 0
- self._jank_count = 0
- self._percentile_95 = 0.0
- self._percentile_99 = 0.0
-
- def getFramesCount(self) -> int:
- return self._frames_count
-
- def getJankCount(self) -> int:
- return self._jank_count
-
- def getP95DurationMillis(self) -> float:
- return self._percentile_95
-
- def getP99DurationMillis(self) -> float:
- return self._percentile_99
-
- def toString(self) -> str:
- return f"WindowFrameStats(frames={self._frames_count}, jank={self._jank_count})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowMetrics
-# ═══════════════════════════════════════════════════════════════
-
-class WindowMetrics(Stub):
- """WindowMetrics — 窗口指标"""
-
- def __init__(self, width: int = 0, height: int = 0,
- densityDpi: int = 320, density: float = 2.0,
- scaledDensity: float = 2.0, xdpi: float = 320.0,
- ydpi: float = 320.0):
- super().__init__()
- self._width = width
- self._height = height
- self._density_dpi = densityDpi
- self._density = density
- self._scaled_density = scaledDensity
- self._xdpi = xdpi
- self._ydpi = ydpi
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def getDensityDpi(self) -> int:
- return self._density_dpi
-
- def getDensity(self) -> float:
- return self._density
-
- def getScaledDensity(self) -> float:
- return self._scaled_density
-
- def getXdpi(self) -> float:
- return self._xdpi
-
- def getYdpi(self) -> float:
- return self._ydpi
-
- def getBounds(self) -> Any:
- return (0, 0, self._width, self._height)
-
- def toString(self) -> str:
- return f"WindowMetrics({self._width}x{self._height})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, WindowMetrics):
- return False
- return self._width == other._width and self._height == other._height
-
- def hashCode(self) -> int:
- return hash((self._width, self._height)) & 0x7FFFFFFF
-
-
-class WindowMetricsCalculator(Stub):
- """WindowMetricsCalculator — 窗口指标计算器"""
-
- @staticmethod
- def getOrCreate() -> "WindowMetricsCalculator":
- return WindowMetricsCalculator()
-
- def computeCurrentWindowMetrics(self, context: Any) -> WindowMetrics:
- return WindowMetrics(width=1920, height=1080)
-
- def computeMaximumWindowMetrics(self, context: Any) -> WindowMetrics:
- return WindowMetrics(width=1920, height=1080)
-
- def toString(self) -> str:
- return "WindowMetricsCalculator"
-
-
-class WindowMetricsCalculatorDecorator(Stub):
- """WindowMetricsCalculatorDecorator — 窗口指标装饰器"""
-
- def __init__(self, base: Optional[WindowMetricsCalculator] = None):
- super().__init__()
- self._base = base
-
- def computeCurrentWindowMetrics(self, context: Any) -> WindowMetrics:
- if self._base:
- return self._base.computeCurrentWindowMetrics(context)
- return WindowMetrics(width=1920, height=1080)
-
- def computeMaximumWindowMetrics(self, context: Any) -> WindowMetrics:
- if self._base:
- return self._base.computeMaximumWindowMetrics(context)
- return WindowMetrics(width=1920, height=1080)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SplashScreen / SplashScreenView / SplashScreenManager
-# ═══════════════════════════════════════════════════════════════
-
-class SplashScreen(Stub):
- """SplashScreen — 启动屏"""
-
- SPLASH_SCREEN_STYLE_SOLID_COLOR = 0
- SPLASH_SCREEN_STYLE_ICON = 1
- SPLASH_SCREEN_STYLE_ANIMATED_ICON = 2
-
- def __init__(self):
- super().__init__()
- self._icon: Any = None
- self._background_color: int = 0
- self._animation_duration: int = 0
- self._style = SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR
-
- def setSplashScreenIcon(self, icon: Any):
- self._icon = icon
-
- def getSplashScreenIcon(self) -> Any:
- return self._icon
-
- def setBackgroundColor(self, color: int):
- self._background_color = color
-
- def getBackgroundColor(self) -> int:
- return self._background_color
-
- def setAnimationDuration(self, duration: int):
- self._animation_duration = duration
-
- def getAnimationDuration(self) -> int:
- return self._animation_duration
-
- def setStyle(self, style: int):
- self._style = style
-
- def getStyle(self) -> int:
- return self._style
-
- def toString(self) -> str:
- return f"SplashScreen(style={self._style})"
-
-
-class SplashScreenView(Stub):
- """SplashScreenView — 启动屏视图"""
-
- def __init__(self):
- super().__init__()
- self._visible = False
- self._icon: Any = None
- self._branding_image: Any = None
-
- def isVisible(self) -> bool:
- return self._visible
-
- def setVisible(self, visible: bool):
- self._visible = visible
-
- def getIconView(self) -> Any:
- return self._icon
-
- def getBrandingImageView(self) -> Any:
- return self._branding_image
-
- def remove(self):
- self._visible = False
-
- def toString(self) -> str:
- return f"SplashScreenView(visible={self._visible})"
-
-
-class SplashScreenManager(Stub):
- """SplashScreenManager — 启动屏管理器"""
-
- def __init__(self):
- super().__init__()
- self._splash_screens: Dict[Any, SplashScreen] = {}
-
- def getSplashScreen(self, activity: Any) -> Optional[SplashScreen]:
- return self._splash_screens.get(id(activity))
-
- def installSplashScreen(self, activity: Any) -> SplashScreen:
- screen = SplashScreen()
- self._splash_screens[id(activity)] = screen
- return screen
-
- def uninstallSplashScreen(self, activity: Any):
- self._splash_screens.pop(id(activity), None)
-
- def toString(self) -> str:
- return f"SplashScreenManager(screens={len(self._splash_screens)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowContext / WindowContextController
-# ═══════════════════════════════════════════════════════════════
-
-class WindowContext(Stub):
- """WindowContext — 窗口上下文"""
-
- def __init__(self, context: Any = None, windowType: int = TYPE_APPLICATION):
- super().__init__()
- self._base_context = context
- self._window_type = windowType
- self._resources: Any = None
-
- def getBaseContext(self) -> Any:
- return self._base_context
-
- def getWindowType(self) -> int:
- return self._window_type
-
- def getResources(self) -> Any:
- return self._resources
-
- def setResources(self, resources: Any):
- self._resources = resources
-
- def toString(self) -> str:
- return f"WindowContext(type={self._window_type})"
-
-
-class WindowContextController(Stub):
- """WindowContextController — 窗口上下文控制器"""
-
- def __init__(self, windowContext: Optional[WindowContext] = None):
- super().__init__()
- self._window_context = windowContext
-
- def attachToDisplay(self, displayId: int):
- pass
-
- def detach(self):
- pass
-
- def toString(self) -> str:
- return f"WindowContextController(ctx={self._window_context})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowHideScrollCaptureTarget
-# ═══════════════════════════════════════════════════════════════
-
-class WindowHideScrollCaptureTarget(Stub):
- """WindowHideScrollCaptureTarget — 窗口隐藏滚动捕获目标"""
-
- def __init__(self, view: Any = None):
- super().__init__()
- self._view = view
-
- def getView(self) -> Any:
- return self._view
-
- def toString(self) -> str:
- return f"WindowHideScrollCaptureTarget(view={self._view})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowLayoutBuilder / WindowLayoutObserver
-# ═══════════════════════════════════════════════════════════════
-
-class WindowLayoutBuilder(Stub):
- """WindowLayoutBuilder — 窗口布局构建器"""
-
- def __init__(self):
- super().__init__()
- self._width = 0
- self._height = 0
- self._gravity = 0
- self._x = 0
- self._y = 0
- self._horizontal_margin = 0.0
- self._vertical_margin = 0.0
-
- def setWidth(self, width: int) -> "WindowLayoutBuilder":
- self._width = width
- return self
-
- def setHeight(self, height: int) -> "WindowLayoutBuilder":
- self._height = height
- return self
-
- def setGravity(self, gravity: int) -> "WindowLayoutBuilder":
- self._gravity = gravity
- return self
-
- def setPosition(self, x: int, y: int) -> "WindowLayoutBuilder":
- self._x = x
- self._y = y
- return self
-
- def build(self) -> WindowManager.LayoutParams:
- params = WindowManager.LayoutParams(w=self._width, h=self._height)
- params.gravity = self._gravity
- params.x = self._x
- params.y = self._y
- return params
-
- def toString(self) -> str:
- return f"WindowLayoutBuilder({self._width}x{self._height})"
-
-
-class WindowLayoutObserver(Stub):
- """WindowLayoutObserver — 窗口布局观察者"""
-
- def onLayoutChanged(self, layout: WindowManager.LayoutParams):
- pass
-
- def toString(self) -> str:
- return f"WindowLayoutObserver@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WindowManagerGlobal / WindowManagerPolicy / WindowProviderService
-# ═══════════════════════════════════════════════════════════════
-
-class WindowManagerGlobal(Stub):
- """WindowManagerGlobal — 全局窗口管理器"""
-
- _instance: Optional["WindowManagerGlobal"] = None
-
- @staticmethod
- def getInstance() -> "WindowManagerGlobal":
- if WindowManagerGlobal._instance is None:
- WindowManagerGlobal._instance = WindowManagerGlobal()
- return WindowManagerGlobal._instance
-
- def __init__(self):
- super().__init__()
- self._views: Dict[int, Any] = {}
- self._params: Dict[int, WindowManager.LayoutParams] = {}
- self._next_id = 0
-
- def addView(self, view: Any, params: WindowManager.LayoutParams):
- vid = id(view)
- self._views[vid] = view
- self._params[vid] = params
-
- def updateViewLayout(self, view: Any, params: WindowManager.LayoutParams):
- vid = id(view)
- if vid in self._params:
- self._params[vid] = params
-
- def removeView(self, view: Any):
- vid = id(view)
- self._views.pop(vid, None)
- self._params.pop(vid, None)
-
- def getWindowViews(self) -> List[Any]:
- return list(self._views.values())
-
- def getViewCount(self) -> int:
- return len(self._views)
-
- def toString(self) -> str:
- return f"WindowManagerGlobal(views={len(self._views)})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-class WindowManagerPolicy(Stub):
- """WindowManagerPolicy — 窗口管理器策略"""
-
- WINDOW_MODE_FULLSCREEN = 0
- WINDOW_MODE_FREEFORM = 1
- WINDOW_MODE_SPLIT_SCREEN = 2
- WINDOW_MODE_PINNED = 3
-
- def __init__(self):
- super().__init__()
-
- def isKeyguardLocked(self) -> bool:
- return False
-
- def isKeyguardSecure(self) -> bool:
- return False
-
- def isScreenOn(self) -> bool:
- return True
-
- def toString(self) -> str:
- return "WindowManagerPolicy"
-
-
-class WindowProviderService(Stub):
- """WindowProviderService — 窗口提供者服务"""
-
- SERVICE_INTERFACE = "android.window.WindowProviderService"
-
- def __init__(self):
- super().__init__()
-
- def onCreateWindowProvider(self):
- pass
-
- def onWindowProviderAttached(self):
- pass
-
- def onWindowProviderDetached(self):
- pass
-
- def toString(self) -> str:
- return f"WindowProviderService@{hex(id(self))}"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/android/webkit.py b/android_pyapi/android/webkit.py
deleted file mode 100644
index e8000c7..0000000
--- a/android_pyapi/android/webkit.py
+++ /dev/null
@@ -1,992 +0,0 @@
-"""
-Android WebKit 组件 — WebView, WebSettings, WebViewClient, WebChromeClient 等
-方法签名完全对齐 Android SDK
-"""
-
-import os
-import sys
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import (
- Stub, AndroidOnlyError, android_context,
- resolve_android_path, to_android_path,
- _sdcard_root, _app_data_dir, _package_name,
-)
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebResourceRequest / WebResourceResponse / WebResourceError
-# ═══════════════════════════════════════════════════════════════
-
-class WebResourceRequest(Stub):
- """WebResourceRequest — 资源请求"""
-
- def __init__(self, url: str = "", is_for_main_frame: bool = False,
- is_redirect: bool = False, method: str = "GET",
- request_headers: Optional[Dict[str, str]] = None):
- super().__init__()
- self._url = url
- self._is_for_main_frame = is_for_main_frame
- self._is_redirect = is_redirect
- self._method = method
- self._request_headers = request_headers or {}
-
- def getUrl(self) -> str:
- return self._url
-
- def isForMainFrame(self) -> bool:
- return self._is_for_main_frame
-
- def isRedirect(self) -> bool:
- return self._is_redirect
-
- def getMethod(self) -> str:
- return self._method
-
- def getRequestHeaders(self) -> Dict[str, str]:
- return dict(self._request_headers)
-
- def toString(self) -> str:
- return f"WebResourceRequest(url={self._url})"
-
-
-class WebResourceResponse(Stub):
- """WebResourceResponse — 资源响应"""
-
- def __init__(self, mime_type: str = "", encoding: str = "",
- data: Any = None, status_code: int = 200,
- reason_phrase: str = "OK",
- response_headers: Optional[Dict[str, str]] = None):
- super().__init__()
- self._mime_type = mime_type
- self._encoding = encoding
- self._data = data
- self._status_code = status_code
- self._reason_phrase = reason_phrase
- self._response_headers = response_headers or {}
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def getEncoding(self) -> str:
- return self._encoding
-
- def getData(self) -> Any:
- return self._data
-
- def getStatusCode(self) -> int:
- return self._status_code
-
- def getReasonPhrase(self) -> str:
- return self._reason_phrase
-
- def getResponseHeaders(self) -> Dict[str, str]:
- return dict(self._response_headers)
-
-
-class WebResourceError(Stub):
- """WebResourceError — 资源错误"""
-
- ERROR_UNKNOWN = -1
- ERROR_HOST_LOOKUP = -2
- ERROR_UNSUPPORTED_AUTH_SCHEME = -3
- ERROR_AUTHENTICATION = -4
- ERROR_PROXY_AUTHENTICATION = -5
- ERROR_CONNECT = -6
- ERROR_IO = -7
- ERROR_TIMEOUT = -8
- ERROR_REDIRECT_LOOP = -9
- ERROR_UNSUPPORTED_SCHEME = -10
- ERROR_FAILED_SSL_HANDSHAKE = -11
- ERROR_BAD_URL = -12
- ERROR_FILE = -13
- ERROR_FILE_NOT_FOUND = -14
- ERROR_TOO_MANY_REQUESTS = -15
-
- def __init__(self, error_code: int = ERROR_UNKNOWN, description: str = ""):
- super().__init__()
- self._error_code = error_code
- self._description = description
-
- def getErrorCode(self) -> int:
- return self._error_code
-
- def getDescription(self) -> str:
- return self._description
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebMessage / WebMessagePort
-# ═══════════════════════════════════════════════════════════════
-
-class WebMessage(Stub):
- """WebMessage — Web 消息"""
-
- def __init__(self, data: str = ""):
- super().__init__()
- self._data = data
-
- def getData(self) -> str:
- return self._data
-
-
-class WebMessagePort(Stub):
- """WebMessagePort — Web 消息端口"""
-
- def postMessage(self, message: WebMessage):
- pass
-
- def close(self):
- pass
-
- def setWebMessageCallback(self, callback: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# JavascriptInterface
-# ═══════════════════════════════════════════════════════════════
-
-class JavascriptInterface(Stub):
- """JavascriptInterface — JavaScript 接口注解"""
-
- def __init__(self, value: str = ""):
- super().__init__()
- self._value = value
-
- def getValue(self) -> str:
- return self._value
-
-
-# ═══════════════════════════════════════════════════════════════
-# JsResult / JsPromptResult
-# ═══════════════════════════════════════════════════════════════
-
-class JsResult(Stub):
- """JsResult — JS 对话框结果"""
-
- def __init__(self):
- super().__init__()
- self._confirmed = False
-
- def confirm(self):
- self._confirmed = True
-
- def cancel(self):
- self._confirmed = False
-
-
-class JsPromptResult(JsResult):
- """JsPromptResult — JS 提示结果"""
-
- def __init__(self):
- super().__init__()
- self._string_result: str = ""
-
- def confirm(self, result: str = ""):
- self._confirmed = True
- self._string_result = result
-
- def getStringResult(self) -> str:
- return self._string_result
-
-
-# ═══════════════════════════════════════════════════════════════
-# HttpAuthHandler / SslErrorHandler
-# ═══════════════════════════════════════════════════════════════
-
-class HttpAuthHandler(Stub):
- """HttpAuthHandler — HTTP 认证处理器"""
-
- def __init__(self):
- super().__init__()
- self._proceeded = False
- self._cancelled = False
-
- def proceed(self, username: str, password: str):
- self._proceeded = True
-
- def cancel(self):
- self._cancelled = True
-
- def useHttpAuthUsernamePassword(self) -> bool:
- return False
-
-
-class SslErrorHandler(Stub):
- """SslErrorHandler — SSL 错误处理器"""
-
- def __init__(self):
- super().__init__()
- self._proceeded = False
- self._cancelled = False
-
- def proceed(self):
- self._proceeded = True
-
- def cancel(self):
- self._cancelled = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# PermissionRequest
-# ═══════════════════════════════════════════════════════════════
-
-class PermissionRequest(Stub):
- """PermissionRequest — 权限请求"""
-
- RESOURCE_VIDEO_CAPTURE = "android.webkit.resource.VIDEO_CAPTURE"
- RESOURCE_AUDIO_CAPTURE = "android.webkit.resource.AUDIO_CAPTURE"
- RESOURCE_PROTECTED_MEDIA_ID = "android.webkit.resource.PROTECTED_MEDIA_ID"
- RESOURCE_MIDI_SYSEX = "android.webkit.resource.MIDI_SYSEX"
-
- def __init__(self):
- super().__init__()
- self._origin: Any = None
- self._resources: List[str] = []
- self._granted_resources: List[str] = []
-
- def getOrigin(self) -> Any:
- return self._origin
-
- def getResources(self) -> List[str]:
- return list(self._resources)
-
- def getGrantedResources(self) -> List[str]:
- return list(self._granted_resources)
-
- def grant(self, resources: List[str]):
- self._granted_resources = list(resources)
-
- def deny(self):
- self._granted_resources.clear()
-
-
-# ═══════════════════════════════════════════════════════════════
-# GeolocationPermissions / WebStorage
-# ═══════════════════════════════════════════════════════════════
-
-class GeolocationPermissions(Stub):
- """GeolocationPermissions — 地理位置权限"""
-
- @staticmethod
- def getInstance() -> "GeolocationPermissions":
- return GeolocationPermissions()
-
- def allow(self, origin: str):
- pass
-
- def clear(self, origin: str):
- pass
-
- def clearAll(self):
- pass
-
- def getAllowed(self, origin: str, callback: Any):
- pass
-
- def getOrigins(self, callback: Any):
- pass
-
-
-class WebStorage(Stub):
- """WebStorage — Web 存储"""
-
- @staticmethod
- def getInstance() -> "WebStorage":
- return WebStorage()
-
- def deleteAllData(self):
- pass
-
- def deleteOrigin(self, origin: str):
- pass
-
- def getOrigins(self, callback: Any):
- pass
-
- def getQuotaForOrigin(self, origin: str, callback: Any):
- pass
-
- def getUsageForOrigin(self, origin: str, callback: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebBackForwardList / WebHistoryItem
-# ═══════════════════════════════════════════════════════════════
-
-class WebHistoryItem(Stub):
- """WebHistoryItem — 历史项"""
-
- def __init__(self):
- super().__init__()
- self._url: str = ""
- self._original_url: str = ""
- self._title: str = ""
- self._favicon: Any = None
-
- def getUrl(self) -> str:
- return self._url
-
- def getOriginalUrl(self) -> str:
- return self._original_url
-
- def getTitle(self) -> str:
- return self._title
-
- def getFavicon(self) -> Any:
- return self._favicon
-
- def toString(self) -> str:
- return f"WebHistoryItem(url={self._url})"
-
-
-class WebBackForwardList(Stub):
- """WebBackForwardList — 前进后退列表"""
-
- def __init__(self):
- super().__init__()
- self._items: List[WebHistoryItem] = []
- self._current_index: int = -1
-
- def getCurrentItem(self) -> Optional[WebHistoryItem]:
- if 0 <= self._current_index < len(self._items):
- return self._items[self._current_index]
- return None
-
- def getCurrentIndex(self) -> int:
- return self._current_index
-
- def getItemAtIndex(self, index: int) -> Optional[WebHistoryItem]:
- if 0 <= index < len(self._items):
- return self._items[index]
- return None
-
- def getSize(self) -> int:
- return len(self._items)
-
-
-# ═══════════════════════════════════════════════════════════════
-# CookieManager / CookieSyncManager
-# ═══════════════════════════════════════════════════════════════
-
-class CookieManager(Stub):
- """CookieManager — Cookie 管理器"""
-
- _instance: Optional["CookieManager"] = None
-
- def __init__(self):
- super().__init__()
- self._accept_cookies: bool = True
- self._accept_third_party: bool = True
- self._cookies: Dict[str, str] = {}
-
- @staticmethod
- def getInstance() -> "CookieManager":
- if CookieManager._instance is None:
- CookieManager._instance = CookieManager()
- return CookieManager._instance
-
- def setAcceptCookies(self, accept: bool):
- self._accept_cookies = accept
-
- def acceptCookies(self) -> bool:
- return self._accept_cookies
-
- def setCookie(self, url: str, value: str):
- if self._accept_cookies:
- self._cookies[url] = value
-
- def getCookie(self, url: str) -> Optional[str]:
- return self._cookies.get(url)
-
- def setAcceptThirdPartyCookies(self, webview: Any, accept: bool):
- self._accept_third_party = accept
-
- def acceptThirdPartyCookies(self) -> bool:
- return self._accept_third_party
-
- def removeSessionCookie(self):
- pass
-
- def removeAllCookies(self):
- self._cookies.clear()
-
- def removeAllCookiesSync(self):
- self._cookies.clear()
-
- def removeSessionCookies(self):
- pass
-
- def flush(self):
- pass
-
- def hasCookies(self) -> bool:
- return bool(self._cookies)
-
- def removeExpiredCookie(self):
- pass
-
-
-class CookieSyncManager(Stub):
- """CookieSyncManager — Cookie 同步管理器"""
-
- _instance: Optional["CookieSyncManager"] = None
-
- @staticmethod
- def createInstance(context: Any) -> "CookieSyncManager":
- if CookieSyncManager._instance is None:
- CookieSyncManager._instance = CookieSyncManager()
- return CookieSyncManager._instance
-
- @staticmethod
- def getInstance() -> "CookieSyncManager":
- if CookieSyncManager._instance is None:
- CookieSyncManager._instance = CookieSyncManager()
- return CookieSyncManager._instance
-
- def sync(self):
- pass
-
- def startSync(self):
- pass
-
- def stopSync(self):
- pass
-
- def resetSync(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebSettings
-# ═══════════════════════════════════════════════════════════════
-
-class WebSettings(Stub):
- """WebSettings — WebView 设置"""
-
- LOAD_DEFAULT = -1
- LOAD_CACHE_ELSE_NETWORK = 1
- LOAD_NO_CACHE = 2
- LOAD_CACHE_ONLY = 3
-
- MIXED_CONTENT_ALWAYS_ALLOW = 0
- MIXED_CONTENT_NEVER_ALLOW = 1
- MIXED_CONTENT_COMPATIBILITY_MODE = 2
-
- class LayoutAlgorithm(Stub):
- NORMAL = 0
- SINGLE_COLUMN = 1
- NARROW_COLUMNS = 2
- TEXT_AUTOSIZING = 3
-
- def __init__(self):
- super().__init__()
- self._js_enabled: bool = True
- self._dom_storage_enabled: bool = True
- self._allow_file_access: bool = True
- self._allow_content_access: bool = True
- self._allow_file_access_from_urls: bool = False
- self._allow_universal_access_from_urls: bool = False
- self._built_in_zoom_controls: bool = True
- self._display_zoom_controls: bool = True
- self._support_zoom: bool = True
- self._load_with_overview_mode: bool = False
- self._use_wide_viewport: bool = False
- self._user_agent_string: str = "Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36"
- self._default_text_encoding: str = "UTF-8"
- self._cache_mode: int = self.LOAD_DEFAULT
- self._app_cache_enabled: bool = False
- self._app_cache_path: str = ""
- self._database_enabled: bool = False
- self._geolocation_enabled: bool = False
- self._js_can_open_windows: bool = False
- self._loads_images_automatically: bool = True
- self._block_network_image: bool = False
- self._block_network_loads: bool = False
- self._minimum_font_size: int = 8
- self._default_font_size: int = 16
- self._text_zoom: int = 100
- self._layout_algorithm: int = WebSettings.LayoutAlgorithm.NORMAL
- self._mixed_content_mode: int = self.MIXED_CONTENT_NEVER_ALLOW
- self._offscreen_pre_raster: bool = False
- self._safe_browsing_enabled: bool = True
- self._javascript_can_open_windows_automatically: bool = False
-
- def setJavaScriptEnabled(self, enabled: bool):
- self._js_enabled = enabled
-
- def setDomStorageEnabled(self, enabled: bool):
- self._dom_storage_enabled = enabled
-
- def setAllowFileAccess(self, allow: bool):
- self._allow_file_access = allow
-
- def setAllowContentAccess(self, allow: bool):
- self._allow_content_access = allow
-
- def setAllowFileAccessFromFileURLs(self, allow: bool):
- self._allow_file_access_from_urls = allow
-
- def setAllowUniversalAccessFromFileURLs(self, allow: bool):
- self._allow_universal_access_from_urls = allow
-
- def setBuiltInZoomControls(self, enabled: bool):
- self._built_in_zoom_controls = enabled
-
- def setDisplayZoomControls(self, enabled: bool):
- self._display_zoom_controls = enabled
-
- def setSupportZoom(self, support: bool):
- self._support_zoom = support
-
- def setLoadWithOverviewMode(self, overview: bool):
- self._load_with_overview_mode = overview
-
- def setUseWideViewPort(self, use: bool):
- self._use_wide_viewport = use
-
- def setUserAgentString(self, ua: str):
- self._user_agent_string = ua
-
- def getUserAgentString(self) -> str:
- return self._user_agent_string
-
- def setDefaultTextEncodingName(self, encoding: str):
- self._default_text_encoding = encoding
-
- def getDefaultTextEncodingName(self) -> str:
- return self._default_text_encoding
-
- def setCacheMode(self, mode: int):
- self._cache_mode = mode
-
- def getCacheMode(self) -> int:
- return self._cache_mode
-
- def setAppCacheEnabled(self, enabled: bool):
- self._app_cache_enabled = enabled
-
- def setAppCachePath(self, path: str):
- self._app_cache_path = path
-
- def setDatabaseEnabled(self, enabled: bool):
- self._database_enabled = enabled
-
- def setGeolocationEnabled(self, enabled: bool):
- self._geolocation_enabled = enabled
-
- def setJavaScriptCanOpenWindowsAutomatically(self, auto: bool):
- self._javascript_can_open_windows_automatically = auto
-
- def setLoadsImagesAutomatically(self, auto: bool):
- self._loads_images_automatically = auto
-
- def setBlockNetworkImage(self, block: bool):
- self._block_network_image = block
-
- def setBlockNetworkLoads(self, block: bool):
- self._block_network_loads = block
-
- def setMinimumFontSize(self, size: int):
- self._minimum_font_size = size
-
- def getMinimumFontSize(self) -> int:
- return self._minimum_font_size
-
- def setDefaultFontSize(self, size: int):
- self._default_font_size = size
-
- def getDefaultFontSize(self) -> int:
- return self._default_font_size
-
- def setTextZoom(self, zoom: int):
- self._text_zoom = zoom
-
- def getTextZoom(self) -> int:
- return self._text_zoom
-
- def setLayoutAlgorithm(self, algo: int):
- self._layout_algorithm = algo
-
- def getLayoutAlgorithm(self) -> int:
- return self._layout_algorithm
-
- def setMixedContentMode(self, mode: int):
- self._mixed_content_mode = mode
-
- def getMixedContentMode(self) -> int:
- return self._mixed_content_mode
-
- def setOffscreenPreRaster(self, enabled: bool):
- self._offscreen_pre_raster = enabled
-
- def getOffscreenPreRaster(self) -> bool:
- return self._offscreen_pre_raster
-
- def setSafeBrowsingEnabled(self, enabled: bool):
- self._safe_browsing_enabled = enabled
-
- def getSafeBrowsingEnabled(self) -> bool:
- return self._safe_browsing_enabled
-
- def toString(self) -> str:
- return f"WebSettings(js={self._js_enabled})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebViewClient
-# ═══════════════════════════════════════════════════════════════
-
-class WebViewClient(Stub):
- """WebViewClient — WebView 客户端"""
-
- def onPageStarted(self, view: "WebView", url: str, favicon: Any):
- pass
-
- def onPageFinished(self, view: "WebView", url: str):
- pass
-
- def onLoadResource(self, view: "WebView", url: str):
- pass
-
- def shouldOverrideUrlLoading(self, view: "WebView", request: Any) -> bool:
- return False
-
- def shouldOverrideUrlLoading(self, view: "WebView", url: str) -> bool:
- return False
-
- def shouldInterceptRequest(self, view: "WebView", request: WebResourceRequest) -> Optional[WebResourceResponse]:
- return None
-
- def shouldInterceptRequest(self, view: "WebView", url: str) -> Optional[WebResourceResponse]:
- return None
-
- def onReceivedHttpError(self, view: "WebView", request: WebResourceRequest,
- error_response: WebResourceResponse):
- pass
-
- def onReceivedSslError(self, view: "WebView", handler: SslErrorHandler, error: Any):
- pass
-
- def onReceivedClientCertRequest(self, view: "WebView", request: Any):
- pass
-
- def onReceivedHttpAuthRequest(self, view: "WebView", handler: HttpAuthHandler,
- host: str, realm: str):
- pass
-
- def onFormResubmission(self, view: "WebView", dont_resend: Any, resend: Any):
- pass
-
- def doUpdateVisitedHistory(self, view: "WebView", url: str, is_reload: bool):
- pass
-
- def onScaleChanged(self, view: "WebView", old_scale: float, new_scale: float):
- pass
-
- def onUnhandledKeyEvent(self, view: "WebView", event: Any):
- pass
-
- def shouldOverrideKeyEvent(self, view: "WebView", event: Any) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebChromeClient
-# ═══════════════════════════════════════════════════════════════
-
-class WebChromeClient(Stub):
- """WebChromeClient — WebView Chrome 客户端"""
-
- def onProgressChanged(self, view: "WebView", new_progress: int):
- pass
-
- def onReceivedTitle(self, view: "WebView", title: str):
- pass
-
- def onReceivedIcon(self, view: "WebView", icon: Any):
- pass
-
- def onReceivedTouchIconUrl(self, view: "WebView", url: str, precomposed: bool):
- pass
-
- def onShowCustomView(self, view: Any, callback: Any):
- pass
-
- def onHideCustomView(self):
- pass
-
- def onCreateWindow(self, view: "WebView", is_dialog: bool,
- is_user_gesture: bool, result_msg: Any) -> bool:
- return False
-
- def onRequestFocus(self, view: "WebView"):
- pass
-
- def onCloseWindow(self, window: "WebView"):
- pass
-
- def onJsAlert(self, view: "WebView", url: str, message: str,
- result: JsResult) -> bool:
- return False
-
- def onJsConfirm(self, view: "WebView", url: str, message: str,
- result: JsResult) -> bool:
- return False
-
- def onJsPrompt(self, view: "WebView", url: str, message: str,
- default_value: str, result: JsPromptResult) -> bool:
- return False
-
- def onJsBeforeUnload(self, view: "WebView", url: str, message: str,
- result: JsResult) -> bool:
- return False
-
- def onExceededDatabaseQuota(self, url: str, database_identifier: str,
- quota: int, estimated_database_size: int,
- total_quota: int, quota_updater: Any):
- pass
-
- def onReachedMaxAppCacheSize(self, space_needed: int, total_quota: int,
- quota_updater: Any):
- pass
-
- def onGeolocationPermissionsShowPrompt(self, origin: str,
- callback: Any):
- pass
-
- def onGeolocationPermissionsHidePrompt(self):
- pass
-
- def onPermissionRequest(self, request: PermissionRequest):
- pass
-
- def onPermissionRequestCanceled(self, request: PermissionRequest):
- pass
-
- def onConsoleMessage(self, message: Any) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebView
-# ═══════════════════════════════════════════════════════════════
-
-class WebView(Stub):
- """WebView — Web 视图"""
-
- _instance_count = 0
-
- def __init__(self, context: Any = None, attrs: Any = None):
- super().__init__()
- WebView._instance_count += 1
- self._context = context
- self._settings = WebSettings()
- self._webview_client: Optional[WebViewClient] = None
- self._chrome_client: Optional[WebChromeClient] = None
- self._current_url: str = ""
- self._original_url: str = ""
- self._title: str = ""
- self._progress: int = 100
- self._content_height: int = 0
- self._scale: float = 1.0
- self._background_color: int = 0xFFFFFFFF
- self._back_forward_list = WebBackForwardList()
- self._javascript_interfaces: Dict[str, Any] = {}
- self._paused: bool = False
- self._timers_paused: bool = False
- self._network_available: bool = True
-
- def loadUrl(self, url: str, additional_headers: Optional[Dict[str, str]] = None):
- self._current_url = url
- self._original_url = url
- self._title = url
- self._progress = 0
- if self._webview_client:
- try:
- self._webview_client.onPageStarted(self, url, None)
- self._webview_client.onPageFinished(self, url)
- except Exception:
- pass
- self._progress = 100
-
- def loadData(self, data: str, mime_type: str = "text/html",
- encoding: str = "utf-8"):
- self._current_url = "data:text/html;charset=utf-8,"
- self._progress = 100
-
- def loadDataWithBaseURL(self, base_url: str, data: str,
- mime_type: str, encoding: str,
- history_url: str):
- self._current_url = history_url or base_url
- self._progress = 100
-
- def setWebViewClient(self, client: WebViewClient):
- self._webview_client = client
-
- def setWebChromeClient(self, client: WebChromeClient):
- self._chrome_client = client
-
- def getSettings(self) -> WebSettings:
- return self._settings
-
- def goBack(self):
- pass
-
- def goForward(self):
- pass
-
- def canGoBack(self) -> bool:
- return False
-
- def canGoForward(self) -> bool:
- return False
-
- def goBackOrForward(self, steps: int):
- pass
-
- def reload(self):
- pass
-
- def stopLoading(self):
- pass
-
- def clearHistory(self):
- pass
-
- def clearCache(self, include_disk_files: bool):
- pass
-
- def clearView(self):
- pass
-
- def destroy(self):
- WebView._instance_count -= 1
-
- def getUrl(self) -> Optional[str]:
- return self._current_url or None
-
- def getTitle(self) -> Optional[str]:
- return self._title or None
-
- def getProgress(self) -> int:
- return self._progress
-
- def getContentHeight(self) -> int:
- return self._content_height
-
- def getScale(self) -> float:
- return self._scale
-
- def addJavascriptInterface(self, obj: Any, interface_name: str):
- self._javascript_interfaces[interface_name] = obj
-
- def removeJavascriptInterface(self, interface_name: str):
- if interface_name in self._javascript_interfaces:
- del self._javascript_interfaces[interface_name]
-
- def evaluateJavascript(self, script: str, callback: Any = None):
- pass
-
- def setInitialScale(self, scale_in_percent: int):
- self._scale = scale_in_percent / 100.0
-
- def setBackgroundColor(self, color: int):
- self._background_color = color
-
- def scrollTo(self, x: int, y: int):
- pass
-
- def scrollBy(self, x: int, y: int):
- pass
-
- def pageUp(self, top: bool) -> bool:
- return True
-
- def pageDown(self, bottom: bool) -> bool:
- return True
-
- def findNext(self, forward: bool):
- pass
-
- def findAll(self, find: str) -> int:
- return 0
-
- def findAllAsync(self, find: str):
- pass
-
- def clearMatches(self):
- pass
-
- def zoomIn(self):
- self._scale *= 1.25
-
- def zoomOut(self):
- self._scale /= 1.25
-
- def setNetworkAvailable(self, available: bool):
- self._network_available = available
-
- def pauseTimers(self):
- self._timers_paused = True
-
- def resumeTimers(self):
- self._timers_paused = False
-
- def onPause(self):
- self._paused = True
-
- def onResume(self):
- self._paused = False
-
- def onWindowFocusChanged(self, has_focus: bool):
- pass
-
- def setLayoutParams(self, params: Any):
- pass
-
- def requestFocus(self, direction: int = 0):
- pass
-
- def getOriginalUrl(self) -> Optional[str]:
- return self._original_url or None
-
- def canZoomIn(self) -> bool:
- return True
-
- def canZoomOut(self) -> bool:
- return self._scale > 0.25
-
- def toString(self) -> str:
- return f"WebView(url={self._current_url})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- "WebView",
- "WebSettings",
- "WebViewClient",
- "WebChromeClient",
- "WebResourceRequest",
- "WebResourceResponse",
- "WebResourceError",
- "WebMessage",
- "WebMessagePort",
- "JavascriptInterface",
- "CookieManager",
- "CookieSyncManager",
- "JsResult",
- "JsPromptResult",
- "HttpAuthHandler",
- "SslErrorHandler",
- "PermissionRequest",
- "GeolocationPermissions",
- "WebStorage",
- "WebBackForwardList",
- "WebHistoryItem",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/webkit_ext.py b/android_pyapi/android/webkit_ext.py
deleted file mode 100644
index 1878d76..0000000
--- a/android_pyapi/android/webkit_ext.py
+++ /dev/null
@@ -1,1554 +0,0 @@
-"""
-Android WebKit 扩展组件 — WebView, WebSettings, WebViewClient, WebChromeClient 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import os
-import json
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebView 常量
-# ═══════════════════════════════════════════════════════════════
-
-LOAD_DEFAULT = 0
-LOAD_CACHE_ONLY = 1
-LOAD_CACHE_ELSE_NETWORK = 2
-LOAD_NO_CACHE = 3
-LOAD_NORMAL = 0
-
-ERROR_UNKNOWN = -1
-ERROR_HOST_LOOKUP = -2
-ERROR_UNSUPPORTED_AUTH_SCHEME = -3
-ERROR_AUTHENTICATION = -4
-ERROR_PROXY_AUTHENTICATION = -5
-ERROR_CONNECT = -6
-ERROR_IO = -7
-ERROR_TIMEOUT = -8
-ERROR_REDIRECT_LOOP = -9
-ERROR_UNSUPPORTED_SCHEME = -10
-ERROR_FAILED_SSL_HANDSHAKE = -11
-ERROR_BAD_URL = -12
-ERROR_FILE = -13
-ERROR_FILE_NOT_FOUND = -14
-ERROR_TOO_MANY_REQUESTS = -15
-
-NAVIGATION_TYPE_LINK_CLICKED = 0
-NAVIGATION_TYPE_FORM_SUBMITTED = 1
-NAVIGATION_TYPE_BACK_FORWARD = 2
-NAVIGATION_TYPE_RELOAD = 3
-NAVIGATION_TYPE_FORM_RESUBMITTED = 4
-NAVIGATION_TYPE_OTHER = -1
-
-OVER_SCROLL_NEVER = 2
-OVER_SCROLL_ALWAYS = 0
-OVER_SCROLL_IF_CONTENT_SCROLLS = 1
-
-RENDERER_PRIORITY_WAIVED = 0
-RENDERER_PRIORITY_BOUND = 1
-RENDERER_PRIORITY_IMPORTANT = 2
-
-SCHEME_HTTP = "http"
-SCHEME_HTTPS = "https"
-SCHEME_FILE = "file"
-SCHEME_ABOUT = "about"
-SCHEME_DATA = "data"
-SCHEME_JAVASCRIPT = "javascript"
-
-WEB_CHROME_CLIENT_GET_DEFAULT_VIDEO_POSTER = 1
-WEB_CHROME_CLIENT_GET_VISITED_HISTORY = 2
-
-WEB_RESOURCE_ERROR_STYLE_BOX = 0
-WEB_RESOURCE_ERROR_STYLE_GENERIC = 1
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebResourceRequest / WebResourceResponse / WebResourceError
-# ═══════════════════════════════════════════════════════════════
-
-class WebResourceRequest(Stub):
- """WebResourceRequest — 资源请求"""
-
- def __init__(self, url: str = "", is_for_main_frame: bool = False,
- is_redirect: bool = False, method: str = "GET",
- request_headers: Optional[Dict[str, str]] = None,
- has_user_gesture: bool = False,
- is_main_frame: bool = False):
- super().__init__()
- self._url = url
- self._is_for_main_frame = is_for_main_frame
- self._is_redirect = is_redirect
- self._method = method
- self._request_headers = request_headers or {}
- self._has_user_gesture = has_user_gesture
- self._is_main_frame = is_main_frame
-
- def getUrl(self) -> str:
- return self._url
-
- def isForMainFrame(self) -> bool:
- return self._is_for_main_frame
-
- def isRedirect(self) -> bool:
- return self._is_redirect
-
- def getMethod(self) -> str:
- return self._method
-
- def getRequestHeaders(self) -> Dict[str, str]:
- return dict(self._request_headers)
-
- def hasUserGesture(self) -> bool:
- return self._has_user_gesture
-
- def isMainFrame(self) -> bool:
- return self._is_main_frame
-
- def toString(self) -> str:
- return f"WebResourceRequest(url={self._url}, method={self._method})"
-
-
-class WebResourceResponse(Stub):
- """WebResourceResponse — 资源响应"""
-
- def __init__(self, mime_type: str = "", encoding: str = "",
- data: Any = None, status_code: int = 200,
- reason_phrase: str = "OK",
- response_headers: Optional[Dict[str, str]] = None):
- super().__init__()
- self._mime_type = mime_type
- self._encoding = encoding
- self._data = data
- self._status_code = status_code
- self._reason_phrase = reason_phrase
- self._response_headers = response_headers or {}
-
- def getMimeType(self) -> str:
- return self._mime_type
-
- def getEncoding(self) -> str:
- return self._encoding
-
- def getData(self) -> Any:
- return self._data
-
- def getStatusCode(self) -> int:
- return self._status_code
-
- def getReasonPhrase(self) -> str:
- return self._reason_phrase
-
- def getResponseHeaders(self) -> Dict[str, str]:
- return dict(self._response_headers)
-
- def setMimeType(self, mime_type: str) -> None:
- self._mime_type = mime_type
-
- def setEncoding(self, encoding: str) -> None:
- self._encoding = encoding
-
- def setData(self, data: Any) -> None:
- self._data = data
-
- def setStatusCodeAndReasonPhrase(self, status_code: int, reason: str) -> None:
- self._status_code = status_code
- self._reason_phrase = reason
-
- def setResponseHeaders(self, headers: Dict[str, str]) -> None:
- self._response_headers = dict(headers)
-
- def toString(self) -> str:
- return (f"WebResourceResponse(status={self._status_code}, "
- f"mime={self._mime_type})")
-
-
-class WebResourceError(Stub):
- """WebResourceError — 资源错误"""
-
- ERROR_UNKNOWN = ERROR_UNKNOWN
- ERROR_HOST_LOOKUP = ERROR_HOST_LOOKUP
- ERROR_UNSUPPORTED_AUTH_SCHEME = ERROR_UNSUPPORTED_AUTH_SCHEME
- ERROR_AUTHENTICATION = ERROR_AUTHENTICATION
- ERROR_PROXY_AUTHENTICATION = ERROR_PROXY_AUTHENTICATION
- ERROR_CONNECT = ERROR_CONNECT
- ERROR_IO = ERROR_IO
- ERROR_TIMEOUT = ERROR_TIMEOUT
- ERROR_REDIRECT_LOOP = ERROR_REDIRECT_LOOP
- ERROR_UNSUPPORTED_SCHEME = ERROR_UNSUPPORTED_SCHEME
- ERROR_FAILED_SSL_HANDSHAKE = ERROR_FAILED_SSL_HANDSHAKE
- ERROR_BAD_URL = ERROR_BAD_URL
- ERROR_FILE = ERROR_FILE
- ERROR_FILE_NOT_FOUND = ERROR_FILE_NOT_FOUND
- ERROR_TOO_MANY_REQUESTS = ERROR_TOO_MANY_REQUESTS
-
- def __init__(self, error_code: int = ERROR_UNKNOWN, description: str = ""):
- super().__init__()
- self._error_code = error_code
- self._description = description
-
- def getErrorCode(self) -> int:
- return self._error_code
-
- def getDescription(self) -> str:
- return self._description
-
- def toString(self) -> str:
- return f"WebResourceError(code={self._error_code}, desc={self._description})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebMessage / WebMessagePort / WebMessageListener
-# ═══════════════════════════════════════════════════════════════
-
-class WebMessage(Stub):
- """WebMessage — Web消息"""
-
- def __init__(self, data: str = "", ports: Optional[List["WebMessagePort"]] = None):
- super().__init__()
- self._data = data
- self._ports = list(ports) if ports else []
-
- def getData(self) -> str:
- return self._data
-
- def getPorts(self) -> List["WebMessagePort"]:
- return list(self._ports)
-
- def toString(self) -> str:
- return f"WebMessage(data={self._data[:50]})"
-
-
-class WebMessagePort(Stub):
- """WebMessagePort — Web消息端口"""
-
- def __init__(self):
- super().__init__()
- self._callback: Optional[Callable] = None
- self._closed = False
-
- def postMessage(self, message: WebMessage) -> None:
- if self._closed:
- raise RuntimeException("WebMessagePort 已关闭")
- if self._callback:
- self._callback(message)
-
- def close(self) -> None:
- self._closed = True
- self._callback = None
-
- def setWebMessageCallback(self, callback: Optional[Callable]) -> None:
- self._callback = callback
-
- def isClosed(self) -> bool:
- return self._closed
-
- def toString(self) -> str:
- return f"WebMessagePort(closed={self._closed})"
-
-
-class WebMessageListener(Stub):
- """WebMessageListener — Web消息监听器"""
-
- def onPostMessage(self, view: Any, message: WebMessage,
- source_origin: str, is_main_frame: bool,
- js_ports: List[WebMessagePort]) -> None:
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebStorage
-# ═══════════════════════════════════════════════════════════════
-
-class WebStorage(Stub):
- """WebStorage — Web存储"""
-
- class UsageInfo(Stub):
- """WebStorage.UsageInfo — 使用信息"""
- def __init__(self, origin: str = "", usage: int = 0, quota: int = 0):
- super().__init__()
- self._origin = origin
- self._usage = usage
- self._quota = quota
-
- def getOrigin(self) -> str:
- return self._origin
-
- def getUsage(self) -> int:
- return self._usage
-
- def getQuota(self) -> int:
- return self._quota
-
- def toString(self) -> str:
- return f"UsageInfo(origin={self._origin}, usage={self._usage})"
-
- def __init__(self):
- super().__init__()
- self._storage: Dict[str, int] = {}
- self._lock = threading.Lock()
-
- def getOrigins(self, callback: Callable) -> None:
- with self._lock:
- callback(list(self._storage.keys()))
-
- def getUsageForOrigin(self, origin: str, callback: Callable) -> None:
- with self._lock:
- callback(self._storage.get(origin, 0))
-
- def getQuotaForOrigin(self, origin: str, callback: Callable) -> None:
- with self._lock:
- callback(self._storage.get(origin, 5 * 1024 * 1024))
-
- def setQuotaForOrigin(self, origin: str, quota: int) -> None:
- with self._lock:
- self._storage[origin] = quota
-
- def deleteOrigin(self, origin: str) -> None:
- with self._lock:
- self._storage.pop(origin, None)
-
- def deleteAllData(self) -> None:
- with self._lock:
- self._storage.clear()
-
- def toString(self) -> str:
- return f"WebStorage(origins={len(self._storage)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebView 扩展
-# ═══════════════════════════════════════════════════════════════
-
-class WebView(Stub):
- """WebView — Web视图扩展"""
-
- RENDERER_PRIORITY_WAIVED = RENDERER_PRIORITY_WAIVED
- RENDERER_PRIORITY_BOUND = RENDERER_PRIORITY_BOUND
- RENDERER_PRIORITY_IMPORTANT = RENDERER_PRIORITY_IMPORTANT
-
- SCHEME_HTTP = SCHEME_HTTP
- SCHEME_HTTPS = SCHEME_HTTPS
- SCHEME_FILE = SCHEME_FILE
- SCHEME_ABOUT = SCHEME_ABOUT
- SCHEME_DATA = SCHEME_DATA
- SCHEME_JAVASCRIPT = SCHEME_JAVASCRIPT
-
- LOAD_DEFAULT = LOAD_DEFAULT
- LOAD_CACHE_ONLY = LOAD_CACHE_ONLY
- LOAD_CACHE_ELSE_NETWORK = LOAD_CACHE_ELSE_NETWORK
- LOAD_NO_CACHE = LOAD_NO_CACHE
- LOAD_NORMAL = LOAD_NORMAL
-
- OVER_SCROLL_NEVER = OVER_SCROLL_NEVER
- OVER_SCROLL_ALWAYS = OVER_SCROLL_ALWAYS
- OVER_SCROLL_IF_CONTENT_SCROLLS = OVER_SCROLL_IF_CONTENT_SCROLLS
-
- class WebViewTransport(Stub):
- """WebView.WebViewTransport — WebView传输"""
- def __init__(self):
- super().__init__()
- self._webview: Optional[WebView] = None
-
- def setWebView(self, webview: "WebView") -> None:
- self._webview = webview
-
- def getWebView(self) -> Optional["WebView"]:
- return self._webview
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._url: Optional[str] = None
- self._content: Optional[str] = None
- self._settings: Optional["WebSettings"] = None
- self._client: Optional["WebViewClient"] = None
- self._chrome_client: Optional["WebChromeClient"] = None
- self._web_message_listeners: Dict[str, WebMessageListener] = {}
- self._renderer_priority: int = self.RENDERER_PRIORITY_BOUND
- self._renderer_priority_overridden = False
- self._lock = threading.Lock()
-
- def loadUrl(self, url: str, additional_headers: Optional[Dict[str, str]] = None) -> None:
- self._url = url
- self._content = None
- if self._client:
- self._client.onPageStarted(self, url, None)
-
- def loadData(self, data: str, mime_type: str = "text/html",
- encoding: str = "utf-8") -> None:
- self._content = data
- self._url = "data:text/html;charset=utf-8," + data[:100]
-
- def loadDataWithBaseURL(self, base_url: str, data: str,
- mime_type: str, encoding: str,
- history_url: Optional[str]) -> None:
- self._content = data
- self._url = base_url
-
- def postUrl(self, url: str, post_data: bytes) -> None:
- self._url = url
-
- def getUrl(self) -> Optional[str]:
- return self._url
-
- def getTitle(self) -> str:
- return ""
-
- def getSettings(self) -> "WebSettings":
- if self._settings is None:
- self._settings = WebSettings(self)
- return self._settings
-
- def setWebViewClient(self, client: "WebViewClient") -> None:
- self._client = client
-
- def getWebViewClient(self) -> Optional["WebViewClient"]:
- return self._client
-
- def setWebChromeClient(self, client: "WebChromeClient") -> None:
- self._chrome_client = client
-
- def getWebChromeClient(self) -> Optional["WebChromeClient"]:
- return self._chrome_client
-
- def setWebMessageListener(self, js_object_name: str,
- listener: WebMessageListener) -> None:
- with self._lock:
- self._web_message_listeners[js_object_name] = listener
-
- def addJavascriptInterface(self, obj: Any, name: str) -> None:
- pass
-
- def removeJavascriptInterface(self, name: str) -> None:
- pass
-
- def evaluateJavascript(self, script: str, callback: Optional[Callable] = None) -> None:
- pass
-
- def evaluateJavascriptForTests(self, script: str, callback: Optional[Callable] = None) -> None:
- pass
-
- def canGoBack(self) -> bool:
- return False
-
- def canGoForward(self) -> bool:
- return False
-
- def goBack(self) -> None:
- pass
-
- def goForward(self) -> None:
- pass
-
- def reload(self) -> None:
- if self._url:
- self.loadUrl(self._url)
-
- def stopLoading(self) -> None:
- pass
-
- def clearHistory(self) -> None:
- pass
-
- def clearCache(self, include_disk: bool) -> None:
- pass
-
- def clearFormData(self) -> None:
- pass
-
- def destroy(self) -> None:
- pass
-
- def onPause(self) -> None:
- pass
-
- def onResume(self) -> None:
- pass
-
- def isPaused(self) -> bool:
- return False
-
- def pageUp(self, top: bool) -> bool:
- return True
-
- def pageDown(self, bottom: bool) -> bool:
- return True
-
- def setInitialScale(self, scale: int) -> None:
- pass
-
- def getScale(self) -> float:
- return 1.0
-
- def setRendererPriorityPolicy(self, priority: int, overridden: bool) -> None:
- self._renderer_priority = priority
- self._renderer_priority_overridden = overridden
-
- def getRendererRequestedPriority(self) -> int:
- return self._renderer_priority
-
- def getRendererPriorityWaivedWhenNotVisible(self) -> bool:
- return self._renderer_priority_overridden
-
- def setNetworkAvailable(self, available: bool) -> None:
- pass
-
- def setLayoutParams(self, params: Any) -> None:
- pass
-
- def toString(self) -> str:
- return f"WebView(url={self._url})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebSettings 扩展
-# ═══════════════════════════════════════════════════════════════
-
-class WebSettings(Stub):
- """WebSettings — Web设置扩展"""
-
- LOAD_DEFAULT = LOAD_DEFAULT
- LOAD_CACHE_ONLY = LOAD_CACHE_ONLY
- LOAD_CACHE_ELSE_NETWORK = LOAD_CACHE_ELSE_NETWORK
- LOAD_NO_CACHE = LOAD_NO_CACHE
- LOAD_NORMAL = LOAD_NORMAL
-
- MIXED_CONTENT_ALWAYS_ALLOW = 0
- MIXED_CONTENT_NEVER_ALLOW = 1
- MIXED_CONTENT_COMPATIBILITY_MODE = 2
-
- LAYOUT_ALGORITHM_NORMAL = 0
- LAYOUT_ALGORITHM_SINGLE_COLUMN = 1
- LAYOUT_ALGORITHM_NARROW_COLUMNS = 2
- LAYOUT_ALGORITHM_TEXT_AUTOSIZING = 3
-
- PLUGIN_STATE_ON = 0
- PLUGIN_STATE_ON_DEMAND = 1
- PLUGIN_STATE_OFF = 2
-
- RENDER_GOOGLE_SUIT = 0
- RENDER_PRIORITY_NORMAL = 0
- RENDER_PRIORITY_HIGH = 1
- RENDER_PRIORITY_LOW = 2
-
- TEXT_AUTOSIZING_TEXT_SIZE_INCREMENT = 0
-
- USER_AGENT_DESKTOP = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
- USER_AGENT_MOBILE = "Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36"
-
- def __init__(self, webview: Optional[WebView] = None):
- super().__init__()
- self._webview = webview
- self._java_script_enabled = False
- self._java_script_can_open_windows = False
- self._allow_file_access = True
- self._allow_file_access_from_file_urls = True
- self._allow_universal_access_from_file_urls = False
- self._built_in_zoom_controls = True
- self._display_zoom_controls = True
- self._support_zoom = True
- self._load_with_overview_mode = False
- self._use_wide_viewport = True
- self._dom_storage_enabled = True
- self._database_enabled = True
- self._app_cache_enabled = True
- self._cache_mode = LOAD_DEFAULT
- self._user_agent_string: Optional[str] = None
- self._default_font_size: int = 16
- self._default_fixed_font_size: int = 13
- self._minimum_font_size: int = 8
- self._minimum_logical_font_size: int = 8
- self._text_zoom: int = 100
- self._standard_font_family: str = "sans-serif"
- self._serif_font_family: str = "serif"
- self._sans_serif_font_family: str = "sans-serif"
- self._fixed_font_family: str = "monospace"
- self._cursive_font_family: str = "cursive"
- self._fantasy_font_family: str = "fantasy"
- self._default_text_encoding: str = "UTF-8"
- self._layout_algorithm = self.LAYOUT_ALGORITHM_NORMAL
- self._block_network_image = False
- self._block_network_loads = False
- self._accept_cookies = True
- self._mixed_content_mode = self.MIXED_CONTENT_NEVER_ALLOW
- self._offscreen_prefetch_rss = False
- self._safe_browsing_enabled = True
- self._save_form_data = True
- self._save_password = False
- self._need_initial_focus = True
- self._support_multiple_windows = False
- self._allow_content_access = True
- self._loads_images_automatically = True
- self._javascript_enabled = False
- self._media_playback_requires_user_gesture = True
-
- def setJavaScriptEnabled(self, enabled: bool) -> None:
- self._javascript_enabled = enabled
-
- def getJavaScriptEnabled(self) -> bool:
- return self._javascript_enabled
-
- def setJavaScriptCanOpenWindowsAutomatically(self, can: bool) -> None:
- self._java_script_can_open_windows = can
-
- def getJavaScriptCanOpenWindowsAutomatically(self) -> bool:
- return self._java_script_can_open_windows
-
- def setAllowFileAccess(self, allow: bool) -> None:
- self._allow_file_access = allow
-
- def getAllowFileAccess(self) -> bool:
- return self._allow_file_access
-
- def setAllowFileAccessFromFileURLs(self, allow: bool) -> None:
- self._allow_file_access_from_file_urls = allow
-
- def getAllowFileAccessFromFileURLs(self) -> bool:
- return self._allow_file_access_from_file_urls
-
- def setAllowUniversalAccessFromFileURLs(self, allow: bool) -> None:
- self._allow_universal_access_from_file_urls = allow
-
- def getAllowUniversalAccessFromFileURLs(self) -> bool:
- return self._allow_universal_access_from_file_urls
-
- def setBuiltInZoomControls(self, enabled: bool) -> None:
- self._built_in_zoom_controls = enabled
-
- def getBuiltInZoomControls(self) -> bool:
- return self._built_in_zoom_controls
-
- def setDisplayZoomControls(self, enabled: bool) -> None:
- self._display_zoom_controls = enabled
-
- def getDisplayZoomControls(self) -> bool:
- return self._display_zoom_controls
-
- def setSupportZoom(self, support: bool) -> None:
- self._support_zoom = support
-
- def supportZoom(self) -> bool:
- return self._support_zoom
-
- def setLoadWithOverviewMode(self, overview: bool) -> None:
- self._load_with_overview_mode = overview
-
- def getLoadWithOverviewMode(self) -> bool:
- return self._load_with_overview_mode
-
- def setUseWideViewPort(self, use: bool) -> None:
- self._use_wide_viewport = use
-
- def getUseWideViewPort(self) -> bool:
- return self._use_wide_viewport
-
- def setDomStorageEnabled(self, enabled: bool) -> None:
- self._dom_storage_enabled = enabled
-
- def getDomStorageEnabled(self) -> bool:
- return self._dom_storage_enabled
-
- def setDatabaseEnabled(self, enabled: bool) -> None:
- self._database_enabled = enabled
-
- def getDatabaseEnabled(self) -> bool:
- return self._database_enabled
-
- def setAppCacheEnabled(self, enabled: bool) -> None:
- self._app_cache_enabled = enabled
-
- def getAppCacheEnabled(self) -> bool:
- return self._app_cache_enabled
-
- def setCacheMode(self, mode: int) -> None:
- self._cache_mode = mode
-
- def getCacheMode(self) -> int:
- return self._cache_mode
-
- def setUserAgentString(self, ua: Optional[str]) -> None:
- self._user_agent_string = ua
-
- def getUserAgentString(self) -> str:
- return self._user_agent_string or self.USER_AGENT_MOBILE
-
- def setDefaultFontSize(self, size: int) -> None:
- self._default_font_size = max(1, size)
-
- def getDefaultFontSize(self) -> int:
- return self._default_font_size
-
- def setDefaultFixedFontSize(self, size: int) -> None:
- self._default_fixed_font_size = max(1, size)
-
- def getDefaultFixedFontSize(self) -> int:
- return self._default_fixed_font_size
-
- def setMinimumFontSize(self, size: int) -> None:
- self._minimum_font_size = max(1, size)
-
- def getMinimumFontSize(self) -> int:
- return self._minimum_font_size
-
- def setTextZoom(self, text_zoom: int) -> None:
- self._text_zoom = max(50, min(200, text_zoom))
-
- def getTextZoom(self) -> int:
- return self._text_zoom
-
- def setStandardFontFamily(self, font: str) -> None:
- self._standard_font_family = font
-
- def getStandardFontFamily(self) -> str:
- return self._standard_font_family
-
- def setSerifFontFamily(self, font: str) -> None:
- self._serif_font_family = font
-
- def getSerifFontFamily(self) -> str:
- return self._serif_font_family
-
- def setSansSerifFontFamily(self, font: str) -> None:
- self._sans_serif_font_family = font
-
- def getSansSerifFontFamily(self) -> str:
- return self._sans_serif_font_family
-
- def setFixedFontFamily(self, font: str) -> None:
- self._fixed_font_family = font
-
- def getFixedFontFamily(self) -> str:
- return self._fixed_font_family
-
- def setCursiveFontFamily(self, font: str) -> None:
- self._cursive_font_family = font
-
- def getCursiveFontFamily(self) -> str:
- return self._cursive_font_family
-
- def setFantasyFontFamily(self, font: str) -> None:
- self._fantasy_font_family = font
-
- def getFantasyFontFamily(self) -> str:
- return self._fantasy_font_family
-
- def setDefaultTextEncodingName(self, encoding: str) -> None:
- self._default_text_encoding = encoding
-
- def getDefaultTextEncodingName(self) -> str:
- return self._default_text_encoding
-
- def setLayoutAlgorithm(self, algorithm: int) -> None:
- self._layout_algorithm = algorithm
-
- def getLayoutAlgorithm(self) -> int:
- return self._layout_algorithm
-
- def setBlockNetworkImage(self, block: bool) -> None:
- self._block_network_image = block
-
- def getBlockNetworkImage(self) -> bool:
- return self._block_network_image
-
- def setBlockNetworkLoads(self, block: bool) -> None:
- self._block_network_loads = block
-
- def getBlockNetworkLoads(self) -> bool:
- return self._block_network_loads
-
- def setMixedContentMode(self, mode: int) -> None:
- self._mixed_content_mode = mode
-
- def getMixedContentMode(self) -> int:
- return self._mixed_content_mode
-
- def setLoadsImagesAutomatically(self, enabled: bool) -> None:
- self._loads_images_automatically = enabled
-
- def getLoadsImagesAutomatically(self) -> bool:
- return self._loads_images_automatically
-
- def setMediaPlaybackRequiresUserGesture(self, requires: bool) -> None:
- self._media_playback_requires_user_gesture = requires
-
- def getMediaPlaybackRequiresUserGesture(self) -> bool:
- return self._media_playback_requires_user_gesture
-
- def setSupportMultipleWindows(self, support: bool) -> None:
- self._support_multiple_windows = support
-
- def supportMultipleWindows(self) -> bool:
- return self._support_multiple_windows
-
- def setSaveFormData(self, save: bool) -> None:
- self._save_form_data = save
-
- def getSaveFormData(self) -> bool:
- return self._save_form_data
-
- def setSavePassword(self, save: bool) -> None:
- self._save_password = save
-
- def getSavePassword(self) -> bool:
- return self._save_password
-
- def setNeedInitialFocus(self, need: bool) -> None:
- self._need_initial_focus = need
-
- def getNeedInitialFocus(self) -> bool:
- return self._need_initial_focus
-
- def setSafeBrowsingEnabled(self, enabled: bool) -> None:
- self._safe_browsing_enabled = enabled
-
- def getSafeBrowsingEnabled(self) -> bool:
- return self._safe_browsing_enabled
-
- def toString(self) -> str:
- return (f"WebSettings(js={self._javascript_enabled}, "
- f"zoom={self._support_zoom})")
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebViewClient 扩展
-# ═══════════════════════════════════════════════════════════════
-
-class WebViewClient(Stub):
- """WebViewClient — Web视图客户端扩展"""
-
- def __init__(self):
- super().__init__()
-
- def shouldOverrideUrlLoading(self, view: WebView, request: WebResourceRequest) -> bool:
- return False
-
- def shouldOverrideKeyEvent(self, view: WebView, event: Any) -> bool:
- return False
-
- def onPageStarted(self, view: WebView, url: str, favicon: Any) -> None:
- pass
-
- def onPageFinished(self, view: WebView, url: str) -> None:
- pass
-
- def onLoadResource(self, view: WebView, url: str) -> None:
- pass
-
- def onPageCommitVisible(self, view: WebView, url: str) -> None:
- pass
-
- def shouldInterceptRequest(self, view: WebView, request: WebResourceRequest) -> Optional[WebResourceResponse]:
- return None
-
- def onReceivedError(self, view: WebView, request: WebResourceRequest,
- error: WebResourceError) -> None:
- pass
-
- def onReceivedHttpError(self, view: WebView, request: WebResourceRequest,
- error_response: WebResourceResponse) -> None:
- pass
-
- def onReceivedHttpAuthRequest(self, view: WebView, handler: Any,
- host: str, realm: str) -> None:
- pass
-
- def onReceivedLoginRequest(self, view: WebView, realm: str,
- account: str, args: str) -> None:
- pass
-
- def onReceivedSslError(self, view: WebView, handler: Any,
- error: Any) -> None:
- pass
-
- def onReceivedClientCertRequest(self, view: WebView,
- request: Any) -> None:
- pass
-
- def onFormResubmission(self, view: WebView, dont_resend: Any,
- resend: Any) -> None:
- pass
-
- def doUpdateVisitedHistory(self, view: WebView, url: str,
- is_reloa: bool) -> None:
- pass
-
- def onUnhandledKeyEvent(self, view: WebView, event: Any) -> None:
- pass
-
- def onScaleChanged(self, view: WebView, old_scale: float, new_scale: float) -> None:
- pass
-
- def onRenderProcessGone(self, view: WebView, detail: Any) -> bool:
- return True
-
- def onUnhandledInputEvent(self, view: WebView, event: Any) -> None:
- pass
-
- def safebrowsingOnBackForwardTransitioned(self, view: WebView,
- safe: bool) -> None:
- pass
-
- def toString(self) -> str:
- return "WebViewClient()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebChromeClient 扩展
-# ═══════════════════════════════════════════════════════════════
-
-class WebChromeClient(Stub):
- """WebChromeClient — Web Chrome客户端扩展"""
-
- GET_DEFAULT_VIDEO_POSTER = WEB_CHROME_CLIENT_GET_DEFAULT_VIDEO_POSTER
- GET_VISITED_HISTORY = WEB_CHROME_CLIENT_GET_VISITED_HISTORY
-
- def __init__(self):
- super().__init__()
-
- def onProgressChanged(self, view: WebView, new_progress: int) -> None:
- pass
-
- def onReceivedTitle(self, view: WebView, title: str) -> None:
- pass
-
- def onReceivedIcon(self, view: WebView, icon: Any) -> None:
- pass
-
- def onReceivedTouchIconUrl(self, view: WebView, url: str,
- precomposed: bool) -> None:
- pass
-
- def onShowCustomView(self, view: Any, callback: Any) -> None:
- pass
-
- def onHideCustomView(self) -> None:
- pass
-
- def onCreateWindow(self, view: WebView, is_dialog: bool,
- is_user_gesture: bool,
- result_msg: Any) -> bool:
- return False
-
- def onRequestFocus(self, view: WebView) -> None:
- pass
-
- def onCloseWindow(self, window: WebView) -> None:
- pass
-
- def onJsAlert(self, view: WebView, url: str, message: str,
- result: Any) -> bool:
- return False
-
- def onJsConfirm(self, view: WebView, url: str, message: str,
- result: Any) -> bool:
- return False
-
- def onJsPrompt(self, view: WebView, url: str, message: str,
- default_value: str, result: Any) -> bool:
- return False
-
- def onJsBeforeUnload(self, view: WebView, url: str, message: str,
- result: Any) -> bool:
- return False
-
- def onConsoleMessage(self, console_message: Any) -> bool:
- return True
-
- def getVideoLoadingProgressView(self) -> Optional[Any]:
- return None
-
- def getDefaultVideoPoster(self) -> Optional[Any]:
- return None
-
- def onShowFileChooser(self, view: WebView, callback: Any,
- params: Any) -> bool:
- return False
-
- def onPermissionRequest(self, request: Any) -> None:
- pass
-
- def onPermissionRequestCanceled(self, request: Any) -> None:
- pass
-
- def onGeolocationPermissionsShowPrompt(self, origin: str,
- callback: Any) -> None:
- pass
-
- def onGeolocationPermissionsHidePrompt(self) -> None:
- pass
-
- def onJsTimeout(self) -> bool:
- return True
-
- def onExceededDatabaseQuota(self, url: str, database_id: str,
- quota: int, estimated: int,
- quota_updater: Any) -> None:
- pass
-
- def onReachedMaxAppCacheSize(self, space_needed: int, total: int,
- quota_updater: Any) -> None:
- pass
-
- def onConsoleMessage(self, source_id: str, message: str,
- line_number: int, msg_type: int) -> bool:
- return True
-
- def toString(self) -> str:
- return "WebChromeClient()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CookieManager 扩展
-# ═══════════════════════════════════════════════════════════════
-
-class CookieManager(Stub):
- """CookieManager — Cookie管理器扩展"""
-
- _instance: Optional["CookieManager"] = None
- _lock = threading.Lock()
-
- def __init__(self):
- super().__init__()
- self._cookies: Dict[str, Dict[str, str]] = {}
- self._accept_cookie = True
-
- @staticmethod
- def getInstance() -> "CookieManager":
- with CookieManager._lock:
- if CookieManager._instance is None:
- CookieManager._instance = CookieManager()
- return CookieManager._instance
-
- def setAcceptCookie(self, accept: bool) -> None:
- self._accept_cookie = accept
-
- def acceptCookie(self) -> bool:
- return self._accept_cookie
-
- def setAcceptThirdPartyCookies(self, webview: WebView, accept: bool) -> None:
- pass
-
- def acceptThirdPartyCookies(self, webview: WebView) -> bool:
- return False
-
- def setCookie(self, url: str, value: str) -> None:
- domain = self._extract_domain(url)
- if domain not in self._cookies:
- self._cookies[domain] = {}
- if "=" in value:
- key, val = value.split("=", 1)
- self._cookies[domain][key.strip()] = val.strip()
-
- def getCookie(self, url: str) -> Optional[str]:
- domain = self._extract_domain(url)
- if domain in self._cookies:
- parts = [f"{k}={v}" for k, v in self._cookies[domain].items()]
- return "; ".join(parts)
- return None
-
- def removeSessionCookies(self) -> None:
- self._cookies.clear()
-
- def removeAllCookies(self) -> None:
- self._cookies.clear()
-
- def removeExpiredCookie(self) -> None:
- pass
-
- def hasCookies(self) -> bool:
- return bool(self._cookies)
-
- def _extract_domain(self, url: str) -> str:
- if "://" in url:
- url = url.split("://", 1)[1]
- return url.split("/")[0].split(":")[0]
-
- def flush(self) -> None:
- pass
-
- def toString(self) -> str:
- return f"CookieManager(domains={len(self._cookies)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GeolocationPermissions / JsResult / JsPromptResult
-# ═══════════════════════════════════════════════════════════════
-
-class GeolocationPermissions(Stub):
- """GeolocationPermissions — 地理位置权限"""
-
- _origins: Dict[str, bool] = {}
- _lock = threading.Lock()
-
- @classmethod
- def getInstance(cls) -> "GeolocationPermissions":
- return cls()
-
- def getOrigins(self, callback: Callable) -> None:
- with self._lock:
- callback(list(self._origins.keys()))
-
- def getAllowed(self, origin: str, callback: Callable) -> None:
- with self._lock:
- callback(origin, self._origins.get(origin, False), False)
-
- def clear(self, origin: str) -> None:
- with self._lock:
- self._origins.pop(origin, None)
-
- def clearAll(self) -> None:
- with self._lock:
- self._origins.clear()
-
- def allow(self, origin: str, allow: bool) -> None:
- with self._lock:
- self._origins[origin] = allow
-
-
-class JsResult(Stub):
- """JsResult — JavaScript 对话框结果"""
-
- def __init__(self):
- super().__init__()
- self._result: Optional[bool] = None
-
- def confirm(self) -> None:
- self._result = True
-
- def cancel(self) -> None:
- self._result = False
-
- def getResult(self) -> Optional[bool]:
- return self._result
-
- def toString(self) -> str:
- return f"JsResult(result={self._result})"
-
-
-class JsPromptResult(JsResult):
- """JsPromptResult — JavaScript 提示框结果"""
-
- def __init__(self):
- super().__init__()
- self._string_result: str = ""
-
- def confirm(self, result: str) -> None:
- super().confirm()
- self._string_result = result
-
- def getStringResult(self) -> str:
- return self._string_result
-
- def toString(self) -> str:
- return f"JsPromptResult(result={self._result}, string={self._string_result})"
-
-
-class HttpAuthHandler(Stub):
- """HttpAuthHandler — HTTP 认证处理器"""
-
- def __init__(self):
- super().__init__()
- self._handled = False
-
- def proceed(self, username: str, password: str) -> None:
- self._handled = True
-
- def cancel(self) -> None:
- self._handled = True
-
- def useHttpAuthUsernamePassword(self, use: bool) -> None:
- pass
-
- def isHandled(self) -> bool:
- return self._handled
-
- def toString(self) -> str:
- return f"HttpAuthHandler(handled={self._handled})"
-
-
-class SslErrorHandler(Stub):
- """SslErrorHandler — SSL 错误处理器"""
-
- def __init__(self):
- super().__init__()
- self._handled = False
-
- def proceed(self) -> None:
- self._handled = True
-
- def cancel(self) -> None:
- self._handled = True
-
- def isHandled(self) -> bool:
- return self._handled
-
- def toString(self) -> str:
- return f"SslErrorHandler(handled={self._handled})"
-
-
-class ClientCertRequest(Stub):
- """ClientCertRequest — 客户端证书请求"""
-
- def __init__(self):
- super().__init__()
- self._handled = False
-
- def getHost(self) -> str:
- return ""
-
- def getPort(self) -> int:
- return 443
-
- def getKeyTypes(self) -> List[str]:
- return ["RSA"]
-
- def getPrincipals(self) -> List[str]:
- return []
-
- def cancel(self) -> None:
- self._handled = True
-
- def proceed(self, private_key: Any, chain: List[Any]) -> None:
- self._handled = True
-
- def ignore(self) -> None:
- self._handled = True
-
- def isHandled(self) -> bool:
- return self._handled
-
-
-class PermissionRequest(Stub):
- """PermissionRequest — 权限请求"""
-
- RESOURCE_VIDEO_CAPTURE = "android.webkit.resource.VIDEO_CAPTURE"
- RESOURCE_AUDIO_CAPTURE = "android.webkit.resource.AUDIO_CAPTURE"
- RESOURCE_PROTECTED_MEDIA_ID = "android.webkit.resource.PROTECTED_MEDIA_ID"
- RESOURCE_MIDI_SYSEX = "android.webkit.resource.MIDI_SYSEX"
-
- def __init__(self):
- super().__init__()
- self._origin: Optional[str] = None
- self._resources: List[str] = []
- self._granted = False
-
- def getOrigin(self) -> str:
- return self._origin or ""
-
- def getResources(self) -> List[str]:
- return list(self._resources)
-
- def grant(self, resources: List[str]) -> None:
- self._granted = True
-
- def deny(self) -> None:
- self._granted = False
-
- def isGranted(self) -> bool:
- return self._granted
-
- def toString(self) -> str:
- return f"PermissionRequest(origin={self._origin}, granted={self._granted})"
-
-
-class ConsoleMessage(Stub):
- """ConsoleMessage — 控制台消息"""
-
- MessageLevel = type("MessageLevel", (), {
- "TIP": 0, "LOG": 1, "WARNING": 2, "ERROR": 3, "DEBUG": 4
- })
-
- def __init__(self, message: str = "", source_id: str = "",
- line_number: int = 0, msg_level: int = MessageLevel.LOG):
- super().__init__()
- self._message = message
- self._source_id = source_id
- self._line_number = line_number
- self._msg_level = msg_level
-
- def message(self) -> str:
- return self._message
-
- def sourceId(self) -> str:
- return self._source_id
-
- def lineNumber(self) -> int:
- return self._line_number
-
- def messageLevel(self) -> int:
- return self._msg_level
-
- def toString(self) -> str:
- return f"ConsoleMessage({self._message[:50]})"
-
-
-class ValueCallback(Stub):
- """ValueCallback — 值回调接口"""
-
- def onReceiveValue(self, value: Any) -> None:
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebBackForwardList / WebHistoryItem / WebIconDatabase / etc.
-# ═══════════════════════════════════════════════════════════════
-
-class WebBackForwardList(Stub):
- """WebBackForwardList — 后退/前进列表"""
-
- def __init__(self):
- super().__init__()
- self._items: List["WebHistoryItem"] = []
- self._current_index: int = -1
-
- def getCurrentItem(self) -> Optional["WebHistoryItem"]:
- if 0 <= self._current_index < len(self._items):
- return self._items[self._current_index]
- return None
-
- def getCurrentIndex(self) -> int:
- return self._current_index
-
- def getItemAtIndex(self, index: int) -> Optional["WebHistoryItem"]:
- if 0 <= index < len(self._items):
- return self._items[index]
- return None
-
- def getSize(self) -> int:
- return len(self._items)
-
- def toString(self) -> str:
- return f"WebBackForwardList(size={len(self._items)}, current={self._current_index})"
-
-
-class WebHistoryItem(Stub):
- """WebHistoryItem — Web历史条目"""
-
- def __init__(self, url: str = "", title: str = "",
- favicon: Any = None):
- super().__init__()
- self._url = url
- self._title = title
- self._favicon = favicon
-
- def getUrl(self) -> str:
- return self._url
-
- def getTitle(self) -> str:
- return self._title
-
- def getFavicon(self) -> Optional[Any]:
- return self._favicon
-
- def setUrl(self, url: str) -> None:
- self._url = url
-
- def setTitle(self, title: str) -> None:
- self._title = title
-
- def setFavicon(self, favicon: Any) -> None:
- self._favicon = favicon
-
- def toString(self) -> str:
- return f"WebHistoryItem(url={self._url}, title={self._title})"
-
-
-class WebIconDatabase(Stub):
- """WebIconDatabase — Web图标数据库"""
-
- _instance: Optional["WebIconDatabase"] = None
-
- @staticmethod
- def getInstance() -> "WebIconDatabase":
- if WebIconDatabase._instance is None:
- WebIconDatabase._instance = WebIconDatabase()
- return WebIconDatabase._instance
-
- def open(self, path: str) -> None:
- pass
-
- def close(self) -> None:
- pass
-
- def removeAllIcons(self) -> None:
- pass
-
- def requestIconForPageUrl(self, url: str, callback: Callable) -> None:
- callback(url, None)
-
- def retainIconForPageUrl(self, url: str) -> None:
- pass
-
- def releaseIconForPageUrl(self, url: str) -> None:
- pass
-
- def getIconForPageUrl(self, url: str) -> Optional[Any]:
- return None
-
- def toString(self) -> str:
- return "WebIconDatabase()"
-
-
-class WebViewDatabase(Stub):
- """WebViewDatabase — WebView数据库"""
-
- _instance: Optional["WebViewDatabase"] = None
-
- @staticmethod
- def getInstance(context: Any) -> "WebViewDatabase":
- if WebViewDatabase._instance is None:
- WebViewDatabase._instance = WebViewDatabase()
- return WebViewDatabase._instance
-
- def hasFormData(self) -> bool:
- return False
-
- def clearFormData(self) -> None:
- pass
-
- def hasUsernamePassword(self) -> bool:
- return False
-
- def clearUsernamePassword(self) -> None:
- pass
-
- def hasHttpAuthUsernamePassword(self) -> bool:
- return False
-
- def clearHttpAuthUsernamePassword(self) -> None:
- pass
-
- def toString(self) -> str:
- return "WebViewDatabase()"
-
-
-class WebViewFragment(Stub):
- """WebViewFragment — WebView片段"""
-
- def __init__(self):
- super().__init__()
- self._webview: Optional[WebView] = None
-
- def onCreateView(self, inflater: Any, container: Any,
- savedInstanceState: Any) -> Optional[WebView]:
- self._webview = WebView()
- return self._webview
-
- def onPause(self) -> None:
- if self._webview:
- self._webview.onPause()
-
- def onResume(self) -> None:
- if self._webview:
- self._webview.onResume()
-
- def onDestroyView(self) -> None:
- if self._webview:
- self._webview.destroy()
-
- def getWebView(self) -> Optional[WebView]:
- return self._webview
-
- def toString(self) -> str:
- return f"WebViewFragment(webview={'yes' if self._webview else 'no'})"
-
-
-class DateSorter(Stub):
- """DateSorter — 日期排序器"""
-
- DAY_COUNT = 5
-
- def __init__(self, context: Any):
- super().__init__()
- self._bounds: List[int] = [0, 0, 0, 0, 0]
- self._labels: List[str] = ["Today", "Yesterday", "Earlier"]
-
- def getBounds(self) -> List[int]:
- return list(self._bounds)
-
- def getLabel(self, index: int) -> str:
- if 0 <= index < len(self._labels):
- return self._labels[index]
- return ""
-
- def toString(self) -> str:
- return "DateSorter()"
-
-
-class FindActionModeCallback(Stub):
- """FindActionModeCallback — 查找操作模式回调"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._search_text: str = ""
- self._global_search_count: int = 0
- self._match_count: int = 0
-
- def finishActionMode(self) -> None:
- pass
-
- def setText(self, text: str) -> None:
- self._search_text = text
-
- def getText(self) -> str:
- return self._search_text
-
- def setGlobalSearchCount(self, count: int) -> None:
- self._global_search_count = count
-
- def getGlobalSearchCount(self) -> int:
- return self._global_search_count
-
- def setMatchCount(self, count: int) -> None:
- self._match_count = count
-
- def getMatchCount(self) -> int:
- return self._match_count
-
- def toString(self) -> str:
- return (f"FindActionModeCallback(search={self._search_text}, "
- f"matches={self._match_count})")
-
-
-class JsDialogHelper(Stub):
- """JsDialogHelper — JavaScript 对话框助手"""
-
- ALERT = 1
- CONFIRM = 2
- PROMPT = 3
- UNLOAD = 4
-
- def __init__(self, result: JsResult, default_value: str = "",
- dialog_type: int = ALERT, message: str = ""):
- super().__init__()
- self._result = result
- self._default_value = default_value
- self._dialog_type = dialog_type
- self._message = message
-
- def getDialogType(self) -> int:
- return self._dialog_type
-
- def getMessage(self) -> str:
- return self._message
-
- def getDefaultValue(self) -> str:
- return self._default_value
-
- def invokeCallback(self, result: Any) -> None:
- if self._result:
- self._result.confirm()
-
- def cancelDialog(self) -> None:
- if self._result:
- self._result.cancel()
-
- def toString(self) -> str:
- types = {1: "ALERT", 2: "CONFIRM", 3: "PROMPT", 4: "UNLOAD"}
- return f"JsDialogHelper(type={types.get(self._dialog_type, 'UNKNOWN')})"
\ No newline at end of file
diff --git a/android_pyapi/android/widget.py b/android_pyapi/android/widget.py
deleted file mode 100644
index 6d1cbaa..0000000
--- a/android_pyapi/android/widget.py
+++ /dev/null
@@ -1,4891 +0,0 @@
-"""
-Android Widget 组件 — TextView, Button, RecyclerView, ListView, WebView 等
-方法签名完全对齐 Android SDK
-"""
-
-import math
-import time
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError, android_context
-from .view import (
- View, ViewGroup, ViewTreeObserver,
- MotionEvent, KeyEvent, Gravity, SurfaceView,
- ViewGroup as VG,
-)
-
-try:
- from .._linux_impl import IS_LINUX, LinuxNotify, LinuxClipboard
- _USE_LINUX = IS_LINUX
-except ImportError:
- _USE_LINUX = False
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextView
-# ═══════════════════════════════════════════════════════════════
-
-class TextView(View):
- """TextView — 文本显示视图"""
-
- # 自动链接
- AUTO_LINK_NONE = 0x00
- AUTO_LINK_WEB_URLS = 0x01
- AUTO_LINK_EMAIL_ADDRESSES = 0x02
- AUTO_LINK_PHONE_NUMBERS = 0x04
- AUTO_LINK_MAP_ADDRESSES = 0x08
- AUTO_LINK_ALL = 0x0F
-
- # Buffer类型
- BUFFER_TYPE_NORMAL = 0
- BUFFER_TYPE_SPANNABLE = 1
- BUFFER_TYPE_EDITABLE = 2
-
- # 截断位置
- TRUNCATE_AT_END = 0
- TRUNCATE_AT_MIDDLE = 1
- TRUNCATE_AT_START = 2
-
- # 文本方向
- TEXT_DIRECTION_INHERIT = 0
- TEXT_DIRECTION_FIRST_STRONG = 1
- TEXT_DIRECTION_ANY_RTL = 2
- TEXT_DIRECTION_LTR = 3
- TEXT_DIRECTION_RTL = 4
- TEXT_DIRECTION_LOCALE = 5
- TEXT_DIRECTION_FIRST_STRONG_LTR = 6
- TEXT_DIRECTION_FIRST_STRONG_RTL = 7
-
- # 文本对齐
- TEXT_ALIGNMENT_INHERIT = 0
- TEXT_ALIGNMENT_GRAVITY = 1
- TEXT_ALIGNMENT_TEXT_START = 2
- TEXT_ALIGNMENT_TEXT_END = 3
- TEXT_ALIGNMENT_CENTER = 4
- TEXT_ALIGNMENT_VIEW_START = 5
- TEXT_ALIGNMENT_VIEW_END = 6
-
- def __init__(self, context=None):
- super().__init__(context)
- self._text: str = ""
- self._hint: str = ""
- self._text_size: float = 14.0
- self._text_color: int = 0xFF000000
- self._hint_text_color: int = 0xFF808080
- self._link_text_color: int = 0xFFFF0000
- self._highlight_color: int = 0x556633CC
- self._gravity = Gravity.NO_GRAVITY
- self._typeface: Any = None
- self._input_type: int = 0
- self._lines: int = 0
- self._max_lines: int = 0
- self._min_lines: int = 0
- self._single_line: bool = False
- self._ellipsize: Optional[str] = None # "end", "start", "middle", "marquee"
- self._movement_method: Any = None
- self._auto_link_mask: int = TextView.AUTO_LINK_NONE
- self._transformation_method: Optional[Callable] = None
- self._shadow_radius: float = 0.0
- self._shadow_dx: float = 0.0
- self._shadow_dy: float = 0.0
- self._shadow_color: int = 0
- self._line_spacing_extra: float = 0.0
- self._line_spacing_mult: float = 1.0
- self._compound_drawables: List[Any] = [None, None, None, None]
- self._compound_drawable_padding: int = 0
- self._include_font_padding: bool = True
- self._elegant_text_height: bool = False
- self._letter_spacing: float = 0.0
- self._font_feature_settings: str = ""
- self._key_listener: Any = None
- self._filters: List[Any] = []
- self._select_all_on_focus: bool = False
- self._horizontally_scrolling: bool = False
- self._on_editor_action_listener: Optional[Callable] = None
- self._paint: Any = None
- self._line_count: int = 1
- self._layout: Any = None
- self._links_clickable: bool = False
- self._cursor_visible: bool = True
- self._editable: bool = False
- self._selection_start: int = 0
- self._selection_end: int = 0
- self._scroll_horizontally: bool = False
-
- # ─── text ──────────────────────────────────────────────────
-
- def setText(self, text: str, buffer_type: int = BUFFER_TYPE_NORMAL):
- self._text = str(text) if text is not None else ""
- self._line_count = self._text.count("\n") + 1 if self._text else 0
-
- def getText(self) -> str:
- return self._text
-
- def append(self, text: str):
- self._text += str(text) if text is not None else ""
- self._line_count = self._text.count("\n") + 1 if self._text else 0
-
- # ─── text size / color ─────────────────────────────────────
-
- def setTextSize(self, size: float, unit: int = 2): # unit=2 means SP
- self._text_size = size
-
- def getTextSize(self) -> float:
- return self._text_size
-
- def setTextColor(self, color: int):
- self._text_color = color
-
- def getCurrentTextColor(self) -> int:
- return self._text_color
-
- def setHintTextColor(self, color: int):
- self._hint_text_color = color
-
- def getHintTextColor(self) -> int:
- return self._hint_text_color
-
- def setLinkTextColor(self, color: int):
- self._link_text_color = color
-
- def getLinkTextColor(self) -> int:
- return self._link_text_color
-
- def setHighlightColor(self, color: int):
- self._highlight_color = color
-
- def getHighlightColor(self) -> int:
- return self._highlight_color
-
- # ─── gravity ──────────────────────────────────────────────
-
- def setGravity(self, gravity: int):
- self._gravity = gravity
-
- def getGravity(self) -> int:
- return self._gravity
-
- # ─── typeface ──────────────────────────────────────────────
-
- def setTypeface(self, typeface: Any, style: int = 0):
- self._typeface = typeface
-
- def getTypeface(self) -> Any:
- return self._typeface
-
- # ─── hint ──────────────────────────────────────────────────
-
- def setHint(self, hint: str):
- self._hint = str(hint) if hint is not None else ""
-
- def getHint(self) -> str:
- return self._hint
-
- # ─── input type ────────────────────────────────────────────
-
- def setInputType(self, input_type: int):
- self._input_type = input_type
-
- def getInputType(self) -> int:
- return self._input_type
-
- # ─── lines ─────────────────────────────────────────────────
-
- def setLines(self, lines: int):
- self._lines = lines
-
- def setMaxLines(self, max_lines: int):
- self._max_lines = max_lines
-
- def getMaxLines(self) -> int:
- return self._max_lines
-
- def setMinLines(self, min_lines: int):
- self._min_lines = min_lines
-
- def getMinLines(self) -> int:
- return self._min_lines
-
- def getLineCount(self) -> int:
- return self._line_count
-
- def setSingleLine(self, single_line: bool = True):
- self._single_line = single_line
-
- # ─── ellipsize ─────────────────────────────────────────────
-
- def setEllipsize(self, where: Optional[str]):
- self._ellipsize = where
-
- def getEllipsize(self) -> Optional[str]:
- return self._ellipsize
-
- # ─── movement method ──────────────────────────────────────
-
- def setMovementMethod(self, movement: Any):
- self._movement_method = movement
-
- def getMovementMethod(self) -> Any:
- return self._movement_method
-
- # ─── auto link ─────────────────────────────────────────────
-
- def setAutoLinkMask(self, mask: int):
- self._auto_link_mask = mask
-
- def getAutoLinkMask(self) -> int:
- return self._auto_link_mask
-
- # ─── transformation ───────────────────────────────────────
-
- def setTransformationMethod(self, method: Optional[Callable]):
- self._transformation_method = method
-
- def getTransformationMethod(self) -> Optional[Callable]:
- return self._transformation_method
-
- # ─── shadow ────────────────────────────────────────────────
-
- def setShadowLayer(self, radius: float, dx: float, dy: float, color: int):
- self._shadow_radius = radius
- self._shadow_dx = dx
- self._shadow_dy = dy
- self._shadow_color = color
-
- # ─── line spacing ─────────────────────────────────────────
-
- def setLineSpacing(self, extra: float, multiplier: float):
- self._line_spacing_extra = extra
- self._line_spacing_mult = multiplier
-
- # ─── compound drawables ───────────────────────────────────
-
- def setCompoundDrawables(self, left: Any, top: Any, right: Any, bottom: Any):
- self._compound_drawables = [left, top, right, bottom]
-
- def setCompoundDrawablesWithIntrinsicBounds(self, left: Any, top: Any,
- right: Any, bottom: Any):
- self._compound_drawables = [left, top, right, bottom]
-
- def setCompoundDrawablePadding(self, pad: int):
- self._compound_drawable_padding = pad
-
- def getCompoundDrawablePadding(self) -> int:
- return self._compound_drawable_padding
-
- def getCompoundDrawables(self) -> List[Any]:
- return list(self._compound_drawables)
-
- # ─── editor action ────────────────────────────────────────
-
- def setOnEditorActionListener(self, listener: Optional[Callable]):
- self._on_editor_action_listener = listener
-
- # ─── key listener ─────────────────────────────────────────
-
- def setKeyListener(self, key_listener: Any):
- self._key_listener = key_listener
-
- def getKeyListener(self) -> Any:
- return self._key_listener
-
- # ─── filters ───────────────────────────────────────────────
-
- def setFilters(self, filters: List[Any]):
- self._filters = list(filters)
-
- def getFilters(self) -> List[Any]:
- return list(self._filters)
-
- # ─── misc ──────────────────────────────────────────────────
-
- def setSelectAllOnFocus(self, select_all_on_focus: bool):
- self._select_all_on_focus = select_all_on_focus
-
- def setHorizontallyScrolling(self, horizontally_scrolling: bool):
- self._horizontally_scrolling = horizontally_scrolling
-
- def setIncludeFontPadding(self, include_font_padding: bool):
- self._include_font_padding = include_font_padding
-
- def setElegantTextHeight(self, elegant: bool):
- self._elegant_text_height = elegant
-
- def setLetterSpacing(self, letter_spacing: float):
- self._letter_spacing = letter_spacing
-
- def getLetterSpacing(self) -> float:
- return self._letter_spacing
-
- def setFontFeatureSettings(self, settings: str):
- self._font_feature_settings = settings
-
- def getFontFeatureSettings(self) -> str:
- return self._font_feature_settings
-
- def getPaint(self) -> Any:
- return self._paint
-
- def getLayout(self) -> Any:
- return self._layout
-
- def setLinksClickable(self, links_clickable: bool):
- self._links_clickable = links_clickable
-
- def getLinksClickable(self) -> bool:
- return self._links_clickable
-
- def setCursorVisible(self, visible: bool):
- self._cursor_visible = visible
-
- def isCursorVisible(self) -> bool:
- return self._cursor_visible
-
- def setTextCursorDrawable(self, drawable: Any):
- pass
-
- def setFreezesText(self, freezes_text: bool):
- pass
-
- def getFreezesText(self) -> bool:
- return False
-
- def setEditableFactory(self, factory: Any):
- pass
-
- def setSpannableFactory(self, factory: Any):
- pass
-
- def getTextSize(self) -> float:
- return self._text_size
-
- def setBackgroundColor(self, color: int):
- super().setBackgroundColor(color)
-
- def setPadding(self, left: int, top: int, right: int, bottom: int):
- super().setPadding(left, top, right, bottom)
-
- def setPaddingRelative(self, start: int, top: int, end: int, bottom: int):
- self._padding_left = start
- self._padding_top = top
- self._padding_right = end
- self._padding_bottom = bottom
-
- # ─── text color getter ───────────────────────────────────
-
- def getTextColor(self) -> int:
- return self._text_color
-
- # ─── selection action mode ───────────────────────────────
-
- def setCustomSelectionActionModeCallback(self, callback: Any):
- self._custom_selection_action_mode_callback = callback
-
- def getCustomSelectionActionModeCallback(self) -> Any:
- return getattr(self, '_custom_selection_action_mode_callback', None)
-
- # ─── break / justification strategy ──────────────────────
-
- def setBreakStrategy(self, break_strategy: int):
- self._break_strategy = break_strategy
-
- def getBreakStrategy(self) -> int:
- return getattr(self, '_break_strategy', 0)
-
- def setJustificationMode(self, justification_mode: int):
- self._justification_mode = justification_mode
-
- def getJustificationMode(self) -> int:
- return getattr(self, '_justification_mode', 0)
-
- def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
- from .view import MeasureSpec
- w = MeasureSpec.getSize(width_measure_spec)
- h = MeasureSpec.getSize(height_measure_spec)
- if MeasureSpec.getMode(width_measure_spec) == MeasureSpec.AT_MOST:
- text_len = len(self._text) * 4
- w = min(w, max(100, text_len))
- if MeasureSpec.getMode(height_measure_spec) == MeasureSpec.AT_MOST:
- text_lines = self._line_count
- h = min(h, max(20, text_lines * int(self._text_size) + 10))
- self.setMeasuredDimension(w, h)
-
- def onDraw(self, canvas: Any):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# EditText
-# ═══════════════════════════════════════════════════════════════
-
-class EditText(TextView):
- """EditText — 可编辑文本"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._editable = True
- self._selection_start = 0
- self._selection_end = 0
-
- def setSelection(self, start: int, stop: Optional[int] = None):
- if stop is None:
- self._selection_start = start
- self._selection_end = start
- else:
- self._selection_start = start
- self._selection_end = stop
-
- def getSelectionStart(self) -> int:
- return self._selection_start
-
- def getSelectionEnd(self) -> int:
- return self._selection_end
-
- def selectAll(self):
- self._selection_start = 0
- self._selection_end = len(self._text)
-
- def extendSelection(self, index: int):
- self._selection_end = index
-
- def setText(self, text: str, buffer_type: int = TextView.BUFFER_TYPE_EDITABLE):
- super().setText(text, buffer_type)
-
- def getEditableText(self):
- return self._text
-
-
-# ═══════════════════════════════════════════════════════════════
-# Button
-# ═══════════════════════════════════════════════════════════════
-
-class Button(TextView):
- """Button — 按钮"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._clickable = True
- self._focusable = True
-
- def onTouchEvent(self, event: MotionEvent) -> bool:
- if event.getAction() == MotionEvent.ACTION_UP:
- self.performClick()
- return super().onTouchEvent(event)
-
-
-class CheckBox(Button):
- """CheckBox — 复选框"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._checked = False
-
- def setChecked(self, checked: bool):
- self._checked = checked
-
- def isChecked(self) -> bool:
- return self._checked
-
- def toggle(self):
- self._checked = not self._checked
-
- def setOnCheckedChangeListener(self, listener: Optional[Callable]):
- self._on_checked_change_listener = listener
-
- def getOnCheckedChangeListener(self) -> Optional[Callable]:
- return getattr(self, '_on_checked_change_listener', None)
-
- def performClick(self) -> bool:
- self.toggle()
- return super().performClick()
-
-
-class RadioButton(Button):
- """RadioButton — 单选按钮"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._checked = False
-
- def setChecked(self, checked: bool):
- self._checked = checked
-
- def isChecked(self) -> bool:
- return self._checked
-
- def toggle(self):
- self._checked = not self._checked
-
- def performClick(self) -> bool:
- self.toggle()
- return super().performClick()
-
-
-class ToggleButton(Button):
- """ToggleButton — 开关按钮"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._checked = False
- self._text_on = "ON"
- self._text_off = "OFF"
- self._disabled_alpha = 0.5
-
- def setChecked(self, checked: bool):
- self._checked = checked
- if self._checked:
- self.setText(self._text_on)
- else:
- self.setText(self._text_off)
-
- def isChecked(self) -> bool:
- return self._checked
-
- def toggle(self):
- self.setChecked(not self._checked)
-
- def setTextOn(self, text_on: str):
- self._text_on = text_on
- if self._checked:
- self.setText(text_on)
-
- def getTextOn(self) -> str:
- return self._text_on
-
- def setTextOff(self, text_off: str):
- self._text_off = text_off
- if not self._checked:
- self.setText(text_off)
-
- def getTextOff(self) -> str:
- return self._text_off
-
- def performClick(self) -> bool:
- self.toggle()
- return super().performClick()
-
-
-class Switch(Button):
- """Switch — 开关组件"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._checked = False
- self._show_text = True
- self._split_track = False
- self._thumb_text_padding: int = 0
- self._switch_min_width: int = 0
- self._switch_padding: int = 0
- self._thumb_drawable: Any = None
- self._track_drawable: Any = None
- self._text_on = "ON"
- self._text_off = "OFF"
- self._thumb_width = 40
- self._switch_width = 100
-
- def isChecked(self) -> bool:
- return self._checked
-
- def setChecked(self, checked: bool):
- self._checked = checked
-
- def toggle(self):
- self._checked = not self._checked
-
- def setShowText(self, show_text: bool):
- self._show_text = show_text
-
- def getShowText(self) -> bool:
- return self._show_text
-
- def setSplitTrack(self, split_track: bool):
- self._split_track = split_track
-
- def getSplitTrack(self) -> bool:
- return self._split_track
-
- def setThumbTextPadding(self, padding: int):
- self._thumb_text_padding = padding
-
- def getThumbTextPadding(self) -> int:
- return self._thumb_text_padding
-
- def setSwitchMinWidth(self, min_width: int):
- self._switch_min_width = min_width
-
- def getSwitchMinWidth(self) -> int:
- return self._switch_min_width
-
- def setSwitchPadding(self, padding: int):
- self._switch_padding = padding
-
- def getSwitchPadding(self) -> int:
- return self._switch_padding
-
- def getThumbDrawable(self) -> Any:
- return self._thumb_drawable
-
- def setThumbDrawable(self, drawable: Any):
- self._thumb_drawable = drawable
-
- def getTrackDrawable(self) -> Any:
- return self._track_drawable
-
- def setTrackDrawable(self, drawable: Any):
- self._track_drawable = drawable
-
- def setTextOn(self, text_on: str):
- self._text_on = text_on
-
- def getTextOn(self) -> str:
- return self._text_on
-
- def setTextOff(self, text_off: str):
- self._text_off = text_off
-
- def getTextOff(self) -> str:
- return self._text_off
-
- # ─── checked change listener ─────────────────────────────
-
- def setOnCheckedChangeListener(self, listener: Optional[Callable]):
- self._on_checked_change_listener = listener
-
- def getOnCheckedChangeListener(self) -> Optional[Callable]:
- return getattr(self, '_on_checked_change_listener', None)
-
- # ─── switch text appearance ──────────────────────────────
-
- def setSwitchTextAppearance(self, context: Any, resid: int):
- self._switch_text_appearance = resid
-
- def getSwitchTextAppearance(self) -> int:
- return getattr(self, '_switch_text_appearance', 0)
-
- def performClick(self) -> bool:
- self.toggle()
- return super().performClick()
-
- def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
- from .view import MeasureSpec
- w = MeasureSpec.getSize(width_measure_spec)
- h = MeasureSpec.getSize(height_measure_spec)
- self.setMeasuredDimension(w, max(30, h))
-
-
-# ═══════════════════════════════════════════════════════════════
-# ImageView
-# ═══════════════════════════════════════════════════════════════
-
-class ImageView(View):
- """ImageView — 图片视图"""
-
- # ScaleType常量
- ScaleType = type("ScaleType", (), {
- "MATRIX": 0,
- "FIT_XY": 1,
- "FIT_START": 2,
- "FIT_CENTER": 3,
- "FIT_END": 4,
- "CENTER": 5,
- "CENTER_CROP": 6,
- "CENTER_INSIDE": 7,
- })
-
- def __init__(self, context=None):
- super().__init__(context)
- self._drawable: Any = None
- self._image_resource: int = 0
- self._uri: Any = None
- self._scale_type: int = ImageView.ScaleType.FIT_CENTER
- self._max_width: int = 0
- self._max_height: int = 0
- self._adjust_view_bounds: bool = False
- self._crop_to_padding: bool = False
- self._baseline: int = 0
- self._baseline_align_bottom: bool = False
- self._image_matrix: Any = None
- self._image_bitmap: Any = None
-
- def setImageDrawable(self, drawable: Any):
- self._drawable = drawable
-
- def getDrawable(self) -> Any:
- return self._drawable
-
- def setImageResource(self, res_id: int):
- self._image_resource = res_id
-
- def setImageURI(self, uri: Any):
- self._uri = uri
-
- def setImageBitmap(self, bitmap: Any):
- self._image_bitmap = bitmap
-
- def getImageBitmap(self) -> Any:
- return self._image_bitmap
-
- def setScaleType(self, scale_type: int):
- self._scale_type = scale_type
-
- def getScaleType(self) -> int:
- return self._scale_type
-
- def setMaxWidth(self, max_width: int):
- self._max_width = max_width
-
- def setMaxHeight(self, max_height: int):
- self._max_height = max_height
-
- def setAdjustViewBounds(self, adjust: bool):
- self._adjust_view_bounds = adjust
-
- def getAdjustViewBounds(self) -> bool:
- return self._adjust_view_bounds
-
- def setCropToPadding(self, crop: bool):
- self._crop_to_padding = crop
-
- def getCropToPadding(self) -> bool:
- return self._crop_to_padding
-
- # ─── color filter ─────────────────────────────────────────
-
- def setColorFilter(self, color_filter: Any):
- self._color_filter = color_filter
-
- def getColorFilter(self) -> Any:
- return getattr(self, '_color_filter', None)
-
- def clearColorFilter(self):
- self._color_filter = None
-
- def setBaseline(self, baseline: int):
- self._baseline = baseline
-
- def getBaseline(self) -> int:
- return self._baseline
-
- def setBaselineAlignBottom(self, aligned: bool):
- self._baseline_align_bottom = aligned
-
- def getBaselineAlignBottom(self) -> bool:
- return self._baseline_align_bottom
-
- def setImageMatrix(self, matrix: Any):
- self._image_matrix = matrix
-
- def getImageMatrix(self) -> Any:
- return self._image_matrix
-
- def invalidateDrawable(self, dr: Any):
- pass
-
- def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
- from .view import MeasureSpec
- w = MeasureSpec.getSize(width_measure_spec)
- h = MeasureSpec.getSize(height_measure_spec)
- if w == 0:
- w = 100
- if h == 0:
- h = 100
- self.setMeasuredDimension(w, h)
-
-
-class ImageButton(ImageView):
- """ImageButton — 图片按钮"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._clickable = True
- self._focusable = True
-
- def onTouchEvent(self, event: MotionEvent) -> bool:
- if event.getAction() == MotionEvent.ACTION_UP:
- self.performClick()
- return super().onTouchEvent(event)
-
-
-# ═══════════════════════════════════════════════════════════════
-# ProgressBar
-# ═══════════════════════════════════════════════════════════════
-
-class ProgressBar(View):
- """ProgressBar — 进度条"""
-
- def __init__(self, context=None, attrs: Any = None, def_style_attr: int = 0,
- def_style_res: int = 0):
- super().__init__(context)
- self._progress: int = 0
- self._max: int = 100
- self._indeterminate: bool = False
- self._indeterminate_drawable: Any = None
- self._progress_drawable: Any = None
- self._secondary_progress: int = 0
- self._min: int = 0
- self._interpolator: Any = None
- self._animation: Any = None
-
- def setProgress(self, progress: int):
- self._progress = max(self._min, min(self._max, progress))
-
- def getProgress(self) -> int:
- return self._progress
-
- def setMax(self, max_val: int):
- self._max = max_val
- if self._progress > self._max:
- self._progress = self._max
-
- def getMax(self) -> int:
- return self._max
-
- def setMin(self, min_val: int):
- self._min = min_val
-
- def getMin(self) -> int:
- return self._min
-
- def incrementProgressBy(self, diff: int):
- self.setProgress(self._progress + diff)
-
- def setIndeterminate(self, indeterminate: bool):
- self._indeterminate = indeterminate
-
- def isIndeterminate(self) -> bool:
- return self._indeterminate
-
- def getIndeterminateDrawable(self) -> Any:
- return self._indeterminate_drawable
-
- def setIndeterminateDrawable(self, drawable: Any):
- self._indeterminate_drawable = drawable
-
- def setProgressDrawable(self, drawable: Any):
- self._progress_drawable = drawable
-
- def getProgressDrawable(self) -> Any:
- return self._progress_drawable
-
- def setSecondaryProgress(self, secondary_progress: int):
- self._secondary_progress = max(self._min, min(self._max, secondary_progress))
-
- def getSecondaryProgress(self) -> int:
- return self._secondary_progress
-
- def setInterpolator(self, interpolator: Any):
- self._interpolator = interpolator
-
- def getInterpolator(self) -> Any:
- return self._interpolator
-
- def setAnimation(self, animation: Any):
- self._animation = animation
-
- def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
- from .view import MeasureSpec
- w = MeasureSpec.getSize(width_measure_spec)
- h = MeasureSpec.getSize(height_measure_spec)
- if h == 0:
- h = 20
- self.setMeasuredDimension(w, h)
-
-
-class SeekBar(ProgressBar):
- """SeekBar — 可拖动进度条"""
-
- def __init__(self, context=None, attrs: Any = None,
- def_style_attr: int = 0, def_style_res: int = 0):
- super().__init__(context, attrs, def_style_attr, def_style_res)
- self._on_seek_bar_change_listener: Optional[Callable] = None
-
- class OnSeekBarChangeListener:
- def onProgressChanged(self, seek_bar: "SeekBar", progress: int, from_user: bool):
- pass
- def onStartTrackingTouch(self, seek_bar: "SeekBar"):
- pass
- def onStopTrackingTouch(self, seek_bar: "SeekBar"):
- pass
-
- def setOnSeekBarChangeListener(self, listener: Optional[OnSeekBarChangeListener]):
- self._on_seek_bar_change_listener = listener
-
- def getOnSeekBarChangeListener(self) -> Optional[OnSeekBarChangeListener]:
- return self._on_seek_bar_change_listener
-
- def setThumb(self, thumb: Any):
- pass
-
- def getThumb(self) -> Any:
- return None
-
- def setThumbOffset(self, thumb_offset: int):
- pass
-
- def getThumbOffset(self) -> int:
- return 0
-
- def setKeyProgressIncrement(self, increment: int):
- pass
-
- def getKeyProgressIncrement(self) -> int:
- return 1
-
-
-class RatingBar(ProgressBar):
- """RatingBar — 评分条"""
-
- def __init__(self, context=None, attrs: Any = None,
- def_style_attr: int = 0, def_style_res: int = 0):
- super().__init__(context, attrs, def_style_attr, def_style_res)
- self._num_stars: int = 5
- self._rating: float = 0.0
- self._step_size: float = 0.5
- self._is_indicator: bool = False
- self._on_rating_bar_change_listener: Optional[Callable] = None
-
- class OnRatingBarChangeListener:
- def onRatingChanged(self, rating_bar: "RatingBar", rating: float, from_user: bool):
- pass
-
- def setOnRatingBarChangeListener(self, listener: Optional[OnRatingBarChangeListener]):
- self._on_rating_bar_change_listener = listener
-
- def getOnRatingBarChangeListener(self) -> Optional[OnRatingBarChangeListener]:
- return self._on_rating_bar_change_listener
-
- def setNumStars(self, num_stars: int):
- self._num_stars = max(1, num_stars)
-
- def getNumStars(self) -> int:
- return self._num_stars
-
- def setRating(self, rating: float):
- self._rating = max(0.0, min(float(self._num_stars), rating))
-
- def getRating(self) -> float:
- return self._rating
-
- def setStepSize(self, step_size: float):
- self._step_size = max(0.1, step_size)
-
- def getStepSize(self) -> float:
- return self._step_size
-
- def setIsIndicator(self, is_indicator: bool):
- self._is_indicator = is_indicator
-
- def isIndicator(self) -> bool:
- return self._is_indicator
-
-
-# ═══════════════════════════════════════════════════════════════
-# AdapterView
-# ═══════════════════════════════════════════════════════════════
-
-class AdapterView(ViewGroup):
- """AdapterView — 适配器视图基类"""
-
- CHOICE_MODE_NONE = 0
- CHOICE_MODE_SINGLE = 1
- CHOICE_MODE_MULTIPLE = 2
- CHOICE_MODE_MULTIPLE_MODAL = 3
-
- INVALID_POSITION = -1
- INVALID_ROW_ID = -9223372036854775808 # Long.MIN_VALUE
-
- def __init__(self, context=None):
- super().__init__(context)
- self._adapter: Any = None
- self._on_item_click_listener: Optional[Callable] = None
- self._on_item_long_click_listener: Optional[Callable] = None
- self._on_item_selected_listener: Optional[Callable] = None
- self._choice_mode = AdapterView.CHOICE_MODE_NONE
- self._checked_item_positions: Dict[int, bool] = {}
- self._checked_id_positions: Dict[int, bool] = {}
- self._selected_position = AdapterView.INVALID_POSITION
- self._empty_view: Optional[View] = None
- self._selection_notifier: Any = None
-
- def setAdapter(self, adapter: Any):
- self._adapter = adapter
-
- def getAdapter(self) -> Any:
- return self._adapter
-
- def setOnItemClickListener(self, listener: Optional[Callable]):
- self._on_item_click_listener = listener
-
- def getOnItemClickListener(self) -> Optional[Callable]:
- return self._on_item_click_listener
-
- def setOnItemLongClickListener(self, listener: Optional[Callable]):
- self._on_item_long_click_listener = listener
-
- def getOnItemLongClickListener(self) -> Optional[Callable]:
- return self._on_item_long_click_listener
-
- def setOnItemSelectedListener(self, listener: Optional[Callable]):
- self._on_item_selected_listener = listener
-
- def getOnItemSelectedListener(self) -> Optional[Callable]:
- return self._on_item_selected_listener
-
- def getSelectedItemPosition(self) -> int:
- return self._selected_position
-
- def getSelectedItemId(self) -> int:
- return 0
-
- def getSelectedItem(self) -> Any:
- if self._adapter is not None and 0 <= self._selected_position < self._adapter.getCount():
- return self._adapter.getItem(self._selected_position)
- return None
-
- def setSelection(self, position: int):
- self._selected_position = position
-
- def setEmptyView(self, empty_view: View):
- self._empty_view = empty_view
-
- def getEmptyView(self) -> Optional[View]:
- return self._empty_view
-
- def setChoiceMode(self, choice_mode: int):
- self._choice_mode = choice_mode
-
- def getChoiceMode(self) -> int:
- return self._choice_mode
-
- def setItemChecked(self, position: int, checked: bool):
- if self._choice_mode == AdapterView.CHOICE_MODE_SINGLE:
- self._checked_item_positions.clear()
- self._checked_item_positions[position] = checked
- elif self._choice_mode == AdapterView.CHOICE_MODE_MULTIPLE:
- self._checked_item_positions[position] = checked
-
- def isItemChecked(self, position: int) -> bool:
- return self._checked_item_positions.get(position, False)
-
- def getCheckedItemPositions(self) -> Dict[int, bool]:
- return dict(self._checked_item_positions)
-
- def getCheckedItemCount(self) -> int:
- return len(self._checked_item_positions)
-
- def getCheckedItemIds(self) -> List[int]:
- return list(self._checked_id_positions.keys())
-
- def performItemClick(self, view: View, position: int, id_: int) -> bool:
- if self._on_item_click_listener:
- self._on_item_click_listener(self, view, position, id_)
- return True
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# ListView
-# ═══════════════════════════════════════════════════════════════
-
-class ListView(AdapterView):
- """ListView — 列表视图"""
-
- CHOICE_MODE_NONE = 0
- CHOICE_MODE_SINGLE = 1
- CHOICE_MODE_MULTIPLE = 2
- CHOICE_MODE_MULTIPLE_MODAL = 3
-
- TRANSCRIPT_MODE_DISABLED = 0
- TRANSCRIPT_MODE_NORMAL = 1
- TRANSCRIPT_MODE_ALWAYS_SCROLL = 2
-
- def __init__(self, context=None):
- super().__init__(context)
- self._divider: Any = None
- self._divider_height: int = 0
- self._footer_divider: Any = None
- self._header_divider: Any = None
- self._footer_views: List[View] = []
- self._header_views: List[View] = []
- self._transcript_mode = ListView.TRANSCRIPT_MODE_DISABLED
- self._items_can_focus = True
- self._smooth_scroll_position = 0
- self._stack_from_bottom = False
- self._selection_division = 0
-
- def setAdapter(self, adapter: Any):
- super().setAdapter(adapter)
-
- def getAdapter(self) -> Any:
- return super().getAdapter()
-
- def setSelection(self, position: int):
- super().setSelection(position)
-
- def smoothScrollToPosition(self, position: int):
- self._smooth_scroll_position = position
-
- def setDivider(self, divider: Any):
- self._divider = divider
-
- def setDividerHeight(self, height: int):
- self._divider_height = height
-
- def getDivider(self) -> Any:
- return self._divider
-
- def getDividerHeight(self) -> int:
- return self._divider_height
-
- def addFooterView(self, v: View, data: Any = None, is_selectable: bool = True):
- self._footer_views.append(v)
-
- def removeFooterView(self, v: View) -> bool:
- if v in self._footer_views:
- self._footer_views.remove(v)
- return True
- return False
-
- def addHeaderView(self, v: View, data: Any = None, is_selectable: bool = True):
- self._header_views.append(v)
-
- def removeHeaderView(self, v: View) -> bool:
- if v in self._header_views:
- self._header_views.remove(v)
- return True
- return False
-
- def getHeaderViewsCount(self) -> int:
- return len(self._header_views)
-
- def getFooterViewsCount(self) -> int:
- return len(self._footer_views)
-
- def setTranscriptMode(self, mode: int):
- self._transcript_mode = mode
-
- def getTranscriptMode(self) -> int:
- return self._transcript_mode
-
- def setItemsCanFocus(self, items_can_focus: bool):
- self._items_can_focus = items_can_focus
-
- def getItemsCanFocus(self) -> bool:
- return self._items_can_focus
-
- def setStackFromBottom(self, stack_from_bottom: bool):
- self._stack_from_bottom = stack_from_bottom
-
- def isStackFromBottom(self) -> bool:
- return self._stack_from_bottom
-
- def getCheckItemIds(self) -> List[int]:
- return list(self._checked_id_positions.keys())
-
- def clearChoices(self):
- self._checked_item_positions.clear()
- self._checked_id_positions.clear()
-
-
-class GridView(AdapterView):
- """GridView — 网格视图"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._num_columns: int = 1
- self._column_width: int = 0
- self._horizontal_spacing: int = 0
- self._vertical_spacing: int = 0
- self._stretch_mode: int = 0 # NO_STRETCH
- self._gravity = Gravity.LEFT
-
- STRETCH_NO_STRETCH = 0
- STRETCH_STRETCH_COLUMN_WIDTH = 1
- STRETCH_STRETCH_SPACING = 2
- STRETCH_STRETCH_SPACING_UNIFORM = 3
- STRETCH_STRETCH_COLUMN_WIDTH_UNIFORM = 4
-
- def setNumColumns(self, num_columns: int):
- self._num_columns = max(1, num_columns)
-
- def getNumColumns(self) -> int:
- return self._num_columns
-
- def setColumnWidth(self, column_width: int):
- self._column_width = column_width
-
- def getColumnWidth(self) -> int:
- return self._column_width
-
- def setHorizontalSpacing(self, horizontal_spacing: int):
- self._horizontal_spacing = horizontal_spacing
-
- def getHorizontalSpacing(self) -> int:
- return self._horizontal_spacing
-
- def setVerticalSpacing(self, vertical_spacing: int):
- self._vertical_spacing = vertical_spacing
-
- def getVerticalSpacing(self) -> int:
- return self._vertical_spacing
-
- def setStretchMode(self, stretch_mode: int):
- self._stretch_mode = stretch_mode
-
- def getStretchMode(self) -> int:
- return self._stretch_mode
-
- def setGravity(self, gravity: int):
- self._gravity = gravity
-
- def getGravity(self) -> int:
- return self._gravity
-
- def setAdapter(self, adapter: Any):
- super().setAdapter(AdapterView)
-
-
-# ═══════════════════════════════════════════════════════════════
-# RecyclerView
-# ═══════════════════════════════════════════════════════════════
-
-class RecyclerView(ViewGroup):
- """RecyclerView — 可回收视图列表"""
-
- HORIZONTAL = 0
- VERTICAL = 1
- NO_POSITION = -1
- INVALID_TYPE = -1
- TOUCH_SLOP_DEFAULT = 0
- TOUCH_SLOP_PAGING = 1
-
- def __init__(self, context=None):
- super().__init__(context)
- self._adapter: Optional["RecyclerView.Adapter"] = None
- self._layout_manager: Optional["RecyclerView.LayoutManager"] = None
- self._item_decorations: List[Any] = []
- self._recycler: Any = None
- self._child_attached_listener: Optional[Callable] = None
- self._child_detached_listener: Optional[Callable] = None
- self._item_animator: Any = None
- self._on_scroll_listener: Optional[Callable] = None
- self._nested_scrolling_enabled = True
- self._scroll_state = RecyclerView.SCROLL_STATE_IDLE
- self._layout_frozen = False
- self._suppress_layout = False
- self._clip_to_padding = True
-
- SCROLL_STATE_IDLE = 0
- SCROLL_STATE_DRAGGING = 1
- SCROLL_STATE_SETTLING = 2
-
- # ─── Adapter ─────────────────────────────────────────────
-
- class Adapter(Stub):
- """RecyclerView.Adapter — 适配器"""
-
- def __init__(self):
- super().__init__()
- self._observable: Any = None
- self._has_stable_ids = False
- self._state_restoration_policy = 0
-
- def onCreateViewHolder(self, parent: "RecyclerView", view_type: int) -> "RecyclerView.ViewHolder":
- raise NotImplementedError
-
- def onBindViewHolder(self, holder: "RecyclerView.ViewHolder", position: int):
- raise NotImplementedError
-
- def getItemCount(self) -> int:
- return 0
-
- def getItemViewType(self, position: int) -> int:
- return 0
-
- def getItemId(self, position: int) -> int:
- return position
-
- def hasStableIds(self) -> bool:
- return self._has_stable_ids
-
- def setHasStableIds(self, has_stable_ids: bool):
- self._has_stable_ids = has_stable_ids
-
- def onAttachedToRecyclerView(self, recycler_view: "RecyclerView"):
- pass
-
- def onDetachedFromRecyclerView(self, recycler_view: "RecyclerView"):
- pass
-
- def onViewAttachedToWindow(self, holder: "RecyclerView.ViewHolder"):
- pass
-
- def onViewDetachedFromWindow(self, holder: "RecyclerView.ViewHolder"):
- pass
-
- def onViewRecycled(self, holder: "RecyclerView.ViewHolder"):
- pass
-
- def onFailedToRecycleView(self, holder: "RecyclerView.ViewHolder") -> bool:
- return False
-
- def notifyDataSetChanged(self):
- for observer in getattr(self, '_observers', []):
- observer.onChanged()
-
- def notifyItemChanged(self, position, payload=None):
- for observer in getattr(self, '_observers', []):
- observer.onItemRangeChanged(position, 1, payload)
-
- def notifyItemInserted(self, position):
- for observer in getattr(self, '_observers', []):
- observer.onItemRangeInserted(position, 1)
-
- def notifyItemRemoved(self, position):
- for observer in getattr(self, '_observers', []):
- observer.onItemRangeRemoved(position, 1)
-
- def notifyItemMoved(self, fromPosition, toPosition):
- for observer in getattr(self, '_observers', []):
- observer.onItemRangeMoved(fromPosition, toPosition, 1)
-
- def notifyItemRangeChanged(self, positionStart, itemCount, payload=None):
- for observer in getattr(self, '_observers', []):
- observer.onItemRangeChanged(positionStart, itemCount, payload)
-
- def notifyItemRangeInserted(self, positionStart, itemCount):
- for observer in getattr(self, '_observers', []):
- observer.onItemRangeInserted(positionStart, itemCount)
-
- def notifyItemRangeRemoved(self, positionStart, itemCount):
- for observer in getattr(self, '_observers', []):
- observer.onItemRangeRemoved(positionStart, itemCount)
-
- def registerAdapterDataObserver(self, observer):
- if not hasattr(self, '_observers'):
- self._observers = []
- self._observers.append(observer)
-
- def unregisterAdapterDataObserver(self, observer):
- if hasattr(self, '_observers'):
- try:
- self._observers.remove(observer)
- except ValueError:
- pass
-
- def getStateRestorationPolicy(self) -> int:
- return 0
-
- # ─── ViewHolder ───────────────────────────────────────────
-
- class ViewHolder(Stub):
- """RecyclerView.ViewHolder — 视图持有者"""
-
- FLAG_BOUND = 1
- FLAG_NOT_RECYCLABLE = 2
- FLAG_RETURNED_FROM_SCRAP = 4
- FLAG_CHANGED = 8
- FLAG_IGNORE = 16
- FLAG_TMP_DETACHED = 32
- FLAG_UPDATE = 64
- FLAG_ADAPTER_POSITION_UNKNOWN = 128
- FLAG_ADAPTER_FULLUPDATE = 256
- FLAG_MOVED = 512
- FLAG_APPEARED_IN_PRE_LAYOUT = 1024
-
- def __init__(self, item_view: View):
- super().__init__()
- self.itemView = item_view
- self._position = RecyclerView.NO_POSITION
- self._old_position = RecyclerView.NO_POSITION
- self._item_id = RecyclerView.NO_ID
- self._item_view_type = RecyclerView.INVALID_TYPE
- self._flags = 0
- self._pre_layout_position = RecyclerView.NO_POSITION
- self._is_recyclable = True
- self._scrap_container: Optional[RecyclerView] = None
- self._shadowed_holder: Optional["RecyclerView.ViewHolder"] = None
- self._shadowing_holder: Optional["RecyclerView.ViewHolder"] = None
-
- NO_ID = -1
-
- def getAdapterPosition(self) -> int:
- return self._position
-
- def getLayoutPosition(self) -> int:
- return self._position
-
- def getOldPosition(self) -> int:
- return self._old_position
-
- def getItemId(self) -> int:
- return self._item_id
-
- def getItemViewType(self) -> int:
- return self._item_view_type
-
- def setIsRecyclable(self, recyclable: bool):
- self._is_recyclable = recyclable
-
- def isRecyclable(self) -> bool:
- return self._is_recyclable
-
- def getBindingAdapterPosition(self) -> int:
- return self._position
-
- # ─── LayoutManager ────────────────────────────────────────
-
- class LayoutManager(Stub):
- """RecyclerView.LayoutManager — 布局管理器"""
-
- def __init__(self):
- super().__init__()
- self._recycler_view: Optional["RecyclerView"] = None
- self._child_count = 0
- self._width = 0
- self._height = 0
- self._auto_measure = True
- self._item_prefetch_enabled = True
-
- def onLayoutChildren(self, recycler: Any, state: Any):
- pass
-
- def getChildCount(self) -> int:
- return self._child_count
-
- def getPosition(self, view: View) -> int:
- if isinstance(view, View):
- return 0
- return RecyclerView.NO_POSITION
-
- def scrollToPosition(self, position: int):
- pass
-
- def smoothScrollToPosition(self, recycler_view: "RecyclerView", state: Any, position: int):
- pass
-
- def onAdapterChanged(self, old_adapter: Any, new_adapter: Any):
- pass
-
- def generateDefaultLayoutParams(self) -> ViewGroup.LayoutParams:
- return ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT)
-
- def getWidth(self) -> int:
- return self._width
-
- def getHeight(self) -> int:
- return self._height
-
- def setAutoMeasureEnabled(self, enabled: bool):
- self._auto_measure = enabled
-
- def isAutoMeasureEnabled(self) -> bool:
- return self._auto_measure
-
- def requestLayout(self):
- pass
-
- def requestSimpleAnimationsInNextLayout(self):
- pass
-
- def assertNotInLayoutOrScroll(self, tag: str = ""):
- pass
-
- def getPaddingLeft(self) -> int:
- return 0
-
- def getPaddingTop(self) -> int:
- return 0
-
- def getPaddingRight(self) -> int:
- return 0
-
- def getPaddingBottom(self) -> int:
- return 0
-
- # ─── ItemDecoration ──────────────────────────────────────
-
- class ItemDecoration(Stub):
- """RecyclerView.ItemDecoration — 条目装饰"""
-
- def onDraw(self, c: Any, parent: "RecyclerView", state: Any):
- pass
-
- def onDrawOver(self, c: Any, parent: "RecyclerView", state: Any):
- pass
-
- def getItemOffsets(self, out_rect: Any, view: View, parent: "RecyclerView", state: Any):
- if hasattr(out_rect, "set"):
- out_rect.set(0, 0, 0, 0)
-
- # ─── RecycledViewPool ─────────────────────────────────────
-
- class RecycledViewPool(Stub):
- """RecyclerView.RecycledViewPool — 回收视图池"""
-
- def __init__(self):
- super().__init__()
- self._max_recycled_views = 5
-
- def getRecycledView(self, view_type: int) -> Optional["RecyclerView.ViewHolder"]:
- return None
-
- def putRecycledView(self, scrap: "RecyclerView.ViewHolder"):
- pass
-
- def setMaxRecycledViews(self, view_type: int, max_count: int):
- self._max_recycled_views = max_count
-
- def clear(self):
- pass
-
- # ─── Recycler ─────────────────────────────────────────────
-
- class Recycler(Stub):
- """RecyclerView.Recycler — 回收器"""
-
- def __init__(self):
- super().__init__()
- self._view_cache: Dict[int, List["RecyclerView.ViewHolder"]] = {}
-
- def getViewForPosition(self, position: int) -> View:
- raise AndroidOnlyError("RecyclerView.Recycler.getViewForPosition")
-
- def recycleView(self, view: View):
- pass
-
- def getRecycledViewPool(self) -> "RecyclerView.RecycledViewPool":
- return RecyclerView.RecycledViewPool()
-
- def setViewCacheSize(self, view_count: int):
- pass
-
- def clear(self):
- self._view_cache.clear()
-
- # ─── RecyclerView Instance Methods ───────────────────────
-
- def setAdapter(self, adapter: Optional["RecyclerView.Adapter"]):
- self._adapter = adapter
-
- def getAdapter(self) -> Optional["RecyclerView.Adapter"]:
- return self._adapter
-
- def setLayoutManager(self, layout_manager: Optional["RecyclerView.LayoutManager"]):
- self._layout_manager = layout_manager
- if layout_manager:
- layout_manager._recycler_view = self
-
- def getLayoutManager(self) -> Optional["RecyclerView.LayoutManager"]:
- return self._layout_manager
-
- def addItemDecoration(self, decoration: "RecyclerView.ItemDecoration", index: int = -1):
- if index < 0 or index >= len(self._item_decorations):
- self._item_decorations.append(decoration)
- else:
- self._item_decorations.insert(index, decoration)
-
- def removeItemDecoration(self, decoration: "RecyclerView.ItemDecoration"):
- if decoration in self._item_decorations:
- self._item_decorations.remove(decoration)
-
- def getItemDecorationAt(self, index: int) -> "RecyclerView.ItemDecoration":
- return self._item_decorations[index]
-
- def getItemDecorationCount(self) -> int:
- return len(self._item_decorations)
-
- def swapAdapter(self, adapter: Optional["RecyclerView.Adapter"], remove_and_recycle: bool):
- self._adapter = adapter
-
- def getRecycledViewPool(self) -> "RecyclerView.RecycledViewPool":
- return RecyclerView.RecycledViewPool()
-
- def setRecycledViewPool(self, pool: "RecyclerView.RecycledViewPool"):
- pass
-
- def getRecycler(self) -> "RecyclerView.Recycler":
- return RecyclerView.Recycler()
-
- def setItemAnimator(self, animator: Any):
- self._item_animator = animator
-
- def getItemAnimator(self) -> Any:
- return self._item_animator
-
- def setOnScrollListener(self, listener: Optional[Callable]):
- self._on_scroll_listener = listener
-
- def addOnScrollListener(self, listener: Callable):
- pass
-
- def removeOnScrollListener(self, listener: Callable):
- pass
-
- def clearOnScrollListeners(self):
- pass
-
- def addOnChildAttachStateChangeListener(self, listener: Callable):
- self._child_attached_listener = listener
-
- def removeOnChildAttachStateChangeListener(self, listener: Callable):
- pass
-
- def setHasFixedSize(self, has_fixed_size: bool):
- pass
-
- def hasFixedSize(self) -> bool:
- return False
-
- def setNestedScrollingEnabled(self, enabled: bool):
- self._nested_scrolling_enabled = enabled
-
- def isNestedScrollingEnabled(self) -> bool:
- return self._nested_scrolling_enabled
-
- def startNestedScroll(self, axes: int) -> bool:
- return False
-
- def stopNestedScroll(self):
- pass
-
- def hasNestedScrollingParent(self) -> bool:
- return False
-
- def dispatchNestedPreScroll(self, dx: int, dy: int, consumed: List[int], offset: List[int]) -> bool:
- return False
-
- def dispatchNestedScroll(self, dx_consumed: int, dy_consumed: int,
- dx_unconsumed: int, dy_unconsumed: int,
- offset: List[int]) -> bool:
- return False
-
- def dispatchNestedPreFling(self, velocity_x: float, velocity_y: float) -> bool:
- return False
-
- def dispatchNestedFling(self, velocity_x: float, velocity_y: float, consumed: bool) -> bool:
- return False
-
- def stopScroll(self):
- pass
-
- def getScrollState(self) -> int:
- return self._scroll_state
-
- def setLayoutFrozen(self, frozen: bool):
- self._layout_frozen = frozen
-
- def isLayoutFrozen(self) -> bool:
- return self._layout_frozen
-
- def smoothScrollBy(self, dx: int, dy: int):
- pass
-
- def scrollBy(self, x: int, y: int):
- pass
-
- def computeHorizontalScrollOffset(self) -> int:
- return 0
-
- def computeHorizontalScrollRange(self) -> int:
- return 0
-
- def computeVerticalScrollOffset(self) -> int:
- return 0
-
- def computeVerticalScrollRange(self) -> int:
- return 0
-
- def findViewHolderForAdapterPosition(self, position: int) -> Optional["RecyclerView.ViewHolder"]:
- return None
-
- def findViewHolderForLayoutPosition(self, position: int) -> Optional["RecyclerView.ViewHolder"]:
- return None
-
- def findViewHolderForItemId(self, id_: int) -> Optional["RecyclerView.ViewHolder"]:
- return None
-
- NO_ID = -1
-
-
-# 为 __all__ 导出创建别名
-RecyclerViewAdapter = RecyclerView.Adapter
-RecyclerViewViewHolder = RecyclerView.ViewHolder
-RecyclerViewLayoutManager = RecyclerView.LayoutManager
-
-
-class LinearLayoutManager(RecyclerView.LayoutManager):
- """LinearLayoutManager — 线性布局管理器"""
-
- HORIZONTAL = 0
- VERTICAL = 1
-
- def __init__(self, context: Any = None, orientation: int = VERTICAL, reverse_layout: bool = False):
- super().__init__()
- self._orientation = orientation
- self._reverse_layout = reverse_layout
- self._stack_from_end = False
- self._item_count = 0
-
- def setOrientation(self, orientation: int):
- self._orientation = orientation
-
- def getOrientation(self) -> int:
- return self._orientation
-
- def setReverseLayout(self, reverse_layout: bool):
- self._reverse_layout = reverse_layout
-
- def getReverseLayout(self) -> bool:
- return self._reverse_layout
-
- def setStackFromEnd(self, stack_from_end: bool):
- self._stack_from_end = stack_from_end
-
- def getStackFromEnd(self) -> bool:
- return self._stack_from_end
-
- def generateDefaultLayoutParams(self) -> ViewGroup.LayoutParams:
- return ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT)
-
- def onLayoutChildren(self, recycler: Any, state: Any):
- pass
-
-
-class GridLayoutManager(LinearLayoutManager):
- """GridLayoutManager — 网格布局管理器"""
-
- def __init__(self, context: Any = None, span_count: int = 1,
- orientation: int = LinearLayoutManager.VERTICAL,
- reverse_layout: bool = False):
- super().__init__(context, orientation, reverse_layout)
- self._span_count = max(1, span_count)
-
- class SpanSizeLookup(Stub):
- """GridLayoutManager.SpanSizeLookup — 跨度大小查找"""
-
- def __init__(self):
- super().__init__()
- self._span_index_cache = {}
-
- def getSpanSize(self, position: int) -> int:
- return 1
-
- def getSpanIndex(self, position: int, span_count: int) -> int:
- return position % span_count
-
- def getSpanGroupIndex(self, position: int, span_count: int) -> int:
- return position // span_count
-
- def invalidateSpanIndexCache(self):
- self._span_index_cache.clear()
-
- def setSpanCount(self, span_count: int):
- self._span_count = max(1, span_count)
-
- def getSpanCount(self) -> int:
- return self._span_count
-
- def setSpanSizeLookup(self, span_size_lookup: SpanSizeLookup):
- pass
-
- def getSpanSizeLookup(self) -> SpanSizeLookup:
- return GridLayoutManager.SpanSizeLookup()
-
-
-class StaggeredGridLayoutManager(RecyclerView.LayoutManager):
- """StaggeredGridLayoutManager — 瀑布流布局管理器"""
-
- HORIZONTAL = 0
- VERTICAL = 1
-
- GAP_HANDLING_NONE = 0
- GAP_HANDLING_LAZY = 1
- GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2
-
- def __init__(self, span_count: int = 1, orientation: int = VERTICAL):
- super().__init__()
- self._span_count = max(1, span_count)
- self._orientation = orientation
- self._gap_strategy = StaggeredGridLayoutManager.GAP_HANDLING_LAZY
-
- def setSpanCount(self, span_count: int):
- self._span_count = max(1, span_count)
-
- def getSpanCount(self) -> int:
- return self._span_count
-
- def setOrientation(self, orientation: int):
- self._orientation = orientation
-
- def getOrientation(self) -> int:
- return self._orientation
-
- def setGapStrategy(self, gap_strategy: int):
- self._gap_strategy = gap_strategy
-
- def getGapStrategy(self) -> int:
- return self._gap_strategy
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinearLayout
-# ═══════════════════════════════════════════════════════════════
-
-class LinearLayout(ViewGroup):
- """LinearLayout — 线性布局"""
-
- HORIZONTAL = 0
- VERTICAL = 1
- SHOW_DIVIDER_NONE = 0
- SHOW_DIVIDER_BEGINNING = 1
- SHOW_DIVIDER_MIDDLE = 2
- SHOW_DIVIDER_END = 4
-
- def __init__(self, context=None):
- super().__init__(context)
- self._orientation = LinearLayout.VERTICAL
- self._gravity = Gravity.NO_GRAVITY
- self._weight_sum: float = 0.0
- self._baseline_aligned = True
- self._baseline_aligned_child_index = -1
- self._divider: Any = None
- self._divider_padding: int = 0
- self._divider_show: int = LinearLayout.SHOW_DIVIDER_NONE
- self._total_length: int = 0
-
- def setOrientation(self, orientation: int):
- self._orientation = orientation
-
- def getOrientation(self) -> int:
- return self._orientation
-
- def setGravity(self, gravity: int):
- self._gravity = gravity
-
- def getGravity(self) -> int:
- return self._gravity
-
- def setWeightSum(self, weight_sum: float):
- self._weight_sum = weight_sum
-
- def getWeightSum(self) -> float:
- return self._weight_sum
-
- def setBaselineAligned(self, baseline_aligned: bool):
- self._baseline_aligned = baseline_aligned
-
- def isBaselineAligned(self) -> bool:
- return self._baseline_aligned
-
- def setDividerDrawable(self, divider: Any):
- self._divider = divider
-
- def setShowDividers(self, show_dividers: int):
- self._divider_show = show_dividers
-
- def getShowDividers(self) -> int:
- return self._divider_show
-
- def getDividerDrawable(self) -> Any:
- return self._divider
-
- def setDividerPadding(self, padding: int):
- self._divider_padding = padding
-
- def getDividerPadding(self) -> int:
- return self._divider_padding
-
- def getBaseline(self) -> int:
- return -1
-
- def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
- from .view import MeasureSpec
- w = MeasureSpec.getSize(width_measure_spec)
- h = MeasureSpec.getSize(height_measure_spec)
- self.setMeasuredDimension(w, h)
-
- def onLayout(self, changed: bool, l: int, t: int, r: int, b: int):
- pass
-
- class LayoutParams(ViewGroup.MarginLayoutParams):
- """LinearLayout.LayoutParams — 线性布局参数"""
-
- def __init__(self, width: int = ViewGroup.LayoutParams.WRAP_CONTENT,
- height: int = ViewGroup.LayoutParams.WRAP_CONTENT,
- weight: float = 0.0):
- super().__init__(width, height)
- self.weight = weight
- self.gravity = -1
-
- def setLayoutWeight(self, weight: float):
- self.weight = weight
-
-
-# ═══════════════════════════════════════════════════════════════
-# RelativeLayout
-# ═══════════════════════════════════════════════════════════════
-
-class RelativeLayout(ViewGroup):
- """RelativeLayout — 相对布局"""
-
- TRUE = -1
- FALSE = 0
-
- # 规则常量
- ALIGN_PARENT_LEFT = 0
- ALIGN_PARENT_TOP = 1
- ALIGN_PARENT_RIGHT = 2
- ALIGN_PARENT_BOTTOM = 3
- ALIGN_PARENT_START = 4
- ALIGN_PARENT_END = 5
- CENTER_IN_PARENT = 6
- CENTER_HORIZONTAL = 7
- CENTER_VERTICAL = 8
- ABOVE = 9
- BELOW = 10
- LEFT_OF = 11
- RIGHT_OF = 12
- ALIGN_LEFT = 13
- ALIGN_TOP = 14
- ALIGN_RIGHT = 15
- ALIGN_BOTTOM = 16
- ALIGN_BASELINE = 17
- ALIGN_WITH_PARENT_IF_MISSING = 18
- START_OF = 19
- END_OF = 20
- ALIGN_START = 21
- ALIGN_END = 22
-
- def __init__(self, context=None):
- super().__init__(context)
- self._gravity = Gravity.NO_GRAVITY
- self._ignore_gravity_of_view_ids: List[int] = []
- self._has_left_weight = False
- self._has_right_weight = False
- self._has_top_weight = False
- self._has_bottom_weight = False
-
- def setGravity(self, gravity: int):
- self._gravity = gravity
-
- def getGravity(self) -> int:
- return self._gravity
-
- def setHorizontalGravity(self, horizontal_gravity: int):
- pass
-
- def setVerticalGravity(self, vertical_gravity: int):
- pass
-
- def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
- from .view import MeasureSpec
- w = MeasureSpec.getSize(width_measure_spec)
- h = MeasureSpec.getSize(height_measure_spec)
- self.setMeasuredDimension(w, h)
-
- def onLayout(self, changed: bool, l: int, t: int, r: int, b: int):
- pass
-
- class LayoutParams(ViewGroup.MarginLayoutParams):
- """RelativeLayout.LayoutParams — 相对布局参数"""
-
- def __init__(self, width: int = ViewGroup.LayoutParams.WRAP_CONTENT,
- height: int = ViewGroup.LayoutParams.WRAP_CONTENT):
- super().__init__(width, height)
- self._rules: Dict[int, int] = {}
- self.align_with_parent = False
-
- def addRule(self, verb: int, subject: int = -1):
- self._rules[verb] = subject
-
- def removeRule(self, verb: int):
- self._rules.pop(verb, None)
-
- def getRule(self, verb: int) -> int:
- return self._rules.get(verb, 0)
-
- def getRules(self) -> Dict[int, int]:
- return dict(self._rules)
-
- def addLayoutRules(self, layout_rules: int):
- pass
-
- def removeLayoutRule(self, layout_rule: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# FrameLayout
-# ═══════════════════════════════════════════════════════════════
-
-class FrameLayout(ViewGroup):
- """FrameLayout — 帧布局"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._foreground: Any = None
- self._foreground_gravity = Gravity.FILL
- self._measure_all_children = False
- self._foreground_bounds_padding: int = 0
- self._foreground_in_padding = False
-
- def setForeground(self, drawable: Any):
- self._foreground = drawable
-
- def getForeground(self) -> Any:
- return self._foreground
-
- def setForegroundGravity(self, gravity: int):
- self._foreground_gravity = gravity
-
- def getForegroundGravity(self) -> int:
- return self._foreground_gravity
-
- def setMeasureAllChildren(self, measure_all: bool):
- self._measure_all_children = measure_all
-
- def getMeasureAllChildren(self) -> bool:
- return self._measure_all_children
-
- def setForegroundBoundsPadding(self, padding: int):
- self._foreground_bounds_padding = padding
-
- def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
- from .view import MeasureSpec
- w = MeasureSpec.getSize(width_measure_spec)
- h = MeasureSpec.getSize(height_measure_spec)
- if self._measure_all_children:
- for child in self._children:
- child.measure(width_measure_spec, height_measure_spec)
- self.setMeasuredDimension(w, h)
-
- def onLayout(self, changed: bool, l: int, t: int, r: int, b: int):
- pass
-
- def gatherTransparentRegion(self, region: Any) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# TableLayout / TableRow
-# ═══════════════════════════════════════════════════════════════
-
-class TableLayout(LinearLayout):
- """TableLayout — 表格布局"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._stretchable_columns: List[bool] = []
- self._shrinkable_columns: List[bool] = []
- self._collapsed_columns: List[bool] = []
- self._max_columns: int = 0
-
- def setStretchAllColumns(self, stretch_all: bool):
- pass
-
- def setShrinkAllColumns(self, shrink_all: bool):
- pass
-
- def setColumnStretchable(self, column_index: int, stretchable: bool):
- pass
-
- def setColumnShrinkable(self, column_index: int, shrinkable: bool):
- pass
-
- def setColumnCollapsed(self, column_index: int, collapsed: bool):
- pass
-
- def isColumnStretchable(self, column_index: int) -> bool:
- return False
-
- def isColumnShrinkable(self, column_index: int) -> bool:
- return False
-
- def isColumnCollapsed(self, column_index: int) -> bool:
- return False
-
-
-class TableRow(LinearLayout):
- """TableRow — 表格行"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._layout_params: Dict[int, Any] = {}
-
- class LayoutParams(LinearLayout.LayoutParams):
- """TableRow.LayoutParams — 表格行布局参数"""
-
- def __init__(self, width: int = ViewGroup.LayoutParams.WRAP_CONTENT,
- height: int = ViewGroup.LayoutParams.WRAP_CONTENT):
- super().__init__(width, height)
- self.column = -1
- self.span = 1
-
-
-# ═══════════════════════════════════════════════════════════════
-# ScrollView / HorizontalScrollView
-# ═══════════════════════════════════════════════════════════════
-
-class ScrollView(FrameLayout):
- """ScrollView — 滚动视图"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._fill_viewport = False
- self._smooth_scrolling_enabled = True
- self._max_scroll_amount = 0
- self._scroll_position = 0
- self._is_layout_after_scroll = False
-
- def setFillViewport(self, fill_viewport: bool):
- self._fill_viewport = fill_viewport
-
- def isFillViewport(self) -> bool:
- return self._fill_viewport
-
- def setSmoothScrollingEnabled(self, enabled: bool):
- self._smooth_scrolling_enabled = enabled
-
- def isSmoothScrollingEnabled(self) -> bool:
- return self._smooth_scrolling_enabled
-
- def fullScroll(self, direction: int) -> bool:
- return True
-
- def arrowScroll(self, direction: int) -> bool:
- return True
-
- def smoothScrollTo(self, x, y):
- self._scroll_x = x
- self._scroll_y = y
-
- def smoothScrollBy(self, dx, dy):
- self._scroll_x = getattr(self, '_scroll_x', 0) + dx
- self._scroll_y = getattr(self, '_scroll_y', 0) + dy
-
- def pageScroll(self, direction: int) -> bool:
- return True
-
- def getMaxScrollAmount(self) -> int:
- return self._max_scroll_amount
-
- def computeScrollDeltaToGetChildRectOnScreen(self, rect: Any) -> int:
- return 0
-
- def isLayoutAfterScroll(self) -> bool:
- return self._is_layout_after_scroll
-
-
-class HorizontalScrollView(FrameLayout):
- """HorizontalScrollView — 水平滚动视图"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._fill_viewport = False
-
- def setFillViewport(self, fill_viewport: bool):
- self._fill_viewport = fill_viewport
-
- def isFillViewport(self) -> bool:
- return self._fill_viewport
-
- def fullScroll(self, direction: int) -> bool:
- return True
-
- def arrowScroll(self, direction: int) -> bool:
- return True
-
- def smoothScrollTo(self, x, y):
- self._scroll_x = x
- self._scroll_y = y
-
- def smoothScrollBy(self, dx, dy):
- self._scroll_x = getattr(self, '_scroll_x', 0) + dx
- self._scroll_y = getattr(self, '_scroll_y', 0) + dy
-
- def pageScroll(self, direction: int) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# WebView
-# ═══════════════════════════════════════════════════════════════
-
-class WebView(ViewGroup):
- """WebView — 网页视图"""
-
- # 布局模式
- NORMAL = 0
- SMALL_SCREEN = 1
- LARGE_SCREEN = 2
-
- def __init__(self, context=None):
- super().__init__(context)
- self._settings: "WebSettings" = WebSettings()
- self._web_view_client: Optional[Callable] = None
- self._web_chrome_client: Optional[Callable] = None
- self._can_go_back: bool = False
- self._can_go_forward: bool = False
- self._current_url: str = ""
- self._history: List[str] = []
- self._current_index: int = -1
- self._download_listener: Optional[Callable] = None
- self._find_listener: Optional[Callable] = None
- self._picture_listener: Optional[Callable] = None
-
- def loadUrl(self, url: str, additional_headers: Optional[Dict[str, str]] = None):
- self._current_url = url
- self._history = self._history[:self._current_index + 1]
- self._history.append(url)
- self._current_index = len(self._history) - 1
- self._can_go_back = self._current_index > 0
- self._can_go_forward = False
-
- def loadData(self, data: str, mime_type: str = "text/html",
- encoding: str = "utf-8"):
- self._current_url = "about:blank"
-
- def loadDataWithBaseURL(self, base_url: str, data: str, mime_type: str,
- encoding: str, history_url: str):
- self._current_url = base_url or "about:blank"
-
- def getSettings(self) -> "WebSettings":
- return self._settings
-
- def setWebViewClient(self, client: Any):
- self._web_view_client = client
-
- def getWebViewClient(self) -> Any:
- return self._web_view_client
-
- def setWebChromeClient(self, client: Any):
- self._web_chrome_client = client
-
- def getWebChromeClient(self) -> Any:
- return self._web_chrome_client
-
- def goBack(self):
- if self._can_go_back:
- self._current_index -= 1
- self._current_url = self._history[self._current_index]
- self._can_go_back = self._current_index > 0
- self._can_go_forward = True
-
- def goForward(self):
- if self._can_go_forward:
- self._current_index += 1
- self._current_url = self._history[self._current_index]
- self._can_go_forward = self._current_index < len(self._history) - 1
- self._can_go_back = True
-
- def reload(self):
- pass
-
- def canGoBack(self) -> bool:
- return self._can_go_back
-
- def canGoForward(self) -> bool:
- return self._can_go_forward
-
- def clearHistory(self):
- self._history.clear()
- self._current_index = -1
- self._can_go_back = False
- self._can_go_forward = False
-
- def destroy(self):
- pass
-
- def onPause(self):
- pass
-
- def onResume(self):
- pass
-
- def pauseTimers(self):
- pass
-
- def resumeTimers(self):
- pass
-
- def getUrl(self) -> Optional[str]:
- return self._current_url if self._current_url else None
-
- def getTitle(self) -> Optional[str]:
- return None
-
- def evaluateJavascript(self, script: str, callback: Optional[Callable] = None):
- if callback:
- callback("")
-
- def addJavascriptInterface(self, obj: Any, name: str):
- pass
-
- def removeJavascriptInterface(self, name: str):
- pass
-
- def canGoBackOrForward(self, steps: int) -> bool:
- target = self._current_index + steps
- return 0 <= target < len(self._history)
-
- def goBackOrForward(self, steps: int):
- target = self._current_index + steps
- if 0 <= target < len(self._history):
- self._current_index = target
- self._current_url = self._history[target]
- self._can_go_back = target > 0
- self._can_go_forward = target < len(self._history) - 1
-
- def setDownloadListener(self, listener: Optional[Callable]):
- self._download_listener = listener
-
- def setFindListener(self, listener: Optional[Callable]):
- self._find_listener = listener
-
- class WebViewTransport:
- def setWebView(self, web_view: "WebView"):
- pass
- def getWebView(self) -> Optional["WebView"]:
- return None
-
- class HitTestResult:
- UNKNOWN_TYPE = 0
- ANCHOR_TYPE = 1
- EDIT_TEXT_TYPE = 2
- IMAGE_TYPE = 3
- SRC_ANCHOR_TYPE = 4
- SRC_IMAGE_ANCHOR_TYPE = 5
- PHONE_TYPE = 6
- GEO_TYPE = 7
- EMAIL_TYPE = 8
-
- def __init__(self):
- self._type = WebView.HitTestResult.UNKNOWN_TYPE
- self._extra = ""
-
- def getType(self) -> int:
- return self._type
- def getExtra(self) -> str:
- return self._extra
-
- def getHitTestResult(self) -> HitTestResult:
- return WebView.HitTestResult()
-
- def findAllAsync(self, find_str: str):
- pass
-
- def findNext(self, forward: bool):
- pass
-
- def clearMatches(self):
- pass
-
- def zoomIn(self) -> bool:
- return False
-
- def zoomOut(self) -> bool:
- return False
-
- def setInitialScale(self, scale_in_percent: int):
- pass
-
- def getScale(self) -> float:
- return 1.0
-
- def setPictureListener(self, listener: Optional[Callable]):
- self._picture_listener = listener
-
-
-class WebSettings(Stub):
- """WebSettings — WebView 设置"""
-
- # 渲染模式
- RENDER_GOES_BROWSER = 0
- RENDER_GOES_SURFACE_VIEW = 1
- RENDER_GOES_DISPLAY_LIST = 2
- RENDER_GOES_GPU = 3
- RENDER_GOES_SURFACE = 4
-
- # 布局算法
- LAYOUT_ALGORITHM_NORMAL = 0
- LAYOUT_ALGORITHM_SINGLE_COLUMN = 1
- LAYOUT_ALGORITHM_NARROW_COLUMNS = 2
- LAYOUT_ALGORITHM_TEXT_AUTOSIZING = 3
-
- def __init__(self):
- super().__init__()
- self._javascript_enabled = False
- self._dom_storage_enabled = False
- self._allow_file_access = True
- self._built_in_zoom_controls = True
- self._display_zoom_controls = True
- self._load_with_overview_mode = False
- self._support_zoom = True
- self._use_wide_view_port = False
- self._database_enabled = False
- self._allow_content_access = True
- self._cache_mode = -1 # LOAD_DEFAULT
- self._user_agent_string: str = "Mozilla/5.0 (Linux; Android 13)"
- self._default_font_size = 16
- self._minimum_font_size = 8
- self._text_zoom = 100
- self._standard_font_family = "sans-serif"
- self._serif_font_family = "serif"
- self._sans_serif_font_family = "sans-serif"
- self._fixed_font_family = "monospace"
- self._cursive_font_family = "cursive"
- self._fantasy_font_family = "fantasy"
- self._default_encoding = "utf-8"
- self._layout_algorithm = WebSettings.LAYOUT_ALGORITHM_NORMAL
- self._block_network_image = False
- self._block_network_loads = False
- self._mixed_content_mode = 0 # MIXED_CONTENT_ALWAYS_ALLOW
- self._offscreen_pre_raster = False
- self._safe_browsing_enabled = True
-
- def setJavaScriptEnabled(self, enabled: bool):
- self._javascript_enabled = enabled
-
- def getJavaScriptEnabled(self) -> bool:
- return self._javascript_enabled
-
- def setDomStorageEnabled(self, enabled: bool):
- self._dom_storage_enabled = enabled
-
- def getDomStorageEnabled(self) -> bool:
- return self._dom_storage_enabled
-
- def setAllowFileAccess(self, allow: bool):
- self._allow_file_access = allow
-
- def getAllowFileAccess(self) -> bool:
- return self._allow_file_access
-
- def setBuiltInZoomControls(self, enabled: bool):
- self._built_in_zoom_controls = enabled
-
- def getBuiltInZoomControls(self) -> bool:
- return self._built_in_zoom_controls
-
- def setDisplayZoomControls(self, enabled: bool):
- self._display_zoom_controls = enabled
-
- def getDisplayZoomControls(self) -> bool:
- return self._display_zoom_controls
-
- def setSupportZoom(self, support: bool):
- self._support_zoom = support
-
- def supportZoom(self) -> bool:
- return self._support_zoom
-
- def setLoadWithOverviewMode(self, overview: bool):
- self._load_with_overview_mode = overview
-
- def getLoadWithOverviewMode(self) -> bool:
- return self._load_with_overview_mode
-
- def setUseWideViewPort(self, use: bool):
- self._use_wide_view_port = use
-
- def getUseWideViewPort(self) -> bool:
- return self._use_wide_view_port
-
- def setDatabaseEnabled(self, enabled: bool):
- self._database_enabled = enabled
-
- def getDatabaseEnabled(self) -> bool:
- return self._database_enabled
-
- def setAllowContentAccess(self, allow: bool):
- self._allow_content_access = allow
-
- def getAllowContentAccess(self) -> bool:
- return self._allow_content_access
-
- def setCacheMode(self, mode: int):
- self._cache_mode = mode
-
- def getCacheMode(self) -> int:
- return self._cache_mode
-
- LOAD_DEFAULT = -1
- LOAD_CACHE_ELSE_NETWORK = 1
- LOAD_NO_CACHE = 2
- LOAD_CACHE_ONLY = 3
-
- def setUserAgentString(self, ua: str):
- self._user_agent_string = ua
-
- def getUserAgentString(self) -> str:
- return self._user_agent_string
-
- def setDefaultFontSize(self, size: int):
- self._default_font_size = size
-
- def getDefaultFontSize(self) -> int:
- return self._default_font_size
-
- def setMinimumFontSize(self, size: int):
- self._minimum_font_size = size
-
- def getMinimumFontSize(self) -> int:
- return self._minimum_font_size
-
- def setTextZoom(self, text_zoom: int):
- self._text_zoom = text_zoom
-
- def getTextZoom(self) -> int:
- return self._text_zoom
-
- def setStandardFontFamily(self, font: str):
- self._standard_font_family = font
-
- def setSerifFontFamily(self, font: str):
- self._serif_font_family = font
-
- def setSansSerifFontFamily(self, font: str):
- self._sans_serif_font_family = font
-
- def setFixedFontFamily(self, font: str):
- self._fixed_font_family = font
-
- def setCursiveFontFamily(self, font: str):
- self._cursive_font_family = font
-
- def setFantasyFontFamily(self, font: str):
- self._fantasy_font_family = font
-
- def setDefaultTextEncodingName(self, encoding: str):
- self._default_encoding = encoding
-
- def getDefaultTextEncodingName(self) -> str:
- return self._default_encoding
-
- def setLayoutAlgorithm(self, algorithm: int):
- self._layout_algorithm = algorithm
-
- def getLayoutAlgorithm(self) -> int:
- return self._layout_algorithm
-
- def setBlockNetworkImage(self, block: bool):
- self._block_network_image = block
-
- def getBlockNetworkImage(self) -> bool:
- return self._block_network_image
-
- def setBlockNetworkLoads(self, block: bool):
- self._block_network_loads = block
-
- def getBlockNetworkLoads(self) -> bool:
- return self._block_network_loads
-
- def setMixedContentMode(self, mode: int):
- self._mixed_content_mode = mode
-
- def getMixedContentMode(self) -> int:
- return self._mixed_content_mode
-
- MIXED_CONTENT_ALWAYS_ALLOW = 0
- MIXED_CONTENT_NEVER_ALLOW = 1
- MIXED_CONTENT_COMPATIBILITY_MODE = 2
-
- def setOffscreenPreRaster(self, enabled: bool):
- self._offscreen_pre_raster = enabled
-
- def getOffscreenPreRaster(self) -> bool:
- return self._offscreen_pre_raster
-
- def setSafeBrowsingEnabled(self, enabled: bool):
- self._safe_browsing_enabled = enabled
-
- def getSafeBrowsingEnabled(self) -> bool:
- return self._safe_browsing_enabled
-
- def setNeedInitialFocus(self, flag: bool):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ViewAnimator / ViewFlipper / ViewSwitcher etc.
-# ═══════════════════════════════════════════════════════════════
-
-class ViewAnimator(FrameLayout):
- """ViewAnimator — 视图动画容器"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._which_child: int = 0
- self._animate_first_view: bool = False
- self._in_animation: Any = None
- self._out_animation: Any = None
-
- def setDisplayedChild(self, which_child: int):
- if 0 <= which_child < self.getChildCount():
- self._which_child = which_child
-
- def getDisplayedChild(self) -> int:
- return self._which_child
-
- def showNext(self):
- if self._which_child < self.getChildCount() - 1:
- self._which_child += 1
-
- def showPrevious(self):
- if self._which_child > 0:
- self._which_child -= 1
-
- def setInAnimation(self, in_animation: Any):
- self._in_animation = in_animation
-
- def getInAnimation(self) -> Any:
- return self._in_animation
-
- def setOutAnimation(self, out_animation: Any):
- self._out_animation = out_animation
-
- def getOutAnimation(self) -> Any:
- return self._out_animation
-
- def setAnimateFirstView(self, animate: bool):
- self._animate_first_view = animate
-
- def getAnimateFirstView(self) -> bool:
- return self._animate_first_view
-
- def getBaseline(self) -> int:
- return -1
-
-
-class ViewFlipper(ViewAnimator):
- """ViewFlipper — 视图翻转器"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._flip_interval: int = 3000
- self._auto_start: bool = False
- self._running: bool = False
- self._flip_timer: Any = None
-
- def setFlipInterval(self, milliseconds: int):
- self._flip_interval = milliseconds
-
- def getFlipInterval(self) -> int:
- return self._flip_interval
-
- def setAutoStart(self, auto_start: bool):
- self._auto_start = auto_start
-
- def isAutoStart(self) -> bool:
- return self._auto_start
-
- def startFlipping(self):
- self._running = True
-
- def stopFlipping(self):
- self._running = False
-
- def isFlipping(self) -> bool:
- return self._running
-
- def onDetachedFromWindow(self):
- super().onDetachedFromWindow()
- self._running = False
-
- def onAttachedToWindow(self):
- super().onAttachedToWindow()
- if self._auto_start:
- self._running = True
-
-
-class ViewSwitcher(ViewAnimator):
- """ViewSwitcher — 视图切换器"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._factory: Optional[Callable] = None
-
- class ViewFactory:
- def makeView(self) -> View:
- return View()
-
- def setFactory(self, factory: ViewFactory):
- self._factory = factory
-
- def getCurrentView(self) -> Optional[View]:
- return self.getChildAt(self._which_child)
-
- def getNextView(self) -> Optional[View]:
- next_index = self._which_child + 1
- if next_index < self.getChildCount():
- return self.getChildAt(next_index)
- return None
-
- def setInAnimation(self, in_animation: Any):
- super().setInAnimation(in_animation)
-
- def setOutAnimation(self, out_animation: Any):
- super().setOutAnimation(out_animation)
-
-
-class ImageSwitcher(ViewSwitcher):
- """ImageSwitcher — 图片切换器"""
-
- def setImageDrawable(self, drawable: Any):
- pass
-
- def setImageResource(self, resid: int):
- pass
-
- def setImageURI(self, uri: Any):
- pass
-
- def setImageBitmap(self, bitmap: Any):
- pass
-
-
-class TextSwitcher(ViewSwitcher):
- """TextSwitcher — 文本切换器"""
-
- def setCurrentText(self, text: str):
- if self.getChildCount() > 0:
- child = self.getChildAt(0)
- if hasattr(child, "setText"):
- child.setText(text)
-
- def setText(self, text: str):
- self.setCurrentText(text)
-
-
-class AdapterViewAnimator(AdapterView):
- """AdapterViewAnimator — 适配器视图动画器"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._in_animation: Any = None
- self._out_animation: Any = None
- self._displayed_child: int = 0
- self._loop_views: bool = False
-
- def setDisplayedChild(self, which_child: int):
- self._displayed_child = which_child
-
- def getDisplayedChild(self) -> int:
- return self._displayed_child
-
- def showNext(self):
- self._displayed_child = (self._displayed_child + 1) % max(1, self.getCount())
-
- def showPrevious(self):
- last = max(1, self.getCount())
- self._displayed_child = (self._displayed_child - 1) % last
-
- def setInAnimation(self, in_animation: Any):
- self._in_animation = in_animation
-
- def getInAnimation(self) -> Any:
- return self._in_animation
-
- def setOutAnimation(self, out_animation: Any):
- self._out_animation = out_animation
-
- def getOutAnimation(self) -> Any:
- return self._out_animation
-
- def getCurrentView(self) -> Optional[View]:
- return self.getChildAt(self._displayed_child)
-
- def getBaseline(self) -> int:
- return -1
-
- def getCount(self) -> int:
- if self._adapter:
- return self._adapter.getCount()
- return 0
-
-
-class AdapterViewFlipper(AdapterViewAnimator):
- """AdapterViewFlipper — 适配器视图翻转器"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._flip_interval: int = 10000
- self._auto_start: bool = False
- self._running: bool = False
-
- def setFlipInterval(self, milliseconds: int):
- self._flip_interval = milliseconds
-
- def getFlipInterval(self) -> int:
- return self._flip_interval
-
- def startFlipping(self):
- self._running = True
-
- def stopFlipping(self):
- self._running = False
-
- def isFlipping(self) -> bool:
- return self._running
-
- def setAutoStart(self, auto_start: bool):
- self._auto_start = auto_start
-
- def isAutoStart(self) -> bool:
- return self._auto_start
-
-
-class StackView(AdapterViewAnimator):
- """StackView — 栈视图"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# Adapters
-# ═══════════════════════════════════════════════════════════════
-
-class BaseAdapter(Stub):
- """BaseAdapter — 基础适配器"""
-
- def __init__(self):
- super().__init__()
- self._data_set_observable: Any = None
-
- def getCount(self) -> int:
- return 0
-
- def getItem(self, position: int) -> Any:
- return None
-
- def getItemId(self, position: int) -> int:
- return position
-
- def getView(self, position: int, convert_view: Optional[View], parent: Optional[ViewGroup]) -> View:
- return View()
-
- def getItemViewType(self, position: int) -> int:
- return 0
-
- def getViewTypeCount(self) -> int:
- return 1
-
- def hasStableIds(self) -> bool:
- return False
-
- def isEmpty(self) -> bool:
- return self.getCount() == 0
-
- def areAllItemsEnabled(self) -> bool:
- return True
-
- def isEnabled(self, position: int) -> bool:
- return True
-
- def getDropDownView(self, position: int, convert_view: Optional[View],
- parent: Optional[ViewGroup]) -> View:
- return self.getView(position, convert_view, parent)
-
- def notifyDataSetChanged(self):
- for observer in getattr(self, '_observers', []):
- observer.onChanged()
-
- def notifyDataSetInvalidated(self):
- for observer in getattr(self, '_observers', []):
- observer.onInvalidated()
-
- def registerDataSetObserver(self, observer):
- if not hasattr(self, '_observers'):
- self._observers = []
- self._observers.append(observer)
-
- def unregisterDataSetObserver(self, observer):
- if hasattr(self, '_observers'):
- try:
- self._observers.remove(observer)
- except ValueError:
- pass
-
-
-class ArrayAdapter(BaseAdapter):
- """ArrayAdapter — 数组适配器"""
-
- def __init__(self, context: Any, resource: int, objects: Optional[List[Any]] = None):
- super().__init__()
- self._context = context
- self._resource = resource
- self._drop_down_resource = resource
- self._objects: List[Any] = list(objects) if objects is not None else []
- self._field_id = 0
- self._notify_on_change = True
-
- def getCount(self) -> int:
- return len(self._objects)
-
- def getItem(self, position: int) -> Any:
- if 0 <= position < len(self._objects):
- return self._objects[position]
- return None
-
- def getPosition(self, item: Any) -> int:
- try:
- return self._objects.index(item)
- except ValueError:
- return -1
-
- def getView(self, position: int, convert_view: Optional[View],
- parent: Optional[ViewGroup]) -> View:
- if convert_view is not None:
- tv = convert_view
- else:
- tv = TextView(self._context)
- if hasattr(tv, "setText"):
- tv.setText(str(self.getItem(position) if self.getItem(position) is not None else ""))
- return tv
-
- def add(self, obj: Any):
- self._objects.append(obj)
- if self._notify_on_change:
- self.notifyDataSetChanged()
-
- def addAll(self, *items: Any):
- for item in items:
- self._objects.append(item)
- if self._notify_on_change:
- self.notifyDataSetChanged()
-
- def insert(self, obj: Any, index: int):
- self._objects.insert(index, obj)
- if self._notify_on_change:
- self.notifyDataSetChanged()
-
- def remove(self, obj: Any):
- if obj in self._objects:
- self._objects.remove(obj)
- if self._notify_on_change:
- self.notifyDataSetChanged()
-
- def clear(self):
- self._objects.clear()
- if self._notify_on_change:
- self.notifyDataSetChanged()
-
- def sort(self, comparator: Callable):
- self._objects.sort(key=comparator)
- if self._notify_on_change:
- self.notifyDataSetChanged()
-
- def setNotifyOnChange(self, notify_on_change: bool):
- self._notify_on_change = notify_on_change
-
- def getContext(self):
- return self._context
-
- def getCount(self) -> int:
- return len(self._objects)
-
- def setDropDownViewResource(self, resource: int):
- self._drop_down_resource = resource
-
- def getDropDownViewResource(self) -> int:
- return self._drop_down_resource
-
-
-class SimpleAdapter(BaseAdapter):
- """SimpleAdapter — 简单适配器"""
-
- def __init__(self, context: Any, data: List[Dict[str, Any]], resource: int,
- from_cols: List[str], to_ids: List[int]):
- super().__init__()
- self._context = context
- self._data = data
- self._resource = resource
- self._from = from_cols
- self._to = to_ids
- self._drop_down_resource = resource
-
- def getCount(self) -> int:
- return len(self._data)
-
- def getItem(self, position: int) -> Any:
- if 0 <= position < len(self._data):
- return self._data[position]
- return None
-
- def getView(self, position: int, convert_view: Optional[View],
- parent: Optional[ViewGroup]) -> View:
- if convert_view is not None:
- v = convert_view
- else:
- v = View(self._context)
- return v
-
- def setDropDownViewResource(self, resource: int):
- self._drop_down_resource = resource
-
-
-class CursorAdapter(BaseAdapter):
- """CursorAdapter — 游标适配器"""
-
- FLAG_AUTO_REQUERY = 0x01
- FLAG_REGISTER_CONTENT_OBSERVER = 0x02
-
- def __init__(self, context: Any, c: Any, flags: int = FLAG_AUTO_REQUERY):
- super().__init__()
- self._context = context
- self._cursor = c
- self._flags = flags
-
- def getCount(self) -> int:
- return 0
-
- def getItem(self, position: int) -> Any:
- return None
-
- def getView(self, position: int, convert_view: Optional[View],
- parent: Optional[ViewGroup]) -> View:
- return View(self._context)
-
- def bindView(self, view: View, context: Any, cursor: Any):
- pass
-
- def newView(self, context: Any, cursor: Any, parent: ViewGroup) -> View:
- return View(context)
-
- def getCursor(self) -> Any:
- return self._cursor
-
- def changeCursor(self, cursor: Any):
- self._cursor = cursor
- self.notifyDataSetChanged()
-
- def swapCursor(self, new_cursor: Any) -> Any:
- old = self._cursor
- self._cursor = new_cursor
- self.notifyDataSetChanged()
- return old
-
-
-# ═══════════════════════════════════════════════════════════════
-# Spinner
-# ═══════════════════════════════════════════════════════════════
-
-class Spinner(AdapterView):
- """Spinner — 下拉选择器"""
-
- MODE_DIALOG = 0
- MODE_DROPDOWN = 1
-
- def __init__(self, context=None, mode: int = MODE_DROPDOWN):
- super().__init__(context)
- self._mode = mode
- self._prompt: str = ""
- self._popup: Any = None
- self._on_item_selected_listener: Optional[Callable] = None
-
- class OnItemSelectedListener:
- def onItemSelected(self, parent: AdapterView, view: View, position: int, id_: int):
- pass
- def onNothingSelected(self, parent: AdapterView):
- pass
-
- def setOnItemSelectedListener(self, listener: Optional[OnItemSelectedListener]):
- self._on_item_selected_listener = listener
-
- def getOnItemSelectedListener(self) -> Optional[OnItemSelectedListener]:
- return self._on_item_selected_listener
-
- def setSelection(self, position: int, animate: bool = True):
- super().setSelection(position)
-
- def getSelectedItem(self) -> Any:
- return super().getSelectedItem()
-
- def getSelectedItemPosition(self) -> int:
- return self._selected_position
-
- def getSelectedView(self) -> Optional[View]:
- return None
-
- def setPrompt(self, prompt: str):
- self._prompt = prompt
-
- def getPrompt(self) -> str:
- return self._prompt
-
- def setPopupBackgroundDrawable(self, drawable: Any):
- pass
-
- def getPopupBackgroundDrawable(self) -> Any:
- return None
-
- def performClick(self) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# AutoCompleteTextView
-# ═══════════════════════════════════════════════════════════════
-
-class AutoCompleteTextView(EditText):
- """AutoCompleteTextView — 自动完成文本"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._threshold: int = 2
- self._completion_hint: str = ""
- self._drop_down_anchor: Optional[View] = None
- self._drop_down_horizontal_offset: int = 0
- self._drop_down_vertical_offset: int = 0
- self._drop_down_width: int = 0
- self._drop_down_height: int = 0
- self._on_item_click_listener: Optional[Callable] = None
- self._on_dismiss_listener: Optional[Callable] = None
- self._validator: Optional[Callable] = None
-
- def setThreshold(self, threshold: int):
- self._threshold = max(1, threshold)
-
- def getThreshold(self) -> int:
- return self._threshold
-
- def setAdapter(self, adapter: Any):
- self._adapter = adapter
-
- def getAdapter(self) -> Any:
- return self._adapter
-
- def setOnItemClickListener(self, listener: Optional[Callable]):
- self._on_item_click_listener = listener
-
- def getOnItemClickListener(self) -> Optional[Callable]:
- return self._on_item_click_listener
-
- def setCompletionHint(self, hint: str):
- self._completion_hint = hint
-
- def getCompletionHint(self) -> str:
- return self._completion_hint
-
- def setDropDownAnchor(self, anchor_id: int):
- pass
-
- def setDropDownHorizontalOffset(self, offset: int):
- self._drop_down_horizontal_offset = offset
-
- def getDropDownHorizontalOffset(self) -> int:
- return self._drop_down_horizontal_offset
-
- def setDropDownVerticalOffset(self, offset: int):
- self._drop_down_vertical_offset = offset
-
- def getDropDownVerticalOffset(self) -> int:
- return self._drop_down_vertical_offset
-
- def setDropDownWidth(self, width: int):
- self._drop_down_width = width
-
- def getDropDownWidth(self) -> int:
- return self._drop_down_width
-
- def showDropDown(self):
- pass
-
- def dismissDropDown(self):
- pass
-
- def isDropDownShowing(self) -> bool:
- return False
-
- def enoughToFilter(self) -> bool:
- return len(self._text) >= self._threshold
-
- def setValidator(self, validator: Optional[Callable]):
- self._validator = validator
-
- def getValidator(self) -> Optional[Callable]:
- return self._validator
-
- def performValidation(self):
- pass
-
- def setOnDismissListener(self, listener: Optional[Callable]):
- self._on_dismiss_listener = listener
-
- def performFiltering(self, text: str, key_code: int):
- pass
-
- def onFilterComplete(self, count: int):
- pass
-
-
-class MultiAutoCompleteTextView(AutoCompleteTextView):
- """MultiAutoCompleteTextView — 多值自动完成文本"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._tokenizer: Optional[Callable] = None
-
- class CommaTokenizer:
- def tokenize(self, text: str) -> List[str]:
- return text.split(",")
- def findTokenStart(self, text: str, cursor: int) -> int:
- return text.rfind(",", 0, cursor) + 1
- def findTokenEnd(self, text: str, cursor: int) -> int:
- next_comma = text.find(",", cursor)
- return next_comma if next_comma >= 0 else len(text)
- def terminateToken(self, text: str) -> str:
- return text + ","
-
- def setTokenizer(self, tokenizer: Any):
- self._tokenizer = tokenizer
-
- def getTokenizer(self) -> Any:
- return self._tokenizer
-
-
-# ═══════════════════════════════════════════════════════════════
-# DatePicker / TimePicker / CalendarView / NumberPicker
-# ═══════════════════════════════════════════════════════════════
-
-class DatePicker(FrameLayout):
- """DatePicker — 日期选择器"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._year: int = 2024
- self._month: int = 0 # 0-based
- self._day_of_month: int = 1
- self._min_date: int = 0
- self._max_date: int = 0
- self._spinners_shown: bool = True
- self._calendar_view_shown: bool = False
- self._on_date_changed_listener: Optional[Callable] = None
- self._calendar_view: Optional[CalendarView] = None
-
- class OnDateChangedListener:
- def onDateChanged(self, view: "DatePicker", year: int, month_of_year: int, day_of_month: int):
- pass
-
- def init(self, year: int, month: int, day_of_month: int,
- listener: Optional[OnDateChangedListener] = None):
- self._year = year
- self._month = month
- self._day_of_month = day_of_month
- self._on_date_changed_listener = listener
- if listener:
- listener.onDateChanged(self, year, month, day_of_month)
-
- def getYear(self) -> int:
- return self._year
-
- def getMonth(self) -> int:
- return self._month
-
- def getDayOfMonth(self) -> int:
- return self._day_of_month
-
- def setMinDate(self, min_date: int):
- self._min_date = min_date
-
- def getMinDate(self) -> int:
- return self._min_date
-
- def setMaxDate(self, max_date: int):
- self._max_date = max_date
-
- def getMaxDate(self) -> int:
- return self._max_date
-
- def setSpinnersShown(self, shown: bool):
- self._spinners_shown = shown
-
- def setCalendarViewShown(self, shown: bool):
- self._calendar_view_shown = shown
-
- def getCalendarView(self) -> Optional["CalendarView"]:
- return self._calendar_view
-
- def setOnDateChangedListener(self, listener: Optional[OnDateChangedListener]):
- self._on_date_changed_listener = listener
-
- def updateDate(self, year: int, month: int, day_of_month: int):
- self._year = year
- self._month = month
- self._day_of_month = day_of_month
- if self._on_date_changed_listener:
- self._on_date_changed_listener.onDateChanged(self, year, month, day_of_month)
-
-
-class TimePicker(FrameLayout):
- """TimePicker — 时间选择器"""
-
- MODE_CLOCK = 0
- MODE_SPINNER = 1
-
- def __init__(self, context=None, mode: int = MODE_CLOCK):
- super().__init__(context)
- self._current_hour: int = 12
- self._current_minute: int = 0
- self._is24_hour_view: Optional[bool] = None # None = system default
- self._mode = mode
- self._on_time_changed_listener: Optional[Callable] = None
-
- class OnTimeChangedListener:
- def onTimeChanged(self, view: "TimePicker", hour_of_day: int, minute: int):
- pass
-
- def setOnTimeChangedListener(self, listener: Optional[OnTimeChangedListener]):
- self._on_time_changed_listener = listener
-
- def getOnTimeChangedListener(self) -> Optional[OnTimeChangedListener]:
- return self._on_time_changed_listener
-
- def getCurrentHour(self) -> int:
- return self._current_hour
-
- def setCurrentHour(self, current_hour: int):
- self._current_hour = current_hour % 24
- if self._on_time_changed_listener:
- self._on_time_changed_listener.onTimeChanged(self, self._current_hour, self._current_minute)
-
- def getCurrentMinute(self) -> int:
- return self._current_minute
-
- def setCurrentMinute(self, current_minute: int):
- self._current_minute = current_minute % 60
- if self._on_time_changed_listener:
- self._on_time_changed_listener.onTimeChanged(self, self._current_hour, self._current_minute)
-
- def setIs24HourView(self, is24_hour_view: Optional[bool]):
- self._is24_hour_view = is24_hour_view
-
- def is24HourView(self) -> bool:
- if self._is24_hour_view is not None:
- return self._is24_hour_view
- return False
-
- def getMode(self) -> int:
- return self._mode
-
- def setHour(self, hour: int):
- self.setCurrentHour(hour)
-
- def getHour(self) -> int:
- return self.getCurrentHour()
-
- def setMinute(self, minute: int):
- self.setCurrentMinute(minute)
-
- def getMinute(self) -> int:
- return self.getCurrentMinute()
-
-
-class CalendarView(FrameLayout):
- """CalendarView — 日历视图"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._date: int = 0
- self._min_date: int = 0
- self._max_date: int = 0
- self._first_day_of_week: int = 1 # Sunday=1
- self._week_separator: bool = False
- self._on_date_change_listener: Optional[Callable] = None
- self._shown_week_count: int = 6
-
- class OnDateChangeListener:
- def onSelectedDayChange(self, view: "CalendarView", year: int, month: int, day_of_month: int):
- pass
-
- def setOnDateChangeListener(self, listener: Optional[OnDateChangeListener]):
- self._on_date_change_listener = listener
-
- def getDate(self) -> int:
- return self._date
-
- def setDate(self, date: int, animate: bool = True, center: bool = True):
- self._date = date
-
- def getMinDate(self) -> int:
- return self._min_date
-
- def setMinDate(self, min_date: int):
- self._min_date = min_date
-
- def getMaxDate(self) -> int:
- return self._max_date
-
- def setMaxDate(self, max_date: int):
- self._max_date = max_date
-
- def getFirstDayOfWeek(self) -> int:
- return self._first_day_of_week
-
- def setFirstDayOfWeek(self, first_day_of_week: int):
- self._first_day_of_week = first_day_of_week
-
- def setWeekSeparatorDrawable(self, drawable: Any):
- self._week_separator = True
-
- def getShownWeekCount(self) -> int:
- return self._shown_week_count
-
- def setShownWeekCount(self, count: int):
- self._shown_week_count = count
-
-
-class NumberPicker(ViewGroup):
- """NumberPicker — 数字选择器"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._min_value: int = 0
- self._max_value: int = 100
- self._value: int = 0
- self._displayed_values: Optional[List[str]] = None
- self._on_value_change_listener: Optional[Callable] = None
- self._on_scroll_listener: Optional[Callable] = None
- self._wrap_selector_wheel: bool = True
- self._selection_divider: bool = True
-
- class OnValueChangeListener:
- def onValueChange(self, picker: "NumberPicker", old_val: int, new_val: int):
- pass
-
- class OnScrollListener:
- def onScrollStateChange(self, picker: "NumberPicker", state: int):
- pass
-
- SCROLL_STATE_IDLE = 0
- SCROLL_STATE_TOUCH_SCROLL = 1
- SCROLL_STATE_FLING = 2
-
- def setMinValue(self, min_value: int):
- self._min_value = min_value
- if self._value < self._min_value:
- self._value = self._min_value
-
- def getMinValue(self) -> int:
- return self._min_value
-
- def setMaxValue(self, max_value: int):
- self._max_value = max_value
- if self._value > self._max_value:
- self._value = self._max_value
-
- def getMaxValue(self) -> int:
- return self._max_value
-
- def setValue(self, value: int):
- old_value = self._value
- self._value = max(self._min_value, min(self._max_value, value))
- if self._on_value_change_listener and old_value != self._value:
- self._on_value_change_listener.onValueChange(self, old_value, self._value)
-
- def getValue(self) -> int:
- return self._value
-
- def setDisplayedValues(self, displayed_values: Optional[List[str]]):
- self._displayed_values = displayed_values
-
- def getDisplayedValues(self) -> Optional[List[str]]:
- return self._displayed_values
-
- def setOnValueChangedListener(self, listener: Optional[OnValueChangeListener]):
- self._on_value_change_listener = listener
-
- def setOnScrollListener(self, listener: Optional[OnScrollListener]):
- self._on_scroll_listener = listener
-
- def setWrapSelectorWheel(self, wrap: bool):
- self._wrap_selector_wheel = wrap
-
- def getWrapSelectorWheel(self) -> bool:
- return self._wrap_selector_wheel
-
- def setSelectionDivider(self, divider: Any):
- self._selection_divider = True
-
-
-# ═══════════════════════════════════════════════════════════════
-# VideoView / MediaController
-# ═══════════════════════════════════════════════════════════════
-
-class VideoView(SurfaceView):
- """VideoView — 视频播放视图"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._video_path: Optional[str] = None
- self._uri: Any = None
- self._media_controller: Optional["MediaController"] = None
- self._on_prepared_listener: Optional[Callable] = None
- self._on_completion_listener: Optional[Callable] = None
- self._on_error_listener: Optional[Callable] = None
- self._is_playing: bool = False
- self._current_position: int = 0
- self._duration: int = 0
- self._can_seek_back: bool = True
- self._can_seek_forward: bool = True
- self._can_pause: bool = True
- self._video_width: int = 0
- self._video_height: int = 0
-
- def setVideoPath(self, path: str):
- self._video_path = path
-
- def setVideoURI(self, uri: Any):
- self._uri = uri
-
- def setMediaController(self, controller: "MediaController"):
- self._media_controller = controller
-
- def setOnPreparedListener(self, listener: Optional[Callable]):
- self._on_prepared_listener = listener
-
- def setOnCompletionListener(self, listener: Optional[Callable]):
- self._on_completion_listener = listener
-
- def setOnErrorListener(self, listener: Optional[Callable]):
- self._on_error_listener = listener
-
- def start(self):
- self._is_playing = True
-
- def stopPlayback(self):
- self._is_playing = False
- self._current_position = 0
-
- def pause(self):
- self._is_playing = False
-
- def resume(self):
- self._is_playing = True
-
- def seekTo(self, msec: int):
- self._current_position = max(0, min(msec, self._duration))
-
- def getCurrentPosition(self) -> int:
- return self._current_position
-
- def getDuration(self) -> int:
- return self._duration
-
- def isPlaying(self) -> bool:
- return self._is_playing
-
- def canSeekForward(self) -> bool:
- return self._can_seek_forward
-
- def canSeekBackward(self) -> bool:
- return self._can_seek_back
-
- def canPause(self) -> bool:
- return self._can_pause
-
- def getBufferPercentage(self) -> int:
- return 100
-
- def resolveAdjustedSize(self, desired_size: int, measure_spec: int) -> int:
- from .view import MeasureSpec
- return MeasureSpec.getSize(measure_spec)
-
- def setVideoWidth(self, video_width: int):
- self._video_width = video_width
-
- def setVideoHeight(self, video_height: int):
- self._video_height = video_height
-
- @property
- def videoWidth(self) -> int:
- return self._video_width
-
- @property
- def videoHeight(self) -> int:
- return self._video_height
-
-
-class MediaController(FrameLayout):
- """MediaController — 媒体控制器"""
-
- def __init__(self, context=None, target: Optional[VideoView] = None):
- super().__init__(context)
- self._target = target
- self._anchor_view: Optional[View] = None
- self._is_showing: bool = False
- self._set_up_listener: Optional[Callable] = None
-
- def setMediaPlayer(self, player: "MediaController.MediaPlayerControl"):
- pass
-
- def setAnchorView(self, view: View):
- self._anchor_view = view
-
- def show(self, timeout: int = 3000):
- self._is_showing = True
-
- def hide(self):
- self._is_showing = False
-
- def isShowing(self) -> bool:
- return self._is_showing
-
- def setEnabled(self, enabled: bool):
- super().setEnabled(enabled)
-
- def setOnPrepareListener(self, listener: Optional[Callable]):
- self._set_up_listener = listener
-
- class MediaPlayerControl:
- def start(self):
- pass
- def pause(self):
- pass
- def getDuration(self) -> int:
- return 0
- def getCurrentPosition(self) -> int:
- return 0
- def seekTo(self, pos: int):
- pass
- def isPlaying(self) -> bool:
- return False
- def getBufferPercentage(self) -> int:
- return 0
- def canPause(self) -> bool:
- return False
- def canSeekBackward(self) -> bool:
- return False
- def canSeekForward(self) -> bool:
- return False
- def getAudioSessionId(self) -> int:
- return 0
-
-
-# ═══════════════════════════════════════════════════════════════
-# Toast
-# ═══════════════════════════════════════════════════════════════
-
-class Toast(Stub):
- """Toast — 提示消息"""
-
- LENGTH_SHORT = 0
- LENGTH_LONG = 1
-
- def __init__(self, context=None):
- super().__init__()
- if context is None:
- context = android_context
- self._context = context
- self._duration = Toast.LENGTH_SHORT
- self._gravity = Gravity.NO_GRAVITY
- self._x_offset: int = 0
- self._y_offset: int = 0
- self._view: Optional[View] = None
- self._text: str = ""
- self._horizontal_margin: float = 0.0
- self._vertical_margin: float = 0.0
- self._next_view: Optional[View] = None
-
- @staticmethod
- def makeText(context: Any, text: str, duration: int) -> "Toast":
- toast = Toast(context)
- toast._text = text
- toast._duration = duration
- return toast
-
- def show(self):
- if _USE_LINUX:
- LinuxNotify.send("Toast", self._text)
- else:
- print(f"[Toast] {self._text}")
-
- def cancel(self):
- if _USE_LINUX:
- # 桌面通知自动消失,无需操作
- return
- pass
-
- def setGravity(self, gravity: int, x_offset: int, y_offset: int):
- self._gravity = gravity
- self._x_offset = x_offset
- self._y_offset = y_offset
-
- def setDuration(self, duration: int):
- self._duration = duration
-
- def getDuration(self) -> int:
- return self._duration
-
- def setView(self, view: View):
- self._view = view
-
- def getView(self) -> Optional[View]:
- return self._view
-
- def setMargin(self, horizontal_margin: float, vertical_margin: float):
- self._horizontal_margin = horizontal_margin
- self._vertical_margin = vertical_margin
-
- def getHorizontalMargin(self) -> float:
- return self._horizontal_margin
-
- def getVerticalMargin(self) -> float:
- return self._vertical_margin
-
- def setText(self, text: str):
- self._text = text
-
- def setNextAnnouncementView(self, view: View):
- self._next_view = view
-
- def getNextAnnouncementView(self) -> Optional[View]:
- return self._next_view
-
- def isTouchable(self) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# PopupMenu / PopupWindow
-# ═══════════════════════════════════════════════════════════════
-
-class PopupMenu(Stub):
- """PopupMenu — 弹出菜单"""
-
- def __init__(self, context: Any, anchor: View, gravity: int = Gravity.NO_GRAVITY):
- super().__init__()
- self._context = context
- self._anchor = anchor
- self._gravity = gravity
- self._menu: "PopupMenu.Menu" = PopupMenu.Menu()
- self._on_menu_item_click_listener: Optional[Callable] = None
- self._on_dismiss_listener: Optional[Callable] = None
-
- class Menu(Stub):
- """PopupMenu.Menu — 弹出菜单项列表"""
-
- def __init__(self):
- super().__init__()
- self._items: List[Dict] = []
-
- def add(self, title: str) -> Any:
- item_id = len(self._items)
- self._items.append({"id": item_id, "title": title, "enabled": True})
- return item_id
-
- def findItem(self, id_: int) -> Optional[Dict]:
- for item in self._items:
- if item["id"] == id_:
- return item
- return None
-
- def removeItem(self, id_: int):
- for i, item in enumerate(self._items):
- if item["id"] == id_:
- self._items.pop(i)
- break
-
- def size(self) -> int:
- return len(self._items)
-
- def getItem(self, index: int) -> Optional[Dict]:
- if 0 <= index < len(self._items):
- return self._items[index]
- return None
-
- def clear(self):
- self._items.clear()
-
- def setOnMenuItemClickListener(self, listener: Optional[Callable]):
- pass
-
- def getMenu(self) -> "PopupMenu.Menu":
- return self._menu
-
- def inflate(self, menu_res_id: int):
- pass
-
- def show(self):
- pass
-
- def dismiss(self):
- pass
-
- def setOnMenuItemClickListener(self, listener: Optional[Callable]):
- self._on_menu_item_click_listener = listener
-
- def setOnDismissListener(self, listener: Optional[Callable]):
- self._on_dismiss_listener = listener
-
- def getDragToOpenListener(self) -> Optional[Callable]:
- return None
-
- def setForceShowIcon(self, force_show: bool):
- pass
-
-
-class PopupWindow(Stub):
- """PopupWindow — 弹出窗口"""
-
- def __init__(self, content_view: Optional[View] = None,
- width: int = ViewGroup.LayoutParams.WRAP_CONTENT,
- height: int = ViewGroup.LayoutParams.WRAP_CONTENT,
- focusable: bool = True):
- super().__init__()
- self._content_view = content_view
- self._width = width
- self._height = height
- self._focusable = focusable
- self._is_showing: bool = False
- self._outside_touchable: bool = False
- self._touchable: bool = True
- self._background_drawable: Any = None
- self._animation_style: int = -1
- self._elevation: float = 0.0
- self._input_method_mode: int = -1
- self._soft_input_mode: int = -1
- self._on_dismiss_listener: Optional[Callable] = None
- self._window_layout_type: int = 1000 # TYPE_APPLICATION_PANEL
- self._overlap_anchor: bool = True
- self._clip_to_screen: bool = True
- self._split_enabled: bool = False
- self._width_mode: int = 0
- self._height_mode: int = 0
-
- def showAsDropDown(self, anchor: View, x_off: int = 0, y_off: int = 0,
- gravity: int = Gravity.NO_GRAVITY):
- self._is_showing = True
-
- def showAtLocation(self, parent: View, gravity: int, x: int, y: int):
- self._is_showing = True
-
- def dismiss(self):
- self._is_showing = False
- if self._on_dismiss_listener:
- self._on_dismiss_listener()
-
- def isShowing(self) -> bool:
- return self._is_showing
-
- def setContentView(self, content_view: View):
- self._content_view = content_view
-
- def getContentView(self) -> Optional[View]:
- return self._content_view
-
- def setWidth(self, width: int):
- self._width = width
-
- def getWidth(self) -> int:
- return self._width
-
- def setHeight(self, height: int):
- self._height = height
-
- def getHeight(self) -> int:
- return self._height
-
- def setFocusable(self, focusable: bool):
- self._focusable = focusable
-
- def isFocusable(self) -> bool:
- return self._focusable
-
- def setOutsideTouchable(self, touchable: bool):
- self._outside_touchable = touchable
-
- def isOutsideTouchable(self) -> bool:
- return self._outside_touchable
-
- def setTouchable(self, touchable: bool):
- self._touchable = touchable
-
- def isTouchable(self) -> bool:
- return self._touchable
-
- def setBackgroundDrawable(self, background: Any):
- self._background_drawable = background
-
- def getBackground(self) -> Any:
- return self._background_drawable
-
- def setAnimationStyle(self, anim_style: int):
- self._animation_style = anim_style
-
- def getAnimationStyle(self) -> int:
- return self._animation_style
-
- def setElevation(self, elevation: float):
- self._elevation = elevation
-
- def getElevation(self) -> float:
- return self._elevation
-
- def setOnDismissListener(self, listener: Optional[Callable]):
- self._on_dismiss_listener = listener
-
- def setTouchInterceptor(self, interceptor: Optional[Callable]):
- pass
-
- def setClippingEnabled(self, enabled: bool):
- self._clip_to_screen = enabled
-
- def isClippingEnabled(self) -> bool:
- return self._clip_to_screen
-
- def setSplitTouchEnabled(self, enabled: bool):
- self._split_enabled = enabled
-
- def isSplitTouchEnabled(self) -> bool:
- return self._split_enabled
-
- def setWindowLayoutType(self, layout_type: int):
- self._window_layout_type = layout_type
-
- def getWindowLayoutType(self) -> int:
- return self._window_layout_type
-
- def setSoftInputMode(self, mode: int):
- self._soft_input_mode = mode
-
- def getSoftInputMode(self) -> int:
- return self._soft_input_mode
-
- def setInputMethodMode(self, mode: int):
- self._input_method_mode = mode
-
- def getInputMethodMode(self) -> int:
- return self._input_method_mode
-
- INPUT_METHOD_FROM_FOCUSABLE = 0
- INPUT_METHOD_NEEDED = 1
- INPUT_METHOD_NOT_NEEDED = 2
-
-
-# ═══════════════════════════════════════════════════════════════
-# Toolbar
-# ═══════════════════════════════════════════════════════════════
-
-class Toolbar(ViewGroup):
- """Toolbar — 工具栏"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._title: str = ""
- self._subtitle: str = ""
- self._navigation_icon: Any = None
- self._navigation_content_description: str = ""
- self._logo: Any = None
- self._logo_description: str = ""
- self._title_text_color: int = 0
- self._subtitle_text_color: int = 0
- self._collapse_icon: Any = None
- self._menu: Any = None
- self._on_menu_item_click_listener: Optional[Callable] = None
- self._navigation_on_click_listener: Optional[Callable] = None
- self._popup_theme: int = 0
- self._content_inset_start: int = 16
- self._content_inset_end: int = 16
- self._title_margin_start: int = 0
-
- def setTitle(self, title: str):
- self._title = title
-
- def getTitle(self) -> str:
- return self._title
-
- def setSubtitle(self, subtitle: str):
- self._subtitle = subtitle
-
- def getSubtitle(self) -> str:
- return self._subtitle
-
- def setNavigationIcon(self, icon: Any):
- self._navigation_icon = icon
-
- def getNavigationIcon(self) -> Any:
- return self._navigation_icon
-
- def setNavigationContentDescription(self, description: str):
- self._navigation_content_description = description
-
- def getNavigationContentDescription(self) -> str:
- return self._navigation_content_description
-
- def setLogo(self, logo: Any):
- self._logo = logo
-
- def getLogo(self) -> Any:
- return self._logo
-
- def setLogoDescription(self, description: str):
- self._logo_description = description
-
- def getLogoDescription(self) -> str:
- return self._logo_description
-
- def setTitleTextColor(self, color: int):
- self._title_text_color = color
-
- def setSubtitleTextColor(self, color: int):
- self._subtitle_text_color = color
-
- def inflateMenu(self, menu_res_id: int):
- pass
-
- def getMenu(self) -> Any:
- return self._menu
-
- def setOnMenuItemClickListener(self, listener: Optional[Callable]):
- self._on_menu_item_click_listener = listener
-
- def setNavigationOnClickListener(self, listener: Optional[Callable]):
- self._navigation_on_click_listener = listener
-
- def setCollapseIcon(self, icon: Any):
- self._collapse_icon = icon
-
- def getCollapseIcon(self) -> Any:
- return self._collapse_icon
-
- def setPopupTheme(self, res_id: int):
- self._popup_theme = res_id
-
- def getPopupTheme(self) -> int:
- return self._popup_theme
-
- def setContentInsetsRelative(self, content_inset_start: int, content_inset_end: int):
- self._content_inset_start = content_inset_start
- self._content_inset_end = content_inset_end
-
- def getContentInsetStart(self) -> int:
- return self._content_inset_start
-
- def getContentInsetEnd(self) -> int:
- return self._content_inset_end
-
- def collapseActionView(self):
- pass
-
- def dismissPopupMenus(self):
- pass
-
- def isOverflowMenuShowing(self) -> bool:
- return False
-
- def showOverflowMenu(self) -> bool:
- return False
-
- def hideOverflowMenu(self) -> bool:
- return False
-
- def getOverflowIcon(self) -> Any:
- return None
-
- def setOverflowIcon(self, icon: Any):
- pass
-
-
-class ActionMenuView(LinearLayout):
- """ActionMenuView — 操作菜单视图"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# TabHost / TabWidget
-# ═══════════════════════════════════════════════════════════════
-
-class TabHost(FrameLayout):
- """TabHost — 标签主机"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._tab_widget: Optional["TabWidget"] = None
- self._tab_content: Optional[FrameLayout] = None
- self._tabs: List["TabHost.TabSpec"] = []
- self._current_tab: int = 0
- self._on_tab_changed_listener: Optional[Callable] = None
- self._local_activity_manager: Any = None
-
- class TabSpec(Stub):
- """TabHost.TabSpec — 标签规格"""
-
- def __init__(self, tag: str):
- super().__init__()
- self._tag = tag
- self._indicator: Any = None
- self._content: Any = None
- self._content_view: Optional[View] = None
-
- def setIndicator(self, indicator: Any) -> "TabHost.TabSpec":
- self._indicator = indicator
- return self
-
- def setContent(self, content: Any) -> "TabHost.TabSpec":
- self._content = content
- return self
-
- def setContent(self, view_id: int) -> "TabHost.TabSpec":
- return self
-
- def setContent(self, view: View) -> "TabHost.TabSpec":
- self._content_view = view
- return self
-
- def getTag(self) -> str:
- return self._tag
-
- def getIndicator(self) -> Any:
- return self._indicator
-
- class OnTabChangeListener:
- def onTabChanged(self, tab_id: str):
- pass
-
- def setup(self):
- pass
-
- def newTabSpec(self, tag: str) -> "TabHost.TabSpec":
- spec = TabHost.TabSpec(tag)
- self._tabs.append(spec)
- return spec
-
- def addTab(self, tab_spec: "TabHost.TabSpec"):
- if tab_spec not in self._tabs:
- self._tabs.append(tab_spec)
-
- def setCurrentTab(self, index: int):
- if 0 <= index < len(self._tabs):
- self._current_tab = index
-
- def setCurrentTabByTag(self, tag: str):
- for i, tab in enumerate(self._tabs):
- if tab.getTag() == tag:
- self._current_tab = i
- break
-
- def getCurrentTab(self) -> int:
- return self._current_tab
-
- def getCurrentTabTag(self) -> str:
- if 0 <= self._current_tab < len(self._tabs):
- return self._tabs[self._current_tab].getTag()
- return ""
-
- def getTabWidget(self) -> "TabWidget":
- return self._tab_widget
-
- def getTabContentView(self) -> FrameLayout:
- return self._tab_content
-
- def setOnTabChangedListener(self, listener: Optional[OnTabChangeListener]):
- self._on_tab_changed_listener = listener
-
- def clearAllTabs(self):
- self._tabs.clear()
- self._current_tab = 0
-
-
-class TabWidget(LinearLayout):
- """TabWidget — 标签部件"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._strip: Any = None
- self._left_strip: Any = None
- self._right_strip: Any = None
- self._selected_tab: int = -1
- self._draw_full_strip: bool = False
-
- def setStripEnabled(self, strip_enabled: bool):
- self._draw_full_strip = strip_enabled
-
- def isStripEnabled(self) -> bool:
- return self._draw_full_strip
-
- def setLeftStripDrawable(self, drawable: Any):
- self._left_strip = drawable
-
- def setRightStripDrawable(self, drawable: Any):
- self._right_strip = drawable
-
- def setDividerDrawable(self, drawable: Any):
- pass
-
- def focusCurrentTab(self, index: int):
- self._selected_tab = index
-
- def isEnabled(self) -> bool:
- return True
-
-
-# ═══════════════════════════════════════════════════════════════
-# ExpandableListView
-# ═══════════════════════════════════════════════════════════════
-
-class ExpandableListView(ListView):
- """ExpandableListView — 可展开列表视图"""
-
- PACKED_POSITION_TYPE_GROUP = 0
- PACKED_POSITION_TYPE_CHILD = 1
- PACKED_POSITION_TYPE_NULL = 2
- PACKED_POSITION_VALUE_NULL = 0xFFFFFFFF
-
- def __init__(self, context=None):
- super().__init__(context)
- self._expandable_adapter: Optional["ExpandableListAdapter"] = None
- self._on_group_collapse_listener: Optional[Callable] = None
- self._on_group_expand_listener: Optional[Callable] = None
- self._on_child_click_listener: Optional[Callable] = None
- self._on_group_click_listener: Optional[Callable] = None
-
- def setAdapter(self, adapter: "ExpandableListAdapter"):
- self._expandable_adapter = adapter
- self._adapter = adapter
-
- def getExpandableListAdapter(self) -> Optional["ExpandableListAdapter"]:
- return self._expandable_adapter
-
- def setOnGroupCollapseListener(self, listener: Optional[Callable]):
- self._on_group_collapse_listener = listener
-
- def setOnGroupExpandListener(self, listener: Optional[Callable]):
- self._on_group_expand_listener = listener
-
- def setOnChildClickListener(self, listener: Optional[Callable]):
- self._on_child_click_listener = listener
-
- def setOnGroupClickListener(self, listener: Optional[Callable]):
- self._on_group_click_listener = listener
-
- def expandGroup(self, group_pos: int, animate: bool = True) -> bool:
- return True
-
- def collapseGroup(self, group_pos: int) -> bool:
- return True
-
- def setOnItemClickListener(self, listener: Optional[Callable]):
- self._on_item_click_listener = listener
-
- def getOnItemClickListener(self) -> Optional[Callable]:
- return self._on_item_click_listener
-
- def setOnItemLongClickListener(self, listener: Optional[Callable]):
- self._on_item_long_click_listener = listener
-
- def getOnItemLongClickListener(self) -> Optional[Callable]:
- return self._on_item_long_click_listener
-
- def getPackedPositionType(self, packed_position: int) -> int:
- if packed_position == ExpandableListView.PACKED_POSITION_VALUE_NULL:
- return ExpandableListView.PACKED_POSITION_TYPE_NULL
- return ExpandableListView.PACKED_POSITION_TYPE_GROUP
-
- def getPackedPositionGroup(self, packed_position: int) -> int:
- return packed_position & 0xFFFF
-
- def getPackedPositionChild(self, packed_position: int) -> int:
- return (packed_position >> 16) & 0xFFFF
-
- @staticmethod
- def getPackedPositionForChild(group_position: int, child_position: int) -> int:
- return (child_position << 16) | group_position
-
- @staticmethod
- def getPackedPositionForGroup(group_position: int) -> int:
- return group_position
-
- def isGroupExpanded(self, group_position: int) -> bool:
- return False
-
- def setSelectedGroup(self, group_position: int):
- pass
-
- def setSelectedChild(self, group_position: int, child_position: int, should_expand_group: bool):
- pass
-
- def smoothScrollToPosition(self, position: int):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ExpandableListAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class ExpandableListAdapter(Stub):
- """ExpandableListAdapter — 可扩展列表适配器接口"""
-
- def __init__(self):
- super().__init__()
-
- def getGroupCount(self) -> int:
- raise AndroidOnlyError("ExpandableListAdapter.getGroupCount: not implemented")
-
- def getChildrenCount(self, group_position: int) -> int:
- raise AndroidOnlyError("ExpandableListAdapter.getChildrenCount: not implemented")
-
- def getGroup(self, group_position: int) -> Any:
- raise AndroidOnlyError("ExpandableListAdapter.getGroup: not implemented")
-
- def getChild(self, group_position: int, child_position: int) -> Any:
- raise AndroidOnlyError("ExpandableListAdapter.getChild: not implemented")
-
- def getGroupId(self, group_position: int) -> int:
- raise AndroidOnlyError("ExpandableListAdapter.getGroupId: not implemented")
-
- def getChildId(self, group_position: int, child_position: int) -> int:
- raise AndroidOnlyError("ExpandableListAdapter.getChildId: not implemented")
-
- def hasStableIds(self) -> bool:
- return False
-
- def getGroupView(self, group_position: int, is_expanded: bool,
- convert_view: Optional[Any], parent: Optional[Any]) -> Any:
- raise AndroidOnlyError("ExpandableListAdapter.getGroupView: not implemented")
-
- def getChildView(self, group_position: int, child_position: int,
- is_last_child: bool, convert_view: Optional[Any],
- parent: Optional[Any]) -> Any:
- raise AndroidOnlyError("ExpandableListAdapter.getChildView: not implemented")
-
- def isChildSelectable(self, group_position: int, child_position: int) -> bool:
- return True
-
- def areAllItemsEnabled(self) -> bool:
- return True
-
- def isEmpty(self) -> bool:
- return self.getGroupCount() == 0
-
- def onGroupCollapsed(self, group_position: int):
- pass
-
- def onGroupExpanded(self, group_position: int):
- pass
-
- def getCombinedGroupId(self, group_id: int) -> int:
- return group_id
-
- def getCombinedChildId(self, group_id: int, child_id: int) -> int:
- return (group_id << 32) | child_id
-
-
-# ═══════════════════════════════════════════════════════════════
-# SimpleExpandableListAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class SimpleExpandableListAdapter(ExpandableListAdapter, BaseAdapter):
- """SimpleExpandableListAdapter — 简单的可展开列表适配器"""
-
- def __init__(self, context: Any,
- group_data: List[Dict[str, Any]],
- group_layout: int,
- group_from: List[str],
- group_to: List[int],
- child_data: List[List[Dict[str, Any]]],
- child_layout: int,
- child_from: List[str],
- child_to: List[int]):
- super().__init__()
- self._context = context
- self._group_data = group_data
- self._group_layout = group_layout
- self._group_from = group_from
- self._group_to = group_to
- self._child_data = child_data
- self._child_layout = child_layout
- self._child_from = child_from
- self._child_to = child_to
-
- def getGroupCount(self) -> int:
- return len(self._group_data)
-
- def getChildrenCount(self, group_position: int) -> int:
- if 0 <= group_position < len(self._child_data):
- return len(self._child_data[group_position])
- return 0
-
- def getGroup(self, group_position: int) -> Any:
- if 0 <= group_position < len(self._group_data):
- return self._group_data[group_position]
- return None
-
- def getChild(self, group_position: int, child_position: int) -> Any:
- if 0 <= group_position < len(self._child_data):
- children = self._child_data[group_position]
- if 0 <= child_position < len(children):
- return children[child_position]
- return None
-
- def getGroupId(self, group_position: int) -> int:
- return group_position
-
- def getChildId(self, group_position: int, child_position: int) -> int:
- return child_position
-
- def getGroupView(self, group_position: int, is_expanded: bool,
- convert_view: Optional[Any], parent: Optional[Any]) -> Any:
- if convert_view is not None:
- view = convert_view
- else:
- view = TextView(self._context)
- view.setText(str(self.getGroup(group_position)))
- return view
-
- def getChildView(self, group_position: int, child_position: int,
- is_last_child: bool, convert_view: Optional[Any],
- parent: Optional[Any]) -> Any:
- if convert_view is not None:
- view = convert_view
- else:
- view = TextView(self._context)
- child = self.getChild(group_position, child_position)
- view.setText(str(child) if child else "")
- return view
-
- def isChildSelectable(self, group_position: int, child_position: int) -> bool:
- return True
-
- def getCount(self) -> int:
- return self.getGroupCount()
-
- def getItem(self, position: int) -> Any:
- return self.getGroup(position)
-
- def getItemId(self, position: int) -> int:
- return position
-
- def getView(self, position: int, convert_view: Optional[Any],
- parent: Optional[Any]) -> Any:
- return self.getGroupView(position, False, convert_view, parent)
-
-
-# ═══════════════════════════════════════════════════════════════
-# BaseExpandableListAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class BaseExpandableListAdapter(ExpandableListAdapter, BaseAdapter):
- """BaseExpandableListAdapter — 可展开列表适配器基类"""
-
- def __init__(self):
- super().__init__()
-
- def getGroupCount(self) -> int:
- return 0
-
- def getChildrenCount(self, group_position: int) -> int:
- return 0
-
- def getGroup(self, group_position: int) -> Any:
- return None
-
- def getChild(self, group_position: int, child_position: int) -> Any:
- return None
-
- def getGroupId(self, group_position: int) -> int:
- return group_position
-
- def getChildId(self, group_position: int, child_position: int) -> int:
- return child_position
-
- def getGroupView(self, group_position: int, is_expanded: bool,
- convert_view: Optional[Any], parent: Optional[Any]) -> Any:
- if convert_view is not None:
- view = convert_view
- else:
- view = TextView(android_context)
- view.setText(f"Group {group_position}")
- return view
-
- def getChildView(self, group_position: int, child_position: int,
- is_last_child: bool, convert_view: Optional[Any],
- parent: Optional[Any]) -> Any:
- if convert_view is not None:
- view = convert_view
- else:
- view = TextView(android_context)
- view.setText(f"Child {group_position}:{child_position}")
- return view
-
- def isChildSelectable(self, group_position: int, child_position: int) -> bool:
- return True
-
- def areAllItemsEnabled(self) -> bool:
- return True
-
- def onGroupCollapsed(self, group_position: int):
- pass
-
- def onGroupExpanded(self, group_position: int):
- pass
-
- def notifyDataSetChanged(self):
- pass
-
- def notifyDataSetInvalidated(self):
- pass
-
- def getCount(self) -> int:
- return self.getGroupCount()
-
- def getItem(self, position: int) -> Any:
- return self.getGroup(position)
-
- def getItemId(self, position: int) -> int:
- return position
-
- def getView(self, position: int, convert_view: Optional[Any],
- parent: Optional[Any]) -> Any:
- return self.getGroupView(position, False, convert_view, parent)
-
-
-# ═══════════════════════════════════════════════════════════════
-# SearchView
-# ═══════════════════════════════════════════════════════════════
-
-class SearchView(LinearLayout):
- """SearchView — 搜索视图"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._query: str = ""
- self._query_hint: Optional[str] = None
- self._iconified: bool = True
- self._iconified_by_default: bool = True
- self._submit_button_enabled: bool = False
- self._query_refinement_enabled: bool = False
- self._searchable_info: Any = None
- self._on_query_text_listener: Optional[Callable] = None
- self._on_close_listener: Optional[Callable] = None
- self._on_suggestion_listener: Optional[Callable] = None
- self._on_query_text_focus_change_listener: Optional[Callable] = None
- self._suggestion_adapter: Optional["CursorAdapter"] = None
- self._max_width: int = sys.maxsize
- self._on_search_click_listener: Optional[Callable] = None
-
- class OnQueryTextListener:
- def onQueryTextSubmit(self, query: str) -> bool:
- return False
-
- def onQueryTextChange(self, new_text: str) -> bool:
- return False
-
- class OnCloseListener:
- def onClose(self) -> bool:
- return False
-
- class OnSuggestionListener:
- def onSuggestionSelect(self, position: int) -> bool:
- return False
-
- def onSuggestionClick(self, position: int) -> bool:
- return False
-
- def setQuery(self, query: str, submit: bool = False):
- self._query = query
- if self._on_query_text_listener:
- self._on_query_text_listener.onQueryTextChange(query)
- if submit and self._on_query_text_listener:
- self._on_query_text_listener.onQueryTextSubmit(query)
-
- def getQuery(self) -> str:
- return self._query
-
- def setQueryHint(self, hint: Optional[str]):
- self._query_hint = hint
-
- def getQueryHint(self) -> Optional[str]:
- return self._query_hint
-
- def setIconified(self, iconified: bool):
- self._iconified = iconified
-
- def isIconified(self) -> bool:
- return self._iconified
-
- def setIconifiedByDefault(self, iconified: bool):
- self._iconified_by_default = iconified
-
- def isIconifiedByDefault(self) -> bool:
- return self._iconified_by_default
-
- def setSubmitButtonEnabled(self, enabled: bool):
- self._submit_button_enabled = enabled
-
- def isSubmitButtonEnabled(self) -> bool:
- return self._submit_button_enabled
-
- def setQueryRefinementEnabled(self, enable: bool):
- self._query_refinement_enabled = enable
-
- def isQueryRefinementEnabled(self) -> bool:
- return self._query_refinement_enabled
-
- def setOnQueryTextListener(self, listener: Optional["SearchView.OnQueryTextListener"]):
- self._on_query_text_listener = listener
-
- def getOnQueryTextListener(self) -> Optional["SearchView.OnQueryTextListener"]:
- return self._on_query_text_listener
-
- def setOnCloseListener(self, listener: Optional["SearchView.OnCloseListener"]):
- self._on_close_listener = listener
-
- def setOnSuggestionListener(self, listener: Optional["SearchView.OnSuggestionListener"]):
- self._on_suggestion_listener = listener
-
- def setOnSearchClickListener(self, listener: Optional[Callable]):
- self._on_search_click_listener = listener
-
- def setSuggestionsAdapter(self, adapter: Optional["CursorAdapter"]):
- self._suggestion_adapter = adapter
-
- def getSuggestionsAdapter(self) -> Optional["CursorAdapter"]:
- return self._suggestion_adapter
-
- def setMaxWidth(self, max_width: int):
- self._max_width = max_width
-
- def getMaxWidth(self) -> int:
- return self._max_width
-
- def onActionViewExpanded(self):
- self._iconified = False
-
- def onActionViewCollapsed(self):
- self._iconified = True
-
- def onClose(self) -> bool:
- if self._on_close_listener:
- return self._on_close_listener.onClose()
- self._iconified = self._iconified_by_default
- return True
-
- def clearFocus(self):
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# ZoomControls
-# ═══════════════════════════════════════════════════════════════
-
-class ZoomControls(LinearLayout):
- """ZoomControls — 缩放控件"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._zoom_in_enabled: bool = True
- self._zoom_out_enabled: bool = True
- self._zoom_speed: int = 300
- self._on_zoom_in_listener: Optional[Callable] = None
- self._on_zoom_out_listener: Optional[Callable] = None
-
- def show(self):
- self.setVisibility(View.VISIBLE)
-
- def hide(self):
- self.setVisibility(View.GONE)
-
- def setIsZoomInEnabled(self, is_enabled: bool):
- self._zoom_in_enabled = is_enabled
-
- def setIsZoomOutEnabled(self, is_enabled: bool):
- self._zoom_out_enabled = is_enabled
-
- def setOnZoomInClickListener(self, listener: Optional[Callable]):
- self._on_zoom_in_listener = listener
-
- def setOnZoomOutClickListener(self, listener: Optional[Callable]):
- self._on_zoom_out_listener = listener
-
- def setZoomSpeed(self, speed: int):
- self._zoom_speed = speed
-
- def getZoomSpeed(self) -> int:
- return self._zoom_speed
-
- def hasFocus(self) -> bool:
- return False
-
-
-# ═══════════════════════════════════════════════════════════════
-# DigitalClock
-# ═══════════════════════════════════════════════════════════════
-
-class DigitalClock(TextView):
- """DigitalClock — 数字时钟(API 14+ 已弃用)"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._format: str = "%H:%M:%S"
- self._update_interval: int = 1000
- self._running: bool = False
- self._timer: Optional[Any] = None
-
- def start(self):
- self._running = True
-
- def stop(self):
- self._running = False
-
- def setFormat(self, fmt: str):
- self._format = fmt
-
- def getFormat(self) -> str:
- return self._format
-
- def onTimeChanged(self):
- now = datetime.now().strftime(self._format) if hasattr(datetime, 'now') else "00:00:00"
- self.setText(now)
-
-
-# ═══════════════════════════════════════════════════════════════
-# AnalogClock
-# ═══════════════════════════════════════════════════════════════
-
-class AnalogClock(View):
- """AnalogClock — 模拟时钟(API 14+ 已弃用)"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._dial: Optional[Any] = None
- self._hand_hour: Optional[Any] = None
- self._hand_minute: Optional[Any] = None
- self._running: bool = False
- self._update_interval: int = 1000
-
- def start(self):
- self._running = True
- self.invalidate()
-
- def stop(self):
- self._running = False
-
- def onDraw(self, canvas: Any):
- super().onDraw(canvas)
-
- def setDialDrawable(self, drawable: Any):
- self._dial = drawable
-
- def setHourDrawable(self, drawable: Any):
- self._hand_hour = drawable
-
- def setMinuteDrawable(self, drawable: Any):
- self._hand_minute = drawable
-
-
-# ═══════════════════════════════════════════════════════════════
-# Chronometer
-# ═══════════════════════════════════════════════════════════════
-
-class Chronometer(TextView):
- """Chronometer — 计时器"""
-
- def __init__(self, context=None):
- super().__init__(context)
- self._base: int = 0
- self._format: Optional[str] = None
- self._running: bool = False
- self._visible: bool = True
- self._on_chronometer_tick_listener: Optional[Callable] = None
- self._count_down: bool = False
- self._elapsed: float = 0.0
-
- def start(self):
- self._running = True
-
- def stop(self):
- self._running = False
-
- def setBase(self, base: int):
- self._base = base
-
- def getBase(self) -> int:
- return self._base
-
- def setFormat(self, fmt: str):
- self._format = fmt
-
- def getFormat(self) -> Optional[str]:
- return self._format
-
- def setOnChronometerTickListener(self, listener: Optional[Callable]):
- self._on_chronometer_tick_listener = listener
-
- def getOnChronometerTickListener(self) -> Optional[Callable]:
- return self._on_chronometer_tick_listener
-
- def isCountDown(self) -> bool:
- return self._count_down
-
- def setCountDown(self, count_down: bool):
- self._count_down = count_down
-
- def getElapsedRealtime(self) -> float:
- return self._elapsed
-
- def setVisibility(self, visibility: int):
- self._visible = (visibility == View.VISIBLE)
- super().setVisibility(visibility)
-
- def onDraw(self, canvas: Any):
- super().onDraw(canvas)
- if self._running and self._on_chronometer_tick_listener:
- try:
- self._on_chronometer_tick_listener(self)
- except Exception:
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# __all__
-# ═══════════════════════════════════════════════════════════════
-
-__all__ = [
- # TextView hierarchy
- "TextView", "EditText", "Button", "ImageButton", "CheckBox",
- "RadioButton", "ToggleButton", "Switch",
- # ImageView
- "ImageView",
- # Progress
- "ProgressBar", "SeekBar", "RatingBar",
- # AdapterView hierarchy
- "AdapterView", "ListView", "GridView", "ExpandableListView",
- "Spinner", "AutoCompleteTextView", "MultiAutoCompleteTextView",
- # RecyclerView
- "RecyclerView", "RecyclerViewAdapter", "RecyclerViewViewHolder",
- "RecyclerViewLayoutManager", "LinearLayoutManager",
- "GridLayoutManager", "StaggeredGridLayoutManager",
- # Layouts
- "LinearLayout", "RelativeLayout", "FrameLayout",
- "TableLayout", "TableRow",
- # Scrolling
- "ScrollView", "HorizontalScrollView",
- # WebView
- "WebView", "WebSettings",
- # Adapters
- "BaseAdapter", "ArrayAdapter", "SimpleAdapter", "CursorAdapter",
- "ExpandableListAdapter", "SimpleExpandableListAdapter",
- "BaseExpandableListAdapter",
- # ViewAnimator
- "ViewAnimator", "ViewFlipper", "ViewSwitcher",
- "ImageSwitcher", "TextSwitcher",
- "AdapterViewAnimator", "StackView", "AdapterViewFlipper",
- # Date/Time
- "DatePicker", "TimePicker", "CalendarView", "NumberPicker",
- "DigitalClock", "AnalogClock", "Chronometer",
- # Media
- "VideoView", "MediaController",
- # Toast/Popup
- "Toast", "PopupMenu", "PopupWindow",
- # Toolbar
- "Toolbar", "ActionMenuView",
- # Tabs
- "TabHost", "TabWidget",
- # Search
- "SearchView",
- # Zoom
- "ZoomControls",
-]
\ No newline at end of file
diff --git a/android_pyapi/android/widget_adapter.py b/android_pyapi/android/widget_adapter.py
deleted file mode 100644
index 10e30c4..0000000
--- a/android_pyapi/android/widget_adapter.py
+++ /dev/null
@@ -1,1145 +0,0 @@
-"""
-Android Widget Adapter 组件 — ListAdapter, SpinnerAdapter, ArrayAdapter (扩展),
-CursorAdapter (扩展), RecyclerView.Adapter (扩展), RecyclerView.ViewHolder,
-PagerAdapter, FragmentPagerAdapter, PagerTitleStrip 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-from typing import Any, Callable, Dict, Generic, List, Optional, Tuple, TypeVar
-
-from .._core import Stub, AndroidOnlyError
-
-T = TypeVar("T")
-
-__all__ = [
- "ListAdapter", "SpinnerAdapter", "WrapperListAdapter",
- "HeaderViewListAdapter", "ArrayAdapter", "CursorAdapter",
- "SimpleCursorAdapter", "ResourceCursorAdapter", "SimpleAdapter",
- "BaseAdapter", "RecyclerView",
- "PagerAdapter", "FragmentPagerAdapter", "FragmentStatePagerAdapter",
- "PagerTitleStrip", "PagerTabStrip",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 适配器常量
-# ═══════════════════════════════════════════════════════════════
-
-ADAPTER_IGNORE_ITEM_VIEW_TYPE = -1
-ADAPTER_NO_SELECTION = -1
-ADAPTER_INVALID_POSITION = -1
-ADAPTER_INVALID_ROW_ID = -1
-ADAPTER_HAS_STABLE_IDS = True
-ADAPTER_NO_STABLE_IDS = False
-
-PAGER_POSITION_UNCHANGED = -1
-PAGER_POSITION_NONE = -2
-
-
-# ═══════════════════════════════════════════════════════════════
-# BaseAdapter (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class BaseAdapter(Stub):
- """BaseAdapter — 基础适配器 (完整版)"""
-
- def __init__(self):
- super().__init__()
- self._observers: List[Any] = []
-
- def getCount(self) -> int:
- return 0
-
- def getItem(self, position: int) -> Optional[Any]:
- return None
-
- def getItemId(self, position: int) -> int:
- return position
-
- def getView(self, position: int, convertView: Any, parent: Any) -> Any:
- return None
-
- def getItemViewType(self, position: int) -> int:
- return ADAPTER_IGNORE_ITEM_VIEW_TYPE
-
- def getViewTypeCount(self) -> int:
- return 1
-
- def hasStableIds(self) -> bool:
- return False
-
- def isEmpty(self) -> bool:
- return self.getCount() == 0
-
- def registerDataSetObserver(self, observer: Any):
- self._observers.append(observer)
-
- def unregisterDataSetObserver(self, observer: Any):
- self._observers = [o for o in self._observers if o is not observer]
-
- def notifyDataSetChanged(self):
- for o in self._observers:
- if hasattr(o, 'onChanged'):
- o.onChanged()
-
- def notifyDataSetInvalidated(self):
- for o in self._observers:
- if hasattr(o, 'onInvalidated'):
- o.onInvalidated()
-
- def areAllItemsEnabled(self) -> bool:
- return True
-
- def isEnabled(self, position: int) -> bool:
- return True
-
- def getDropDownView(self, position: int, convertView: Any, parent: Any) -> Any:
- return self.getView(position, convertView, parent)
-
- def toString(self) -> str:
- return f"BaseAdapter(count={self.getCount()})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# ListAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class ListAdapter(Stub):
- """ListAdapter — 列表适配器接口"""
-
- def getCount(self) -> int:
- return 0
-
- def getItem(self, position: int) -> Optional[Any]:
- return None
-
- def getItemId(self, position: int) -> int:
- return position
-
- def getView(self, position: int, convertView: Any, parent: Any) -> Any:
- return None
-
- def isEmpty(self) -> bool:
- return self.getCount() == 0
-
- def registerDataSetObserver(self, observer: Any):
- pass
-
- def unregisterDataSetObserver(self, observer: Any):
- pass
-
- def areAllItemsEnabled(self) -> bool:
- return True
-
- def isEnabled(self, position: int) -> bool:
- return True
-
- def getItemViewType(self, position: int) -> int:
- return ADAPTER_IGNORE_ITEM_VIEW_TYPE
-
- def getViewTypeCount(self) -> int:
- return 1
-
- def hasStableIds(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"ListAdapter@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SpinnerAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class SpinnerAdapter(Stub):
- """SpinnerAdapter — 下拉适配器接口"""
-
- def getCount(self) -> int:
- return 0
-
- def getItem(self, position: int) -> Optional[Any]:
- return None
-
- def getItemId(self, position: int) -> int:
- return position
-
- def getView(self, position: int, convertView: Any, parent: Any) -> Any:
- return None
-
- def getDropDownView(self, position: int, convertView: Any, parent: Any) -> Any:
- return self.getView(position, convertView, parent)
-
- def toString(self) -> str:
- return f"SpinnerAdapter@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# WrapperListAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class WrapperListAdapter(Stub):
- """WrapperListAdapter — 包装列表适配器"""
-
- def getWrappedAdapter(self) -> Optional[ListAdapter]:
- return None
-
- def getCount(self) -> int:
- wrapped = self.getWrappedAdapter()
- return wrapped.getCount() if wrapped else 0
-
- def getItem(self, position: int) -> Optional[Any]:
- wrapped = self.getWrappedAdapter()
- return wrapped.getItem(position) if wrapped else None
-
- def getItemId(self, position: int) -> int:
- wrapped = self.getWrappedAdapter()
- return wrapped.getItemId(position) if wrapped else position
-
- def toString(self) -> str:
- return f"WrapperListAdapter@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# HeaderViewListAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class HeaderViewListAdapter(WrapperListAdapter):
- """HeaderViewListAdapter — 页眉视图列表适配器"""
-
- def __init__(self, wrappedAdapter: Optional[ListAdapter] = None):
- super().__init__()
- self._wrapped_adapter = wrappedAdapter
- self._headers: List[Any] = []
- self._footers: List[Any] = []
-
- def getWrappedAdapter(self) -> Optional[ListAdapter]:
- return self._wrapped_adapter
-
- def addHeader(self, view: Any, data: Any = None, isSelectable: bool = True):
- self._headers.append((view, data, isSelectable))
-
- def addFooter(self, view: Any, data: Any = None, isSelectable: bool = True):
- self._footers.append((view, data, isSelectable))
-
- def removeHeader(self, view: Any) -> bool:
- for i, (v, _, _) in enumerate(self._headers):
- if v is view:
- self._headers.pop(i)
- return True
- return False
-
- def removeFooter(self, view: Any) -> bool:
- for i, (v, _, _) in enumerate(self._footers):
- if v is view:
- self._footers.pop(i)
- return True
- return False
-
- def getHeadersCount(self) -> int:
- return len(self._headers)
-
- def getFootersCount(self) -> int:
- return len(self._footers)
-
- def getCount(self) -> int:
- count = len(self._headers) + len(self._footers)
- if self._wrapped_adapter:
- count += self._wrapped_adapter.getCount()
- return count
-
- def getItem(self, position: int) -> Optional[Any]:
- if position < len(self._headers):
- return self._headers[position][1]
- offset = position - len(self._headers)
- if self._wrapped_adapter and offset < self._wrapped_adapter.getCount():
- return self._wrapped_adapter.getItem(offset)
- footer_offset = offset - (self._wrapped_adapter.getCount() if self._wrapped_adapter else 0)
- if 0 <= footer_offset < len(self._footers):
- return self._footers[footer_offset][1]
- return None
-
- def getView(self, position: int, convertView: Any, parent: Any) -> Any:
- if position < len(self._headers):
- return self._headers[position][0]
- offset = position - len(self._headers)
- if self._wrapped_adapter and offset < self._wrapped_adapter.getCount():
- return self._wrapped_adapter.getView(offset, convertView, parent)
- footer_offset = offset - (self._wrapped_adapter.getCount() if self._wrapped_adapter else 0)
- if 0 <= footer_offset < len(self._footers):
- return self._footers[footer_offset][0]
- return None
-
- def toString(self) -> str:
- return f"HeaderViewListAdapter(headers={len(self._headers)}, footers={len(self._footers)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ArrayAdapter (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class ArrayAdapter(BaseAdapter):
- """ArrayAdapter — 数组适配器 (完整版)"""
-
- def __init__(self, context: Any = None, resource: int = 0,
- textViewResourceId: int = 0, objects: List[Any] = None):
- super().__init__()
- self._context = context
- self._resource = resource
- self._text_view_resource_id = textViewResourceId
- self._objects: List[Any] = list(objects) if objects else []
- self._drop_down_resource = resource
- self._field_id = 0
- self._filter: Optional[Any] = None
-
- def add(self, obj: Any):
- self._objects.append(obj)
- self.notifyDataSetChanged()
-
- def addAll(self, *objects: Any):
- for obj in objects:
- self._objects.append(obj)
- self.notifyDataSetChanged()
-
- def insert(self, obj: Any, index: int):
- self._objects.insert(index, obj)
- self.notifyDataSetChanged()
-
- def remove(self, obj: Any):
- if obj in self._objects:
- self._objects.remove(obj)
- self.notifyDataSetChanged()
-
- def clear(self):
- self._objects.clear()
- self.notifyDataSetChanged()
-
- def sort(self, comparator: Callable[[Any, Any], int]):
- self._objects.sort(key=lambda x: x)
- self.notifyDataSetChanged()
-
- def getCount(self) -> int:
- return len(self._objects)
-
- def getItem(self, position: int) -> Optional[Any]:
- if 0 <= position < len(self._objects):
- return self._objects[position]
- return None
-
- def getPosition(self, item: Any) -> int:
- try:
- return self._objects.index(item)
- except ValueError:
- return ADAPTER_INVALID_POSITION
-
- def setDropDownViewResource(self, resource: int):
- self._drop_down_resource = resource
-
- def getDropDownViewResource(self) -> int:
- return self._drop_down_resource
-
- def getContext(self) -> Any:
- return self._context
-
- def getFilter(self) -> Optional[Any]:
- return self._filter
-
- def createFromResource(context: Any, textArrayResId: int,
- textViewResId: int) -> "ArrayAdapter":
- return ArrayAdapter(context=context, resource=textViewResId)
-
- def toString(self) -> str:
- return f"ArrayAdapter(count={len(self._objects)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CursorAdapter (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class CursorAdapter(BaseAdapter):
- """CursorAdapter — 游标适配器 (完整版)"""
-
- FLAG_AUTO_REQUERY = 0x01
- FLAG_REGISTER_CONTENT_OBSERVER = 0x02
-
- def __init__(self, context: Any = None, cursor: Any = None,
- flags: int = FLAG_AUTO_REQUERY):
- super().__init__()
- self._context = context
- self._cursor = cursor
- self._flags = flags
- self._row_id_column = "_id"
- self._count = 0
- if cursor:
- self._count = len(cursor) if hasattr(cursor, '__len__') else 0
-
- def getCursor(self) -> Any:
- return self._cursor
-
- def setCursor(self, cursor: Any):
- self._cursor = cursor
- self._count = len(cursor) if cursor and hasattr(cursor, '__len__') else 0
- self.notifyDataSetChanged()
-
- def getCount(self) -> int:
- return self._count
-
- def getItem(self, position: int) -> Optional[Any]:
- if self._cursor and 0 <= position < self._count:
- if hasattr(self._cursor, '__getitem__'):
- return self._cursor[position]
- return self._cursor
- return None
-
- def getItemId(self, position: int) -> int:
- if self._cursor and 0 <= position < self._count:
- item = self.getItem(position)
- if item and hasattr(item, 'get'):
- return int(item.get(self._row_id_column, position))
- return position
-
- def getView(self, position: int, convertView: Any, parent: Any) -> Any:
- return self.newView(self._context, self._cursor, parent) if not convertView else convertView
-
- def newView(self, context: Any, cursor: Any, parent: Any) -> Any:
- return None
-
- def bindView(self, view: Any, context: Any, cursor: Any):
- pass
-
- def changeCursor(self, cursor: Any):
- self.setCursor(cursor)
-
- def getFilterQueryProvider(self) -> Optional[Any]:
- return None
-
- def setFilterQueryProvider(self, provider: Any):
- pass
-
- def runQueryOnBackgroundThread(self, constraint: str) -> Any:
- return self._cursor
-
- def toString(self) -> str:
- return f"CursorAdapter(count={self._count})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SimpleCursorAdapter (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class SimpleCursorAdapter(CursorAdapter):
- """SimpleCursorAdapter — 简单游标适配器 (完整版)"""
-
- def __init__(self, context: Any = None, layout: int = 0,
- cursor: Any = None, fromColumns: List[str] = None,
- toViews: List[int] = None, flags: int = 0):
- super().__init__(context=context, cursor=cursor, flags=flags)
- self._layout = layout
- self._from_columns = fromColumns or []
- self._to_views = toViews or []
-
- def getLayout(self) -> int:
- return self._layout
-
- def setViewText(self, view: Any, text: str):
- pass
-
- def setViewImage(self, view: Any, value: str):
- pass
-
- def getStringConversionColumn(self) -> int:
- return 0
-
- def setStringConversionColumn(self, column: int):
- pass
-
- def getViewBinder(self) -> Optional[Any]:
- return None
-
- def setViewBinder(self, viewBinder: Any):
- pass
-
- def toString(self) -> str:
- return f"SimpleCursorAdapter(layout={self._layout})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ResourceCursorAdapter (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class ResourceCursorAdapter(CursorAdapter):
- """ResourceCursorAdapter — 资源游标适配器 (完整版)"""
-
- def __init__(self, context: Any = None, layout: int = 0,
- cursor: Any = None, flags: int = 0,
- dropDownLayout: int = 0):
- super().__init__(context=context, cursor=cursor, flags=flags)
- self._layout = layout
- self._drop_down_layout = dropDownLayout or layout
-
- def setDropDownViewResource(self, dropDownLayout: int):
- self._drop_down_layout = dropDownLayout
-
- def getDropDownView(self, position: int, convertView: Any, parent: Any) -> Any:
- return self.newView(self._context, self._cursor, parent)
-
- def toString(self) -> str:
- return f"ResourceCursorAdapter(layout={self._layout})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# SimpleAdapter (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class SimpleAdapter(BaseAdapter):
- """SimpleAdapter — 简单适配器 (完整版)"""
-
- def __init__(self, context: Any = None, data: List[Dict[str, Any]] = None,
- resource: int = 0, from_: List[str] = None,
- to: List[int] = None):
- super().__init__()
- self._context = context
- self._data = data or []
- self._resource = resource
- self._from_keys = from_ or []
- self._to_ids = to or []
- self._drop_down_resource = resource
-
- def getCount(self) -> int:
- return len(self._data)
-
- def getItem(self, position: int) -> Optional[Dict[str, Any]]:
- if 0 <= position < len(self._data):
- return self._data[position]
- return None
-
- def getItemId(self, position: int) -> int:
- return position
-
- def getView(self, position: int, convertView: Any, parent: Any) -> Any:
- return convertView
-
- def setDropDownViewResource(self, resource: int):
- self._drop_down_resource = resource
-
- def getDropDownView(self, position: int, convertView: Any, parent: Any) -> Any:
- return convertView
-
- def getContext(self) -> Any:
- return self._context
-
- def getData(self) -> List[Dict[str, Any]]:
- return list(self._data)
-
- def setData(self, data: List[Dict[str, Any]]):
- self._data = list(data)
- self.notifyDataSetChanged()
-
- def toString(self) -> str:
- return f"SimpleAdapter(count={len(self._data)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# RecyclerView
-# ═══════════════════════════════════════════════════════════════
-
-class RecyclerView(Stub):
- """RecyclerView — 循环视图"""
-
- HORIZONTAL = 0
- VERTICAL = 1
- NO_POSITION = -1
- NO_ID = -1
- INVALID_TYPE = -1
-
- # ═══════════════════════════════════════════════════════════
- # RecyclerView.Adapter (扩展)
- # ═══════════════════════════════════════════════════════════
-
- class Adapter(BaseAdapter):
- """RecyclerView.Adapter — RecyclerView 适配器 (完整版)"""
-
- def __init__(self):
- super().__init__()
- self._has_stable_ids = False
- self._state_restoration_policy = 0
- self._observers: List[RecyclerView.AdapterDataObserver] = []
-
- def onCreateViewHolder(self, parent: Any, viewType: int) -> "RecyclerView.ViewHolder":
- raise NotImplementedError
-
- def onBindViewHolder(self, holder: "RecyclerView.ViewHolder", position: int):
- raise NotImplementedError
-
- def getItemCount(self) -> int:
- return 0
-
- def getItemViewType(self, position: int) -> int:
- return ADAPTER_IGNORE_ITEM_VIEW_TYPE
-
- def setHasStableIds(self, hasStableIds: bool):
- self._has_stable_ids = hasStableIds
-
- def hasStableIds(self) -> bool:
- return self._has_stable_ids
-
- def onAttachedToRecyclerView(self, recyclerView: "RecyclerView"):
- pass
-
- def onDetachedFromRecyclerView(self, recyclerView: "RecyclerView"):
- pass
-
- def onViewAttachedToWindow(self, holder: "RecyclerView.ViewHolder"):
- pass
-
- def onViewDetachedFromWindow(self, holder: "RecyclerView.ViewHolder"):
- pass
-
- def onViewRecycled(self, holder: "RecyclerView.ViewHolder"):
- pass
-
- def onFailedToRecycleView(self, holder: "RecyclerView.ViewHolder") -> bool:
- return False
-
- def registerAdapterDataObserver(self, observer: "RecyclerView.AdapterDataObserver"):
- self._observers.append(observer)
-
- def unregisterAdapterDataObserver(self, observer: "RecyclerView.AdapterDataObserver"):
- self._observers = [o for o in self._observers if o is not observer]
-
- def notifyDataSetChanged(self):
- for o in self._observers:
- o.onChanged()
-
- def notifyItemChanged(self, position: int):
- for o in self._observers:
- o.onItemRangeChanged(position, 1)
-
- def notifyItemRangeChanged(self, positionStart: int, itemCount: int):
- for o in self._observers:
- o.onItemRangeChanged(positionStart, itemCount)
-
- def notifyItemInserted(self, position: int):
- for o in self._observers:
- o.onItemRangeInserted(position, 1)
-
- def notifyItemRangeInserted(self, positionStart: int, itemCount: int):
- for o in self._observers:
- o.onItemRangeInserted(positionStart, itemCount)
-
- def notifyItemRemoved(self, position: int):
- for o in self._observers:
- o.onItemRangeRemoved(position, 1)
-
- def notifyItemRangeRemoved(self, positionStart: int, itemCount: int):
- for o in self._observers:
- o.onItemRangeRemoved(positionStart, itemCount)
-
- def notifyItemMoved(self, fromPosition: int, toPosition: int):
- for o in self._observers:
- o.onItemRangeMoved(fromPosition, toPosition, 1)
-
- def getItemId(self, position: int) -> int:
- return position
-
- def toString(self) -> str:
- return f"RecyclerView.Adapter(items={self.getItemCount()})"
-
- # ═══════════════════════════════════════════════════════════
- # RecyclerView.ViewHolder (扩展)
- # ═══════════════════════════════════════════════════════════
-
- class ViewHolder(Stub):
- """RecyclerView.ViewHolder — 视图持有者 (完整版)"""
-
- def __init__(self, itemView: Any = None):
- super().__init__()
- self.itemView = itemView
- self._adapter_position = RecyclerView.NO_POSITION
- self._old_position = RecyclerView.NO_POSITION
- self._item_id = RecyclerView.NO_ID
- self._item_view_type = RecyclerView.INVALID_TYPE
- self._is_recyclable = True
- self._is_bound = False
-
- def getAdapterPosition(self) -> int:
- return self._adapter_position
-
- def getOldPosition(self) -> int:
- return self._old_position
-
- def getItemId(self) -> int:
- return self._item_id
-
- def getItemViewType(self) -> int:
- return self._item_view_type
-
- def setIsRecyclable(self, recyclable: bool):
- self._is_recyclable = recyclable
-
- def isRecyclable(self) -> bool:
- return self._is_recyclable
-
- def setIsBound(self, bound: bool):
- self._is_bound = bound
-
- def isBound(self) -> bool:
- return self._is_bound
-
- def toString(self) -> str:
- return f"ViewHolder(pos={self._adapter_position})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
- # ═══════════════════════════════════════════════════════════
- # RecyclerView.LayoutManager (扩展)
- # ═══════════════════════════════════════════════════════════
-
- class LayoutManager(Stub):
- """RecyclerView.LayoutManager — 布局管理器 (完整版)"""
-
- def __init__(self):
- super().__init__()
- self._child_count = 0
- self._item_count = 0
- self._auto_measure = True
-
- def generateDefaultLayoutParams(self) -> Any:
- return None
-
- def onLayoutChildren(self, recycler: Any, state: Any):
- pass
-
- def getChildCount(self) -> int:
- return self._child_count
-
- def getItemCount(self) -> int:
- return self._item_count
-
- def setAutoMeasureEnabled(self, enabled: bool):
- self._auto_measure = enabled
-
- def isAutoMeasureEnabled(self) -> bool:
- return self._auto_measure
-
- def canScrollHorizontally(self) -> bool:
- return False
-
- def canScrollVertically(self) -> bool:
- return False
-
- def scrollToPosition(self, position: int):
- pass
-
- def smoothScrollToPosition(self, view: Any, state: Any, position: int):
- pass
-
- def computeVerticalScrollOffset(self, state: Any) -> int:
- return 0
-
- def computeVerticalScrollExtent(self, state: Any) -> int:
- return 0
-
- def computeVerticalScrollRange(self, state: Any) -> int:
- return 0
-
- def computeHorizontalScrollOffset(self, state: Any) -> int:
- return 0
-
- def computeHorizontalScrollExtent(self, state: Any) -> int:
- return 0
-
- def computeHorizontalScrollRange(self, state: Any) -> int:
- return 0
-
- def toString(self) -> str:
- return f"LayoutManager(children={self._child_count})"
-
- # ═══════════════════════════════════════════════════════════
- # RecyclerView.AdapterDataObserver
- # ═══════════════════════════════════════════════════════════
-
- class AdapterDataObserver(Stub):
- """RecyclerView.AdapterDataObserver — 适配器数据观察者"""
-
- def onChanged(self):
- pass
-
- def onItemRangeChanged(self, positionStart: int, itemCount: int):
- pass
-
- def onItemRangeInserted(self, positionStart: int, itemCount: int):
- pass
-
- def onItemRangeRemoved(self, positionStart: int, itemCount: int):
- pass
-
- def onItemRangeMoved(self, fromPosition: int, toPosition: int, itemCount: int):
- pass
-
- def toString(self) -> str:
- return f"AdapterDataObserver@{hex(id(self))}"
-
- # ═══════════════════════════════════════════════════════════
- # RecyclerView.ItemDecoration
- # ═══════════════════════════════════════════════════════════
-
- class ItemDecoration(Stub):
- """RecyclerView.ItemDecoration — 项目装饰"""
-
- def onDraw(self, canvas: Any, parent: "RecyclerView", state: Any):
- pass
-
- def onDrawOver(self, canvas: Any, parent: "RecyclerView", state: Any):
- pass
-
- def getItemOffsets(self, outRect: Any, view: Any,
- parent: "RecyclerView", state: Any):
- outRect.set(0, 0, 0, 0)
-
- def toString(self) -> str:
- return f"ItemDecoration@{hex(id(self))}"
-
- # ═══════════════════════════════════════════════════════════
- # RecyclerView.ItemAnimator
- # ═══════════════════════════════════════════════════════════
-
- class ItemAnimator(Stub):
- """RecyclerView.ItemAnimator — 项目动画器"""
-
- def animateDisappearance(self, holder: ViewHolder, preInfo: Any,
- postInfo: Any) -> bool:
- return False
-
- def animateAppearance(self, holder: ViewHolder, preInfo: Any,
- postInfo: Any) -> bool:
- return False
-
- def animatePersistence(self, holder: ViewHolder, preInfo: Any,
- postInfo: Any) -> bool:
- return False
-
- def animateChange(self, oldHolder: ViewHolder, newHolder: ViewHolder,
- preInfo: Any, postInfo: Any) -> bool:
- return False
-
- def endAnimation(self, holder: ViewHolder):
- pass
-
- def endAnimations(self):
- pass
-
- def isRunning(self) -> bool:
- return False
-
- def dispatchAnimationsFinished(self):
- pass
-
- def toString(self) -> str:
- return f"ItemAnimator@{hex(id(self))}"
-
- # ═══════════════════════════════════════════════════════════
- # RecyclerView.SmoothScroller
- # ═══════════════════════════════════════════════════════════
-
- class SmoothScroller(Stub):
- """RecyclerView.SmoothScroller — 平滑滚动器"""
-
- def start(self, recyclerView: "RecyclerView", layoutManager: LayoutManager,
- targetPosition: int):
- pass
-
- def stop(self):
- pass
-
- def isRunning(self) -> bool:
- return False
-
- def getTargetPosition(self) -> int:
- return RecyclerView.NO_POSITION
-
- def toString(self) -> str:
- return f"SmoothScroller@{hex(id(self))}"
-
- # ═══════════════════════════════════════════════════════════
- # RecyclerView.OnScrollListener
- # ═══════════════════════════════════════════════════════════
-
- class OnScrollListener(Stub):
- """RecyclerView.OnScrollListener — 滚动监听器"""
-
- SCROLL_STATE_IDLE = 0
- SCROLL_STATE_DRAGGING = 1
- SCROLL_STATE_SETTLING = 2
-
- def onScrollStateChanged(self, recyclerView: "RecyclerView", newState: int):
- pass
-
- def onScrolled(self, recyclerView: "RecyclerView", dx: int, dy: int):
- pass
-
- def toString(self) -> str:
- return f"OnScrollListener@{hex(id(self))}"
-
- def __init__(self):
- super().__init__()
- self._adapter: Optional[RecyclerView.Adapter] = None
- self._layout_manager: Optional[RecyclerView.LayoutManager] = None
- self._item_animator: Optional[RecyclerView.ItemAnimator] = None
- self._scroll_listeners: List[RecyclerView.OnScrollListener] = []
- self._item_decoration: Optional[RecyclerView.ItemDecoration] = None
-
- def setAdapter(self, adapter: Adapter):
- self._adapter = adapter
-
- def getAdapter(self) -> Optional[Adapter]:
- return self._adapter
-
- def setLayoutManager(self, layoutManager: LayoutManager):
- self._layout_manager = layoutManager
-
- def getLayoutManager(self) -> Optional[LayoutManager]:
- return self._layout_manager
-
- def setItemAnimator(self, animator: ItemAnimator):
- self._item_animator = animator
-
- def getItemAnimator(self) -> Optional[ItemAnimator]:
- return self._item_animator
-
- def addItemDecoration(self, decoration: ItemDecoration, index: int = -1):
- self._item_decoration = decoration
-
- def addOnScrollListener(self, listener: OnScrollListener):
- self._scroll_listeners.append(listener)
-
- def removeOnScrollListener(self, listener: OnScrollListener):
- self._scroll_listeners = [l for l in self._scroll_listeners if l is not listener]
-
- def clearOnScrollListeners(self):
- self._scroll_listeners.clear()
-
- def scrollToPosition(self, position: int):
- pass
-
- def smoothScrollToPosition(self, position: int):
- pass
-
- def toString(self) -> str:
- return f"RecyclerView(adapter={'set' if self._adapter else 'null'})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PagerAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class PagerAdapter(Stub):
- """PagerAdapter — 页面适配器"""
-
- POSITION_UNCHANGED = PAGER_POSITION_UNCHANGED
- POSITION_NONE = PAGER_POSITION_NONE
-
- def __init__(self):
- super().__init__()
- self._observers: List[Any] = []
-
- def getCount(self) -> int:
- return 0
-
- def instantiateItem(self, container: Any, position: int) -> Any:
- return None
-
- def destroyItem(self, container: Any, position: int, obj: Any):
- pass
-
- def isViewFromObject(self, view: Any, obj: Any) -> bool:
- return False
-
- def getPageTitle(self, position: int) -> Optional[str]:
- return None
-
- def getPageWidth(self, position: int) -> float:
- return 1.0
-
- def getItemPosition(self, obj: Any) -> int:
- return PagerAdapter.POSITION_UNCHANGED
-
- def startUpdate(self, container: Any):
- pass
-
- def finishUpdate(self, container: Any):
- pass
-
- def registerDataSetObserver(self, observer: Any):
- self._observers.append(observer)
-
- def unregisterDataSetObserver(self, observer: Any):
- self._observers = [o for o in self._observers if o is not observer]
-
- def notifyDataSetChanged(self):
- for o in self._observers:
- if hasattr(o, 'onChanged'):
- o.onChanged()
-
- def toString(self) -> str:
- return f"PagerAdapter(count={self.getCount()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FragmentPagerAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class FragmentPagerAdapter(PagerAdapter):
- """FragmentPagerAdapter — Fragment 页面适配器"""
-
- BEHAVIOR_SET_USER_VISIBLE_HINT = 0
- BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1
-
- def __init__(self, fm: Any = None, behavior: int = BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT):
- super().__init__()
- self._fm = fm
- self._behavior = behavior
- self._fragments: Dict[int, Any] = {}
-
- def getItem(self, position: int) -> Any:
- raise NotImplementedError
-
- def instantiateItem(self, container: Any, position: int) -> Any:
- fragment = self.getItem(position)
- self._fragments[position] = fragment
- return fragment
-
- def destroyItem(self, container: Any, position: int, obj: Any):
- self._fragments.pop(position, None)
-
- def isViewFromObject(self, view: Any, obj: Any) -> bool:
- if hasattr(obj, 'getView'):
- return obj.getView() is view
- return False
-
- def getPageTitle(self, position: int) -> Optional[str]:
- return None
-
- def getItemId(self, position: int) -> int:
- return position
-
- def toString(self) -> str:
- return f"FragmentPagerAdapter(count={self.getCount()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FragmentStatePagerAdapter
-# ═══════════════════════════════════════════════════════════════
-
-class FragmentStatePagerAdapter(FragmentPagerAdapter):
- """FragmentStatePagerAdapter — Fragment 状态页面适配器"""
-
- def __init__(self, fm: Any = None, behavior: int = FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT):
- super().__init__(fm=fm, behavior=behavior)
- self._saved_states: Dict[int, Any] = {}
-
- def saveState(self, position: int) -> Any:
- state = self._saved_states.get(position)
- self._fragments.pop(position, None)
- return state
-
- def restoreState(self, state: Any, loader: Any):
- pass
-
- def instantiateItem(self, container: Any, position: int) -> Any:
- return super().instantiateItem(container, position)
-
- def destroyItem(self, container: Any, position: int, obj: Any):
- state = self.saveState(position)
- if state:
- self._saved_states[position] = state
- super().destroyItem(container, position, obj)
-
- def toString(self) -> str:
- return f"FragmentStatePagerAdapter(count={self.getCount()})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# PagerTitleStrip / PagerTabStrip
-# ═══════════════════════════════════════════════════════════════
-
-class PagerTitleStrip(Stub):
- """PagerTitleStrip — 页面标题条"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._text_spacing = 16
- self._nonprimary_alpha = 0.6
- self._current_page = 0
- self._adapter: Optional[PagerAdapter] = None
-
- def setAdapter(self, adapter: PagerAdapter):
- self._adapter = adapter
-
- def getAdapter(self) -> Optional[PagerAdapter]:
- return self._adapter
-
- def setTextSpacing(self, spacingPixels: int):
- self._text_spacing = spacingPixels
-
- def getTextSpacing(self) -> int:
- return self._text_spacing
-
- def updateTitle(self, position: int, adapter: PagerAdapter):
- self._current_page = position
-
- def requestLayout(self):
- pass
-
- def toString(self) -> str:
- return f"PagerTitleStrip(page={self._current_page})"
-
-
-class PagerTabStrip(PagerTitleStrip):
- """PagerTabStrip — 页面标签条"""
-
- def __init__(self, context: Any = None):
- super().__init__(context=context)
- self._tab_indicator_color = 0
- self._tab_spacing = 8
- self._draw_full_underline = False
- self._underline_height = 2
- self._tab_padding = 16
-
- def setTabIndicatorColor(self, color: int):
- self._tab_indicator_color = color
-
- def getTabIndicatorColor(self) -> int:
- return self._tab_indicator_color
-
- def setDrawFullUnderline(self, draw: bool):
- self._draw_full_underline = draw
-
- def isDrawFullUnderline(self) -> bool:
- return self._draw_full_underline
-
- def setUnderlineHeight(self, height: int):
- self._underline_height = height
-
- def getUnderlineHeight(self) -> int:
- return self._underline_height
-
- def setTabPadding(self, padding: int):
- self._tab_padding = padding
-
- def getTabPadding(self) -> int:
- return self._tab_padding
-
- def toString(self) -> str:
- return f"PagerTabStrip(page={self._current_page})"
\ No newline at end of file
diff --git a/android_pyapi/android/widget_ext.py b/android_pyapi/android/widget_ext.py
deleted file mode 100644
index 699021f..0000000
--- a/android_pyapi/android/widget_ext.py
+++ /dev/null
@@ -1,2232 +0,0 @@
-"""
-Android Widget 扩展组件 — AbsoluteLayout, AdapterView, ProgressBar, SeekBar, Layouts 等
-方法签名完全对齐 Android SDK
-"""
-
-from __future__ import annotations
-
-import math
-import time
-import threading
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-from .._core import Stub, AndroidOnlyError
-from .widget import AdapterView as _BaseAdapterView
-from .widget import AutoCompleteTextView as _BaseAutoCompleteTextView
-from .widget import ProgressBar as _BaseProgressBar
-from .widget import Chronometer as _BaseChronometer
-from .widget import TableLayout as _BaseTableLayout
-from .widget import TableRow as _BaseTableRow
-from .widget import LinearLayout as _BaseLinearLayout
-from .widget import FrameLayout as _BaseFrameLayout
-from .widget import RelativeLayout as _BaseRelativeLayout
-from .widget import NumberPicker as _BaseNumberPicker
-from .widget import SearchView as _BaseSearchView
-from .widget import TabHost as _BaseTabHost
-from .widget import TabWidget as _BaseTabWidget
-from .widget import ViewAnimator as _BaseViewAnimator
-from .widget import ImageButton as _BaseImageButton
-from .widget import ZoomControls as _BaseZoomControls
-from .widget import DigitalClock as _BaseDigitalClock
-from .widget import AnalogClock as _BaseAnalogClock
-from .widget import ToggleButton as _BaseToggleButton
-from .widget import RadioButton as _BaseRadioButton
-from .widget import SeekBar as _BaseSeekBar
-from .widget import RatingBar as _BaseRatingBar
-from .widget import ViewSwitcher as _BaseViewSwitcher
-from .widget import TextSwitcher as _BaseTextSwitcher
-from .widget import ImageSwitcher as _BaseImageSwitcher
-from .widget import BaseAdapter as _BaseBaseAdapter
-from .widget import ArrayAdapter as _BaseArrayAdapter
-from .widget import SimpleAdapter as _BaseSimpleAdapter
-from .widget import CursorAdapter as _BaseCursorAdapter
-from ..java.lang import RuntimeException
-
-
-# ═══════════════════════════════════════════════════════════════
-# 布局常量
-# ═══════════════════════════════════════════════════════════════
-
-VISIBLE = 0
-INVISIBLE = 4
-GONE = 8
-
-MATCH_PARENT = -1
-WRAP_CONTENT = -2
-
-FILL_PARENT = -1
-
-HORIZONTAL = 0
-VERTICAL = 1
-
-LEFT = 0
-RIGHT = 1
-CENTER = 2
-TOP = 3
-BOTTOM = 4
-
-NO_ID = -1
-
-
-# ═══════════════════════════════════════════════════════════════
-# AbsoluteLayout
-# ═══════════════════════════════════════════════════════════════
-
-class AbsoluteLayout(Stub):
- """AbsoluteLayout — 绝对布局"""
-
- class LayoutParams(Stub):
- """AbsoluteLayout.LayoutParams — 绝对布局参数"""
-
- def __init__(self, width: int = WRAP_CONTENT, height: int = WRAP_CONTENT,
- x: int = 0, y: int = 0):
- super().__init__()
- self.width = width
- self.height = height
- self.x = x
- self.y = y
-
- def toString(self) -> str:
- return (f"AbsoluteLayout.LayoutParams({self.width}x{self.height} "
- f"@{self.x},{self.y})")
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._children: List[Any] = []
-
- def addView(self, child: Any, x: int = 0, y: int = 0) -> None:
- self._children.append(child)
-
- def toString(self) -> str:
- return f"AbsoluteLayout(children={len(self._children)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Adapter / AdapterView / Filter / Filterable
-# ═══════════════════════════════════════════════════════════════
-
-class Adapter(Stub):
- """Adapter — 适配器接口"""
-
- IGNORE_ITEM_VIEW_TYPE = -1
- NO_SELECTION = -2147483648
-
- def __init__(self):
- super().__init__()
- self._data_set_observers: List[Callable] = []
-
- def registerDataSetObserver(self, observer: Callable) -> None:
- if observer not in self._data_set_observers:
- self._data_set_observers.append(observer)
-
- def unregisterDataSetObserver(self, observer: Callable) -> None:
- if observer in self._data_set_observers:
- self._data_set_observers.remove(observer)
-
- def notifyDataSetChanged(self) -> None:
- for obs in list(self._data_set_observers):
- obs()
-
- def notifyDataSetInvalidated(self) -> None:
- for obs in list(self._data_set_observers):
- obs()
-
- def getCount(self) -> int:
- return 0
-
- def getItem(self, position: int) -> Optional[Any]:
- return None
-
- def getItemId(self, position: int) -> int:
- return position
-
- def getItemViewType(self, position: int) -> int:
- return Adapter.IGNORE_ITEM_VIEW_TYPE
-
- def getViewTypeCount(self) -> int:
- return 1
-
- def hasStableIds(self) -> bool:
- return False
-
- def isEmpty(self) -> bool:
- return self.getCount() == 0
-
- def getView(self, position: int, convert_view: Optional[Any],
- parent: Any) -> Optional[Any]:
- return None
-
- def getDropDownView(self, position: int, convert_view: Optional[Any],
- parent: Any) -> Optional[Any]:
- return self.getView(position, convert_view, parent)
-
- def toString(self) -> str:
- return f"Adapter(count={self.getCount()})"
-
-
-class AdapterView(_BaseAdapterView):
- """AdapterView — 适配器视图"""
-
- ITEM_VIEW_TYPE_IGNORE = -1
- ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2
-
- INVALID_POSITION = -1
- INVALID_ROW_ID = -9223372036854775808
- INVALID_TYPE = -1
-
- CHOICE_MODE_NONE = 0
- CHOICE_MODE_SINGLE = 1
- CHOICE_MODE_MULTIPLE = 2
- CHOICE_MODE_MODAL = 3
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._adapter: Optional[Adapter] = None
- self._choice_mode: int = self.CHOICE_MODE_NONE
- self._checked_positions: Set[int] = set()
- self._selected_position: int = self.INVALID_POSITION
- self._item_click_listener: Optional[Callable] = None
- self._item_long_click_listener: Optional[Callable] = None
- self._item_selected_listener: Optional[Callable] = None
- self._empty_view: Optional[Any] = None
- self._first_visible_position: int = 0
- self._last_visible_position: int = 0
- self._lock = threading.Lock()
-
- def setAdapter(self, adapter: Optional[Adapter]) -> None:
- self._adapter = adapter
-
- def getAdapter(self) -> Optional[Adapter]:
- return self._adapter
-
- def setOnItemClickListener(self, listener: Optional[Callable]) -> None:
- self._item_click_listener = listener
-
- def getOnItemClickListener(self) -> Optional[Callable]:
- return self._item_click_listener
-
- def setOnItemLongClickListener(self, listener: Optional[Callable]) -> None:
- self._item_long_click_listener = listener
-
- def setOnItemSelectedListener(self, listener: Optional[Callable]) -> None:
- self._item_selected_listener = listener
-
- def getSelectedItemPosition(self) -> int:
- return self._selected_position
-
- def getSelectedItemId(self) -> int:
- if self._adapter and self._selected_position != self.INVALID_POSITION:
- return self._adapter.getItemId(self._selected_position)
- return self.INVALID_ROW_ID
-
- def getSelectedView(self) -> Optional[Any]:
- return None
-
- def getSelectedItem(self) -> Optional[Any]:
- if self._adapter and self._selected_position != self.INVALID_POSITION:
- return self._adapter.getItem(self._selected_position)
- return None
-
- def setSelection(self, position: int) -> None:
- self._selected_position = position
-
- def getFirstVisiblePosition(self) -> int:
- return self._first_visible_position
-
- def getLastVisiblePosition(self) -> int:
- return self._last_visible_position
-
- def getCount(self) -> int:
- return self._adapter.getCount() if self._adapter else 0
-
- def getChildAt(self, index: int) -> Optional[Any]:
- return None
-
- def getChildCount(self) -> int:
- return 0
-
- def setChoiceMode(self, mode: int) -> None:
- self._choice_mode = mode
-
- def getChoiceMode(self) -> int:
- return self._choice_mode
-
- def setItemChecked(self, position: int, checked: bool) -> None:
- with self._lock:
- if checked:
- if self._choice_mode == self.CHOICE_MODE_SINGLE:
- self._checked_positions.clear()
- self._checked_positions.add(position)
- else:
- self._checked_positions.discard(position)
-
- def isItemChecked(self, position: int) -> bool:
- return position in self._checked_positions
-
- def getCheckedItemPosition(self) -> int:
- if self._checked_positions:
- return next(iter(self._checked_positions))
- return self.INVALID_POSITION
-
- def getCheckedItemPositions(self) -> Set[int]:
- return set(self._checked_positions)
-
- def getCheckedItemIds(self) -> Set[int]:
- ids = set()
- for pos in self._checked_positions:
- if self._adapter:
- ids.add(self._adapter.getItemId(pos))
- return ids
-
- def getCheckItemCount(self) -> int:
- return len(self._checked_positions)
-
- def setEmptyView(self, view: Any) -> None:
- self._empty_view = view
-
- def getEmptyView(self) -> Optional[Any]:
- return self._empty_view
-
- def performItemClick(self, view: Any, position: int, id_val: int) -> bool:
- if self._item_click_listener:
- self._item_click_listener(self, view, position, id_val)
- return True
- return False
-
- def toString(self) -> str:
- return (f"AdapterView(adapter={'yes' if self._adapter else 'no'}, "
- f"count={self.getCount()})")
-
-
-class Filter(Stub):
- """Filter — 过滤器"""
-
- class FilterResults(Stub):
- """Filter.FilterResults — 过滤结果"""
-
- def __init__(self):
- super().__init__()
- self.values: Optional[Any] = None
- self.count: int = 0
-
- def __init__(self):
- super().__init__()
- self._filter_listener: Optional[Callable] = None
-
- def filter(self, constraint: str) -> None:
- results = self.performFiltering(constraint)
- self.publishResults(constraint, results)
-
- def filter(self, constraint: str, listener: Optional[Callable]) -> None:
- self._filter_listener = listener
- self.filter(constraint)
-
- def performFiltering(self, constraint: str) -> FilterResults:
- return Filter.FilterResults()
-
- def publishResults(self, constraint: str, results: FilterResults) -> None:
- pass
-
- def convertResultToString(self, result_value: Any) -> str:
- return str(result_value) if result_value is not None else ""
-
- def toString(self) -> str:
- return "Filter()"
-
-
-class Filterable(Stub):
- """Filterable — 可过滤接口"""
-
- def getFilter(self) -> Filter:
- return Filter()
-
-
-class ThemedSpinnerAdapter(Stub):
- """ThemedSpinnerAdapter — 主题化 Spinner 适配器"""
-
- def setDropDownViewTheme(self, theme: Any) -> None:
- pass
-
- def getDropDownViewTheme(self) -> Optional[Any]:
- return None
-
-
-# ═══════════════════════════════════════════════════════════════
-# AutoCompleteTextView
-# ═══════════════════════════════════════════════════════════════
-
-class AutoCompleteTextView(_BaseAutoCompleteTextView):
- """AutoCompleteTextView — 自动完成文本视图"""
-
- THRESHOLD_DEFAULT = 2
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._threshold = self.THRESHOLD_DEFAULT
- self._adapter: Optional[Adapter] = None
- self._listener: Optional[Callable] = None
- self._validator: Optional[Callable] = None
- self._completion_hint: Optional[str] = None
- self._drop_down_width: int = WRAP_CONTENT
- self._drop_down_height: int = WRAP_CONTENT
- self._drop_down_anchor: Optional[Any] = None
- self._drop_down_horizontal_offset: int = 0
- self._drop_down_vertical_offset: int = 0
- self._showing = False
-
- def setThreshold(self, threshold: int) -> None:
- self._threshold = max(1, threshold)
-
- def getThreshold(self) -> int:
- return self._threshold
-
- def setAdapter(self, adapter: Adapter) -> None:
- self._adapter = adapter
-
- def getAdapter(self) -> Optional[Adapter]:
- return self._adapter
-
- def setOnItemClickListener(self, listener: Optional[Callable]) -> None:
- self._listener = listener
-
- def setOnItemSelectedListener(self, listener: Optional[Callable]) -> None:
- pass
-
- def showDropDown(self) -> None:
- self._showing = True
-
- def dismissDropDown(self) -> None:
- self._showing = False
-
- def isShowing(self) -> bool:
- return self._showing
-
- def setDropDownWidth(self, width: int) -> None:
- self._drop_down_width = width
-
- def getDropDownWidth(self) -> int:
- return self._drop_down_width
-
- def setDropDownHeight(self, height: int) -> None:
- self._drop_down_height = height
-
- def getDropDownHeight(self) -> int:
- return self._drop_down_height
-
- def setDropDownAnchor(self, anchor: Any) -> None:
- self._drop_down_anchor = anchor
-
- def getDropDownAnchor(self) -> Optional[Any]:
- return self._drop_down_anchor
-
- def setDropDownHorizontalOffset(self, offset: int) -> None:
- self._drop_down_horizontal_offset = offset
-
- def getDropDownHorizontalOffset(self) -> int:
- return self._drop_down_horizontal_offset
-
- def setDropDownVerticalOffset(self, offset: int) -> None:
- self._drop_down_vertical_offset = offset
-
- def getDropDownVerticalOffset(self) -> int:
- return self._drop_down_vertical_offset
-
- def setCompletionHint(self, hint: str) -> None:
- self._completion_hint = hint
-
- def getCompletionHint(self) -> Optional[str]:
- return self._completion_hint
-
- def setValidator(self, validator: Optional[Callable]) -> None:
- self._validator = validator
-
- def getValidator(self) -> Optional[Callable]:
- return self._validator
-
- def performValidation(self) -> None:
- if self._validator:
- self._validator()
-
- def enoughToFilter(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"AutoCompleteTextView(threshold={self._threshold})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# ProgressBar / SeekBar / AbsSeekBar / RatingBar
-# ═══════════════════════════════════════════════════════════════
-
-class ProgressBar(_BaseProgressBar):
- """ProgressBar — 进度条扩展"""
-
- STYLE_HORIZONTAL = 0x00000001
- STYLE_SPINNER = 0x00000000
-
- def __init__(self, context: Any = None, style: int = STYLE_SPINNER):
- super().__init__()
- self._min: int = 0
- self._max: int = 100
- self._progress: int = 0
- self._secondary_progress: int = 0
- self._indeterminate = (style == self.STYLE_SPINNER)
- self._indeterminate_drawable: Optional[Any] = None
- self._progress_drawable: Optional[Any] = None
- self._on_progress_listener: Optional[Callable] = None
- self._mirror = False
-
- def setMin(self, min_val: int) -> None:
- self._min = min_val
- if self._progress < min_val:
- self._progress = min_val
-
- def getMin(self) -> int:
- return self._min
-
- def setMax(self, max_val: int) -> None:
- self._max = max_val
- if self._progress > max_val:
- self._progress = max_val
-
- def getMax(self) -> int:
- return self._max
-
- def setProgress(self, progress: int) -> None:
- self._progress = max(self._min, min(self._max, progress))
- if self._on_progress_listener:
- self._on_progress_listener(self, self._progress)
-
- def getProgress(self) -> int:
- return self._progress
-
- def setSecondaryProgress(self, progress: int) -> None:
- self._secondary_progress = max(self._min, min(self._max, progress))
-
- def getSecondaryProgress(self) -> int:
- return self._secondary_progress
-
- def incrementProgressBy(self, diff: int) -> None:
- self.setProgress(self._progress + diff)
-
- def incrementSecondaryProgressBy(self, diff: int) -> None:
- self._secondary_progress = max(self._min, min(self._max, self._secondary_progress + diff))
-
- def setIndeterminate(self, indeterminate: bool) -> None:
- self._indeterminate = indeterminate
-
- def isIndeterminate(self) -> bool:
- return self._indeterminate
-
- def setIndeterminateDrawable(self, drawable: Any) -> None:
- self._indeterminate_drawable = drawable
-
- def getIndeterminateDrawable(self) -> Optional[Any]:
- return self._indeterminate_drawable
-
- def setProgressDrawable(self, drawable: Any) -> None:
- self._progress_drawable = drawable
-
- def getProgressDrawable(self) -> Optional[Any]:
- return self._progress_drawable
-
- def setOnProgressBarChangeListener(self, listener: Optional[Callable]) -> None:
- self._on_progress_listener = listener
-
- def setMirrorForRtl(self, mirror: bool) -> None:
- self._mirror = mirror
-
- def getMirrorForRtl(self) -> bool:
- return self._mirror
-
- def getProgressScale(self) -> float:
- if self._max <= self._min:
- return 0.0
- return (self._progress - self._min) / (self._max - self._min)
-
- def toString(self) -> str:
- return (f"ProgressBar(min={self._min}, max={self._max}, "
- f"progress={self._progress}, "
- f"indeterminate={self._indeterminate})")
-
-
-class AbsSeekBar(ProgressBar):
- """AbsSeekBar — 抽象进度条"""
-
- def __init__(self, context: Any = None):
- super().__init__(context, ProgressBar.STYLE_HORIZONTAL)
- self._thumb: Optional[Any] = None
- self._thumb_offset: int = 0
- self._key_progress_increment: int = 1
- self._is_dragging = False
- self._on_seek_bar_change: Optional[Callable] = None
- self._split_track: bool = False
- self._tick_mark: Optional[Any] = None
-
- def setThumb(self, thumb: Any) -> None:
- self._thumb = thumb
-
- def getThumb(self) -> Optional[Any]:
- return self._thumb
-
- def setThumbOffset(self, offset: int) -> None:
- self._thumb_offset = offset
-
- def getThumbOffset(self) -> int:
- return self._thumb_offset
-
- def setKeyProgressIncrement(self, increment: int) -> None:
- self._key_progress_increment = max(1, increment)
-
- def getKeyProgressIncrement(self) -> int:
- return self._key_progress_increment
-
- def setSplitTrack(self, split: bool) -> None:
- self._split_track = split
-
- def getSplitTrack(self) -> bool:
- return self._split_track
-
- def setTickMark(self, mark: Any) -> None:
- self._tick_mark = mark
-
- def getTickMark(self) -> Optional[Any]:
- return self._tick_mark
-
- def setOnSeekBarChangeListener(self, listener: Optional[Callable]) -> None:
- self._on_seek_bar_change = listener
-
-
-class SeekBar(_BaseSeekBar, AbsSeekBar):
- """SeekBar — 拖动条"""
-
- def __init__(self, context: Any = None):
- AbsSeekBar.__init__(self, context)
- self._on_seek_bar_change: Optional[Callable] = None
-
- def setOnSeekBarChangeListener(self, listener: Optional[Callable]) -> None:
- self._on_seek_bar_change = listener
-
- def getOnSeekBarChangeListener(self) -> Optional[Callable]:
- return self._on_seek_bar_change
-
- def toString(self) -> str:
- return f"SeekBar(progress={self.getProgress()})"
-
-
-class RatingBar(_BaseRatingBar, ProgressBar):
- """RatingBar — 评分条"""
-
- def __init__(self, context: Any = None, num_stars: int = 5,
- step_size: float = 0.5):
- ProgressBar.__init__(self, context, ProgressBar.STYLE_HORIZONTAL)
- self._num_stars = num_stars
- self._step_size = step_size
- self._rating: float = 0.0
- self._is_indicator = False
- self._on_rating_change: Optional[Callable] = None
- self.setMax(num_stars)
-
- def setNumStars(self, num: int) -> None:
- self._num_stars = num
- self.setMax(num)
-
- def getNumStars(self) -> int:
- return self._num_stars
-
- def setRating(self, rating: float) -> None:
- self._rating = max(0.0, min(float(self._num_stars), rating))
- self.setProgress(int(self._rating))
-
- def getRating(self) -> float:
- return self._rating
-
- def setStepSize(self, size: float) -> None:
- self._step_size = max(0.1, size)
-
- def getStepSize(self) -> float:
- return self._step_size
-
- def setIsIndicator(self, indicator: bool) -> None:
- self._is_indicator = indicator
-
- def isIndicator(self) -> bool:
- return self._is_indicator
-
- def setOnRatingBarChangeListener(self, listener: Optional[Callable]) -> None:
- self._on_rating_change = listener
-
- def getOnRatingBarChangeListener(self) -> Optional[Callable]:
- return self._on_rating_change
-
- def toString(self) -> str:
- return f"RatingBar(rating={self._rating}/{self._num_stars})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# Chronometer
-# ═══════════════════════════════════════════════════════════════
-
-class Chronometer(_BaseChronometer):
- """Chronometer — 计时器"""
-
- FORMAT_ELAPSED_TIME = 1
- FORMAT_SECONDS = 2
- FORMAT_MINUTES = 3
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._base: int = 0
- self._elapsed: int = 0
- self._running = False
- self._format: str = "%H:%M:%S"
- self._on_tick: Optional[Callable] = None
- self._lock = threading.Lock()
-
- def setBase(self, base: int) -> None:
- self._base = base
-
- def getBase(self) -> int:
- return self._base
-
- def start(self) -> None:
- with self._lock:
- self._running = True
-
- def stop(self) -> None:
- with self._lock:
- self._running = False
- self._elapsed = int(time.time() * 1000) - self._base
-
- def setFormat(self, format_str: str) -> None:
- self._format = format_str
-
- def getFormat(self) -> str:
- return self._format
-
- def setOnChronometerTickListener(self, listener: Optional[Callable]) -> None:
- self._on_tick = listener
-
- def getOnChronometerTickListener(self) -> Optional[Callable]:
- return self._on_tick
-
- def isRunning(self) -> bool:
- return self._running
-
- def getElapsedTime(self) -> int:
- if self._running:
- return int(time.time() * 1000) - self._base
- return self._elapsed
-
- def toString(self) -> str:
- return f"Chronometer(running={self._running})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# CompoundButton / ToggleButton / RadioButton / RadioGroup
-# ═══════════════════════════════════════════════════════════════
-
-class CompoundButton(Stub):
- """CompoundButton — 复合按钮"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._checked = False
- self._on_check_listener: Optional[Callable] = None
- self._button_drawable: Optional[Any] = None
-
- def toggle(self) -> None:
- self.setChecked(not self._checked)
-
- def setChecked(self, checked: bool) -> None:
- if self._checked != checked:
- self._checked = checked
- if self._on_check_listener:
- self._on_check_listener(self, checked)
-
- def isChecked(self) -> bool:
- return self._checked
-
- def setOnCheckedChangeListener(self, listener: Optional[Callable]) -> None:
- self._on_check_listener = listener
-
- def getOnCheckedChangeListener(self) -> Optional[Callable]:
- return self._on_check_listener
-
- def setButtonDrawable(self, drawable: Any) -> None:
- self._button_drawable = drawable
-
- def getButtonDrawable(self) -> Optional[Any]:
- return self._button_drawable
-
- def toString(self) -> str:
- return f"CompoundButton(checked={self._checked})"
-
-
-class ToggleButton(_BaseToggleButton, CompoundButton):
- """ToggleButton — 开关按钮"""
-
- def __init__(self, context: Any = None):
- super().__init__(context)
- CompoundButton.__init__(self, context)
- self._text_on: str = "ON"
- self._text_off: str = "OFF"
-
- def setTextOn(self, text: str) -> None:
- self._text_on = text
-
- def getTextOn(self) -> str:
- return self._text_on
-
- def setTextOff(self, text: str) -> None:
- self._text_off = text
-
- def getTextOff(self) -> str:
- return self._text_off
-
- def toString(self) -> str:
- return f"ToggleButton(checked={self.isChecked()})"
-
-
-class RadioButton(_BaseRadioButton, CompoundButton):
- """RadioButton — 单选按钮"""
-
- def __init__(self, context: Any = None):
- super().__init__(context)
- CompoundButton.__init__(self, context)
-
- def toggle(self) -> None:
- if not self.isChecked():
- super().toggle()
-
- def toString(self) -> str:
- return f"RadioButton(checked={self.isChecked()})"
-
-
-class RadioGroup(Stub):
- """RadioGroup — 单选按钮组"""
-
- class LayoutParams(Stub):
- """RadioGroup.LayoutParams — 单选按钮组布局参数"""
-
- def __init__(self, width: int = WRAP_CONTENT, height: int = WRAP_CONTENT):
- super().__init__()
- self.width = width
- self.height = height
-
- def toString(self) -> str:
- return f"RadioGroup.LayoutParams({self.width}x{self.height})"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._checked_id: int = NO_ID
- self._on_check_listener: Optional[Callable] = None
- self._children: List[RadioButton] = []
- self._protect_from_checked_change = False
-
- def setOnCheckedChangeListener(self, listener: Optional[Callable]) -> None:
- self._on_check_listener = listener
-
- def getOnCheckedChangeListener(self) -> Optional[Callable]:
- return self._on_check_listener
-
- def check(self, id_val: int) -> None:
- self._checked_id = id_val
- if self._on_check_listener:
- self._on_check_listener(self, id_val)
-
- def getCheckedRadioButtonId(self) -> int:
- return self._checked_id
-
- def clearCheck(self) -> None:
- self._checked_id = NO_ID
-
- def addView(self, child: RadioButton, index: int = -1) -> None:
- if index < 0 or index >= len(self._children):
- self._children.append(child)
- else:
- self._children.insert(index, child)
-
- def getChildCount(self) -> int:
- return len(self._children)
-
- def toString(self) -> str:
- return f"RadioGroup(checkedId={self._checked_id})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TableLayout / TableRow
-# ═══════════════════════════════════════════════════════════════
-
-class TableLayout(_BaseTableLayout):
- """TableLayout — 表格布局"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._rows: List[TableRow] = []
- self._columns_stretchable: Set[int] = set()
- self._columns_collapsible: Set[int] = set()
- self._shrink_allowed = False
- self._stretch_allowed = False
-
- def addView(self, child: Any, index: int = -1) -> None:
- pass
-
- def setColumnStretchable(self, column_index: int, stretchable: bool) -> None:
- if stretchable:
- self._columns_stretchable.add(column_index)
- else:
- self._columns_stretchable.discard(column_index)
-
- def setColumnCollapsible(self, column_index: int, collapsible: bool) -> None:
- if collapsible:
- self._columns_collapsible.add(column_index)
- else:
- self._columns_collapsible.discard(column_index)
-
- def setShrinkAllColumns(self, shrink: bool) -> None:
- self._shrink_allowed = shrink
-
- def setStretchAllColumns(self, stretch: bool) -> None:
- self._stretch_allowed = stretch
-
- def toString(self) -> str:
- return f"TableLayout(rows={len(self._rows)})"
-
-
-class TableRow(_BaseTableRow):
- """TableRow — 表格行"""
-
- class LayoutParams(Stub):
- """TableRow.LayoutParams — 行布局参数"""
-
- def __init__(self, width: int = MATCH_PARENT, height: int = WRAP_CONTENT):
- super().__init__()
- self.width = width
- self.height = height
- self.column: int = -1
- self.span: int = 1
-
- def toString(self) -> str:
- return f"TableRow.LayoutParams(col={self.column}, span={self.span})"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._children: List[Any] = []
-
- def addView(self, child: Any, index: int = -1) -> None:
- if index < 0 or index >= len(self._children):
- self._children.append(child)
- else:
- self._children.insert(index, child)
-
- def getChildCount(self) -> int:
- return len(self._children)
-
- def getVirtualChildAt(self, index: int) -> Optional[Any]:
- if 0 <= index < len(self._children):
- return self._children[index]
- return None
-
- def toString(self) -> str:
- return f"TableRow(children={len(self._children)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# GridLayout
-# ═══════════════════════════════════════════════════════════════
-
-class GridLayout(Stub):
- """GridLayout — 网格布局"""
-
- class Alignment(Stub):
- """GridLayout.Alignment — 对齐方式"""
-
- def __init__(self, name: str = ""):
- super().__init__()
- self._name = name
-
- def toString(self) -> str:
- return f"Alignment({self._name})"
-
- FILL = Alignment("FILL")
- CENTER = Alignment("CENTER")
- LEFT = Alignment("LEFT")
- RIGHT = Alignment("RIGHT")
- TOP = Alignment("TOP")
- BOTTOM = Alignment("BOTTOM")
- BASELINE = Alignment("BASELINE")
- START = Alignment("START")
- END = Alignment("END")
-
- ALIGN_BOUNDS = 0
- ALIGN_MARGINS = 1
-
- HORIZONTAL = 0
- VERTICAL = 1
-
- UNDEFINED = -2147483648
-
- class Spec(Stub):
- """GridLayout.Spec — 网格规格"""
-
- def __init__(self, start: int = -2147483648, span: int = 1,
- alignment: Optional["GridLayout.Alignment"] = None):
- super().__init__()
- self.start = start
- self.span = span
- self.alignment = alignment
-
- def toString(self) -> str:
- return f"Spec(start={self.start}, span={self.span})"
-
- class LayoutParams(Stub):
- """GridLayout.LayoutParams — 网格布局参数"""
-
- def __init__(self):
- super().__init__()
- self.width = WRAP_CONTENT
- self.height = WRAP_CONTENT
- self.columnSpec = GridLayout.Spec(GridLayout.UNDEFINED, 1, GridLayout.FILL)
- self.rowSpec = GridLayout.Spec(GridLayout.UNDEFINED, 1, GridLayout.FILL)
- self.setMargins(0, 0, 0, 0)
- self.leftMargin = 0
- self.topMargin = 0
- self.rightMargin = 0
- self.bottomMargin = 0
-
- def setMargins(self, left: int, top: int, right: int, bottom: int) -> None:
- self.leftMargin = left
- self.topMargin = top
- self.rightMargin = right
- self.bottomMargin = bottom
-
- def setGravity(self, gravity: int) -> None:
- pass
-
- def toString(self) -> str:
- return (f"GridLayout.LayoutParams(col={self.columnSpec}, "
- f"row={self.rowSpec})")
-
- @staticmethod
- def spec(start: int = UNDEFINED, span: int = 1,
- alignment: Optional[Alignment] = None) -> Spec:
- return GridLayout.Spec(start, span, alignment)
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._orientation = self.HORIZONTAL
- self._column_count: int = 2
- self._row_count: int = 2
- self._alignment_mode = self.ALIGN_BOUNDS
- self._use_default_margins = False
- self._children: List[Any] = []
-
- def setOrientation(self, orientation: int) -> None:
- self._orientation = orientation
-
- def getOrientation(self) -> int:
- return self._orientation
-
- def setColumnCount(self, count: int) -> None:
- self._column_count = max(0, count)
-
- def getColumnCount(self) -> int:
- return self._column_count
-
- def setRowCount(self, count: int) -> None:
- self._row_count = max(0, count)
-
- def getRowCount(self) -> int:
- return self._row_count
-
- def setAlignmentMode(self, mode: int) -> None:
- self._alignment_mode = mode
-
- def getAlignmentMode(self) -> int:
- return self._alignment_mode
-
- def setUseDefaultMargins(self, use: bool) -> None:
- self._use_default_margins = use
-
- def getUseDefaultMargins(self) -> bool:
- return self._use_default_margins
-
- def toString(self) -> str:
- return f"GridLayout({self._column_count}x{self._row_count})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# LinearLayout / FrameLayout / RelativeLayout
-# ═══════════════════════════════════════════════════════════════
-
-class LinearLayout(_BaseLinearLayout):
- """LinearLayout — 线性布局"""
-
- HORIZONTAL = 0
- VERTICAL = 1
- SHOW_DIVIDER_NONE = 0
- SHOW_DIVIDER_BEGINNING = 1
- SHOW_DIVIDER_MIDDLE = 2
- SHOW_DIVIDER_END = 4
-
- class LayoutParams(Stub):
- """LinearLayout.LayoutParams — 线性布局参数"""
-
- def __init__(self, width: int = MATCH_PARENT, height: int = WRAP_CONTENT,
- weight: float = 0.0):
- super().__init__()
- self.width = width
- self.height = height
- self.weight = weight
- self.gravity = -1
- self.leftMargin = 0
- self.topMargin = 0
- self.rightMargin = 0
- self.bottomMargin = 0
-
- def setMargins(self, left: int, top: int, right: int, bottom: int) -> None:
- self.leftMargin = left
- self.topMargin = top
- self.rightMargin = right
- self.bottomMargin = bottom
-
- def toString(self) -> str:
- return (f"LinearLayout.LayoutParams({self.width}x{self.height}, "
- f"weight={self.weight})")
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._orientation = self.HORIZONTAL
- self._weight_sum: float = 0.0
- self._baseline_aligned = True
- self._divider: Optional[Any] = None
- self._divider_padding: int = 0
- self._show_dividers = self.SHOW_DIVIDER_NONE
- self._gravity: int = -1
-
- def setOrientation(self, orientation: int) -> None:
- self._orientation = orientation
-
- def getOrientation(self) -> int:
- return self._orientation
-
- def setWeightSum(self, weight_sum: float) -> None:
- self._weight_sum = weight_sum
-
- def getWeightSum(self) -> float:
- return self._weight_sum
-
- def setBaselineAligned(self, aligned: bool) -> None:
- self._baseline_aligned = aligned
-
- def isBaselineAligned(self) -> bool:
- return self._baseline_aligned
-
- def setDividerDrawable(self, divider: Any) -> None:
- self._divider = divider
-
- def getDividerDrawable(self) -> Optional[Any]:
- return self._divider
-
- def setDividerPadding(self, padding: int) -> None:
- self._divider_padding = padding
-
- def getDividerPadding(self) -> int:
- return self._divider_padding
-
- def setShowDividers(self, show: int) -> None:
- self._show_dividers = show
-
- def getShowDividers(self) -> int:
- return self._show_dividers
-
- def setGravity(self, gravity: int) -> None:
- self._gravity = gravity
-
- def getGravity(self) -> int:
- return self._gravity
-
- def toString(self) -> str:
- return f"LinearLayout(orientation={'H' if self._orientation == 0 else 'V'})"
-
-
-class FrameLayout(_BaseFrameLayout):
- """FrameLayout — 帧布局"""
-
- class LayoutParams(Stub):
- """FrameLayout.LayoutParams — 帧布局参数"""
-
- UNSPECIFIED_GRAVITY = -1
-
- def __init__(self, width: int = MATCH_PARENT, height: int = MATCH_PARENT,
- gravity: int = UNSPECIFIED_GRAVITY):
- super().__init__()
- self.width = width
- self.height = height
- self.gravity = gravity
- self.leftMargin = 0
- self.topMargin = 0
- self.rightMargin = 0
- self.bottomMargin = 0
-
- def setMargins(self, left: int, top: int, right: int, bottom: int) -> None:
- self.leftMargin = left
- self.topMargin = top
- self.rightMargin = right
- self.bottomMargin = bottom
-
- def toString(self) -> str:
- return (f"FrameLayout.LayoutParams({self.width}x{self.height}, "
- f"gravity={self.gravity})")
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._foreground: Optional[Any] = None
- self._foreground_gravity: int = 0
- self._measure_all_children = False
-
- def setForeground(self, drawable: Any) -> None:
- self._foreground = drawable
-
- def getForeground(self) -> Optional[Any]:
- return self._foreground
-
- def setForegroundGravity(self, gravity: int) -> None:
- self._foreground_gravity = gravity
-
- def getForegroundGravity(self) -> int:
- return self._foreground_gravity
-
- def setMeasureAllChildren(self, measure: bool) -> None:
- self._measure_all_children = measure
-
- def getMeasureAllChildren(self) -> bool:
- return self._measure_all_children
-
- def toString(self) -> str:
- return "FrameLayout()"
-
-
-class RelativeLayout(_BaseRelativeLayout):
- """RelativeLayout — 相对布局"""
-
- TRUE = -1
- FALSE = -2
-
- ALIGN_PARENT_LEFT = 1
- ALIGN_PARENT_TOP = 2
- ALIGN_PARENT_RIGHT = 4
- ALIGN_PARENT_BOTTOM = 8
- ALIGN_PARENT_START = 16
- ALIGN_PARENT_END = 32
- CENTER_IN_PARENT = 64
- CENTER_HORIZONTAL = 128
- CENTER_VERTICAL = 256
- ABOVE = 512
- BELOW = 1024
- LEFT_OF = 2048
- RIGHT_OF = 4096
- ALIGN_LEFT = 8192
- ALIGN_TOP = 16384
- ALIGN_RIGHT = 32768
- ALIGN_BOTTOM = 65536
- ALIGN_BASELINE = 131072
- ALIGN_START = 262144
- ALIGN_END = 524288
- START_OF = 1048576
- END_OF = 2097152
- LAYOUT_DIRECTION = 4194304
-
- class LayoutParams(Stub):
- """RelativeLayout.LayoutParams — 相对布局参数"""
-
- def __init__(self, width: int = WRAP_CONTENT, height: int = WRAP_CONTENT):
- super().__init__()
- self.width = width
- self.height = height
- self.leftMargin = 0
- self.topMargin = 0
- self.rightMargin = 0
- self.bottomMargin = 0
- self.marginStart = 0
- self.marginEnd = 0
- self._rules: Dict[int, int] = {}
- self._align_with_parent = False
-
- def addRule(self, verb: int, subject: int = -1) -> None:
- self._rules[verb] = subject
-
- def removeRule(self, verb: int) -> None:
- self._rules.pop(verb, None)
-
- def getRule(self, verb: int) -> int:
- return self._rules.get(verb, 0)
-
- def getRules(self) -> Dict[int, int]:
- return dict(self._rules)
-
- def setMargins(self, left: int, top: int, right: int, bottom: int) -> None:
- self.leftMargin = left
- self.topMargin = top
- self.rightMargin = right
- self.bottomMargin = bottom
-
- def setMarginStart(self, start: int) -> None:
- self.marginStart = start
-
- def setMarginEnd(self, end: int) -> None:
- self.marginEnd = end
-
- def toString(self) -> str:
- return (f"RelativeLayout.LayoutParams({self.width}x{self.height}, "
- f"rules={len(self._rules)})")
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._gravity: int = -1
- self._horizontal_gravity: int = -1
- self._vertical_gravity: int = -1
- self._ignore_gravity = False
-
- def setGravity(self, gravity: int) -> None:
- self._gravity = gravity
-
- def getGravity(self) -> int:
- return self._gravity
-
- def setHorizontalGravity(self, gravity: int) -> None:
- self._horizontal_gravity = gravity
-
- def setVerticalGravity(self, gravity: int) -> None:
- self._vertical_gravity = gravity
-
- def setIgnoreGravity(self, view_id: int) -> None:
- self._ignore_gravity = True
-
- def getIgnoreGravity(self) -> int:
- return 0
-
- def toString(self) -> str:
- return "RelativeLayout()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# NumberPicker / SearchView / TabHost / TabWidget
-# ═══════════════════════════════════════════════════════════════
-
-class NumberPicker(_BaseNumberPicker):
- """NumberPicker — 数字选择器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._min_value: int = 0
- self._max_value: int = 100
- self._value: int = 0
- self._wrap_selector_wheel = True
- self._on_value_change: Optional[Callable] = None
- self._on_scroll: Optional[Callable] = None
- self._displayed_values: Optional[List[str]] = None
- self._descendant_focus = False
-
- def setMinValue(self, value: int) -> None:
- self._min_value = value
- if self._value < value:
- self._value = value
-
- def getMinValue(self) -> int:
- return self._min_value
-
- def setMaxValue(self, value: int) -> None:
- self._max_value = value
- if self._value > value:
- self._value = value
-
- def getMaxValue(self) -> int:
- return self._max_value
-
- def setValue(self, value: int) -> None:
- self._value = max(self._min_value, min(self._max_value, value))
- if self._on_value_change:
- self._on_value_change(self, self._value, self._value)
-
- def getValue(self) -> int:
- return self._value
-
- def setWrapSelectorWheel(self, wrap: bool) -> None:
- self._wrap_selector_wheel = wrap
-
- def getWrapSelectorWheel(self) -> bool:
- return self._wrap_selector_wheel
-
- def setDisplayedValues(self, values: Optional[List[str]]) -> None:
- self._displayed_values = values
-
- def getDisplayedValues(self) -> Optional[List[str]]:
- return self._displayed_values
-
- def setOnValueChangedListener(self, listener: Optional[Callable]) -> None:
- self._on_value_change = listener
-
- def setOnScrollListener(self, listener: Optional[Callable]) -> None:
- self._on_scroll = listener
-
- def toString(self) -> str:
- return f"NumberPicker(value={self._value}, range=[{self._min_value}-{self._max_value}])"
-
-
-class SearchView(_BaseSearchView):
- """SearchView — 搜索视图扩展"""
-
- ICONIFIED = 0
- EXPANDED = 1
- COLLAPSED = 2
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._query: str = ""
- self._query_hint: Optional[str] = None
- self._iconified = True
- self._iconified_by_default = True
- self._submit_button_enabled = True
- self._query_refinement_enabled = False
- self._searchable_info: Optional[Any] = None
- self._on_query: Optional[Callable] = None
- self._on_query_text: Optional[Callable] = None
- self._on_close: Optional[Callable] = None
- self._on_suggestion: Optional[Callable] = None
-
- def setQuery(self, query: str, submit: bool = False) -> None:
- self._query = query
- if submit and self._on_query:
- self._on_query(query)
-
- def getQuery(self) -> str:
- return self._query
-
- def setQueryHint(self, hint: Optional[str]) -> None:
- self._query_hint = hint
-
- def getQueryHint(self) -> Optional[str]:
- return self._query_hint
-
- def setIconified(self, iconified: bool) -> None:
- self._iconified = iconified
-
- def isIconified(self) -> bool:
- return self._iconified
-
- def setIconifiedByDefault(self, iconified: bool) -> None:
- self._iconified_by_default = iconified
-
- def isIconifiedByDefault(self) -> bool:
- return self._iconified_by_default
-
- def setSubmitButtonEnabled(self, enabled: bool) -> None:
- self._submit_button_enabled = enabled
-
- def isSubmitButtonEnabled(self) -> bool:
- return self._submit_button_enabled
-
- def setQueryRefinementEnabled(self, enabled: bool) -> None:
- self._query_refinement_enabled = enabled
-
- def isQueryRefinementEnabled(self) -> bool:
- return self._query_refinement_enabled
-
- def setOnQueryTextListener(self, listener: Optional[Callable]) -> None:
- self._on_query_text = listener
-
- def setOnCloseListener(self, listener: Optional[Callable]) -> None:
- self._on_close = listener
-
- def setOnSuggestionListener(self, listener: Optional[Callable]) -> None:
- self._on_suggestion = listener
-
- def setSearchableInfo(self, info: Any) -> None:
- self._searchable_info = info
-
- def onActionViewExpanded(self) -> None:
- self._iconified = False
-
- def onActionViewCollapsed(self) -> None:
- self._iconified = True
-
- def toString(self) -> str:
- return f"SearchView(query={self._query})"
-
-
-class TabHost(_BaseTabHost):
- """TabHost — 标签宿主"""
-
- class TabSpec(Stub):
- """TabHost.TabSpec — 标签规格"""
-
- def __init__(self, tag: str = ""):
- super().__init__()
- self._tag = tag
- self._indicator: Optional[Any] = None
- self._content: Optional[Any] = None
-
- def setIndicator(self, indicator: Any) -> "TabHost.TabSpec":
- self._indicator = indicator
- return self
-
- def setContent(self, content: Any) -> "TabHost.TabSpec":
- self._content = content
- return self
-
- def getTag(self) -> str:
- return self._tag
-
- def toString(self) -> str:
- return f"TabSpec(tag={self._tag})"
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._tabs: List[TabHost.TabSpec] = []
- self._current_tab: int = 0
-
- def newTabSpec(self, tag: str) -> TabSpec:
- return TabHost.TabSpec(tag)
-
- def addTab(self, spec: TabSpec) -> None:
- self._tabs.append(spec)
-
- def setCurrentTab(self, index: int) -> None:
- if 0 <= index < len(self._tabs):
- self._current_tab = index
-
- def setCurrentTabByTag(self, tag: str) -> None:
- for i, spec in enumerate(self._tabs):
- if spec.getTag() == tag:
- self._current_tab = i
- break
-
- def getCurrentTab(self) -> int:
- return self._current_tab
-
- def getCurrentTabTag(self) -> str:
- if 0 <= self._current_tab < len(self._tabs):
- return self._tabs[self._current_tab].getTag()
- return ""
-
- def getTabWidget(self) -> Optional["TabWidget"]:
- return None
-
- def getTabContentView(self) -> Optional[Any]:
- return None
-
- def getTabCount(self) -> int:
- return len(self._tabs)
-
- def toString(self) -> str:
- return f"TabHost(tabs={len(self._tabs)}, current={self._current_tab})"
-
-
-class TabWidget(_BaseTabWidget):
- """TabWidget — 标签小部件"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._tabs: List[Any] = []
- self._current_tab: int = 0
- self._strip_enabled = False
- self._strip_left: int = 0
- self._strip_top: int = 0
- self._strip_right: int = 0
- self._strip_bottom: int = 0
-
- def setCurrentTab(self, index: int) -> None:
- self._current_tab = max(0, min(index, len(self._tabs) - 1))
-
- def getCurrentTab(self) -> int:
- return self._current_tab
-
- def setStripEnabled(self, enabled: bool) -> None:
- self._strip_enabled = enabled
-
- def isStripEnabled(self) -> bool:
- return self._strip_enabled
-
- def getTabCount(self) -> int:
- return len(self._tabs)
-
- def toString(self) -> str:
- return f"TabWidget(tabs={len(self._tabs)})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# TextSwitcher / ViewSwitcher / ViewAnimator / ImageSwitcher
-# ═══════════════════════════════════════════════════════════════
-
-class ViewAnimator(_BaseViewAnimator):
- """ViewAnimator — 视图动画器"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._children: List[Any] = []
- self._displayed_child: int = 0
- self._in_animation: Optional[Any] = None
- self._out_animation: Optional[Any] = None
- self._animate_first_view = False
-
- def addView(self, child: Any) -> None:
- self._children.append(child)
-
- def removeView(self, child: Any) -> None:
- if child in self._children:
- self._children.remove(child)
-
- def removeAllViews(self) -> None:
- self._children.clear()
-
- def getChildCount(self) -> int:
- return len(self._children)
-
- def getCurrentView(self) -> Optional[Any]:
- if 0 <= self._displayed_child < len(self._children):
- return self._children[self._displayed_child]
- return None
-
- def getDisplayedChild(self) -> int:
- return self._displayed_child
-
- def setDisplayedChild(self, index: int) -> None:
- if 0 <= index < len(self._children):
- self._displayed_child = index
-
- def showNext(self) -> None:
- if self._children:
- self._displayed_child = (self._displayed_child + 1) % len(self._children)
-
- def showPrevious(self) -> None:
- if self._children:
- self._displayed_child = (self._displayed_child - 1) % len(self._children)
-
- def setInAnimation(self, animation: Any) -> None:
- self._in_animation = animation
-
- def getInAnimation(self) -> Optional[Any]:
- return self._in_animation
-
- def setOutAnimation(self, animation: Any) -> None:
- self._out_animation = animation
-
- def getOutAnimation(self) -> Optional[Any]:
- return self._out_animation
-
- def setAnimateFirstView(self, animate: bool) -> None:
- self._animate_first_view = animate
-
- def getAnimateFirstView(self) -> bool:
- return self._animate_first_view
-
- def toString(self) -> str:
- return f"ViewAnimator(children={len(self._children)}, displayed={self._displayed_child})"
-
-
-class ViewSwitcher(_BaseViewSwitcher, ViewAnimator):
- """ViewSwitcher — 视图切换器"""
-
- class ViewFactory(Stub):
- """ViewSwitcher.ViewFactory — 视图工厂"""
- def makeView(self) -> Any:
- return None
-
- def __init__(self, context: Any = None):
- super().__init__(context)
- ViewAnimator.__init__(self, context)
- self._factory: Optional[ViewSwitcher.ViewFactory] = None
-
- def setFactory(self, factory: ViewFactory) -> None:
- self._factory = factory
-
- def getNextView(self) -> Optional[Any]:
- next_idx = (self.getDisplayedChild() + 1) % max(1, self.getChildCount())
- if 0 <= next_idx < self.getChildCount():
- return None
- return None
-
- def reset(self) -> None:
- self.removeAllViews()
-
- def toString(self) -> str:
- return f"ViewSwitcher()"
-
-
-class TextSwitcher(_BaseTextSwitcher, ViewSwitcher):
- """TextSwitcher — 文本切换器"""
-
- def __init__(self, context: Any = None):
- super().__init__(context)
- ViewSwitcher.__init__(self, context)
- self._factory = None
-
- def setCurrentText(self, text: str) -> None:
- pass
-
- def getCurrentText(self) -> str:
- return ""
-
- def toString(self) -> str:
- return "TextSwitcher()"
-
-
-class ImageSwitcher(_BaseImageSwitcher, ViewSwitcher):
- """ImageSwitcher — 图片切换器"""
-
- def __init__(self, context: Any = None):
- super().__init__(context)
- ViewSwitcher.__init__(self, context)
-
- def setImageResource(self, res_id: int) -> None:
- pass
-
- def setImageDrawable(self, drawable: Any) -> None:
- pass
-
- def setImageURI(self, uri: Any) -> None:
- pass
-
- def toString(self) -> str:
- return "ImageSwitcher()"
-
-
-class ImageButton(_BaseImageButton):
- """ImageButton — 图片按钮"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._adjust_view_bounds = False
- self._scale_type: Optional[Any] = None
-
- def setAdjustViewBounds(self, adjust: bool) -> None:
- self._adjust_view_bounds = adjust
-
- def getAdjustViewBounds(self) -> bool:
- return self._adjust_view_bounds
-
- def setScaleType(self, scale_type: Any) -> None:
- self._scale_type = scale_type
-
- def getScaleType(self) -> Optional[Any]:
- return self._scale_type
-
- def toString(self) -> str:
- return "ImageButton()"
-
-
-class ZoomButton(ImageButton):
- """ZoomButton — 缩放按钮"""
-
- def __init__(self, context: Any = None):
- super().__init__(context)
- self._zoom_in = False
- self._zoom_speed: int = 300
- self._on_click: Optional[Callable] = None
-
- def setZoomIn(self, zoom_in: bool) -> None:
- self._zoom_in = zoom_in
-
- def isZoomIn(self) -> bool:
- return self._zoom_in
-
- def setZoomSpeed(self, speed: int) -> None:
- self._zoom_speed = speed
-
- def getZoomSpeed(self) -> int:
- return self._zoom_speed
-
- def setOnZoomListener(self, listener: Optional[Callable]) -> None:
- self._on_click = listener
-
- def toString(self) -> str:
- return f"ZoomButton(zoomIn={self._zoom_in})"
-
-
-class ZoomControls(_BaseZoomControls):
- """ZoomControls — 缩放控件"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._zoom_in_enabled = True
- self._zoom_out_enabled = True
- self._on_zoom_in: Optional[Callable] = None
- self._on_zoom_out: Optional[Callable] = None
- self._show_zoom_controls = True
-
- def setOnZoomInClickListener(self, listener: Optional[Callable]) -> None:
- self._on_zoom_in = listener
-
- def setOnZoomOutClickListener(self, listener: Optional[Callable]) -> None:
- self._on_zoom_out = listener
-
- def setZoomInEnabled(self, enabled: bool) -> None:
- self._zoom_in_enabled = enabled
-
- def setZoomOutEnabled(self, enabled: bool) -> None:
- self._zoom_out_enabled = enabled
-
- def show(self) -> None:
- self._show_zoom_controls = True
-
- def hide(self) -> None:
- self._show_zoom_controls = False
-
- def setIsZoomInEnabled(self, enabled: bool) -> None:
- self._zoom_in_enabled = enabled
-
- def setIsZoomOutEnabled(self, enabled: bool) -> None:
- self._zoom_out_enabled = enabled
-
- def hasFocus(self) -> bool:
- return False
-
- def toString(self) -> str:
- return "ZoomControls()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# DigitalClock / TextClock / AnalogClock
-# ═══════════════════════════════════════════════════════════════
-
-class DigitalClock(_BaseDigitalClock):
- """DigitalClock — 数字时钟"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._format: str = "%H:%M:%S"
- self._on_tick: Optional[Callable] = None
-
- def setFormat(self, format_str: str) -> None:
- self._format = format_str
-
- def getFormat(self) -> str:
- return self._format
-
- def getTime(self) -> str:
- import datetime
- return datetime.datetime.now().strftime(self._format)
-
- def setOnTickListener(self, listener: Optional[Callable]) -> None:
- self._on_tick = listener
-
- def toString(self) -> str:
- return f"DigitalClock(time={self.getTime()})"
-
-
-class TextClock(Stub):
- """TextClock — 文本时钟"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._format_12_hour: str = "hh:mm:ss a"
- self._format_24_hour: str = "HH:mm:ss"
- self._time_zone: Optional[str] = None
-
- def setFormat12Hour(self, format_str: str) -> None:
- self._format_12_hour = format_str
-
- def getFormat12Hour(self) -> str:
- return self._format_12_hour
-
- def setFormat24Hour(self, format_str: str) -> None:
- self._format_24_hour = format_str
-
- def getFormat24Hour(self) -> str:
- return self._format_24_hour
-
- def setTimeZone(self, tz: str) -> None:
- self._time_zone = tz
-
- def getTimeZone(self) -> Optional[str]:
- return self._time_zone
-
- def is24HourModeEnabled(self) -> bool:
- return True
-
- def getText(self) -> str:
- import datetime
- if self._time_zone:
- import pytz
- now = datetime.datetime.now(pytz.timezone(self._time_zone))
- else:
- now = datetime.datetime.now()
- return now.strftime(self._format_24_hour)
-
- def toString(self) -> str:
- return f"TextClock(time={self.getText()})"
-
-
-class AnalogClock(_BaseAnalogClock):
- """AnalogClock — 模拟时钟"""
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._dial: Optional[Any] = None
- self._hour_hand: Optional[Any] = None
- self._minute_hand: Optional[Any] = None
- self._second_hand: Optional[Any] = None
-
- def toString(self) -> str:
- return "AnalogClock()"
-
-
-# ═══════════════════════════════════════════════════════════════
-# QuickContactBadge
-# ═══════════════════════════════════════════════════════════════
-
-class QuickContactBadge(Stub):
- """QuickContactBadge — 快速联系人徽章"""
-
- MODE_SMALL = 0
- MODE_MEDIUM = 1
- MODE_LARGE = 2
-
- def __init__(self, context: Any = None):
- super().__init__()
- self._contact_uri: Optional[str] = None
- self._mode = self.MODE_MEDIUM
- self._on_click: Optional[Callable] = None
-
- def assignContactUri(self, uri: str) -> None:
- self._contact_uri = uri
-
- def assignContactFromEmail(self, email: str, lazy: bool = False) -> None:
- self._contact_uri = f"mailto:{email}"
-
- def assignContactFromPhone(self, phone: str, lazy: bool = False) -> None:
- self._contact_uri = f"tel:{phone}"
-
- def setMode(self, mode: int) -> None:
- self._mode = mode
-
- def getMode(self) -> int:
- return self._mode
-
- def setOnClickListener(self, listener: Optional[Callable]) -> None:
- self._on_click = listener
-
- def toString(self) -> str:
- return f"QuickContactBadge(contact={self._contact_uri})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# 各种 Adapter 实现
-# ═══════════════════════════════════════════════════════════════
-
-class BaseAdapter(_BaseBaseAdapter, Adapter):
- """BaseAdapter — 基础适配器"""
-
- def __init__(self):
- super().__init__()
- self._data_set_observers: List[Callable] = []
-
- def registerDataSetObserver(self, observer: Callable) -> None:
- if observer not in self._data_set_observers:
- self._data_set_observers.append(observer)
-
- def unregisterDataSetObserver(self, observer: Callable) -> None:
- if observer in self._data_set_observers:
- self._data_set_observers.remove(observer)
-
- def notifyDataSetChanged(self) -> None:
- for obs in list(self._data_set_observers):
- obs()
-
- def notifyDataSetInvalidated(self) -> None:
- self.notifyDataSetChanged()
-
- def areAllItemsEnabled(self) -> bool:
- return True
-
- def isEnabled(self, position: int) -> bool:
- return True
-
- def getItemViewType(self, position: int) -> int:
- return Adapter.IGNORE_ITEM_VIEW_TYPE
-
- def getViewTypeCount(self) -> int:
- return 1
-
- def hasStableIds(self) -> bool:
- return False
-
- def isEmpty(self) -> bool:
- return self.getCount() == 0
-
-
-class ArrayAdapter(_BaseArrayAdapter, BaseAdapter):
- """ArrayAdapter — 数组适配器"""
-
- def __init__(self, context: Any = None, resource: int = 0,
- objects: Optional[List[Any]] = None):
- BaseAdapter.__init__(self)
- self._context = context
- self._resource = resource
- self._drop_down_resource: int = resource
- self._objects: List[Any] = list(objects) if objects else []
- self._lock = threading.Lock()
-
- def add(self, obj: Any) -> None:
- with self._lock:
- self._objects.append(obj)
- self.notifyDataSetChanged()
-
- def addAll(self, collection: List[Any]) -> None:
- with self._lock:
- self._objects.extend(collection)
- self.notifyDataSetChanged()
-
- def insert(self, obj: Any, index: int) -> None:
- with self._lock:
- self._objects.insert(index, obj)
- self.notifyDataSetChanged()
-
- def remove(self, obj: Any) -> None:
- with self._lock:
- if obj in self._objects:
- self._objects.remove(obj)
- self.notifyDataSetChanged()
-
- def clear(self) -> None:
- with self._lock:
- self._objects.clear()
- self.notifyDataSetChanged()
-
- def sort(self, comparator: Callable) -> None:
- with self._lock:
- self._objects.sort(key=comparator)
- self.notifyDataSetChanged()
-
- def getCount(self) -> int:
- return len(self._objects)
-
- def getItem(self, position: int) -> Optional[Any]:
- if 0 <= position < len(self._objects):
- return self._objects[position]
- return None
-
- def getPosition(self, item: Any) -> int:
- try:
- return self._objects.index(item)
- except ValueError:
- return -1
-
- def setDropDownViewResource(self, resource: int) -> None:
- self._drop_down_resource = resource
-
- def getDropDownViewResource(self) -> int:
- return self._drop_down_resource
-
- def toString(self) -> str:
- return f"ArrayAdapter(items={len(self._objects)})"
-
-
-class SimpleAdapter(_BaseSimpleAdapter, BaseAdapter):
- """SimpleAdapter — 简单适配器"""
-
- def __init__(self, context: Any = None,
- data: Optional[List[Dict[str, Any]]] = None,
- resource: int = 0,
- from_keys: Optional[List[str]] = None,
- to_ids: Optional[List[int]] = None):
- BaseAdapter.__init__(self)
- self._context = context
- self._data: List[Dict[str, Any]] = data or []
- self._resource = resource
- self._from_keys: List[str] = list(from_keys) if from_keys else []
- self._to_ids: List[int] = list(to_ids) if to_ids else []
- self._drop_down_resource: int = resource
- self._view_binder: Optional[Callable] = None
-
- def getCount(self) -> int:
- return len(self._data)
-
- def getItem(self, position: int) -> Optional[Dict[str, Any]]:
- if 0 <= position < len(self._data):
- return self._data[position]
- return None
-
- def getViewBinder(self) -> Optional[Callable]:
- return self._view_binder
-
- def setViewBinder(self, binder: Optional[Callable]) -> None:
- self._view_binder = binder
-
- def setDropDownViewResource(self, resource: int) -> None:
- self._drop_down_resource = resource
-
- def getDropDownViewResource(self) -> int:
- return self._drop_down_resource
-
- def toString(self) -> str:
- return f"SimpleAdapter(items={len(self._data)})"
-
-
-class CursorAdapter(_BaseCursorAdapter, BaseAdapter):
- """CursorAdapter — 游标适配器"""
-
- FLAG_AUTO_REQUERY = 1
- FLAG_REGISTER_CONTENT_OBSERVER = 2
-
- def __init__(self, context: Any = None, cursor: Any = None,
- flags: int = FLAG_AUTO_REQUERY):
- BaseAdapter.__init__(self)
- self._context = context
- self._cursor = cursor
- self._flags = flags
- self._row_id_column: str = "_id"
- self._lock = threading.Lock()
-
- def getCursor(self) -> Optional[Any]:
- return self._cursor
-
- def setCursor(self, cursor: Any) -> None:
- self._cursor = cursor
- self.notifyDataSetChanged()
-
- def getCount(self) -> int:
- return 0
-
- def getItem(self, position: int) -> Optional[Any]:
- return None
-
- def getItemId(self, position: int) -> int:
- return position
-
- def changeCursor(self, cursor: Any) -> Optional[Any]:
- old = self._cursor
- self._cursor = cursor
- self.notifyDataSetChanged()
- return old
-
- def swapCursor(self, cursor: Any) -> Optional[Any]:
- old = self._cursor
- self._cursor = cursor
- self.notifyDataSetChanged()
- return old
-
- def toString(self) -> str:
- return f"CursorAdapter(cursor={'yes' if self._cursor else 'no'})"
-
-
-class ResourceCursorAdapter(CursorAdapter):
- """ResourceCursorAdapter — 资源游标适配器"""
-
- def __init__(self, context: Any = None, layout: int = 0,
- cursor: Any = None, flags: int = CursorAdapter.FLAG_AUTO_REQUERY):
- super().__init__(context, cursor, flags)
- self._layout = layout
- self._drop_down_layout: int = layout
-
- def setDropDownViewResource(self, resource: int) -> None:
- self._drop_down_layout = resource
-
- def getDropDownViewResource(self) -> int:
- return self._drop_down_layout
-
- def toString(self) -> str:
- return "ResourceCursorAdapter()"
-
-
-class SimpleCursorAdapter(ResourceCursorAdapter):
- """SimpleCursorAdapter — 简单游标适配器"""
-
- def __init__(self, context: Any = None, layout: int = 0,
- cursor: Any = None, from_columns: Optional[List[str]] = None,
- to_views: Optional[List[int]] = None,
- flags: int = CursorAdapter.FLAG_AUTO_REQUERY):
- super().__init__(context, layout, cursor, flags)
- self._from_columns: List[str] = list(from_columns) if from_columns else []
- self._to_views: List[int] = list(to_views) if to_views else []
- self._view_binder: Optional[Callable] = None
- self._cursor_to_column_map: Optional[Dict[str, int]] = None
-
- def getViewBinder(self) -> Optional[Callable]:
- return self._view_binder
-
- def setViewBinder(self, binder: Optional[Callable]) -> None:
- self._view_binder = binder
-
- def setCursorToStringConverter(self, converter: Optional[Callable]) -> None:
- pass
-
- def toString(self) -> str:
- return "SimpleCursorAdapter()"
-
-
-class HeaderViewListAdapter(Stub):
- """HeaderViewListAdapter — 头部视图列表适配器包装"""
-
- def __init__(self, wrapped_adapter: Optional[Adapter] = None):
- super().__init__()
- self._wrapped: Optional[Adapter] = wrapped_adapter
- self._headers: List[Any] = []
- self._footers: List[Any] = []
-
- def addHeaderView(self, view: Any, data: Any = None, is_selectable: bool = True) -> None:
- self._headers.append(view)
-
- def addFooterView(self, view: Any, data: Any = None, is_selectable: bool = True) -> None:
- self._footers.append(view)
-
- def removeHeaderView(self, view: Any) -> bool:
- if view in self._headers:
- self._headers.remove(view)
- return True
- return False
-
- def removeFooterView(self, view: Any) -> bool:
- if view in self._footers:
- self._footers.remove(view)
- return True
- return False
-
- def getCount(self) -> int:
- base = self._wrapped.getCount() if self._wrapped else 0
- return base + len(self._headers) + len(self._footers)
-
- def getWrappedAdapter(self) -> Optional[Adapter]:
- return self._wrapped
-
- def getHeadersCount(self) -> int:
- return len(self._headers)
-
- def getFootersCount(self) -> int:
- return len(self._footers)
-
- def isEmpty(self) -> bool:
- return self.getCount() == 0
-
- def toString(self) -> str:
- return (f"HeaderViewListAdapter(headers={len(self._headers)}, "
- f"footers={len(self._footers)})")
-
-
-class WrapperListAdapter(Adapter):
- """WrapperListAdapter — 包装列表适配器"""
-
- def __init__(self, wrapped: Optional[Adapter] = None):
- super().__init__()
- self._wrapped = wrapped
-
- def getWrappedAdapter(self) -> Optional[Adapter]:
- return self._wrapped
-
- def getCount(self) -> int:
- return self._wrapped.getCount() if self._wrapped else 0
-
- def getItem(self, position: int) -> Optional[Any]:
- return self._wrapped.getItem(position) if self._wrapped else None
-
- def getItemId(self, position: int) -> int:
- return self._wrapped.getItemId(position) if self._wrapped else position
-
- def getView(self, position: int, convert_view: Optional[Any],
- parent: Any) -> Optional[Any]:
- return self._wrapped.getView(position, convert_view, parent) if self._wrapped else None
-
- def toString(self) -> str:
- return "WrapperListAdapter()"
\ No newline at end of file
diff --git a/android_pyapi/dalvik/__init__.py b/android_pyapi/dalvik/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/android_pyapi/dalvik/system.py b/android_pyapi/dalvik/system.py
deleted file mode 100644
index 009c3b6..0000000
--- a/android_pyapi/dalvik/system.py
+++ /dev/null
@@ -1,721 +0,0 @@
-"""
-Android dalvik.system APIs implemented in Python.
-dalvik.system package - DexClassLoader, PathClassLoader, DexFile, VMRuntime, VMDebug, etc.
-Desktop stub implementation.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-import sys as _sys
-import os as _os
-from typing import List, Optional
-
-__all__ = [
- "DexClassLoader", "PathClassLoader", "BaseDexClassLoader",
- "DexFile", "InMemoryDexClassLoader",
- "VMRuntime", "VMDebug",
- "CloseGuard", "PotentialDeadlockError",
- "BlockGuard",
-]
-
-
-# ============================================================
-# BaseDexClassLoader
-# ============================================================
-
-class BaseDexClassLoader(Stub):
- """
- dalvik.system.BaseDexClassLoader
- A class loader that loads classes from DEX files.
- """
-
- def __init__(self, dex_path: str = "", optimized_dir: str = None,
- library_search_path: str = None, parent: Any = None):
- super().__init__()
- self._dex_path = dex_path
- self._optimized_dir = optimized_dir
- self._library_search_path = library_search_path
- self._parent = parent or type.__subclasses__
- self._loaded_classes = set()
- self._assertion_status = {}
- self._default_assertion_status = False
-
- def loadClass(self, name: str, resolve: bool = True) -> Optional[type]:
- """Loads a class by name."""
- # Try to find the class in the Python path
- parts = name.split(".")
- module_name = ".".join(parts[:-1])
- class_name = parts[-1]
- try:
- if module_name:
- module = __import__(module_name, fromlist=[class_name])
- cls = getattr(module, class_name, None)
- else:
- cls = globals().get(class_name) or __builtins__.get(class_name)
- if cls:
- self._loaded_classes.add(name)
- return cls
- return None
- except (ImportError, AttributeError):
- return None
-
- def findClass(self, name: str) -> Optional[type]:
- """Finds a class by name."""
- return self.loadClass(name)
-
- def findResource(self, name: str) -> Optional[str]:
- """Finds a resource by name."""
- path = _os.path.join(self._dex_path or "", name)
- if _os.path.exists(path):
- return path
- return None
-
- def findResources(self, name: str) -> List[str]:
- """Finds all resources by name."""
- result = []
- r = self.findResource(name)
- if r:
- result.append(r)
- return result
-
- def getParent(self):
- return self._parent
-
- def getPackage(self, name: str):
- """Gets a package by name."""
- return None
-
- def setClassAssertionStatus(self, class_name: str, enabled: bool):
- self._assertion_status[class_name] = enabled
-
- def setDefaultAssertionStatus(self, enabled: bool):
- self._default_assertion_status = enabled
-
- def setPackageAssertionStatus(self, package_name: str, enabled: bool):
- pass
-
- def clearAssertionStatus(self):
- self._assertion_status = {}
- self._default_assertion_status = False
-
- def toString(self) -> str:
- return f"BaseDexClassLoader@{hex(id(self))}[dex={self._dex_path}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DexClassLoader
-# ============================================================
-
-class DexClassLoader(BaseDexClassLoader):
- """
- dalvik.system.DexClassLoader
- A class loader that loads classes from .jar and .apk files.
- """
-
- def __init__(self, dex_path: str = "", optimized_dir: str = None,
- library_search_path: str = None, parent: Any = None):
- super().__init__(dex_path, optimized_dir, library_search_path, parent)
-
- def loadClass(self, name: str, resolve: bool = True) -> Optional[type]:
- return super().loadClass(name, resolve)
-
- def findClass(self, name: str) -> Optional[type]:
- return super().findClass(name)
-
- def getParent(self):
- return super().getParent()
-
- def getResourceAsStream(self, name: str):
- """Returns an input stream for reading a resource."""
- path = self.findResource(name)
- if path:
- return open(path, 'rb')
- return None
-
- def getResources(self, name: str):
- """Returns an enumeration of URLs for a resource."""
- return iter(self.findResources(name))
-
- def toString(self) -> str:
- return f"DexClassLoader@{hex(id(self))}[dex={self._dex_path}]"
-
-
-# ============================================================
-# PathClassLoader
-# ============================================================
-
-class PathClassLoader(BaseDexClassLoader):
- """
- dalvik.system.PathClassLoader
- A class loader for loading classes from the file system.
- """
-
- def __init__(self, dex_path: str = "", parent: Any = None,
- library_search_path: str = None):
- super().__init__(dex_path, None, library_search_path, parent)
-
- def loadClass(self, name: str, resolve: bool = True) -> Optional[type]:
- return super().loadClass(name, resolve)
-
- def findClass(self, name: str) -> Optional[type]:
- return super().findClass(name)
-
- def getParent(self):
- return super().getParent()
-
- def toString(self) -> str:
- return f"PathClassLoader@{hex(id(self))}[dex={self._dex_path}]"
-
-
-# ============================================================
-# InMemoryDexClassLoader
-# ============================================================
-
-class InMemoryDexClassLoader(BaseDexClassLoader):
- """
- dalvik.system.InMemoryDexClassLoader
- A class loader that loads classes from in-memory DEX buffers.
- """
-
- def __init__(self, dex_buffers: List, parent: Any = None):
- super().__init__("", None, None, parent)
- self._dex_buffers = dex_buffers
-
- def loadClass(self, name: str, resolve: bool = True) -> Optional[type]:
- return super().loadClass(name, resolve)
-
- def findClass(self, name: str) -> Optional[type]:
- return super().findClass(name)
-
- def toString(self) -> str:
- return f"InMemoryDexClassLoader@{hex(id(self))}[buffers={len(self._dex_buffers)}]"
-
-
-# ============================================================
-# DexFile
-# ============================================================
-
-class DexFile(Stub):
- """
- dalvik.system.DexFile
- Represents a single DEX file.
- """
-
- def __init__(self, file_name: str = None):
- super().__init__()
- self._file_name = file_name
- self._closed = False
-
- @staticmethod
- def loadDex(source_path: str, output_path: str, flags: int = 0) -> "DexFile":
- return DexFile(source_path)
-
- def loadClass(self, name: str, loader: Any = None) -> Optional[type]:
- """Loads a class from this DEX file."""
- parts = name.split(".")
- try:
- module = __import__(".".join(parts[:-1]), fromlist=[parts[-1]])
- return getattr(module, parts[-1], None)
- except (ImportError, AttributeError):
- return None
-
- def loadClassBinaryName(self, name: str, loader: Any = None) -> Optional[type]:
- """Loads a class using binary (internal) name format."""
- java_name = name.replace("/", ".")
- return self.loadClass(java_name, loader)
-
- def getName(self) -> str:
- return self._file_name or ""
-
- def close(self):
- self._closed = True
-
- def entries(self):
- """Returns an enumeration of class names."""
- return iter([])
-
- def getEntryCount(self) -> int:
- return 0
-
- @staticmethod
- def isDexOptNeeded(source_path: str) -> bool:
- return False
-
- def toString(self) -> str:
- return f"DexFile@{hex(id(self))}[file={self._file_name}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# VMRuntime
-# ============================================================
-
-class VMRuntime(Stub):
- """
- dalvik.system.VMRuntime
- Provides access to Dalvik/ART VM runtime features.
- """
-
- _runtime = None
-
- def __init__(self):
- super().__init__()
- self._target_sdk_version = 0
- self._jit_compiler_filter = "speed"
- self._large_heap_class = None
- self._large_heap_size = 0
- self._native_allocation_count = 0
- self._disabled_compat_changes = []
-
- @staticmethod
- def getRuntime() -> "VMRuntime":
- if VMRuntime._runtime is None:
- VMRuntime._runtime = VMRuntime()
- return VMRuntime._runtime
-
- def is64Bit(self) -> bool:
- import struct
- return struct.calcsize("P") == 8
-
- def setTargetSdkVersion(self, version: int):
- self._target_sdk_version = version
-
- def getTargetSdkVersion(self) -> int:
- return self._target_sdk_version
-
- def startJitCompilation(self):
- pass
-
- def endJitCompilation(self):
- pass
-
- def concurrentGC(self, enable: bool):
- pass
-
- def enableGcLogging(self, enable: bool):
- pass
-
- def vmInstructionSet(self) -> str:
- import platform
- machine = platform.machine()
- if machine in ("x86_64", "amd64"):
- return "x86_64"
- elif machine in ("i386", "i686"):
- return "x86"
- elif machine in ("aarch64", "arm64"):
- return "arm64"
- elif machine.startswith("arm"):
- return "arm"
- return machine
-
- def isVm64(self) -> bool:
- return self.is64Bit()
-
- def getExprOpts(self) -> str:
- return ""
-
- def setExprOpts(self, opts: str):
- pass
-
- def registerAppInfo(self, app_name: str, app_data_dir: str):
- pass
-
- def getDetachThreadTimeout(self) -> int:
- return 0
-
- def setDetachThreadTimeout(self, timeout_ms: int):
- pass
-
- def setDisabledCompatChanges(self, changes: List[int]):
- self._disabled_compat_changes = list(changes)
-
- def isBootClassPathOnDisk(self) -> bool:
- return True
-
- def isJavaDebuggable(self) -> bool:
- return False
-
- def getJitCompilerFilter(self) -> str:
- return self._jit_compiler_filter
-
- def setJitCompilerFilter(self, filter_: str):
- self._jit_compiler_filter = filter_
-
- def getLargeHeapClass(self) -> str:
- return self._large_heap_class
-
- def setLargeHeapClass(self, class_name: str):
- self._large_heap_class = class_name
-
- def getLargeHeapSize(self) -> int:
- return self._large_heap_size
-
- def setLargeHeapSize(self, size: int):
- self._large_heap_size = size
-
- def registerNativeAllocation(self, bytes_: int):
- self._native_allocation_count += bytes_
-
- def registerNativeFree(self, bytes_: int):
- self._native_allocation_count -= bytes_
-
- def toString(self) -> str:
- return f"VMRuntime@{hex(id(self))}[64bit={self.is64Bit()}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# VMDebug
-# ============================================================
-
-class VMDebug(Stub):
- """
- dalvik.system.VMDebug
- Provides debug features for the VM.
- """
- TRACE_COUNT_ALLOCS: int = 1
- TRACE_COUNT_ALLOCS_SYSTEM_ONLY: int = 2
- TRACE_COUNT_ALLOCS_ALL: int = 3
-
- def __init__(self):
- super().__init__()
- self._alloc_count = 0
- self._alloc_size = 0
- self._freed_count = 0
- self._freed_size = 0
-
- @staticmethod
- def startCountingAllocations():
- pass
-
- @staticmethod
- def stopCountingAllocations():
- pass
-
- @staticmethod
- def getGlobalAllocCount() -> int:
- return 0
-
- @staticmethod
- def getGlobalAllocSize() -> int:
- return 0
-
- @staticmethod
- def getGlobalFreedCount() -> int:
- return 0
-
- @staticmethod
- def getGlobalFreedSize() -> int:
- return 0
-
- @staticmethod
- def getLoadedClasses() -> int:
- return 0
-
- @staticmethod
- def printLoadedClasses(count: int):
- pass
-
- @staticmethod
- def isDebuggerConnected() -> bool:
- return False
-
- @staticmethod
- def isDebuggingEnabled() -> bool:
- return False
-
- @staticmethod
- def resetAllocCount():
- pass
-
- @staticmethod
- def getThreadAllocCount() -> int:
- return 0
-
- @staticmethod
- def getThreadAllocSize() -> int:
- return 0
-
- @staticmethod
- def threadCpuTimeNanos() -> int:
- import time
- return int(time.time() * 1e9)
-
- @staticmethod
- def startEmulatorTracing():
- pass
-
- @staticmethod
- def stopEmulatorTracing():
- pass
-
- @staticmethod
- def startMethodTracing(filename: str = None, buffer_size: int = 0, flags: int = 0, sampling_interval: int = 0):
- pass
-
- @staticmethod
- def stopMethodTracing():
- pass
-
- @staticmethod
- def getMethodTracingMode() -> int:
- return 0
-
- @staticmethod
- def getRuntimeStat(stat_name: str) -> str:
- return ""
-
- @staticmethod
- def getRuntimeStatValue(stat_name: str, value: int) -> int:
- return 0
-
- @staticmethod
- def resolveClassLinkageError(cls: type):
- pass
-
- @staticmethod
- def crash():
- raise RuntimeError("VMDebug.crash() called")
-
- @staticmethod
- def dumpReferenceTables():
- pass
-
- @staticmethod
- def setAllocTrackerStackDepth(depth: int):
- pass
-
- @staticmethod
- def attachAgent(agent: str, options: str = None, class_loader: Any = None):
- pass
-
- @staticmethod
- def startAllocCounting():
- pass
-
- @staticmethod
- def stopAllocCounting():
- pass
-
- @staticmethod
- def getGlobalExternalAllocCount() -> int:
- return 0
-
- @staticmethod
- def getGlobalExternalAllocSize() -> int:
- return 0
-
- @staticmethod
- def getGlobalExternalFreedCount() -> int:
- return 0
-
- @staticmethod
- def getGlobalExternalFreedSize() -> int:
- return 0
-
- @staticmethod
- def setAllocationLimit(limit: int):
- pass
-
- @staticmethod
- def setGlobalCpuLimit(limit: int):
- pass
-
- @staticmethod
- def setThreadCpuLimit(limit: int):
- pass
-
- @staticmethod
- def setMethodTracingPriority(priority: int):
- pass
-
- def toString(self) -> str:
- return f"VMDebug@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# CloseGuard
-# ============================================================
-
-class CloseGuard(Stub):
- """
- dalvik.system.CloseGuard
- Reports when resources are not closed properly.
- """
- REPORTER = None
-
- def __init__(self):
- super().__init__()
- self._open = False
- self._reported = False
-
- @staticmethod
- def get() -> "CloseGuard":
- return CloseGuard()
-
- def open(self, closer: str):
- """Marks this guard as open."""
- self._open = True
-
- def close(self):
- """Marks this guard as closed."""
- self._open = False
-
- def warnIfOpen(self):
- """Warns if the guard is still open."""
- if self._open and not self._reported:
- self._reported = True
-
- @staticmethod
- def setEnabled(enabled: bool):
- pass
-
- @staticmethod
- def getReporter():
- return CloseGuard.REPORTER
-
- @staticmethod
- def setReporter(reporter):
- CloseGuard.REPORTER = reporter
-
- def toString(self) -> str:
- return f"CloseGuard@{hex(id(self))}[open={self._open}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# PotentialDeadlockError
-# ============================================================
-
-class PotentialDeadlockError(Exception, Stub):
- """
- dalvik.system.PotentialDeadlockError
- Thrown when a potential deadlock is detected.
- """
- def __init__(self, message: str = None):
- super().__init__(message or "Potential deadlock detected")
- self._message = message
-
- def toString(self) -> str:
- return f"PotentialDeadlockError: {self._message}"
-
- def equals(self, other) -> bool:
- return isinstance(other, PotentialDeadlockError) and self._message == other._message
-
- def hashCode(self) -> int:
- return hash(self._message) & 0x7FFFFFFF
-
-
-# ============================================================
-# BlockGuard
-# ============================================================
-
-class BlockGuard(Stub):
- """
- dalvik.system.BlockGuard
- Mechanism to detect and prevent blocking operations on the main thread.
- """
- LAX_POLICY = None
-
- class Policy(Stub):
- """
- dalvik.system.BlockGuard.Policy
- Interface for block guard policies.
- """
- def onReadFromDisk(self): pass
- def onWriteToDisk(self): pass
- def onNetwork(self): pass
- def onExplicitSuspend(self): pass
- def getPolicyMask(self) -> int: return 0
- def onFileSystemAccess(self): pass
- def onUnbufferedIO(self): pass
-
- def toString(self) -> str:
- return "BlockGuard.Policy"
-
- def equals(self, other) -> bool:
- return isinstance(other, BlockGuard.Policy)
-
- def hashCode(self) -> int:
- return hash("BlockGuard.Policy") & 0x7FFFFFFF
-
- class Operational(Policy):
- """
- dalvik.system.BlockGuard.Operational
- Operational policy for block guard.
- """
- def toString(self) -> str:
- return "BlockGuard.Operational"
-
- def equals(self, other) -> bool:
- return isinstance(other, BlockGuard.Operational)
-
- def hashCode(self) -> int:
- return hash("BlockGuard.Operational") & 0x7FFFFFFF
-
- _delegate = None
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def setDelegate(delegate):
- BlockGuard._delegate = delegate
-
- @staticmethod
- def isOperational() -> bool:
- return BlockGuard._delegate is not None
-
- @staticmethod
- def initDelegate():
- """Initializes the delegate as a BlockGuard.Operational."""
- BlockGuard._delegate = BlockGuard.Operational()
-
- @staticmethod
- def getThreadPolicy():
- """Returns the policy for the current thread."""
- return BlockGuard.LAX_POLICY or BlockGuard.Policy()
-
- @staticmethod
- def setThreadPolicy(policy: Policy):
- pass
-
- def toString(self) -> str:
- return f"BlockGuard@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-BlockGuard.LAX_POLICY = BlockGuard.Policy()
\ No newline at end of file
diff --git a/android_pyapi/java/__init__.py b/android_pyapi/java/__init__.py
deleted file mode 100644
index 9efbd1e..0000000
--- a/android_pyapi/java/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-"""
-Java standard library APIs implemented in Python.
-Android-pyApi: desktop Python translation of Android Java APIs.
-"""
\ No newline at end of file
diff --git a/android_pyapi/java/beans.py b/android_pyapi/java/beans.py
deleted file mode 100644
index 9f083c5..0000000
--- a/android_pyapi/java/beans.py
+++ /dev/null
@@ -1,806 +0,0 @@
-"""
-Java java.beans standard library APIs implemented in Python.
-java.beans package - BeanInfo, Introspector, PropertyChange, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-from .lang import RuntimeException
-import typing as _typing
-
-__all__ = [
- "BeanInfo", "IntrospectionException", "Introspector",
- "BeanDescriptor", "EventSetDescriptor", "MethodDescriptor",
- "ParameterDescriptor",
- "PropertyChangeListener", "PropertyChangeSupport",
- "PropertyChangeEvent", "PropertyChangeListenerProxy",
- "PropertyDescriptor", "SimpleBeanInfo", "FeatureDescriptor",
- "PropertyEditor", "PropertyEditorManager", "PropertyEditorSupport",
- "VetoableChangeListener", "VetoableChangeSupport",
- "IndexedPropertyChangeEvent", "IndexedPropertyDescriptor",
- "EventHandler", "ExceptionListener",
- "AppletInitializer", "Beans", "Customizer", "DesignMode", "Visibility",
-]
-
-
-# ============================================================
-# Exceptions
-# ============================================================
-
-class IntrospectionException(Exception):
- """java.beans.IntrospectionException"""
- def __init__(self, message):
- super().__init__(message)
-
-
-# ============================================================
-# FeatureDescriptor
-# ============================================================
-
-class FeatureDescriptor(Stub):
- """java.beans.FeatureDescriptor"""
- def __init__(self):
- super().__init__()
- self._name = None
- self._display_name = None
- self._short_description = None
- self._preferred = False
- self._expert = False
- self._hidden = False
- self._attributes = {}
- self._bound = False
- self._constrained = False
-
- def getName(self):
- return self._name
-
- def setName(self, name):
- self._name = name
-
- def getDisplayName(self):
- return self._display_name or self._name or ""
-
- def setDisplayName(self, name):
- self._display_name = name
-
- def getShortDescription(self):
- return self._short_description or self.getDisplayName()
-
- def setShortDescription(self, text):
- self._short_description = text
-
- def isPreferred(self):
- return self._preferred
-
- def setPreferred(self, preferred):
- self._preferred = preferred
-
- def isExpert(self):
- return self._expert
-
- def setExpert(self, expert):
- self._expert = expert
-
- def isHidden(self):
- return self._hidden
-
- def setHidden(self, hidden):
- self._hidden = hidden
-
- def setValue(self, attribute_name, value):
- self._attributes[attribute_name] = value
-
- def getValue(self, attribute_name):
- return self._attributes.get(attribute_name)
-
- def attributeNames(self):
- return list(self._attributes.keys())
-
-
-# ============================================================
-# BeanDescriptor
-# ============================================================
-
-class BeanDescriptor(FeatureDescriptor):
- """java.beans.BeanDescriptor"""
- def __init__(self, bean_class, customizer_class=None):
- super().__init__()
- self._bean_class = bean_class
- self._customizer_class = customizer_class
-
- def getBeanClass(self):
- return self._bean_class
-
- def getCustomizerClass(self):
- return self._customizer_class
-
-
-# ============================================================
-# EventSetDescriptor
-# ============================================================
-
-class EventSetDescriptor(FeatureDescriptor):
- """java.beans.EventSetDescriptor"""
- def __init__(self, source_class, event_set_name, listener_type,
- listener_methods, add_listener_method=None,
- remove_listener_method=None):
- super().__init__()
- self._source_class = source_class
- self._event_set_name = event_set_name
- self._listener_type = listener_type
- self._listener_methods = listener_methods or []
- self._add_listener_method = add_listener_method
- self._remove_listener_method = remove_listener_method
- self._unicast = False
- self._in_default_event_set = False
-
- def getListenerType(self):
- return self._listener_type
-
- def getListenerMethods(self):
- return self._listener_methods
-
- def getAddListenerMethod(self):
- return self._add_listener_method
-
- def getRemoveListenerMethod(self):
- return self._remove_listener_method
-
- def isUnicast(self):
- return self._unicast
-
- def setUnicast(self, unicast):
- self._unicast = unicast
-
- def isInDefaultEventSet(self):
- return self._in_default_event_set
-
- def setInDefaultEventSet(self, in_default):
- self._in_default_event_set = in_default
-
-
-# ============================================================
-# MethodDescriptor / ParameterDescriptor
-# ============================================================
-
-class MethodDescriptor(FeatureDescriptor):
- """java.beans.MethodDescriptor"""
- def __init__(self, method, parameter_descriptors=None):
- super().__init__()
- self._method = method
- self._parameter_descriptors = parameter_descriptors or []
-
- def getMethod(self):
- return self._method
-
- def getParameterDescriptors(self):
- return self._parameter_descriptors
-
-
-class ParameterDescriptor(FeatureDescriptor):
- """java.beans.ParameterDescriptor"""
- pass
-
-
-# ============================================================
-# PropertyDescriptor
-# ============================================================
-
-class PropertyDescriptor(FeatureDescriptor):
- """java.beans.PropertyDescriptor"""
- def __init__(self, property_name, bean_class,
- getter_name=None, setter_name=None):
- super().__init__()
- self._property_name = property_name
- self._bean_class = bean_class
- self._getter_name = getter_name
- self._setter_name = setter_name
- self._property_type = None
- self._read_method = None
- self._write_method = None
- self._bound = False
- self._constrained = False
- self._property_editor_class = None
-
- def getPropertyType(self):
- return self._property_type
-
- def setPropertyType(self, prop_type):
- self._property_type = prop_type
-
- def getReadMethod(self):
- return self._read_method
-
- def setReadMethod(self, method):
- self._read_method = method
-
- def getWriteMethod(self):
- return self._write_method
-
- def setWriteMethod(self, method):
- self._write_method = method
-
- def isBound(self):
- return self._bound
-
- def setBound(self, bound):
- self._bound = bound
-
- def isConstrained(self):
- return self._constrained
-
- def setConstrained(self, constrained):
- self._constrained = constrained
-
- def getPropertyEditorClass(self):
- return self._property_editor_class
-
- def setPropertyEditorClass(self, cls):
- self._property_editor_class = cls
-
-
-class IndexedPropertyDescriptor(PropertyDescriptor):
- """java.beans.IndexedPropertyDescriptor"""
- def __init__(self, property_name, bean_class,
- getter_name=None, setter_name=None,
- indexed_getter_name=None, indexed_setter_name=None):
- super().__init__(property_name, bean_class, getter_name, setter_name)
- self._indexed_read_method = None
- self._indexed_write_method = None
- self._indexed_property_type = None
-
- def getIndexedReadMethod(self):
- return self._indexed_read_method
-
- def setIndexedReadMethod(self, method):
- self._indexed_read_method = method
-
- def getIndexedWriteMethod(self):
- return self._indexed_write_method
-
- def setIndexedWriteMethod(self, method):
- self._indexed_write_method = method
-
- def getIndexedPropertyType(self):
- return self._indexed_property_type
-
- def setIndexedPropertyType(self, prop_type):
- self._indexed_property_type = prop_type
-
-
-# ============================================================
-# Introspector
-# ============================================================
-
-class Introspector(Stub):
- """java.beans.Introspector"""
- @staticmethod
- def getBeanInfo(bean_class, stop_class=None, flags=None):
- bean_descriptor = BeanDescriptor(bean_class)
- bean_info = SimpleBeanInfo()
-
- props = []
- methods = []
- events = []
-
- for name in dir(bean_class):
- if name.startswith('_'):
- continue
- attr = getattr(bean_class, name, None)
- if callable(attr):
- methods.append(MethodDescriptor(attr))
- if name.startswith('get') and not name.startswith('getClass'):
- prop_name = name[3].lower() + name[4:]
- pd = PropertyDescriptor(prop_name, bean_class, getter_name=name)
- props.append(pd)
-
- bean_info._property_descriptors = props
- bean_info._method_descriptors = methods
- bean_info._event_set_descriptors = events
- bean_info._bean_descriptor = bean_descriptor
- return bean_info
-
- @staticmethod
- def decapitalize(name):
- if len(name) == 0:
- return name
- if len(name) > 1 and name[1].islower():
- return name[0].lower() + name[1:]
- return name.lower()
-
- @staticmethod
- def flushCaches():
- pass
-
- @staticmethod
- def flushFromCaches(cls):
- pass
-
- USE_ALL_BEANINFO = 1
- IGNORE_IMMEDIATE_BEANINFO = 2
- IGNORE_ALL_BEANINFO = 3
-
-
-# ============================================================
-# SimpleBeanInfo / BeanInfo
-# ============================================================
-
-class BeanInfo(Stub):
- """java.beans.BeanInfo"""
- ICON_COLOR_16x16 = 1
- ICON_COLOR_32x32 = 2
- ICON_MONO_16x16 = 3
- ICON_MONO_32x32 = 4
-
- def getBeanDescriptor(self):
- return None
-
- def getEventSetDescriptors(self):
- return []
-
- def getDefaultEventIndex(self):
- return -1
-
- def getMethodDescriptors(self):
- return []
-
- def getDefaultMethodIndex(self):
- return -1
-
- def getPropertyDescriptors(self):
- return []
-
- def getDefaultPropertyIndex(self):
- return -1
-
- def getIcon(self, icon_kind):
- return None
-
- def getAdditionalBeanInfo(self):
- return None
-
-
-class SimpleBeanInfo(BeanInfo):
- """java.beans.SimpleBeanInfo"""
- def __init__(self):
- super().__init__()
- self._bean_descriptor = None
- self._property_descriptors = []
- self._method_descriptors = []
- self._event_set_descriptors = []
- self._default_property_index = -1
- self._default_event_index = -1
- self._default_method_index = -1
-
- def getBeanDescriptor(self):
- return self._bean_descriptor
-
- def getPropertyDescriptors(self):
- return self._property_descriptors
-
- def getMethodDescriptors(self):
- return self._method_descriptors
-
- def getEventSetDescriptors(self):
- return self._event_set_descriptors
-
- def getDefaultPropertyIndex(self):
- return self._default_property_index
-
- def getDefaultEventIndex(self):
- return self._default_event_index
-
- def getIcon(self, icon_kind):
- return None
-
- def loadBeanInfo(self, bean_info_class):
- return self
-
-
-# ============================================================
-# PropertyChangeEvent / IndexedPropertyChangeEvent
-# ============================================================
-
-class PropertyChangeEvent(Stub):
- """java.beans.PropertyChangeEvent"""
- def __init__(self, source, property_name, old_value, new_value):
- super().__init__()
- self._source = source
- self._property_name = property_name
- self._old_value = old_value
- self._new_value = new_value
- self._propagation_id = None
-
- def getPropertyName(self):
- return self._property_name
-
- def getOldValue(self):
- return self._old_value
-
- def getNewValue(self):
- return self._new_value
-
- def setPropagationId(self, propagation_id):
- self._propagation_id = propagation_id
-
- def getPropagationId(self):
- return self._propagation_id
-
- def toString(self):
- return (f"PropertyChangeEvent[property={self._property_name}, "
- f"old={self._old_value}, new={self._new_value}]")
-
-
-class IndexedPropertyChangeEvent(PropertyChangeEvent):
- """java.beans.IndexedPropertyChangeEvent"""
- def __init__(self, source, property_name, old_value, new_value, index):
- super().__init__(source, property_name, old_value, new_value)
- self._index = index
-
- def getIndex(self):
- return self._index
-
-
-# ============================================================
-# Listener Interfaces
-# ============================================================
-
-class PropertyChangeListener(Stub):
- """java.beans.PropertyChangeListener"""
- def propertyChange(self, evt):
- pass
-
-
-class PropertyChangeListenerProxy(PropertyChangeListener):
- """java.beans.PropertyChangeListenerProxy"""
- def __init__(self, property_name, listener):
- super().__init__()
- self._property_name = property_name
- self._listener = listener
-
- def propertyChange(self, evt):
- if self._listener:
- self._listener(evt)
-
- def getPropertyName(self):
- return self._property_name
-
- def getListener(self):
- return self._listener
-
-
-class VetoableChangeListener(Stub):
- """java.beans.VetoableChangeListener"""
- def vetoableChange(self, evt):
- pass
-
-
-# ============================================================
-# PropertyChangeSupport
-# ============================================================
-
-class PropertyChangeSupport(Stub):
- """java.beans.PropertyChangeSupport"""
- def __init__(self, source_bean):
- super().__init__()
- self._source = source_bean
- self._listeners = []
-
- def addPropertyChangeListener(self, listener, property_name=None):
- if property_name is not None:
- self._listeners.append(PropertyChangeListenerProxy(property_name, listener))
- else:
- self._listeners.append(listener)
-
- def removePropertyChangeListener(self, listener, property_name=None):
- if property_name is not None:
- self._listeners = [
- l for l in self._listeners
- if not (isinstance(l, PropertyChangeListenerProxy)
- and l.getListener() == listener
- and l.getPropertyName() == property_name)
- ]
- else:
- self._listeners = [
- l for l in self._listeners
- if l != listener
- ]
-
- def getPropertyChangeListeners(self, property_name=None):
- if property_name is not None:
- return [l for l in self._listeners
- if isinstance(l, PropertyChangeListenerProxy)
- and l.getPropertyName() == property_name
- or not isinstance(l, PropertyChangeListenerProxy)]
- return self._listeners
-
- def firePropertyChange(self, property_name_or_evt, old_value=None, new_value=None):
- if isinstance(property_name_or_evt, PropertyChangeEvent):
- evt = property_name_or_evt
- else:
- evt = PropertyChangeEvent(self._source, property_name_or_evt,
- old_value, new_value)
- for listener in self._listeners:
- if isinstance(listener, PropertyChangeListenerProxy):
- if listener.getPropertyName() == evt.getPropertyName():
- listener.propertyChange(evt)
- else:
- listener.propertyChange(evt)
-
- def hasListeners(self, property_name):
- for listener in self._listeners:
- if isinstance(listener, PropertyChangeListenerProxy):
- if listener.getPropertyName() == property_name:
- return True
- return False
-
-
-# ============================================================
-# VetoableChangeSupport
-# ============================================================
-
-class VetoableChangeSupport(Stub):
- """java.beans.VetoableChangeSupport"""
- def __init__(self, source_bean):
- super().__init__()
- self._source = source_bean
- self._listeners = []
-
- def addVetoableChangeListener(self, listener, property_name=None):
- if property_name is not None:
- self._listeners.append(PropertyChangeListenerProxy(property_name, listener))
- else:
- self._listeners.append(listener)
-
- def removeVetoableChangeListener(self, listener, property_name=None):
- if property_name is not None:
- self._listeners = [
- l for l in self._listeners
- if not (isinstance(l, PropertyChangeListenerProxy)
- and l.getListener() == listener
- and l.getPropertyName() == property_name)
- ]
- else:
- self._listeners = [l for l in self._listeners if l != listener]
-
- def fireVetoableChange(self, property_name_or_evt, old_value=None, new_value=None):
- if isinstance(property_name_or_evt, PropertyChangeEvent):
- evt = property_name_or_evt
- else:
- evt = PropertyChangeEvent(self._source, property_name_or_evt,
- old_value, new_value)
- for listener in self._listeners:
- if isinstance(listener, PropertyChangeListenerProxy):
- if listener.getPropertyName() == evt.getPropertyName():
- listener.propertyChange(evt)
- else:
- listener.propertyChange(evt)
-
- def hasListeners(self, property_name):
- for listener in self._listeners:
- if isinstance(listener, PropertyChangeListenerProxy):
- if listener.getPropertyName() == property_name:
- return True
- return False
-
-
-# ============================================================
-# PropertyEditor
-# ============================================================
-
-class PropertyEditor(Stub):
- """java.beans.PropertyEditor"""
- def setValue(self, value):
- pass
-
- def getValue(self):
- return None
-
- def isPaintable(self):
- return False
-
- def paintValue(self, gfx, box):
- pass
-
- def getJavaInitializationString(self):
- return ""
-
- def getAsText(self):
- return ""
-
- def setAsText(self, text):
- pass
-
- def getTags(self):
- return None
-
- def getCustomEditor(self):
- return None
-
- def supportsCustomEditor(self):
- return False
-
- def addPropertyChangeListener(self, listener):
- pass
-
- def removePropertyChangeListener(self, listener):
- pass
-
-
-class PropertyEditorSupport(PropertyEditor):
- """java.beans.PropertyEditorSupport"""
- def __init__(self, source=None):
- super().__init__()
- self._source = source
- self._value = None
- self._listeners = []
-
- def setValue(self, value):
- self._value = value
- self._fire_property_change()
-
- def getValue(self):
- return self._value
-
- def getAsText(self):
- if self._value is None:
- return "null"
- return str(self._value)
-
- def setAsText(self, text):
- self._value = text
- self._fire_property_change()
-
- def getSource(self):
- return self._source
-
- def addPropertyChangeListener(self, listener):
- self._listeners.append(listener)
-
- def removePropertyChangeListener(self, listener):
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def _fire_property_change(self):
- evt = PropertyChangeEvent(self._source, "", None, self._value)
- for listener in self._listeners:
- listener.propertyChange(evt)
-
-
-class PropertyEditorManager(Stub):
- """java.beans.PropertyEditorManager"""
- _editors = {}
-
- @staticmethod
- def findEditor(target_type):
- return PropertyEditorSupport()
-
- @staticmethod
- def registerEditor(target_type, editor_class):
- PropertyEditorManager._editors[target_type] = editor_class
-
- @staticmethod
- def getEditorSearchPath():
- return []
-
- @staticmethod
- def setEditorSearchPath(path):
- pass
-
-
-# ============================================================
-# EventHandler
-# ============================================================
-
-class EventHandler(Stub):
- """java.beans.EventHandler"""
- def __init__(self, target, action, event_property_name, listener_method_name):
- super().__init__()
- self._target = target
- self._action = action
- self._event_property_name = event_property_name
- self._listener_method_name = listener_method_name
-
- @staticmethod
- def create(listener_interface, target, action, event_property_name=None,
- listener_method_name=None):
- return target
-
- def invoke(self, proxy, method, arguments):
- if self._target and self._action:
- action_fn = getattr(self._target, self._action, None)
- if action_fn:
- return action_fn()
-
-
-# ============================================================
-# ExceptionListener
-# ============================================================
-
-class ExceptionListener(Stub):
- """java.beans.ExceptionListener"""
- def exceptionThrown(self, e):
- pass
-
-
-# ============================================================
-# AppletInitializer
-# ============================================================
-
-class AppletInitializer(Stub):
- """java.beans.AppletInitializer"""
- def initialize(self, applet_bean, bean_context):
- pass
-
- def activate(self, applet_bean):
- pass
-
-
-# ============================================================
-# Beans / Customizer / DesignMode / Visibility
-# ============================================================
-
-class Beans(Stub):
- """java.beans.Beans"""
- @staticmethod
- def instantiate(cls_loader, bean_name, bean_context=None, bean_arg=None):
- return None
-
- @staticmethod
- def designTime():
- return False
-
- @staticmethod
- def isDesignTime():
- return False
-
- @staticmethod
- def setDesignTime(is_design_time):
- pass
-
- @staticmethod
- def isGuiAvailable():
- return False
-
- @staticmethod
- def setGuiAvailable(is_gui_available):
- pass
-
-
-class Customizer(Stub):
- """java.beans.Customizer"""
- def setObject(self, bean):
- pass
-
- def addPropertyChangeListener(self, listener):
- pass
-
- def removePropertyChangeListener(self, listener):
- pass
-
-
-class DesignMode(Stub):
- """java.beans.DesignMode"""
- PROPERTYNAME = "designTime"
-
- def isDesignTime(self):
- return False
-
- def setDesignTime(self, design_time):
- pass
-
-
-class Visibility(Stub):
- """java.beans.Visibility"""
- def needsGui(self):
- return False
-
- def dontUseGui(self):
- pass
-
- def okToUseGui(self):
- pass
-
- def avoidingGui(self):
- return True
\ No newline at end of file
diff --git a/android_pyapi/java/crypto.py b/android_pyapi/java/crypto.py
deleted file mode 100644
index fe80f49..0000000
--- a/android_pyapi/java/crypto.py
+++ /dev/null
@@ -1,628 +0,0 @@
-"""
-Java crypto standard library APIs implemented in Python.
-javax.crypto package - Cipher, KeyGenerator, Mac, SecretKey, etc.
-"""
-
-from .._core import Stub, AndroidOnlyError
-from .lang import RuntimeException
-import os as _os
-
-# Try to import cryptography library
-try:
- from cryptography.hazmat.primitives.ciphers import Cipher as _Cipher
- from cryptography.hazmat.primitives.ciphers import algorithms as _algorithms
- from cryptography.hazmat.primitives.ciphers import modes as _modes
- from cryptography.hazmat.primitives import hashes as _hashes
- from cryptography.hazmat.primitives.asymmetric import rsa as _rsa
- from cryptography.hazmat.primitives.asymmetric import padding as _padding
- from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC as _PBKDF2
- from cryptography.hazmat.backends import default_backend as _crypto_backend
- HAS_CRYPTOGRAPHY = True
-except ImportError:
- HAS_CRYPTOGRAPHY = False
-
-from .security import (
- GeneralSecurityException, InvalidKeyException,
- NoSuchAlgorithmException, NoSuchProviderException,
- Key, SecretKeySpec, AlgorithmParameters, AlgorithmParametersSpi,
- AlgorithmParameterGenerator, AlgorithmParameterGeneratorSpi,
- Provider, SecureRandom,
-)
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-AEADBadTagException = type("AEADBadTagException", (GeneralSecurityException,), {})
-BadPaddingException = type("BadPaddingException", (GeneralSecurityException,), {})
-IllegalBlockSizeException = type("IllegalBlockSizeException", (GeneralSecurityException,), {})
-NoSuchPaddingException = type("NoSuchPaddingException", (GeneralSecurityException,), {})
-ShortBufferException = type("ShortBufferException", (GeneralSecurityException,), {})
-ExemptionMechanismException = type("ExemptionMechanismException", (GeneralSecurityException,), {})
-
-__all__ = [
- "Cipher", "CipherSpi",
- "KeyGenerator", "KeyGeneratorSpi",
- "SecretKey", "SecretKeyFactory", "SecretKeyFactorySpi",
- "Mac", "MacSpi",
- "IvParameterSpec", "PBEParameterSpec", "GCMParameterSpec",
- "OAEPParameterSpec", "PSource", "MGF1ParameterSpec",
- "DHParameterSpec", "DSAParameterSpec",
- "ECParameterSpec", "ECGenParameterSpec", "ECPoint",
- "ECField", "ECFieldF2m", "ECFieldFp", "EllipticCurve",
- "AlgorithmParameters", "AlgorithmParameterGenerator",
- "AlgorithmParametersSpi",
- "AEADBadTagException", "BadPaddingException",
- "IllegalBlockSizeException", "NoSuchPaddingException",
- "ShortBufferException",
- "ExemptionMechanism", "ExemptionMechanismException",
- "ExemptionMechanismSpi",
-]
-
-
-# ============================================================
-# SecretKey
-# ============================================================
-
-class SecretKey(Key):
- def __init__(self, key_bytes=None, algorithm=""):
- super().__init__()
- self._key = key_bytes or b""
- self._algorithm = algorithm
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getFormat(self):
- return "RAW"
-
- def getEncoded(self):
- return self._key
-
-
-# ============================================================
-# Cipher
-# ============================================================
-
-class Cipher(Stub):
- ENCRYPT_MODE = 1
- DECRYPT_MODE = 2
- WRAP_MODE = 3
- UNWRAP_MODE = 4
- PUBLIC_KEY = 1
- PRIVATE_KEY = 2
- SECRET_KEY = 3
-
- def __init__(self, transformation):
- super().__init__()
- self._transformation = transformation
- self._opmode = 0
- self._key = None
- self._iv = None
- self._provider = Provider("AndroidOpenSSL", 1.0, "Android OpenSSL provider")
-
- @staticmethod
- def getInstance(transformation, provider=None):
- return Cipher(transformation)
-
- def init(self, opmode, key_or_cert, params=None, random=None):
- self._opmode = opmode
- self._key = key_or_cert
- if isinstance(params, IvParameterSpec):
- self._iv = params.getIV()
- elif isinstance(params, GCMParameterSpec):
- self._iv = params.getIV()
-
- def doFinal(self, input_data=None):
- if input_data is None:
- return b""
- if HAS_CRYPTOGRAPHY and self._key is not None:
- try:
- algo = self._transformation.split("/")[0].upper()
- key_bytes = self._key.getEncoded() if hasattr(self._key, "getEncoded") else bytes(self._key)
- iv = self._iv or b"\x00" * 16
- if algo == "AES":
- if len(iv) == 12:
- mode = _modes.GCM(iv)
- else:
- mode = _modes.CBC(iv)
- cipher = _Cipher(_algorithms.AES(key_bytes), mode, backend=_crypto_backend())
- elif algo == "DES":
- cipher = _Cipher(_algorithms.TripleDES(key_bytes), _modes.CBC(iv), backend=_crypto_backend())
- else:
- return self._basic_cipher(input_data)
- if self._opmode == Cipher.ENCRYPT_MODE:
- encryptor = cipher.encryptor()
- result = encryptor.update(input_data) + encryptor.finalize()
- return result
- else:
- decryptor = cipher.decryptor()
- result = decryptor.update(input_data) + decryptor.finalize()
- return result
- except Exception:
- return self._basic_cipher(input_data)
- else:
- return self._basic_cipher(input_data)
-
- def _basic_cipher(self, data):
- if self._opmode == Cipher.ENCRYPT_MODE:
- if self._key is not None:
- key_bytes = self._key.getEncoded() if hasattr(self._key, "getEncoded") else bytes(self._key)
- return bytes([(b ^ key_bytes[i % len(key_bytes)]) & 0xFF for i, b in enumerate(data)])
- return data
- else:
- if self._key is not None:
- key_bytes = self._key.getEncoded() if hasattr(self._key, "getEncoded") else bytes(self._key)
- return bytes([(b ^ key_bytes[i % len(key_bytes)]) & 0xFF for i, b in enumerate(data)])
- return data
-
- def update(self, input_data):
- return self._basic_cipher(input_data)
-
- def getBlockSize(self):
- algo = self._transformation.split("/")[0].upper()
- if algo == "AES":
- return 16
- if algo == "DES" or algo == "DESede":
- return 8
- return 1
-
- def getOutputSize(self, input_len):
- bs = self.getBlockSize()
- if bs > 1:
- return input_len + bs - (input_len % bs)
- return input_len
-
- def getIV(self):
- return self._iv
-
- def getParameters(self):
- if self._iv:
- return AlgorithmParameters(self._transformation.split("/")[0])
- return None
-
- def getAlgorithm(self):
- return self._transformation
-
- def getProvider(self):
- return self._provider
-
- def getExemptionMechanism(self):
- return None
-
- def unwrap(self, wrapped_key, wrapped_key_algorithm, wrapped_key_type):
- return SecretKey(wrapped_key, wrapped_key_algorithm)
-
- def wrap(self, key):
- key_bytes = key.getEncoded() if hasattr(key, "getEncoded") else b""
- return self.doFinal(key_bytes)
-
- @staticmethod
- def maxAllowedKeyLength(transformation):
- return 2147483647
-
-
-class CipherSpi(Stub):
- pass
-
-
-# ============================================================
-# KeyGenerator
-# ============================================================
-
-class KeyGenerator(Stub):
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
- self._key_size = 128
- self._secure_random = None
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return KeyGenerator(algorithm)
-
- def init(self, size_or_random, random=None):
- if isinstance(size_or_random, int):
- self._key_size = size_or_random
- self._secure_random = random
- else:
- self._secure_random = size_or_random
-
- def generateKey(self):
- key_bytes = _os.urandom(self._key_size // 8)
- return SecretKey(key_bytes, self._algorithm)
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getProvider(self):
- return Provider("AndroidOpenSSL", 1.0, "Android OpenSSL provider")
-
-
-class KeyGeneratorSpi(Stub):
- pass
-
-
-# ============================================================
-# SecretKeyFactory
-# ============================================================
-
-class SecretKeyFactory(Stub):
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return SecretKeyFactory(algorithm)
-
- def generateSecret(self, key_spec):
- if isinstance(key_spec, SecretKeySpec):
- return SecretKey(key_spec.getEncoded(), self._algorithm)
- return SecretKey(b"", self._algorithm)
-
- def getKeySpec(self, secret_key, key_spec_cls):
- return SecretKeySpec(secret_key.getEncoded(), self._algorithm)
-
- def translateKey(self, key):
- return key
-
- def getAlgorithm(self):
- return self._algorithm
-
-
-class SecretKeyFactorySpi(Stub):
- pass
-
-
-# ============================================================
-# Mac
-# ============================================================
-
-class Mac(Stub):
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
- self._key = None
- self._state = "UNINITIALIZED"
- self._data = b""
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return Mac(algorithm)
-
- def init(self, key, params=None):
- self._key = key
- self._state = "INITIALIZED"
- self._data = b""
-
- def update(self, input_data, offset=0, length=-1):
- if length < 0:
- self._data += bytes(input_data)
- else:
- self._data += bytes(input_data[offset:offset+length])
-
- def doFinal(self, input_data=None):
- if input_data is not None:
- self._data += bytes(input_data)
- if HAS_CRYPTOGRAPHY and self._key is not None:
- try:
- key_bytes = self._key.getEncoded() if hasattr(self._key, "getEncoded") else bytes(self._key)
- algo = self._algorithm.lower().replace("-", "")
- if "sha256" in algo or "sha-256" in self._algorithm:
- h = _hashlib.sha256(key_bytes + self._data)
- elif "sha1" in algo or "sha-1" in self._algorithm:
- h = _hashlib.sha1(key_bytes + self._data)
- elif "md5" in algo:
- h = _hashlib.md5(key_bytes + self._data)
- else:
- h = _hashlib.sha256(key_bytes + self._data)
- result = h.digest()
- self._data = b""
- return result
- except Exception:
- pass
- import hashlib as _hashlib
- key_bytes = self._key.getEncoded() if self._key and hasattr(self._key, "getEncoded") else b"key"
- h = _hashlib.sha256(key_bytes + self._data)
- result = h.digest()
- self._data = b""
- return result
-
- def reset(self):
- self._data = b""
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getMacLength(self):
- return 32
-
- def getProvider(self):
- return Provider("AndroidOpenSSL", 1.0, "Android OpenSSL provider")
-
-
-class MacSpi(Stub):
- pass
-
-
-# ============================================================
-# Parameter specs
-# ============================================================
-
-class IvParameterSpec(Stub):
- def __init__(self, iv):
- super().__init__()
- self._iv = bytes(iv)
-
- def getIV(self):
- return self._iv
-
-
-class PBEParameterSpec(Stub):
- def __init__(self, salt, iteration_count):
- super().__init__()
- self._salt = bytes(salt)
- self._iteration_count = iteration_count
-
- def getSalt(self):
- return self._salt
-
- def getIterationCount(self):
- return self._iteration_count
-
-
-class GCMParameterSpec(Stub):
- def __init__(self, t_len, src):
- super().__init__()
- self._t_len = t_len
- self._iv = bytes(src)
-
- def getTLen(self):
- return self._t_len
-
- def getIV(self):
- return self._iv
-
-
-class OAEPParameterSpec(Stub):
- def __init__(self, md_name, mgf_name, mgf_spec, p_src):
- super().__init__()
- self._md_name = md_name
- self._mgf_name = mgf_name
- self._mgf_spec = mgf_spec
- self._p_src = p_src
-
- def getDigestAlgorithm(self):
- return self._md_name
-
- def getMGFAlgorithm(self):
- return self._mgf_name
-
- def getMGFParameters(self):
- return self._mgf_spec
-
- def getPSource(self):
- return self._p_src
-
-
-class PSource(Stub):
- class PSpecified(Stub):
- DEFAULT = None
-
- def __init__(self, p):
- super().__init__()
- self._p = p
-
- def getValue(self):
- return self._p
-
- def __init__(self, p_src_id):
- super().__init__()
- self._p_src_id = p_src_id
-
- def getAlgorithm(self):
- return self._p_src_id
-
-
-PSource.PSpecified.DEFAULT = PSource.PSpecified(b"")
-
-
-class MGF1ParameterSpec(Stub):
- SHA1 = None
- SHA256 = None
- SHA384 = None
- SHA512 = None
-
- def __init__(self, md_name):
- super().__init__()
- self._md_name = md_name
-
- def getDigestAlgorithm(self):
- return self._md_name
-
- def toString(self):
- return f"MGF1 {self._md_name}"
-
-
-MGF1ParameterSpec.SHA1 = MGF1ParameterSpec("SHA-1")
-MGF1ParameterSpec.SHA256 = MGF1ParameterSpec("SHA-256")
-MGF1ParameterSpec.SHA384 = MGF1ParameterSpec("SHA-384")
-MGF1ParameterSpec.SHA512 = MGF1ParameterSpec("SHA-512")
-
-
-# ============================================================
-# DH / DSA / EC parameter specs (stubs)
-# ============================================================
-
-class DHParameterSpec(Stub):
- def __init__(self, p, g, l=0):
- super().__init__()
- self._p = p
- self._g = g
- self._l = l
-
- def getP(self):
- return self._p
-
- def getG(self):
- return self._g
-
- def getL(self):
- return self._l
-
-
-class DSAParameterSpec(Stub):
- def __init__(self, p, q, g):
- super().__init__()
- self._p = p
- self._q = q
- self._g = g
-
- def getP(self):
- return self._p
-
- def getQ(self):
- return self._q
-
- def getG(self):
- return self._g
-
-
-class ECPoint(Stub):
- def __init__(self, affine_x, affine_y):
- super().__init__()
- self._affine_x = affine_x
- self._affine_y = affine_y
-
- def getAffineX(self):
- return self._affine_x
-
- def getAffineY(self):
- return self._affine_y
-
- def equals(self, other):
- if isinstance(other, ECPoint):
- return self._affine_x == other._affine_x and self._affine_y == other._affine_y
- return False
-
- def hashCode(self):
- return hash((self._affine_x, self._affine_y))
-
-
-class ECField(Stub):
- def getFieldSize(self):
- raise NotImplementedError
-
-
-class ECFieldFp(ECField):
- def __init__(self, p):
- super().__init__()
- self._p = p
-
- def getP(self):
- return self._p
-
- def getFieldSize(self):
- return self._p.bit_length()
-
-
-class ECFieldF2m(ECField):
- def __init__(self, m, ks=None):
- super().__init__()
- self._m = m
- self._ks = ks
-
- def getM(self):
- return self._m
-
- def getMidTermsOfReductionPolynomial(self):
- return self._ks
-
- def getFieldSize(self):
- return self._m
-
-
-class EllipticCurve(Stub):
- def __init__(self, field, a, b, seed=None):
- super().__init__()
- self._field = field
- self._a = a
- self._b = b
- self._seed = seed
-
- def getField(self):
- return self._field
-
- def getA(self):
- return self._a
-
- def getB(self):
- return self._b
-
- def getSeed(self):
- return self._seed
-
-
-class ECParameterSpec(Stub):
- def __init__(self, curve, generator, order, cofactor, seed=None):
- super().__init__()
- self._curve = curve
- self._generator = generator
- self._order = order
- self._cofactor = cofactor
-
- def getCurve(self):
- return self._curve
-
- def getGenerator(self):
- return self._generator
-
- def getOrder(self):
- return self._order
-
- def getCofactor(self):
- return self._cofactor
-
-
-class ECGenParameterSpec(Stub):
- def __init__(self, name):
- super().__init__()
- self._name = name
-
- def getName(self):
- return self._name
-
-
-# ============================================================
-# ExemptionMechanism
-# ============================================================
-
-class ExemptionMechanism(Stub):
- def __init__(self, name):
- super().__init__()
- self._name = name
- self._state = False
-
- @staticmethod
- def getInstance(name, provider=None):
- return ExemptionMechanism(name)
-
- def init(self, key):
- self._state = False
-
- def isCryptoAllowed(self, key):
- return True
-
- def genExemptionBlob(self, data=None):
- return b""
-
- def getName(self):
- return self._name
-
- def getOutputSize(self, input_len):
- return input_len
-
- def storeMechanism(self, mechanism):
- pass
-
-
-class ExemptionMechanismSpi(Stub):
- pass
\ No newline at end of file
diff --git a/android_pyapi/java/io.py b/android_pyapi/java/io.py
deleted file mode 100644
index 02974ff..0000000
--- a/android_pyapi/java/io.py
+++ /dev/null
@@ -1,2120 +0,0 @@
-"""
-Java I/O standard library APIs implemented in Python.
-java.io package - File, streams, readers, writers, and exceptions.
-"""
-
-from .._core import Stub, AndroidOnlyError
-import io as _pyio
-import os as _os
-import sys as _sys
-import errno as _errno
-import stat as _stat
-import threading as _threading
-from datetime import datetime as _datetime
-from collections import OrderedDict as _OrderedDict
-from pathlib import Path as _PathLibPath
-
-__all__ = [
- "Serializable", "Externalizable", "ObjectStreamField", "ObjectStreamConstants",
- "FileFilter", "FilenameFilter", "File", "FileDescriptor",
- "FileInputStream", "FileOutputStream",
- "BufferedInputStream", "BufferedOutputStream",
- "BufferedReader", "BufferedWriter",
- "InputStreamReader", "OutputStreamWriter",
- "FileReader", "FileWriter", "PrintWriter",
- "ByteArrayInputStream", "ByteArrayOutputStream",
- "StringReader", "StringWriter",
- "DataInputStream", "DataOutputStream",
- "ObjectInputStream", "ObjectOutputStream",
- "FilterInputStream", "FilterOutputStream",
- "PipedInputStream", "PipedOutputStream",
- "PushbackInputStream", "SequenceInputStream",
- "RandomAccessFile",
- "Closeable", "Flushable",
- "IOError", "IOException", "FileNotFoundException",
- "EOFException", "CharConversionException",
- "ObjectStreamException", "SyncFailedException",
- "UTFDataFormatException", "WriteAbortedException",
- "UnsupportedEncodingException",
-]
-
-
-# ============================================================
-# Marker / mixin interfaces
-# ============================================================
-
-class Closeable(Stub):
- def close(self):
- raise NotImplementedError
-
-class Flushable(Stub):
- def flush(self):
- raise NotImplementedError
-
-class Serializable(Stub):
- pass
-
-class Externalizable(Stub):
- pass
-
-class ObjectStreamConstants:
- STREAM_MAGIC = 0xACED
- STREAM_VERSION = 5
- TC_BASE = 0x70
- TC_NULL = 0x70
- TC_REFERENCE = 0x71
- TC_CLASS = 0x72
- TC_OBJECT = 0x73
- TC_STRING = 0x74
- TC_ARRAY = 0x75
- TC_ENUM = 0x7E
- TC_CLASSDESC = 0x72
- TC_PROXYCLASSDESC = 0x7D
- TC_BLOCKDATA = 0x77
- TC_ENDBLOCKDATA = 0x78
- TC_RESET = 0x79
- TC_EXCEPTION = 0x7A
- TC_LONGSTRING = 0x7C
- baseWireHandle = 0x7E0000
-
-class ObjectStreamField(Stub):
- def __init__(self, name, typ):
- self._name = name
- self._type = typ
-
- def getName(self):
- return self._name
-
- def getType(self):
- return self._type
-
- def toString(self):
- return f"{self._type} {self._name}"
-
-
-# ============================================================
-# FileFilter / FilenameFilter
-# ============================================================
-
-class FileFilter(Stub):
- def accept(self, pathname):
- raise NotImplementedError
-
-class FilenameFilter(Stub):
- def accept(self, dir, name):
- raise NotImplementedError
-
-
-# ============================================================
-# FileDescriptor
-# ============================================================
-
-class FileDescriptor(Stub):
- _valid_fd = -1
-
- def __init__(self, fd=None):
- super().__init__()
- if fd is not None:
- self._valid_fd = fd
-
- def valid(self):
- return self._valid_fd >= 0
-
- def sync(self):
- if self._valid_fd >= 0:
- try:
- _os.fsync(self._valid_fd)
- except OSError:
- pass
-
- def hashCode(self):
- return self._valid_fd
-
- @staticmethod
- def _from_fileno(fd):
- return FileDescriptor(fd)
-
-
-# ============================================================
-# Exception classes
-# ============================================================
-
-class IOException(Exception):
- def __init__(self, message=None, cause=None):
- super().__init__(message)
- self._cause = cause
-
- def getCause(self):
- return self._cause
-
-class FileNotFoundException(IOException):
- pass
-
-class EOFException(IOException):
- pass
-
-class CharConversionException(IOException):
- pass
-
-class ObjectStreamException(IOException):
- pass
-
-class SyncFailedException(IOException):
- pass
-
-class UTFDataFormatException(IOException):
- pass
-
-class WriteAbortedException(ObjectStreamException):
- def __init__(self, message=None, cause=None):
- super().__init__(message)
- self.detail = cause
-
-class UnsupportedEncodingException(IOException):
- pass
-
-class IOError(Exception):
- def __init__(self, message=None, cause=None):
- super().__init__(message)
- self._cause = cause
-
- def getCause(self):
- return self._cause
-
-
-# ============================================================
-# File
-# ============================================================
-
-class File(Stub):
- separator = _os.sep
- separatorChar = _os.sep
- pathSeparator = _os.pathsep
- pathSeparatorChar = _os.pathsep
-
- def __init__(self, *args):
- super().__init__()
- if len(args) == 1:
- path = args[0]
- if isinstance(path, File):
- self._path = path._path
- else:
- self._path = str(path)
- elif len(args) == 2:
- parent, child = args
- if parent is None:
- self._path = str(child)
- else:
- parent_str = parent._path if isinstance(parent, File) else str(parent)
- child_str = str(child)
- if child_str.startswith(self.separator):
- self._path = child_str
- else:
- self._path = _os.path.join(parent_str, child_str)
- else:
- self._path = ""
- self._path = self._path or ""
-
- def _resolve(self):
- return _os.path.realpath(self._path) if self._path else ""
-
- def exists(self):
- return _os.path.exists(self._path)
-
- def isFile(self):
- return _os.path.isfile(self._path)
-
- def isDirectory(self):
- return _os.path.isdir(self._path)
-
- def getName(self):
- return _os.path.basename(self._path)
-
- def getPath(self):
- return self._path
-
- def getAbsolutePath(self):
- return _os.path.abspath(self._path)
-
- def getCanonicalPath(self):
- try:
- return _os.path.realpath(self._path)
- except Exception:
- return self.getAbsolutePath()
-
- def getParent(self):
- p = _os.path.dirname(self._path)
- return p if p else None
-
- def getParentFile(self):
- p = self.getParent()
- return File(p) if p else None
-
- def length(self):
- try:
- return _os.path.getsize(self._path)
- except OSError:
- return 0
-
- def lastModified(self):
- try:
- return int(_os.path.getmtime(self._path) * 1000)
- except OSError:
- return 0
-
- def createNewFile(self):
- try:
- f = _os.open(self._path, _os.O_CREAT | _os.O_EXCL, 0o644)
- _os.close(f)
- return True
- except OSError:
- return False
-
- def delete(self):
- try:
- if self.isDirectory():
- _os.rmdir(self._path)
- else:
- _os.remove(self._path)
- return True
- except OSError:
- return False
-
- def mkdir(self):
- try:
- _os.mkdir(self._path)
- return True
- except OSError:
- return False
-
- def mkdirs(self):
- try:
- _os.makedirs(self._path, exist_ok=True)
- return True
- except OSError:
- return False
-
- def renameTo(self, dest):
- try:
- dest_path = dest._path if isinstance(dest, File) else str(dest)
- _os.rename(self._path, dest_path)
- return True
- except OSError:
- return False
-
- def list(self):
- try:
- return _os.listdir(self._path)
- except OSError:
- return None
-
- def listFiles(self, filter=None):
- try:
- names = _os.listdir(self._path)
- files = [File(self._path, n) for n in names]
- if filter:
- return [f for f in files if filter.accept(f)]
- return files
- except OSError:
- return None
-
- @staticmethod
- def listRoots():
- if _sys.platform == "win32":
- import string
- return [File(d + ":\\") for d in string.ascii_uppercase if _os.path.exists(d + ":\\")]
- return [File("/")]
-
- def canRead(self):
- return _os.access(self._path, _os.R_OK)
-
- def canWrite(self):
- return _os.access(self._path, _os.W_OK)
-
- def canExecute(self):
- return _os.access(self._path, _os.X_OK)
-
- def setReadable(self, readable, ownerOnly=True):
- try:
- if readable:
- if ownerOnly:
- _os.chmod(self._path, _stat.S_IRUSR | (_stat.S_IRGRP if _os.stat(self._path).st_gid else 0))
- else:
- _os.chmod(self._path, _stat.S_IRUSR | _stat.S_IRGRP | _stat.S_IROTH)
- else:
- mode = _os.stat(self._path).st_mode
- if ownerOnly:
- mode &= ~_stat.S_IRUSR
- else:
- mode &= ~(_stat.S_IRUSR | _stat.S_IRGRP | _stat.S_IROTH)
- _os.chmod(self._path, mode)
- return True
- except OSError:
- return False
-
- def setWritable(self, writable, ownerOnly=True):
- try:
- if writable:
- if ownerOnly:
- _os.chmod(self._path, _stat.S_IWUSR)
- else:
- _os.chmod(self._path, _stat.S_IWUSR | _stat.S_IWGRP | _stat.S_IWOTH)
- else:
- mode = _os.stat(self._path).st_mode
- if ownerOnly:
- mode &= ~_stat.S_IWUSR
- else:
- mode &= ~(_stat.S_IWUSR | _stat.S_IWGRP | _stat.S_IWOTH)
- _os.chmod(self._path, mode)
- return True
- except OSError:
- return False
-
- def setExecutable(self, executable, ownerOnly=True):
- try:
- if executable:
- if ownerOnly:
- _os.chmod(self._path, _stat.S_IXUSR)
- else:
- _os.chmod(self._path, _stat.S_IXUSR | _stat.S_IXGRP | _stat.S_IXOTH)
- else:
- mode = _os.stat(self._path).st_mode
- if ownerOnly:
- mode &= ~_stat.S_IXUSR
- else:
- mode &= ~(_stat.S_IXUSR | _stat.S_IXGRP | _stat.S_IXOTH)
- _os.chmod(self._path, mode)
- return True
- except OSError:
- return False
-
- def isHidden(self):
- return _os.path.basename(self._path).startswith(".")
-
- def toURL(self):
- from urllib.parse import quote
- return f"file:{quote(self.getAbsolutePath())}"
-
- def toURI(self):
- return self.toURL()
-
- def getTotalSpace(self):
- try:
- st = _os.statvfs(self._path)
- return st.f_frsize * st.f_blocks
- except OSError:
- return 0
-
- def getFreeSpace(self):
- try:
- st = _os.statvfs(self._path)
- return st.f_frsize * st.f_bfree
- except OSError:
- return 0
-
- def getUsableSpace(self):
- try:
- st = _os.statvfs(self._path)
- return st.f_frsize * st.f_bavail
- except OSError:
- return 0
-
- def compareTo(self, other) -> int:
- if isinstance(other, File):
- if self._path < other._path:
- return -1
- elif self._path > other._path:
- return 1
- return 0
- return -1
-
- def equals(self, other):
- if isinstance(other, File):
- return self._path == other._path
- return False
-
- def hashCode(self):
- return hash(self._path) & 0x7FFFFFFF
-
- def toString(self):
- return self._path
-
- def toPath(self):
- return _PathLibPath(self._path)
-
- @staticmethod
- def createTempFile(prefix, suffix=None, directory=None):
- import tempfile
- if directory:
- fd, path = tempfile.mkstemp(prefix=prefix, suffix=suffix or ".tmp", dir=directory)
- else:
- fd, path = tempfile.mkstemp(prefix=prefix, suffix=suffix or ".tmp")
- _os.close(fd)
- return File(path)
-
- def deleteOnExit(self):
- import atexit
- atexit.register(lambda: self.delete() if self.exists() else None)
-
- def setLastModified(self, time):
- try:
- _os.utime(self._path, (time / 1000, time / 1000))
- return True
- except Exception:
- return False
-
- def setReadOnly(self):
- try:
- _os.chmod(self._path, 0o444)
- return True
- except Exception:
- return False
-
- def isAbsolute(self):
- return _os.path.isabs(self._path)
-
- def getAbsoluteFile(self):
- return File(self.getAbsolutePath())
-
- def getCanonicalFile(self):
- return File(self.getCanonicalPath())
-
- def __str__(self):
- return self._path
-
- def __repr__(self):
- return f"File({self._path!r})"
-
-
-# ============================================================
-# FileInputStream
-# ============================================================
-
-class FileInputStream(Closeable):
- def __init__(self, file):
- super().__init__()
- if isinstance(file, File):
- path = file.getPath()
- else:
- path = str(file)
- self._path = path
- self._fd = None
- self._channel = None
- self._closed = False
- try:
- self._fd = _os.open(path, _os.O_RDONLY)
- except OSError as e:
- raise FileNotFoundException(str(e))
-
- def read(self, b=None, off=None, length=None):
- if self._closed:
- raise IOException("Stream closed")
- if b is None:
- data = _os.read(self._fd, 1)
- return data[0] if data else -1
- if isinstance(b, (bytes, bytearray)):
- if off is None:
- off = 0
- if length is None:
- length = len(b) - off
- data = _os.read(self._fd, length)
- if not data:
- return -1
- n = len(data)
- if isinstance(b, bytearray):
- b[off:off+n] = data
- else:
- ba = bytearray(b)
- ba[off:off+n] = data
- b[:] = bytes(ba)
- return n
- return -1
-
- def skip(self, n):
- try:
- pos = _os.lseek(self._fd, 0, _os.SEEK_CUR)
- end = _os.lseek(self._fd, 0, _os.SEEK_END)
- _os.lseek(self._fd, pos, _os.SEEK_SET)
- actual = min(n, end - pos)
- _os.lseek(self._fd, actual, _os.SEEK_CUR)
- return actual
- except OSError:
- return 0
-
- def available(self):
- if self._closed:
- return 0
- try:
- pos = _os.lseek(self._fd, 0, _os.SEEK_CUR)
- end = _os.lseek(self._fd, 0, _os.SEEK_END)
- _os.lseek(self._fd, pos, _os.SEEK_SET)
- return end - pos
- except OSError:
- return 0
-
- def close(self):
- if not self._closed:
- self._closed = True
- if self._fd is not None:
- _os.close(self._fd)
- self._fd = None
-
- def getFD(self):
- if self._closed:
- raise IOException("Stream closed")
- return FileDescriptor(self._fd)
-
- def getChannel(self):
- if self._closed:
- raise IOException("Stream closed")
- if self._channel is None:
- import io as _pyio_mod
- self._channel = _pyio_mod.FileIO(self._fd, closefd=False)
- return self._channel
-
- def __del__(self):
- self.close()
-
-
-# ============================================================
-# FileOutputStream
-# ============================================================
-
-class FileOutputStream(Closeable, Flushable):
- def __init__(self, file, append=False):
- super().__init__()
- if isinstance(file, File):
- path = file.getPath()
- elif isinstance(file, FileDescriptor):
- self._fd = file._valid_fd
- self._path = None
- self._closed = False
- self._channel = None
- return
- else:
- path = str(file)
- self._path = path
- self._closed = False
- self._channel = None
- try:
- flags = _os.O_WRONLY | _os.O_CREAT
- if append:
- flags |= _os.O_APPEND
- else:
- flags |= _os.O_TRUNC
- self._fd = _os.open(path, flags, 0o644)
- except OSError as e:
- raise FileNotFoundException(str(e))
-
- def write(self, b=None, off=None, length=None):
- if self._closed:
- raise IOException("Stream closed")
- if b is None:
- return
- if isinstance(b, int):
- _os.write(self._fd, bytes([b]))
- elif isinstance(b, (bytes, bytearray)):
- if off is None:
- data = bytes(b)
- else:
- data = bytes(b[off:off+length if length else (len(b)-off)])
- _os.write(self._fd, data)
- else:
- if off is None:
- data = bytes(b)
- else:
- data = bytes(b[off:off+length if length else (len(b)-off)])
- _os.write(self._fd, data)
-
- def close(self):
- if not self._closed:
- self._closed = True
- if self._fd is not None:
- _os.close(self._fd)
- self._fd = None
-
- def getFD(self):
- if self._closed:
- raise IOException("Stream closed")
- return FileDescriptor(self._fd)
-
- def getChannel(self):
- if self._closed:
- raise IOException("Stream closed")
- if self._channel is None:
- import io as _pyio_mod
- self._channel = _pyio_mod.FileIO(self._fd, closefd=False, mode='ab')
- return self._channel
-
- def flush(self):
- if self._fd is not None:
- try:
- _os.fsync(self._fd)
- except OSError:
- pass
-
- def __del__(self):
- self.close()
-
-
-# ============================================================
-# FilterInputStream / FilterOutputStream (abstract wrappers)
-# ============================================================
-
-class FilterInputStream(Closeable):
- def __init__(self, inp):
- super().__init__()
- self._in = inp
-
- def read(self, *args):
- return self._in.read(*args)
-
- def skip(self, n):
- return self._in.skip(n)
-
- def available(self):
- return self._in.available()
-
- def close(self):
- self._in.close()
-
- def mark(self, readlimit):
- pass
-
- def reset(self):
- raise IOException("mark/reset not supported")
-
- def markSupported(self):
- return False
-
-
-class FilterOutputStream(Closeable, Flushable):
- def __init__(self, out):
- super().__init__()
- self._out = out
-
- def write(self, *args):
- self._out.write(*args)
-
- def close(self):
- self._out.close()
-
- def flush(self):
- self._out.flush()
-
-
-# ============================================================
-# BufferedInputStream
-# ============================================================
-
-class BufferedInputStream(FilterInputStream):
- def __init__(self, inp, size=8192):
- super().__init__(inp)
- self._buffer = bytearray()
- self._buf_size = size
- self._pos = 0
- self._count = 0
-
- def read(self, b=None, off=None, length=None):
- if b is None:
- if self._pos >= self._count:
- self._fill()
- if self._pos >= self._count:
- return -1
- val = self._buffer[self._pos]
- self._pos += 1
- return val
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- total = 0
- while total < length:
- if self._pos >= self._count:
- if not self._fill():
- break
- chunk = min(length - total, self._count - self._pos)
- if isinstance(b, bytearray):
- b[off+total:off+total+chunk] = self._buffer[self._pos:self._pos+chunk]
- else:
- ba = bytearray(b)
- ba[off+total:off+total+chunk] = self._buffer[self._pos:self._pos+chunk]
- b[:] = bytes(ba)
- self._pos += chunk
- total += chunk
- return total if total > 0 else -1
-
- def _fill(self):
- tmp = bytearray(self._buf_size)
- n = self._in.read(tmp, 0, self._buf_size)
- if n is None or n == -1:
- return False
- if isinstance(n, (bytes, bytearray)):
- # defensive: underlying stream returned raw data instead of a count
- tmp = bytearray(n)
- n = len(tmp)
- if not isinstance(n, int) or n <= 0:
- return False
- self._buffer = bytearray(tmp[:n])
- self._pos = 0
- self._count = n
- return True
-
- def available(self):
- buf_avail = self._count - self._pos
- if buf_avail < 0:
- buf_avail = 0
- try:
- underlying = self._in.available()
- if underlying and underlying > 0:
- return buf_avail + underlying
- except Exception:
- pass
- return buf_avail
-
- def mark(self, readlimit):
- self._mark_pos = self._pos
- self._mark_buffer = bytes(self._buffer)
- self._mark_count = self._count
- self._mark_limit = readlimit
-
- def reset(self):
- if not hasattr(self, '_mark_pos'):
- raise IOException("Resetting to invalid mark")
- self._buffer = bytearray(self._mark_buffer)
- self._count = self._mark_count
- self._pos = self._mark_pos
-
- def markSupported(self):
- return True
-
-
-# ============================================================
-# BufferedOutputStream
-# ============================================================
-
-class BufferedOutputStream(FilterOutputStream):
- def __init__(self, out, size=8192):
- super().__init__(out)
- self._buf = bytearray()
- self._buf_size = size
-
- def write(self, b=None, off=None, length=None):
- if b is None:
- return
- if isinstance(b, int):
- self._buf.append(b & 0xFF)
- else:
- if off is not None and length is not None:
- data = b[off:off+length]
- else:
- data = b
- self._buf.extend(data)
- if len(self._buf) >= self._buf_size:
- self.flush()
-
- def flush(self):
- if self._buf:
- self._out.write(bytes(self._buf))
- self._buf.clear()
- self._out.flush()
-
-
-# ============================================================
-# InputStreamReader
-# ============================================================
-
-class InputStreamReader(Closeable):
- def __init__(self, inp, charset=None):
- super().__init__()
- self._in = inp
- self._charset = charset or "utf-8"
- self._buffer = None
-
- def read(self, cbuf=None, off=None, length=None):
- if cbuf is None:
- data = self._in.read()
- if data is None or data == -1:
- return -1
- return data & 0xFF
- if off is None:
- off = 0
- if length is None:
- length = len(cbuf)
- raw = self._in.read(bytearray(length), 0, length)
- if raw is None or raw == -1:
- return -1
- n = len(raw) if isinstance(raw, (bytes, bytearray)) else raw
- if isinstance(raw, int):
- return raw
- decoded = raw.decode(self._charset, errors='replace')
- for i, ch in enumerate(decoded):
- if off + i < len(cbuf):
- cbuf[off + i] = ch
- return len(decoded)
-
- def getEncoding(self):
- return self._charset
-
- def close(self):
- self._in.close()
-
-
-# ============================================================
-# OutputStreamWriter
-# ============================================================
-
-class OutputStreamWriter(Closeable, Flushable):
- def __init__(self, out, charset=None):
- super().__init__()
- self._out = out
- self._charset = charset or "utf-8"
-
- def write(self, s, off=None, length=None):
- if isinstance(s, str):
- if off is not None and length is not None:
- s = s[off:off+length]
- self._out.write(s.encode(self._charset))
- elif isinstance(s, (list, tuple)):
- chars = "".join(s)
- if off is not None and length is not None:
- chars = chars[off:off+length]
- self._out.write(chars.encode(self._charset))
-
- def flush(self):
- self._out.flush()
-
- def close(self):
- self._out.close()
-
- def getEncoding(self):
- return self._charset
-
-
-# ============================================================
-# FileReader
-# ============================================================
-
-class FileReader(InputStreamReader):
- def __init__(self, file):
- if isinstance(file, File):
- path = file.getPath()
- else:
- path = str(file)
- inp = FileInputStream(path)
- super().__init__(inp, "utf-8")
- self._file_path = path
-
-
-# ============================================================
-# FileWriter
-# ============================================================
-
-class FileWriter(OutputStreamWriter):
- def __init__(self, file, append=False):
- if isinstance(file, File):
- path = file.getPath()
- append = append
- else:
- path = str(file)
- out = FileOutputStream(path, append)
- super().__init__(out, "utf-8")
- self._file_path = path
-
-
-# ============================================================
-# BufferedReader
-# ============================================================
-
-class BufferedReader(Closeable):
- def __init__(self, reader, size=8192):
- super().__init__()
- self._reader = reader
- self._buf_size = size
- self._buffer = ""
- self._pos = 0
- self._closed = False
-
- def read(self, cbuf=None, off=None, length=None):
- if self._closed:
- raise IOException("Stream closed")
- if cbuf is None:
- if self._pos >= len(self._buffer):
- self._fill()
- if self._pos >= len(self._buffer):
- return -1
- ch = ord(self._buffer[self._pos])
- self._pos += 1
- return ch
- if off is None:
- off = 0
- if length is None:
- length = len(cbuf)
- total = 0
- while total < length:
- if self._pos >= len(self._buffer):
- if not self._fill():
- break
- chunk = min(length - total, len(self._buffer) - self._pos)
- for i in range(chunk):
- cbuf[off + total + i] = self._buffer[self._pos + i]
- self._pos += chunk
- total += chunk
- return total if total > 0 else -1
-
- def _fill(self):
- if hasattr(self._reader, '_in'):
- raw = self._reader._in.read(bytearray(self._buf_size), 0, self._buf_size)
- if raw is None or raw == -1:
- return False
- data = bytes(raw) if isinstance(raw, int) else bytes(raw)
- self._buffer = data.decode(self._reader.getEncoding() if hasattr(self._reader, 'getEncoding') else "utf-8", errors='replace')
- else:
- raw = []
- for _ in range(self._buf_size):
- ch = self._reader.read()
- if ch == -1:
- break
- raw.append(chr(ch))
- self._buffer = "".join(raw)
- self._pos = 0
- return len(self._buffer) > 0
-
- def readLine(self):
- if self._closed:
- raise IOException("Stream closed")
- result = []
- while True:
- if self._pos >= len(self._buffer):
- if not self._fill():
- break
- while self._pos < len(self._buffer):
- ch = self._buffer[self._pos]
- self._pos += 1
- if ch == "\n":
- return "".join(result)
- if ch == "\r":
- if self._pos < len(self._buffer) and self._buffer[self._pos] == "\n":
- self._pos += 1
- return "".join(result)
- result.append(ch)
- return "".join(result) if result else None
-
- def ready(self):
- return self._pos < len(self._buffer)
-
- def mark(self, readAheadLimit):
- self._mark_pos = self._pos
- self._mark_buffer = self._buffer
-
- def reset(self):
- if hasattr(self, '_mark_pos'):
- self._pos = self._mark_pos
- self._buffer = self._mark_buffer
- else:
- raise IOException("Mark not set")
-
- def markSupported(self):
- return True
-
- def skip(self, n):
- skipped = 0
- while skipped < n:
- if self._pos >= len(self._buffer):
- if not self._fill():
- break
- chunk = min(n - skipped, len(self._buffer) - self._pos)
- self._pos += chunk
- skipped += chunk
- return skipped
-
- def close(self):
- self._closed = True
- self._reader.close()
-
- def lines(self):
- line = self.readLine()
- while line is not None:
- yield line
- line = self.readLine()
-
-
-# ============================================================
-# BufferedWriter
-# ============================================================
-
-class BufferedWriter(Closeable, Flushable):
- def __init__(self, writer, size=8192):
- super().__init__()
- self._writer = writer
- self._buf_size = size
- self._buffer = []
-
- def write(self, s, off=None, length=None):
- if isinstance(s, str):
- if off is not None and length is not None:
- s = s[off:off+length]
- self._buffer.append(s)
- elif isinstance(s, (list, tuple)):
- chars = "".join(s)
- if off is not None and length is not None:
- chars = chars[off:off+length]
- self._buffer.append(chars)
- elif isinstance(s, int):
- self._buffer.append(chr(s))
- if sum(len(x) for x in self._buffer) >= self._buf_size:
- self.flush()
-
- def newLine(self):
- self._buffer.append("\n")
-
- def append(self, csq=None, start=None, end=None):
- if csq is None:
- return self
- if isinstance(csq, int):
- self._buffer.append(chr(csq))
- else:
- s = str(csq)
- if start is not None and end is not None:
- s = s[start:end]
- elif start is not None:
- s = s[start:]
- self._buffer.append(s)
- if sum(len(x) for x in self._buffer) >= self._buf_size:
- self.flush()
- return self
-
- def check(self):
- if getattr(self._writer, '_closed', False):
- raise IOException("Stream closed")
-
- def flush(self):
- if self._buffer:
- data = "".join(self._buffer)
- self._writer.write(data)
- self._buffer.clear()
- self._writer.flush()
-
- def close(self):
- self.flush()
- self._writer.close()
-
-
-# ============================================================
-# PrintWriter
-# ============================================================
-
-class PrintWriter(Closeable, Flushable):
- def __init__(self, out, autoFlush=False):
- super().__init__()
- if isinstance(out, _pyio.TextIOBase):
- self._out = out
- else:
- self._out = out
- self._auto_flush = autoFlush
- self._error = False
-
- def _write_str(self, s):
- s = str(s)
- if hasattr(self._out, 'write'):
- self._out.write(s)
- else:
- self._out.write(s.encode('utf-8'))
-
- def print_bool(self, b):
- self._write_str(str(b))
- if self._auto_flush:
- self.flush()
-
- def print_char(self, c):
- self._write_str(str(c))
- if self._auto_flush:
- self.flush()
-
- def print_char_array(self, c):
- self._write_str("".join(c))
- if self._auto_flush:
- self.flush()
-
- def print_double(self, d):
- self._write_str(str(d))
- if self._auto_flush:
- self.flush()
-
- def print_float(self, f):
- self._write_str(str(f))
- if self._auto_flush:
- self.flush()
-
- def print_int(self, i):
- self._write_str(str(i))
- if self._auto_flush:
- self.flush()
-
- def print_long(self, l):
- self._write_str(str(l))
- if self._auto_flush:
- self.flush()
-
- def print_obj(self, obj):
- self._write_str(str(obj))
- if self._auto_flush:
- self.flush()
-
- def print_str(self, s):
- self._write_str(str(s) if s is not None else "null")
- if self._auto_flush:
- self.flush()
-
- print = print_str
- print_boolean = print_bool
-
- def println(self, s=None):
- if s is None:
- self._write_str("\n")
- else:
- self._write_str(str(s) + "\n")
- if self._auto_flush:
- self.flush()
-
- def println_bool(self, b):
- self._write_str(str(b) + "\n")
- if self._auto_flush:
- self.flush()
-
- def println_char(self, c):
- self._write_str(str(c) + "\n")
- if self._auto_flush:
- self.flush()
-
- def println_char_array(self, c):
- self._write_str("".join(c) + "\n")
- if self._auto_flush:
- self.flush()
-
- def println_double(self, d):
- self._write_str(str(d) + "\n")
- if self._auto_flush:
- self.flush()
-
- def println_float(self, f):
- self._write_str(str(f) + "\n")
- if self._auto_flush:
- self.flush()
-
- def println_int(self, i):
- self._write_str(str(i) + "\n")
- if self._auto_flush:
- self.flush()
-
- def println_long(self, l):
- self._write_str(str(l) + "\n")
- if self._auto_flush:
- self.flush()
-
- def println_obj(self, obj):
- self._write_str(str(obj) + "\n")
- if self._auto_flush:
- self.flush()
-
- def write(self, s, off=None, length=None):
- if isinstance(s, str):
- if off is not None and length is not None:
- s = s[off:off+length]
- self._write_str(s)
- else:
- self._write_str(str(s))
-
- def append(self, csq=None, start=None, end=None):
- if csq is None:
- csq = "null"
- if isinstance(csq, int):
- self._write_str(chr(csq))
- else:
- s = str(csq)
- if start is not None and end is not None:
- s = s[start:end]
- elif start is not None:
- s = s[start:]
- self._write_str(s)
- return self
-
- def format(self, fmt, *args):
- s = str(fmt) % args if args else str(fmt)
- self._write_str(s)
- return self
-
- def printf(self, fmt, *args):
- return self.format(fmt, *args)
-
- def flush(self):
- if hasattr(self._out, 'flush'):
- self._out.flush()
-
- def close(self):
- self.flush()
- if hasattr(self._out, 'close'):
- self._out.close()
-
- def checkError(self):
- return self._error
-
- def setError(self):
- self._error = True
-
-
-# ============================================================
-# ByteArrayInputStream
-# ============================================================
-
-class ByteArrayInputStream(Closeable):
- def __init__(self, buf):
- super().__init__()
- self._buf = bytes(buf)
- self._pos = 0
- self._count = len(self._buf)
- self._mark = 0
- self._closed = False
-
- def read(self, b=None, off=None, length=None):
- if self._closed:
- raise IOException("Stream closed")
- if b is None:
- if self._pos >= self._count:
- return -1
- val = self._buf[self._pos] & 0xFF
- self._pos += 1
- return val
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- avail = self._count - self._pos
- if avail <= 0:
- return -1
- n = min(length, avail)
- if isinstance(b, bytearray):
- b[off:off+n] = self._buf[self._pos:self._pos+n]
- else:
- ba = bytearray(b)
- ba[off:off+n] = self._buf[self._pos:self._pos+n]
- b[:] = bytes(ba)
- self._pos += n
- return n
-
- def skip(self, n):
- if self._closed:
- return 0
- avail = self._count - self._pos
- actual = min(n, avail)
- self._pos += actual
- return actual
-
- def available(self):
- if self._closed:
- return 0
- return self._count - self._pos
-
- def close(self):
- self._closed = True
-
- def mark(self, readAheadLimit):
- self._mark = self._pos
-
- def reset(self):
- self._pos = self._mark
-
- def markSupported(self):
- return True
-
-
-# ============================================================
-# ByteArrayOutputStream
-# ============================================================
-
-class ByteArrayOutputStream(Closeable, Flushable):
- def __init__(self, size=32):
- super().__init__()
- self._buf = bytearray()
- self._closed = False
-
- def write(self, b=None, off=None, length=None):
- if self._closed:
- raise IOException("Stream closed")
- if b is None:
- return
- if isinstance(b, int):
- self._buf.append(b & 0xFF)
- elif isinstance(b, (bytes, bytearray)):
- if off is not None and length is not None:
- self._buf.extend(b[off:off+length])
- else:
- self._buf.extend(b)
-
- def toByteArray(self):
- return bytes(self._buf)
-
- def writeTo(self, out):
- if self._closed:
- raise IOException("Stream closed")
- out.write(bytes(self._buf))
-
- def size(self):
- return len(self._buf)
-
- def toString(self, charset=None):
- if charset:
- return bytes(self._buf).decode(charset, errors='replace')
- return bytes(self._buf).decode('utf-8', errors='replace')
-
- def reset(self):
- self._buf.clear()
-
- def close(self):
- self._closed = True
-
- def flush(self):
- pass
-
-
-# ============================================================
-# StringReader
-# ============================================================
-
-class StringReader(Closeable):
- def __init__(self, s):
- super().__init__()
- self._str = s
- self._pos = 0
- self._length = len(s)
- self._mark = 0
- self._closed = False
-
- def read(self, cbuf=None, off=None, length=None):
- if self._closed:
- raise IOException("Stream closed")
- if cbuf is None:
- if self._pos >= self._length:
- return -1
- val = ord(self._str[self._pos])
- self._pos += 1
- return val
- if off is None:
- off = 0
- if length is None:
- length = len(cbuf)
- avail = self._length - self._pos
- if avail <= 0:
- return -1
- n = min(length, avail)
- for i in range(n):
- cbuf[off + i] = self._str[self._pos + i]
- self._pos += n
- return n
-
- def skip(self, n):
- avail = self._length - self._pos
- actual = min(n, avail)
- self._pos += actual
- return max(actual, 0)
-
- def ready(self):
- return self._pos < self._length
-
- def mark(self, readAheadLimit):
- self._mark = self._pos
-
- def reset(self):
- self._pos = self._mark
-
- def markSupported(self):
- return True
-
- def close(self):
- self._closed = True
-
-
-# ============================================================
-# StringWriter
-# ============================================================
-
-class StringWriter(Closeable, Flushable):
- def __init__(self):
- super().__init__()
- self._buffer = []
- self._closed = False
-
- def write(self, s, off=None, length=None):
- if self._closed:
- raise IOException("Stream closed")
- if isinstance(s, str):
- if off is not None and length is not None:
- s = s[off:off+length]
- self._buffer.append(s)
- elif isinstance(s, int):
- self._buffer.append(chr(s))
- elif isinstance(s, (list, tuple)):
- chars = "".join(s)
- if off is not None and length is not None:
- chars = chars[off:off+length]
- self._buffer.append(chars)
-
- def flush(self):
- pass
-
- def close(self):
- self._closed = True
-
- def toString(self):
- return "".join(self._buffer)
-
- def getBuffer(self):
- return "".join(self._buffer)
-
-
-# ============================================================
-# DataInputStream
-# ============================================================
-
-class DataInputStream(Closeable):
- def __init__(self, inp):
- super().__init__()
- self._in = inp
-
- def read(self, b=None):
- if b is None:
- return self._in.read()
- return self._in.read(b)
-
- def readBoolean(self):
- v = self._in.read()
- if v == -1:
- raise EOFException()
- return bool(v)
-
- def readByte(self):
- v = self._in.read()
- if v == -1:
- raise EOFException()
- return (v & 0xFF) if v <= 127 else (v - 256)
-
- def readChar(self):
- hi = self._in.read()
- lo = self._in.read()
- if hi == -1 or lo == -1:
- raise EOFException()
- return chr((hi << 8) | lo)
-
- def readDouble(self):
- return _struct.unpack(">d", self._read_bytes(8))[0]
-
- def readFloat(self):
- return _struct.unpack(">f", self._read_bytes(4))[0]
-
- def readFully(self, b, off=0, length=None):
- if length is None:
- length = len(b)
- total = 0
- while total < length:
- n = self._in.read(b, off + total, length - total)
- if n == -1:
- raise EOFException()
- total += n
-
- def readInt(self):
- return _struct.unpack(">i", self._read_bytes(4))[0]
-
- def readLong(self):
- return _struct.unpack(">q", self._read_bytes(8))[0]
-
- def readShort(self):
- v = _struct.unpack(">h", self._read_bytes(2))[0]
- return v
-
- def readUTF(self):
- length = self.readUnsignedShort()
- data = self._read_bytes(length)
- return data.decode("utf-8")
-
- def readUnsignedByte(self):
- v = self._in.read()
- if v == -1:
- raise EOFException()
- return v & 0xFF
-
- def readUnsignedShort(self):
- hi = self._in.read()
- lo = self._in.read()
- if hi == -1 or lo == -1:
- raise EOFException()
- return ((hi & 0xFF) << 8) | (lo & 0xFF)
-
- def skipBytes(self, n):
- return self._in.skip(n)
-
- def _read_bytes(self, n):
- buf = bytearray(n)
- total = 0
- while total < n:
- r = self._in.read(buf, total, n - total)
- if r == -1:
- raise EOFException()
- total += r
- return bytes(buf)
-
- def close(self):
- self._in.close()
-
-
-# ============================================================
-# DataOutputStream
-# ============================================================
-
-import struct as _struct
-
-class DataOutputStream(Closeable, Flushable):
- def __init__(self, out):
- super().__init__()
- self._out = out
- self._written = 0
-
- def write(self, b=None, off=None, length=None):
- if b is not None:
- self._out.write(b, off, length)
- self._written += length if length else (len(b) if isinstance(b, (bytes, bytearray)) else 1)
-
- def writeBoolean(self, v):
- self._out.write(int(v))
-
- def writeByte(self, v):
- self._out.write(v & 0xFF)
-
- def writeBytes(self, s):
- for ch in str(s):
- self._out.write(ord(ch) & 0xFF)
-
- def writeChar(self, v):
- self._out.write((v >> 8) & 0xFF)
- self._out.write(v & 0xFF)
-
- def writeChars(self, s):
- for ch in str(s):
- self.writeChar(ord(ch))
-
- def writeDouble(self, v):
- self._write_struct(">d", v)
-
- def writeFloat(self, v):
- self._write_struct(">f", v)
-
- def writeInt(self, v):
- self._write_struct(">i", v)
-
- def writeLong(self, v):
- self._write_struct(">q", v)
-
- def writeShort(self, v):
- self._write_struct(">h", v)
-
- def writeUTF(self, s):
- encoded = str(s).encode("utf-8")
- self.writeShort(len(encoded))
- for b in encoded:
- self._out.write(b)
-
- def size(self):
- return self._written
-
- def _write_struct(self, fmt, v):
- data = _struct.pack(fmt, v)
- for b in data:
- self._out.write(b)
-
- def flush(self):
- self._out.flush()
-
- def close(self):
- self._out.close()
-
-
-# ============================================================
-# ObjectInputStream / ObjectOutputStream (stub)
-# ============================================================
-
-class ObjectInputStream(Closeable):
- def __init__(self, inp):
- super().__init__()
- self._in = inp
-
- def readObject(self):
- raise AndroidOnlyError("ObjectInputStream.readObject()")
-
- def readInt(self):
- return DataInputStream(self._in).readInt()
-
- def close(self):
- self._in.close()
-
-
-class ObjectOutputStream(Closeable, Flushable):
- def __init__(self, out):
- super().__init__()
- self._out = out
-
- def writeObject(self, obj):
- raise AndroidOnlyError("ObjectOutputStream.writeObject()")
-
- def writeInt(self, v):
- DataOutputStream(self._out).writeInt(v)
-
- def flush(self):
- self._out.flush()
-
- def close(self):
- self._out.close()
-
-
-# ============================================================
-# PipedInputStream / PipedOutputStream
-# ============================================================
-
-class PipedInputStream(Closeable):
- def __init__(self, src=None, pipe_size=1024):
- super().__init__()
- self._buffer = bytearray()
- self._pipe_size = pipe_size
- self._closed = False
- self._lock = _threading.RLock()
- self._data_available = _threading.Condition(self._lock)
- if src:
- src.connect(self)
-
- def connect(self, src):
- src._sink = self
-
- def receive(self, b):
- with self._lock:
- self._buffer.append(b & 0xFF)
- self._data_available.notify()
-
- def read(self, b=None, off=None, length=None):
- with self._lock:
- while len(self._buffer) == 0 and not self._closed:
- self._data_available.wait(timeout=1)
- if self._closed and len(self._buffer) == 0:
- return -1
- if b is None:
- if len(self._buffer) == 0:
- return -1
- return self._buffer.pop(0)
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- n = min(length, len(self._buffer))
- for i in range(n):
- if isinstance(b, bytearray):
- b[off + i] = self._buffer.pop(0)
- else:
- b[off + i] = self._buffer.pop(0)
- return n
-
- def close(self):
- with self._lock:
- self._closed = True
- self._data_available.notify_all()
-
-
-class PipedOutputStream(Closeable):
- def __init__(self, sink=None):
- super().__init__()
- self._sink = sink
-
- def connect(self, sink):
- self._sink = sink
-
- def write(self, b, off=None, length=None):
- if self._sink is None:
- raise IOException("Pipe not connected")
- if isinstance(b, int):
- self._sink.receive(b)
- else:
- if off is not None and length is not None:
- for i in range(off, off + length):
- self._sink.receive(b[i])
- else:
- for byte in b:
- self._sink.receive(byte)
-
- def flush(self):
- pass
-
- def close(self):
- if self._sink:
- self._sink.close()
-
-
-# ============================================================
-# PushbackInputStream
-# ============================================================
-
-class PushbackInputStream(FilterInputStream):
- def __init__(self, inp, size=1):
- super().__init__(inp)
- self._pushback_buf = bytearray()
- self._max_size = size
-
- def read(self, b=None, off=None, length=None):
- if b is None:
- if self._pushback_buf:
- return self._pushback_buf.pop(0)
- return self._in.read()
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- total = 0
- while self._pushback_buf and total < length:
- if isinstance(b, bytearray):
- b[off + total] = self._pushback_buf.pop(0)
- else:
- ba = bytearray(b)
- ba[off + total] = self._pushback_buf.pop(0)
- b[:] = bytes(ba)
- total += 1
- if total < length:
- n = self._in.read(b, off + total, length - total)
- if n > 0:
- total += n
- return total if total > 0 else -1
-
- def unread(self, b):
- if isinstance(b, int):
- if len(self._pushback_buf) >= self._max_size:
- raise IOException("Pushback buffer overflow")
- self._pushback_buf.append(b & 0xFF)
- else:
- for byte_val in b:
- self.unread(byte_val)
-
- def close(self):
- self._pushback_buf.clear()
- self._in.close()
-
-
-# ============================================================
-# SequenceInputStream
-# ============================================================
-
-def _is_enumeration(obj) -> bool:
- """True if obj really exposes hasMoreElements/nextElement (not via Stub)."""
- for cls in type(obj).__mro__:
- if ('hasMoreElements' in cls.__dict__
- and 'nextElement' in cls.__dict__):
- return True
- return False
-
-
-class SequenceInputStream(Closeable):
- def __init__(self, *args):
- super().__init__()
- self._streams = []
- self._current_idx = 0
- self._closed = False
- if len(args) == 0:
- return
- if len(args) == 1:
- streams = args[0]
- if isinstance(streams, (list, tuple)):
- self._streams = list(streams)
- elif _is_enumeration(streams):
- while streams.hasMoreElements():
- self._streams.append(streams.nextElement())
- else:
- # single stream
- self._streams = [streams]
- else:
- # SequenceInputStream(s1, s2, ...)
- self._streams = list(args)
-
- def _current(self):
- while self._current_idx < len(self._streams):
- inp = self._streams[self._current_idx]
- if inp is None:
- self._current_idx += 1
- continue
- return inp
- return None
-
- def _advance(self):
- if self._current_idx < len(self._streams):
- cur = self._streams[self._current_idx]
- if cur is not None:
- try:
- cur.close()
- except Exception:
- pass
- self._current_idx += 1
-
- def read(self, b=None, off=None, length=None):
- if self._closed:
- raise IOException("Stream closed")
- if b is None:
- while True:
- inp = self._current()
- if inp is None:
- return -1
- result = inp.read()
- if result != -1:
- return result
- self._advance()
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- total = 0
- while total < length:
- inp = self._current()
- if inp is None:
- break
- n = inp.read(b, off + total, length - total)
- if n is None or n == -1:
- self._advance()
- continue
- if n == 0:
- self._advance()
- continue
- total += n
- return total if total > 0 else -1
-
- def available(self):
- inp = self._current()
- if inp is None:
- return 0
- try:
- return inp.available()
- except Exception:
- return 0
-
- def close(self):
- self._closed = True
- for s in self._streams:
- if s is not None:
- try:
- s.close()
- except Exception:
- pass
-
-
-# ============================================================
-# RandomAccessFile
-# ============================================================
-
-class RandomAccessFile(Closeable, Flushable):
- def __init__(self, file, mode="r"):
- super().__init__()
- if isinstance(file, File):
- path = file.getPath()
- else:
- path = str(file)
- self._path = path
- self._mode = mode
- self._closed = False
- py_modes = {"r": "rb", "rw": "r+b", "rws": "r+b", "rwd": "r+b"}
- py_mode = py_modes.get(mode, "r+b")
- try:
- if "w" in mode and mode != "r":
- self._file = open(path, py_mode)
- else:
- self._file = open(path, py_mode)
- except FileNotFoundError as e:
- if "w" in mode:
- self._file = open(path, "w+b")
- else:
- raise FileNotFoundException(str(e))
-
- def seek(self, pos):
- self._file.seek(pos)
-
- def getFilePointer(self):
- return self._file.tell()
-
- def length(self):
- pos = self._file.tell()
- self._file.seek(0, 2)
- end = self._file.tell()
- self._file.seek(pos)
- return end
-
- def read(self, b=None, off=None, length=None):
- if b is None:
- data = self._file.read(1)
- return data[0] if data else -1
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- data = self._file.read(length)
- if not data:
- return -1
- n = len(data)
- if isinstance(b, bytearray):
- b[off:off+n] = data
- else:
- ba = bytearray(b)
- ba[off:off+n] = data
- b[:] = bytes(ba)
- return n
-
- def readBoolean(self):
- v = self.read()
- if v == -1:
- raise EOFException()
- return bool(v)
-
- def readByte(self):
- v = self.read()
- if v == -1:
- raise EOFException()
- return (v & 0xFF) if v <= 127 else (v - 256)
-
- def readChar(self):
- hi = self.read()
- lo = self.read()
- if hi == -1 or lo == -1:
- raise EOFException()
- return chr((hi << 8) | lo)
-
- def readDouble(self):
- data = self._read_bytes(8)
- return _struct.unpack(">d", data)[0]
-
- def readFloat(self):
- data = self._read_bytes(4)
- return _struct.unpack(">f", data)[0]
-
- def readInt(self):
- data = self._read_bytes(4)
- return _struct.unpack(">i", data)[0]
-
- def readLine(self):
- result = []
- while True:
- ch = self.read()
- if ch == -1:
- break
- if ch == 0x0A:
- break
- if ch == 0x0D:
- next_ch = self.read()
- if next_ch != 0x0A:
- self.seek(self.getFilePointer() - 1)
- break
- result.append(chr(ch))
- return "".join(result) if result else None
-
- def readLong(self):
- data = self._read_bytes(8)
- return _struct.unpack(">q", data)[0]
-
- def readShort(self):
- data = self._read_bytes(2)
- return _struct.unpack(">h", data)[0]
-
- def readUnsignedByte(self):
- v = self.read()
- if v == -1:
- raise EOFException()
- return v & 0xFF
-
- def readUnsignedShort(self):
- hi = self.read()
- lo = self.read()
- if hi == -1 or lo == -1:
- raise EOFException()
- return ((hi & 0xFF) << 8) | (lo & 0xFF)
-
- def readUTF(self):
- length = self.readUnsignedShort()
- data = self._read_bytes(length)
- return data.decode("utf-8")
-
- def write(self, b=None, off=None, length=None):
- if b is None:
- return
- if isinstance(b, int):
- self._file.write(bytes([b & 0xFF]))
- else:
- if off is not None and length is not None:
- self._file.write(bytes(b[off:off+length]))
- else:
- self._file.write(bytes(b))
-
- def writeBoolean(self, v):
- self.write(int(v))
-
- def writeByte(self, v):
- self.write(v & 0xFF)
-
- def writeBytes(self, s):
- for ch in str(s):
- self.write(ord(ch) & 0xFF)
-
- def writeChar(self, v):
- self.write((v >> 8) & 0xFF)
- self.write(v & 0xFF)
-
- def writeChars(self, s):
- for ch in str(s):
- self.writeChar(ord(ch))
-
- def writeDouble(self, v):
- data = _struct.pack(">d", v)
- self._file.write(data)
-
- def writeFloat(self, v):
- data = _struct.pack(">f", v)
- self._file.write(data)
-
- def writeInt(self, v):
- data = _struct.pack(">i", v)
- self._file.write(data)
-
- def writeLong(self, v):
- data = _struct.pack(">q", v)
- self._file.write(data)
-
- def writeShort(self, v):
- data = _struct.pack(">h", v)
- self._file.write(data)
-
- def writeUTF(self, s):
- encoded = str(s).encode("utf-8")
- self.writeShort(len(encoded))
- self._file.write(encoded)
-
- def _read_bytes(self, n):
- data = self._file.read(n)
- if len(data) < n:
- raise EOFException()
- return data
-
- def setLength(self, new_length):
- pos = self.getFilePointer()
- self._file.truncate(new_length)
- if pos > new_length:
- self.seek(new_length)
-
- def close(self):
- if not self._closed:
- self._closed = True
- self._file.close()
-
- def getChannel(self):
- return self._file
-
- def flush(self):
- self._file.flush()
-
- def __del__(self):
- self.close()
\ No newline at end of file
diff --git a/android_pyapi/java/io_ext.py b/android_pyapi/java/io_ext.py
deleted file mode 100644
index 99c2874..0000000
--- a/android_pyapi/java/io_ext.py
+++ /dev/null
@@ -1,1414 +0,0 @@
-"""
-Java java.io extended standard library APIs implemented in Python.
-Extends java.io with ObjectStreamField, ObjectStreamConstants, ObjectInput, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub
-from ..java.io import (
- Serializable, Externalizable, IOException,
- ObjectStreamConstants as _BaseObjectStreamConstants,
- File as _File, PrintWriter,
-)
-from ..java.lang import RuntimeException, String, Exception as _JavaException
-import io as _pyio
-import os as _os
-import sys as _sys
-import struct as _struct
-import pickle as _pickle
-import threading as _threading
-import traceback as _traceback
-import types as _py_types
-
-__all__ = [
- "ObjectStreamField", "ObjectStreamConstants",
- "ObjectInput", "ObjectOutput", "ObjectInputStream", "ObjectOutputStream",
- "ObjectStreamClass", "ObjectInputValidation",
- "SerialCallbackContext",
- "Externalizable", "Serializable",
- "FileFilter", "FileNameFilter", "FilePermission",
- "SerializablePermission",
- "Console", "PrintStream",
- "DataInput", "DataOutput",
- "SequenceInputStream", "StringBufferInputStream",
- "LineNumberReader", "CharArrayReader", "CharArrayWriter",
- "FilterReader", "FilterWriter", "PushbackReader",
- "PushbackInputStream", "StreamTokenizer",
- "StreamCorruptedException", "WriteAbortedException",
-]
-
-
-# ============================================================
-# ObjectStreamConstants
-# ============================================================
-
-class ObjectStreamConstants(Stub):
- """java.io.ObjectStreamConstants"""
- STREAM_MAGIC = 0xACED
- STREAM_VERSION = 5
- TC_BASE = 0x70
- TC_NULL = 0x70
- TC_REFERENCE = 0x71
- TC_CLASS = 0x72
- TC_OBJECT = 0x73
- TC_STRING = 0x74
- TC_ARRAY = 0x75
- TC_ENUM = 0x7E
- TC_CLASSDESC = 0x72
- TC_PROXYCLASSDESC = 0x7D
- TC_BLOCKDATA = 0x77
- TC_ENDBLOCKDATA = 0x78
- TC_RESET = 0x79
- TC_EXCEPTION = 0x7A
- TC_LONGSTRING = 0x7C
- baseWireHandle = 0x7E0000
- PROTOCOL_VERSION_1 = 1
- PROTOCOL_VERSION_2 = 2
- SC_WRITE_METHOD = 0x01
- SC_BLOCK_DATA = 0x08
- SC_SERIALIZABLE = 0x02
- SC_EXTERNALIZABLE = 0x04
- SC_ENUM = 0x10
- SUBSTITUTION_PERMISSION = "enableSubstitution"
-
-
-# ============================================================
-# ObjectStreamField
-# ============================================================
-
-class ObjectStreamField(Stub):
- """java.io.ObjectStreamField"""
- def __init__(self, name, field_type, unshared=False):
- super().__init__()
- self._name = name
- self._type = field_type
- self._unshared = unshared
-
- def getName(self):
- return self._name
-
- def getType(self):
- return self._type
-
- def getTypeString(self):
- return self._type.__name__ if hasattr(self._type, '__name__') else str(self._type)
-
- def getTypeCode(self):
- return self.getTypeString()[0].upper()
-
- def isUnshared(self):
- return self._unshared
-
- def isPrimitive(self):
- return self._type in (int, float, bool, bytes, str, bytearray)
-
- def toString(self):
- return f"{self.getTypeString()} {self._name}"
-
-
-# ============================================================
-# ObjectStreamClass
-# ============================================================
-
-class ObjectStreamClass(Stub):
- """java.io.ObjectStreamClass"""
- _descriptors = {}
-
- def __init__(self, cls=None):
- super().__init__()
- self._cls = cls
- self._name = cls.__name__ if cls else ""
- self._serial_version_uid = hash(cls) if cls else 0
- self._fields = []
- self._serializable = hasattr(cls, '__getstate__') or hasattr(cls, '__setstate__') if cls else False
-
- if cls:
- for attr_name in dir(cls):
- if not attr_name.startswith('_'):
- attr_type = type(getattr(cls, attr_name, None))
- self._fields.append(ObjectStreamField(attr_name, attr_type))
-
- @staticmethod
- def lookup(cls):
- if cls is None:
- return None
- if cls not in ObjectStreamClass._descriptors:
- ObjectStreamClass._descriptors[cls] = ObjectStreamClass(cls)
- return ObjectStreamClass._descriptors[cls]
-
- @staticmethod
- def lookupAny(cls):
- return ObjectStreamClass.lookup(cls)
-
- def getName(self):
- return self._name
-
- def getSerialVersionUID(self):
- return self._serial_version_uid
-
- def getFields(self):
- return self._fields
-
- def getField(self, name):
- for f in self._fields:
- if f.getName() == name:
- return f
- return None
-
- def forClass(self):
- return self._cls
-
- def isSerializable(self):
- return self._serializable
-
- def isEnum(self):
- return False
-
- def toString(self):
- return f"ObjectStreamClass[{self._name}]"
-
-
-# ============================================================
-# ObjectInputValidation
-# ============================================================
-
-class ObjectInputValidation(Stub):
- """java.io.ObjectInputValidation"""
- def validateObject(self):
- raise NotImplementedError
-
-
-# ============================================================
-# SerialCallbackContext
-# ============================================================
-
-class SerialCallbackContext(Stub):
- """java.io.SerialCallbackContext"""
- def __init__(self, obj, desc):
- super().__init__()
- self._obj = obj
- self._desc = desc
- self._used = False
-
- def getObj(self):
- return self._obj
-
- def getDesc(self):
- return self._desc
-
- def setUsed(self):
- self._used = True
-
- def isUsed(self):
- return self._used
-
-
-# ============================================================
-# ObjectInput / ObjectOutput interfaces
-# ============================================================
-
-class DataInput(Stub):
- """java.io.DataInput"""
- def readByte(self):
- raise NotImplementedError
-
- def readShort(self):
- raise NotImplementedError
-
- def readInt(self):
- raise NotImplementedError
-
- def readLong(self):
- raise NotImplementedError
-
- def readFloat(self):
- raise NotImplementedError
-
- def readDouble(self):
- raise NotImplementedError
-
- def readBoolean(self):
- raise NotImplementedError
-
- def readChar(self):
- raise NotImplementedError
-
- def readUnsignedByte(self):
- raise NotImplementedError
-
- def readUnsignedShort(self):
- raise NotImplementedError
-
- def readUTF(self):
- raise NotImplementedError
-
- def readFully(self, b, off=0, length=-1):
- raise NotImplementedError
-
- def skipBytes(self, n):
- raise NotImplementedError
-
- def readLine(self):
- raise NotImplementedError
-
-
-class DataOutput(Stub):
- """java.io.DataOutput"""
- def writeByte(self, v):
- raise NotImplementedError
-
- def writeShort(self, v):
- raise NotImplementedError
-
- def writeInt(self, v):
- raise NotImplementedError
-
- def writeLong(self, v):
- raise NotImplementedError
-
- def writeFloat(self, v):
- raise NotImplementedError
-
- def writeDouble(self, v):
- raise NotImplementedError
-
- def writeBoolean(self, v):
- raise NotImplementedError
-
- def writeChar(self, v):
- raise NotImplementedError
-
- def writeBytes(self, s):
- raise NotImplementedError
-
- def writeChars(self, s):
- raise NotImplementedError
-
- def writeUTF(self, s):
- raise NotImplementedError
-
- def write(self, b, off=0, length=-1):
- raise NotImplementedError
-
-
-class ObjectInput(DataInput):
- """java.io.ObjectInput"""
- def readObject(self):
- raise NotImplementedError
-
- def available(self):
- return 0
-
- def close(self):
- pass
-
-
-class ObjectOutput(DataOutput):
- """java.io.ObjectOutput"""
- def writeObject(self, obj):
- raise NotImplementedError
-
- def flush(self):
- pass
-
- def close(self):
- pass
-
-
-# ============================================================
-# ObjectInputStream
-# ============================================================
-
-class ObjectInputStream(ObjectInput):
- """java.io.ObjectInputStream"""
- def __init__(self, inp):
- super().__init__()
- self._input = inp
- self._data = inp.read() if hasattr(inp, 'read') else b""
- self._pos = 0
- self._handles = {}
- self._next_handle = ObjectStreamConstants.baseWireHandle
- self._validation_list = []
- self._resolved = {}
-
- def readObject(self):
- if self._pos >= len(self._data):
- raise StreamCorruptedException("No data")
- try:
- obj = _pickle.loads(self._data[self._pos:])
- return obj
- except Exception:
- return None
-
- def readByte(self):
- val = self._data[self._pos] if self._pos < len(self._data) else 0
- self._pos += 1
- return val
-
- def readInt(self):
- if self._pos + 4 > len(self._data):
- raise StreamCorruptedException()
- val = _struct.unpack_from(">i", self._data, self._pos)[0]
- self._pos += 4
- return val
-
- def readShort(self):
- if self._pos + 2 > len(self._data):
- raise StreamCorruptedException()
- val = _struct.unpack_from(">h", self._data, self._pos)[0]
- self._pos += 2
- return val
-
- def readLong(self):
- if self._pos + 8 > len(self._data):
- raise StreamCorruptedException()
- val = _struct.unpack_from(">q", self._data, self._pos)[0]
- self._pos += 8
- return val
-
- def readFloat(self):
- if self._pos + 4 > len(self._data):
- raise StreamCorruptedException()
- val = _struct.unpack_from(">f", self._data, self._pos)[0]
- self._pos += 4
- return val
-
- def readDouble(self):
- if self._pos + 8 > len(self._data):
- raise StreamCorruptedException()
- val = _struct.unpack_from(">d", self._data, self._pos)[0]
- self._pos += 8
- return val
-
- def readBoolean(self):
- return self.readByte() != 0
-
- def readChar(self):
- if self._pos + 2 > len(self._data):
- raise StreamCorruptedException()
- val = _struct.unpack_from(">H", self._data, self._pos)[0]
- self._pos += 2
- return chr(val)
-
- def readUnsignedByte(self):
- return self.readByte() & 0xFF
-
- def readUnsignedShort(self):
- return self.readShort() & 0xFFFF
-
- def readUTF(self):
- length = self.readUnsignedShort()
- if self._pos + length > len(self._data):
- raise StreamCorruptedException()
- val = self._data[self._pos:self._pos + length].decode("utf-8")
- self._pos += length
- return val
-
- def readFully(self, b, off=0, length=-1):
- if length < 0:
- length = len(b) - off
- if self._pos + length > len(self._data):
- raise StreamCorruptedException()
- for i in range(length):
- b[off + i] = self._data[self._pos + i]
- self._pos += length
-
- def skipBytes(self, n):
- actual = min(n, len(self._data) - self._pos)
- self._pos += actual
- return actual
-
- def readLine(self):
- result = []
- while self._pos < len(self._data):
- c = chr(self._data[self._pos])
- self._pos += 1
- if c == "\n":
- break
- if c == "\r":
- if self._pos < len(self._data) and chr(self._data[self._pos]) == "\n":
- self._pos += 1
- break
- result.append(c)
- return "".join(result)
-
- def available(self):
- return len(self._data) - self._pos
-
- def close(self):
- self._input = None
- self._data = b""
- self._pos = 0
-
- def defaultReadObject(self):
- return self.readObject()
-
- def readFields(self):
- return self.readObject()
-
- def registerValidation(self, obj, prio):
- self._validation_list.append((obj, prio))
-
- def resolveClass(self, desc):
- return desc.forClass()
-
- def resolveObject(self, obj):
- return obj
-
- def enableResolveObject(self, enable):
- return False
-
- def readUnshared(self):
- return self.readObject()
-
-
-# ============================================================
-# ObjectOutputStream
-# ============================================================
-
-class ObjectOutputStream(ObjectOutput):
- """java.io.ObjectOutputStream"""
- def __init__(self, out):
- super().__init__()
- self._output = out
- self._buffer = bytearray()
- self._handles = {}
- self._next_handle = ObjectStreamConstants.baseWireHandle
- self._block_data_mode = False
- self._extended_block_data_mode = False
-
- def writeObject(self, obj):
- data = _pickle.dumps(obj)
- self._buffer.extend(data)
- self._flush_buffer()
-
- def writeByte(self, v):
- self._buffer.extend(_struct.pack(">b", v if isinstance(v, int) else ord(v)))
-
- def writeInt(self, v):
- self._buffer.extend(_struct.pack(">i", int(v)))
-
- def writeShort(self, v):
- self._buffer.extend(_struct.pack(">h", int(v)))
-
- def writeLong(self, v):
- self._buffer.extend(_struct.pack(">q", int(v)))
-
- def writeFloat(self, v):
- self._buffer.extend(_struct.pack(">f", float(v)))
-
- def writeDouble(self, v):
- self._buffer.extend(_struct.pack(">d", float(v)))
-
- def writeBoolean(self, v):
- self._buffer.extend(_struct.pack(">?", bool(v)))
-
- def writeChar(self, v):
- if isinstance(v, str):
- v = ord(v)
- self._buffer.extend(_struct.pack(">H", int(v)))
-
- def writeBytes(self, s):
- if isinstance(s, str):
- self._buffer.extend(s.encode())
- elif isinstance(s, bytes):
- self._buffer.extend(s)
- elif isinstance(s, bytearray):
- self._buffer.extend(s)
-
- def writeChars(self, s):
- for c in s:
- self._buffer.extend(_struct.pack(">H", ord(c)))
-
- def writeUTF(self, s):
- encoded = s.encode("utf-8")
- self.writeShort(len(encoded))
- self._buffer.extend(encoded)
-
- def write(self, b, off=0, length=-1):
- if isinstance(b, int):
- self._buffer.append(b & 0xFF)
- elif isinstance(b, bytes):
- if length < 0:
- length = len(b) - off
- self._buffer.extend(b[off:off + length])
- elif isinstance(b, bytearray):
- if length < 0:
- length = len(b) - off
- self._buffer.extend(b[off:off + length])
-
- def flush(self):
- self._flush_buffer()
- if hasattr(self._output, 'flush'):
- self._output.flush()
-
- def close(self):
- self.flush()
- if hasattr(self._output, 'close'):
- self._output.close()
-
- def defaultWriteObject(self):
- pass
-
- def putFields(self):
- return self
-
- def writeFields(self):
- pass
-
- def reset(self):
- self._handles = {}
- self._next_handle = ObjectStreamConstants.baseWireHandle
- self._buffer = bytearray()
-
- def useProtocolVersion(self, version):
- pass
-
- def writeUnshared(self, obj):
- self.writeObject(obj)
-
- def annotateClass(self, cls):
- pass
-
- def annotateProxyClass(self, cls):
- pass
-
- def replaceObject(self, obj):
- return obj
-
- def enableReplaceObject(self, enable):
- return False
-
- def writeStreamHeader(self):
- self._buffer.extend(_struct.pack(">HH",
- ObjectStreamConstants.STREAM_MAGIC,
- ObjectStreamConstants.STREAM_VERSION))
-
- def _flush_buffer(self):
- if self._buffer:
- data = bytes(self._buffer)
- if hasattr(self._output, 'write'):
- self._output.write(data)
- self._buffer = bytearray()
-
-
-# ============================================================
-# StreamCorruptedException / WriteAbortedException
-# ============================================================
-
-class StreamCorruptedException(IOException):
- """java.io.StreamCorruptedException"""
- def __init__(self, message=None):
- super().__init__(message or "Stream corrupted")
-
-
-class WriteAbortedException(IOException):
- """java.io.WriteAbortedException"""
- def __init__(self, message, exception):
- super().__init__(message)
- self._exception = exception
-
- def getException(self):
- return self._exception
-
-
-# ============================================================
-# FileFilter / FileNameFilter
-# ============================================================
-
-class FileFilter(Stub):
- """java.io.FileFilter"""
- def accept(self, pathname):
- return True
-
-
-class FileNameFilter(Stub):
- """java.io.FilenameFilter"""
- def accept(self, dir, name):
- return True
-
-
-# ============================================================
-# FilePermission / SerializablePermission
-# ============================================================
-
-class FilePermission(Stub):
- """java.io.FilePermission"""
- def __init__(self, path, actions):
- super().__init__()
- self._path = path
- self._actions = actions
-
- def getName(self):
- return self._path
-
- def getActions(self):
- return self._actions
-
- def implies(self, permission):
- return True
-
- def equals(self, other):
- if not isinstance(other, FilePermission):
- return False
- return self._path == other._path and self._actions == other._actions
-
- def hashCode(self):
- return hash((self._path, self._actions))
-
-
-class SerializablePermission(Stub):
- """java.io.SerializablePermission"""
- def __init__(self, name, actions=None):
- super().__init__()
- self._name = name
- self._actions = actions or ""
-
- def getName(self):
- return self._name
-
- def getActions(self):
- return self._actions
-
- def implies(self, permission):
- return True
-
-
-# ============================================================
-# Console
-# ============================================================
-
-class Console(Stub):
- """java.io.Console"""
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def console():
- return Console()
-
- def readLine(self, fmt=None, *args):
- if fmt:
- print(fmt % args, end="")
- return input()
-
- def readPassword(self, fmt=None, *args):
- import getpass
- if fmt:
- print(fmt % args, end="")
- return getpass.getpass("")
-
- def format(self, fmt, *args):
- _sys.stdout.write(fmt % args)
- _sys.stdout.flush()
- return self
-
- def printf(self, format, *args):
- return self.format(format, *args)
-
- def flush(self):
- _sys.stdout.flush()
-
- def reader(self):
- return _pyio.BufferedReader(_pyio.FileIO(_sys.stdin.fileno()))
-
- def writer(self):
- return _pyio.TextIOWrapper(_pyio.BufferedWriter(
- _pyio.FileIO(_sys.stdout.fileno(), "w")
- ))
-
-
-# ============================================================
-# PrintStream
-# ============================================================
-
-class PrintStream(Stub):
- """java.io.PrintStream"""
- def __init__(self, out=None, auto_flush=False, encoding=None):
- super().__init__()
- self._out = out or _sys.stdout
- self._auto_flush = auto_flush
- self._encoding = encoding or "utf-8"
- self._error = False
-
- def print(self, obj=""):
- _sys.stdout.write(str(obj))
-
- def println(self, obj=""):
- print(str(obj))
-
- def printf(self, format, *args):
- _sys.stdout.write(format % args)
- if self._auto_flush:
- _sys.stdout.flush()
- return self
-
- def format(self, format_, *args):
- return self.printf(format_, *args)
-
- def write(self, b, off=0, length=-1):
- if isinstance(b, int):
- self._out.write(bytes([b]))
- elif isinstance(b, bytes):
- if length < 0:
- self._out.write(b[off:])
- else:
- self._out.write(b[off:off + length])
- elif isinstance(b, str):
- self._out.write(b)
- if self._auto_flush:
- self._out.flush()
-
- def flush(self):
- self._out.flush()
-
- def close(self):
- self.flush()
-
- def checkError(self):
- return self._error
-
- def setError(self):
- self._error = True
-
- def clearError(self):
- self._error = False
-
- def append(self, c):
- if isinstance(c, str):
- self._out.write(c)
- else:
- self._out.write(str(c))
- return self
-
-
-# ============================================================
-# SequenceInputStream
-# ============================================================
-
-class SequenceInputStream(Stub):
- """java.io.SequenceInputStream"""
- def __init__(self, *args):
- super().__init__()
- if len(args) == 1:
- self._enumerator = iter(args[0])
- self._current = next(self._enumerator, None)
- elif len(args) == 2:
- self._enumerator = iter(args)
- self._current = args[0]
- else:
- self._enumerator = iter([])
- self._current = None
-
- def read(self, b=None, off=0, length=-1):
- while self._current is not None:
- if hasattr(self._current, 'read'):
- if b is None:
- data = self._current.read()
- else:
- if length < 0:
- data = self._current.read(len(b) - off)
- else:
- data = self._current.read(min(length, len(b) - off))
- if data:
- if b is not None:
- for i, byte in enumerate(data):
- b[off + i] = byte
- return len(data)
- self._current = next(self._enumerator, None)
- else:
- self._current = next(self._enumerator, None)
- return -1
-
- def close(self):
- self._current = None
-
-
-# ============================================================
-# StringBufferInputStream
-# ============================================================
-
-class StringBufferInputStream(Stub):
- """java.io.StringBufferInputStream"""
- def __init__(self, s):
- super().__init__()
- self._string = s
- self._pos = 0
- self._count = len(s)
-
- def read(self, b=None, off=0, length=-1):
- if self._pos >= self._count:
- return -1
- if b is None:
- val = ord(self._string[self._pos]) if self._pos < self._count else -1
- self._pos += 1
- return val
- if length < 0:
- length = len(b) - off
- available = self._count - self._pos
- to_read = min(available, length)
- for i in range(to_read):
- b[off + i] = ord(self._string[self._pos + i])
- self._pos += to_read
- return to_read
-
- def available(self):
- return self._count - self._pos
-
- def reset(self):
- self._pos = 0
-
-
-# ============================================================
-# LineNumberReader
-# ============================================================
-
-class LineNumberReader(Stub):
- """java.io.LineNumberReader"""
- def __init__(self, reader, sz=8192):
- super().__init__()
- self._reader = reader
- self._line_number = 0
- self._buffer = ""
- self._pos = 0
- self._marked_pos = 0
- self._marked_line = 0
- self._sz = sz
-
- def readLine(self):
- result = []
- while self._pos < len(self._buffer) or self._fill_buffer():
- if self._pos < len(self._buffer):
- c = self._buffer[self._pos]
- self._pos += 1
- if c == "\n":
- self._line_number += 1
- return "".join(result)
- if c == "\r":
- self._line_number += 1
- if self._pos < len(self._buffer) and self._buffer[self._pos] == "\n":
- self._pos += 1
- return "".join(result)
- result.append(c)
- else:
- break
- if not result:
- return None
- return "".join(result)
-
- def getLineNumber(self):
- return self._line_number
-
- def setLineNumber(self, line_number):
- self._line_number = line_number
-
- def read(self, cbuf=None, off=0, length=-1):
- if cbuf is None:
- if self._pos < len(self._buffer) or self._fill_buffer():
- if self._pos < len(self._buffer):
- c = self._buffer[self._pos]
- self._pos += 1
- return ord(c)
- return -1
- count = 0
- while count < (length if length >= 0 else len(cbuf) - off):
- if self._pos >= len(self._buffer) and not self._fill_buffer():
- break
- cbuf[off + count] = self._buffer[self._pos]
- self._pos += 1
- count += 1
- return count if count > 0 else -1
-
- def close(self):
- if self._reader and hasattr(self._reader, 'close'):
- self._reader.close()
-
- def mark(self, read_ahead_limit):
- self._marked_pos = self._pos
- self._marked_line = self._line_number
-
- def reset(self):
- self._pos = self._marked_pos
- self._line_number = self._marked_line
-
- def skip(self, n):
- actual = 0
- while actual < n:
- if self._pos >= len(self._buffer) and not self._fill_buffer():
- break
- self._pos += 1
- actual += 1
- return actual
-
- def ready(self):
- return self._pos < len(self._buffer)
-
- def _fill_buffer(self):
- if self._reader and hasattr(self._reader, 'read'):
- data = self._reader.read(self._sz)
- if isinstance(data, str):
- self._buffer = data
- elif isinstance(data, bytes):
- self._buffer = data.decode('utf-8')
- else:
- self._buffer = ""
- self._pos = 0
- return len(self._buffer) > 0
- return False
-
-
-# ============================================================
-# CharArrayReader / CharArrayWriter
-# ============================================================
-
-class CharArrayReader(Stub):
- """java.io.CharArrayReader"""
- def __init__(self, buf, offset=0, length=None):
- super().__init__()
- self._buf = list(buf)
- if length is not None:
- self._buf = self._buf[offset:offset + length]
- else:
- self._buf = self._buf[offset:]
- self._pos = 0
- self._marked_pos = 0
-
- def read(self, cbuf=None, off=0, length=-1):
- if self._pos >= len(self._buf):
- return -1
- if cbuf is None:
- val = ord(self._buf[self._pos]) if isinstance(self._buf[self._pos], str) else self._buf[self._pos]
- self._pos += 1
- return val
- if length < 0:
- length = len(cbuf) - off
- available = len(self._buf) - self._pos
- to_read = min(available, length)
- for i in range(to_read):
- cbuf[off + i] = (
- ord(self._buf[self._pos + i])
- if isinstance(self._buf[self._pos + i], str)
- else self._buf[self._pos + i]
- )
- self._pos += to_read
- return to_read
-
- def close(self):
- self._buf = []
-
- def mark(self, read_ahead_limit):
- self._marked_pos = self._pos
-
- def reset(self):
- self._pos = self._marked_pos
-
- def skip(self, n):
- actual = min(n, len(self._buf) - self._pos)
- self._pos += actual
- return actual
-
- def ready(self):
- return self._pos < len(self._buf)
-
-
-class CharArrayWriter(Stub):
- """java.io.CharArrayWriter"""
- def __init__(self, initial_size=32):
- super().__init__()
- self._buf = []
-
- def write(self, c, off=0, length=-1):
- if isinstance(c, str):
- self._buf.append(c)
- elif isinstance(c, (list, tuple)):
- if length < 0:
- length = len(c) - off
- self._buf.extend(c[off:off + length])
- elif isinstance(c, int):
- self._buf.append(chr(c))
-
- def writeTo(self, out):
- if hasattr(out, 'write'):
- out.write(self.toString())
-
- def toString(self):
- return "".join(str(x) for x in self._buf)
-
- def size(self):
- return len(self._buf)
-
- def toCharArray(self):
- return list(self.toString())
-
- def flush(self):
- pass
-
- def close(self):
- pass
-
- def reset(self):
- self._buf = []
-
-
-# ============================================================
-# FilterReader / FilterWriter
-# ============================================================
-
-class FilterReader(Stub):
- """java.io.FilterReader"""
- def __init__(self, reader):
- super().__init__()
- self._reader = reader
-
- def read(self, cbuf=None, off=0, length=-1):
- if self._reader:
- return self._reader.read(cbuf, off, length)
- return -1
-
- def close(self):
- if self._reader:
- self._reader.close()
-
- def mark(self, read_limit):
- if self._reader and hasattr(self._reader, 'mark'):
- self._reader.mark(read_limit)
-
- def reset(self):
- if self._reader and hasattr(self._reader, 'reset'):
- self._reader.reset()
-
- def ready(self):
- if self._reader and hasattr(self._reader, 'ready'):
- return self._reader.ready()
- return False
-
- def skip(self, n):
- if self._reader and hasattr(self._reader, 'skip'):
- return self._reader.skip(n)
- return 0
-
-
-class FilterWriter(Stub):
- """java.io.FilterWriter"""
- def __init__(self, writer):
- super().__init__()
- self._writer = writer
-
- def write(self, c, off=0, length=-1):
- if self._writer:
- if isinstance(c, str):
- self._writer.write(c)
- elif isinstance(c, int):
- self._writer.write(chr(c))
-
- def flush(self):
- if self._writer:
- self._writer.flush()
-
- def close(self):
- if self._writer:
- self._writer.close()
-
-
-# ============================================================
-# PushbackReader
-# ============================================================
-
-class PushbackReader(FilterReader):
- """java.io.PushbackReader"""
- def __init__(self, reader, size=1):
- super().__init__(reader)
- self._pushback_buf = []
- self._pushback_size = size
-
- def read(self, cbuf=None, off=0, length=-1):
- if self._pushback_buf:
- ch = self._pushback_buf.pop()
- if cbuf is None:
- return ord(ch) if isinstance(ch, str) else ch
- cbuf[off] = ord(ch) if isinstance(ch, str) else ch
- return 1
- return super().read(cbuf, off, length)
-
- def unread(self, c):
- if len(self._pushback_buf) >= self._pushback_size:
- raise IOException("Pushback buffer full")
- if isinstance(c, (list, tuple)):
- for ch in reversed(c):
- self._pushback_buf.append(ch)
- else:
- self._pushback_buf.append(c)
-
-
-# ============================================================
-# PushbackInputStream
-# ============================================================
-
-class PushbackInputStream(Stub):
- """java.io.PushbackInputStream"""
- def __init__(self, inp, size=1):
- super().__init__()
- self._input = inp
- self._pushback_buf = bytearray()
- self._pushback_size = size
-
- def read(self, b=None, off=0, length=-1):
- if self._pushback_buf and b is None:
- return self._pushback_buf.pop(0)
- if b is not None:
- count = 0
- while count < (length if length >= 0 else len(b) - off):
- if self._pushback_buf:
- b[off + count] = self._pushback_buf.pop(0)
- elif self._input:
- val = self._input.read(1)
- if val == -1 or val == b"" or val is None:
- break
- b[off + count] = val[0] if isinstance(val, bytes) else val
- else:
- break
- count += 1
- return count if count > 0 else -1
- if self._pushback_buf:
- return self._pushback_buf.pop(0)
- if self._input:
- val = self._input.read(1)
- if val is not None and val != -1:
- return val[0] if isinstance(val, bytes) else val
- return -1
-
- def unread(self, b, off=0, length=-1):
- if isinstance(b, int):
- if len(self._pushback_buf) >= self._pushback_size:
- raise IOException("Pushback buffer full")
- self._pushback_buf.insert(0, b & 0xFF)
- elif isinstance(b, (bytes, bytearray)):
- if length < 0:
- length = len(b) - off
- if len(self._pushback_buf) + length > self._pushback_size:
- raise IOException("Pushback buffer full")
- for i in range(length - 1, -1, -1):
- self._pushback_buf.insert(0, b[off + i])
-
- def available(self):
- return len(self._pushback_buf) + (self._input.available() if self._input else 0)
-
- def close(self):
- if self._input:
- self._input.close()
- self._pushback_buf = bytearray()
-
-
-# ============================================================
-# StreamTokenizer
-# ============================================================
-
-class StreamTokenizer(Stub):
- """java.io.StreamTokenizer"""
- def __init__(self, reader=None, inp=None):
- super().__init__()
- if reader:
- self._reader = reader
- elif inp:
- import io
- self._reader = io.TextIOWrapper(io.BufferedReader(inp))
- else:
- self._reader = None
-
- self.ttype = 0
- self.sval = None
- self.nval = 0.0
-
- self._reset_syntax()
-
- def _reset_syntax(self):
- self._ordinary_chars = set()
- self._word_chars = set()
- self._whitespace_chars = set(range(0x20))
- self._comment_char = None
- self._quote_char = None
- self._parse_numbers = True
- self._lower_case_mode = False
- self._slash_slash_comments = False
- self._slash_star_comments = False
- self._eol_is_significant = False
- self._lower_case_mode = False
- self._pushback = None
-
- def resetSyntax(self):
- self._reset_syntax()
-
- def wordChars(self, low, high):
- for c in range(low, high + 1):
- self._word_chars.add(c)
-
- def whitespaceChars(self, low, high):
- for c in range(low, high + 1):
- self._whitespace_chars.add(c)
-
- def ordinaryChars(self, low, high):
- for c in range(low, high + 1):
- self._ordinary_chars.add(c)
-
- def ordinaryChar(self, ch):
- self._ordinary_chars.add(ch)
-
- def commentChar(self, ch):
- self._comment_char = ch
-
- def quoteChar(self, ch):
- self._quote_char = ch
-
- def parseNumbers(self):
- self._parse_numbers = True
-
- def eolIsSignificant(self, flag):
- self._eol_is_significant = flag
-
- def slashSlashComments(self, flag):
- self._slash_slash_comments = flag
-
- def slashStarComments(self, flag):
- self._slash_star_comments = flag
-
- def lowerCaseMode(self, flag):
- self._lower_case_mode = flag
-
- def pushBack(self):
- self._pushback = self.ttype
-
- def lineno(self):
- return 1
-
- def toString(self):
- if self.ttype == -1:
- return "EOF"
- if self.ttype == -3:
- return f"WORD={self.sval}"
- if self.ttype == -2:
- return f"NUMBER={self.nval}"
- return f"CHAR={chr(self.ttype) if self.ttype < 256 else '?'}"
-
- def nextToken(self):
- if self._pushback is not None:
- pb = self._pushback
- self._pushback = None
- self.ttype = pb
- return self.ttype
-
- if self._reader is None:
- self.ttype = -1 # TT_EOF
- return -1
-
- ch = self._read_char()
- if ch is None:
- self.ttype = -1
- return -1
-
- # Check for newlines
- if ch == "\n":
- if self._eol_is_significant:
- self.ttype = 10 # TT_EOL
- return 10
- return self.nextToken()
-
- # Whitespace
- if ord(ch) in self._whitespace_chars:
- return self.nextToken()
-
- # Comment char
- if self._comment_char is not None and ord(ch) == self._comment_char:
- while ch is not None and ch != "\n":
- ch = self._read_char()
- return self.nextToken()
-
- # Quote char
- if self._quote_char is not None and ord(ch) == self._quote_char:
- buf = []
- while True:
- ch = self._read_char()
- if ch is None or ord(ch) == self._quote_char:
- break
- buf.append(ch)
- self.sval = "".join(buf)
- if self._lower_case_mode:
- self.sval = self.sval.lower()
- self.ttype = ord(self._quote_char)
- return self.ttype
-
- # Number
- if self._parse_numbers and (ch.isdigit() or ch in ('-', '.')):
- buf = [ch]
- if ch in ('-', '.'):
- next_ch = self._peek_char()
- if next_ch is not None and (next_ch.isdigit() or next_ch == '.'):
- buf.append(self._read_char())
- while True:
- ch = self._read_char()
- if ch is None or not (ch.isdigit() or ch == '.' or ch in ('e', 'E', '-', '+')):
- if ch is not None:
- self._unread_char(ch)
- break
- buf.append(ch)
- num_str = "".join(buf)
- try:
- self.nval = float(num_str)
- except ValueError:
- self.nval = 0.0
- self.ttype = -2 # TT_NUMBER
- return -2
-
- # Word chars
- if ord(ch) in self._word_chars:
- buf = [ch]
- while True:
- next_ch = self._peek_char()
- if next_ch is not None and ord(next_ch) in self._word_chars:
- buf.append(self._read_char())
- else:
- break
- self.sval = "".join(buf)
- if self._lower_case_mode:
- self.sval = self.sval.lower()
- self.ttype = -3 # TT_WORD
- return -3
-
- # Ordinary char
- self.ttype = ord(ch)
- return ord(ch)
-
- def _read_char(self):
- if self._reader is None:
- return None
- try:
- if hasattr(self._reader, 'read'):
- c = self._reader.read(1)
- if c and isinstance(c, bytes):
- c = c.decode('utf-8')
- return c if c else None
- return None
- except Exception:
- return None
-
- def _peek_char(self):
- if self._reader is None:
- return None
- try:
- c = self._reader.read(1)
- if c and isinstance(c, bytes):
- c = c.decode('utf-8')
- if c:
- self._unread_char(c)
- return c if c else None
- except Exception:
- return None
-
- def _unread_char(self, c):
- if hasattr(self._reader, 'seek'):
- self._reader.seek(self._reader.tell() - 1)
-
- TT_EOF = -1
- TT_EOL = 10
- TT_NUMBER = -2
- TT_WORD = -3
\ No newline at end of file
diff --git a/android_pyapi/java/io_file.py b/android_pyapi/java/io_file.py
deleted file mode 100644
index 5e4b7d6..0000000
--- a/android_pyapi/java/io_file.py
+++ /dev/null
@@ -1,1451 +0,0 @@
-"""
-java.io 文件扩展组件 — File扩展, FileSystem, UnixFileSystem,
-FileDescriptor扩展, FileInputStream扩展, FileChannel扩展,
-FilePermission扩展, FileVisitor, FileAlreadyExistsException等
-方法签名完全对齐 Java SDK
-"""
-
-from __future__ import annotations
-
-import errno
-import io
-import os
-import stat
-import struct
-import sys
-import time
-from typing import (Any, Callable, Dict, IO, Iterator, List, Optional,
- Set, Tuple, Union)
-
-from .._core import Stub, AndroidOnlyError
-
-__all__ = [
- "FileSystem", "UnixFileSystem", "WinNTFileSystem",
- "FileStatus", "FileAccess", "FileAccessModes",
- "FileDescriptor", "FileInputStream", "FileOutputStream",
- "RandomAccessFile", "FileLock", "FileChannel",
- "FilePermission", "FileFilter", "FileNameFilter",
- "FileSystemProvider", "FileTreeWalker", "FileTypeDetector",
- "FileVisitOption", "FileVisitResult", "FileVisitor",
- "SimpleFileVisitor",
- "FileAlreadyExistsException", "FileSystemAlreadyExistsException",
- "FileSystemException", "FileSystemLoopException",
- "FileSystemNotFoundException", "AccessDeniedException",
- "AtomicMoveNotSupportedException", "DirectoryIteratorException",
- "DirectoryNotEmptyException", "FileSystemOperationException",
- "InvalidPathException", "ProviderMismatchException",
- "ProviderNotFoundException", "ReadOnlyFileSystemException",
- "UserPrincipalLookupService", "UserPrincipal", "GroupPrincipal",
- "FileAttribute", "FileAttributeView", "FileStore",
- "FileStoreAttributeView", "FileSystems",
-]
-
-
-# ═══════════════════════════════════════════════════════════════
-# 文件系统常量
-# ═══════════════════════════════════════════════════════════════
-
-ACCESS_READ = 0x01
-ACCESS_WRITE = 0x02
-ACCESS_EXECUTE = 0x04
-
-CREATE_FILE = 0x01
-CREATE_DIRECTORY = 0x02
-CREATE_LINK = 0x04
-CREATE_SYMBOLIC_LINK = 0x08
-
-DELETE_FILE = 0x01
-DELETE_DIRECTORY = 0x02
-DELETE_ON_CLOSE = 0x04
-
-OPEN_READ = 0x01
-OPEN_WRITE = 0x02
-OPEN_APPEND = 0x04
-OPEN_TRUNCATE = 0x08
-OPEN_CREATE = 0x10
-OPEN_CREATE_NEW = 0x20
-OPEN_DELETE_ON_CLOSE = 0x40
-OPEN_SPARSE = 0x80
-OPEN_SYNC = 0x100
-OPEN_DSYNC = 0x200
-
-COPY_FILE = 0x01
-COPY_DIRECTORY = 0x02
-COPY_SYMBOLIC_LINK = 0x04
-COPY_ATTRIBUTES = 0x08
-COPY_REPLACE_EXISTING = 0x10
-COPY_COPY_ATTRIBUTES = 0x08
-COPY_NO_FOLLOW_LINKS = 0x04
-
-MOVE_FILE = 0x01
-MOVE_DIRECTORY = 0x02
-MOVE_REPLACE_EXISTING = 0x04
-MOVE_ATOMIC = 0x08
-
-LINK_SYMBOLIC = 0x01
-LINK_HARD = 0x02
-
-WALK_FILE_TREE = 0x01
-WALK_FOLLOW_LINKS = 0x02
-WALK_MAX_DEPTH_UNLIMITED = -1
-
-FILE_TYPE_UNKNOWN = 0
-FILE_TYPE_REGULAR = 1
-FILE_TYPE_DIRECTORY = 2
-FILE_TYPE_SYMBOLIC_LINK = 3
-FILE_TYPE_CHARACTER_DEVICE = 4
-FILE_TYPE_BLOCK_DEVICE = 5
-FILE_TYPE_FIFO = 6
-FILE_TYPE_SOCKET = 7
-
-FILE_ATTRIBUTE_READ_ONLY = 0x01
-FILE_ATTRIBUTE_HIDDEN = 0x02
-FILE_ATTRIBUTE_SYSTEM = 0x04
-FILE_ATTRIBUTE_DIRECTORY = 0x08
-FILE_ATTRIBUTE_ARCHIVE = 0x10
-FILE_ATTRIBUTE_NORMAL = 0x20
-FILE_ATTRIBUTE_TEMPORARY = 0x40
-FILE_ATTRIBUTE_SPARSE = 0x80
-FILE_ATTRIBUTE_REPARSE = 0x100
-FILE_ATTRIBUTE_COMPRESSED = 0x200
-FILE_ATTRIBUTE_OFFLINE = 0x400
-FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x800
-FILE_ATTRIBUTE_ENCRYPTED = 0x1000
-FILE_ATTRIBUTE_VIRTUAL = 0x2000
-FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x4000
-FILE_ATTRIBUTE_NO_SCRUB = 0x8000
-FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000
-FILE_ATTRIBUTE_PINNED = 0x80000
-FILE_ATTRIBUTE_UNPINNED = 0x100000
-FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000
-
-
-# ═══════════════════════════════════════════════════════════════
-# 异常类
-# ═══════════════════════════════════════════════════════════════
-
-class FileSystemException(OSError):
- """FileSystemException — 文件系统异常"""
-
- def __init__(self, file_: str = "", other: str = "",
- reason: str = ""):
- self._file = file_
- self._other = other
- self._reason = reason
- msg = f"{file_}"
- if other:
- msg += f" -> {other}"
- if reason:
- msg += f": {reason}"
- super().__init__(msg)
-
- def getFile(self) -> str:
- return self._file
-
- def getOtherFile(self) -> str:
- return self._other
-
- def getReason(self) -> str:
- return self._reason
-
-
-class FileAlreadyExistsException(FileSystemException):
- """FileAlreadyExistsException — 文件已存在"""
- pass
-
-
-class FileSystemAlreadyExistsException(FileSystemException):
- """FileSystemAlreadyExistsException — 文件系统已存在"""
- pass
-
-
-class FileSystemLoopException(FileSystemException):
- """FileSystemLoopException — 文件系统循环"""
- pass
-
-
-class FileSystemNotFoundException(FileSystemException):
- """FileSystemNotFoundException — 文件系统未找到"""
- pass
-
-
-class AccessDeniedException(FileSystemException):
- """AccessDeniedException — 访问被拒绝"""
- pass
-
-
-class AtomicMoveNotSupportedException(FileSystemException):
- """AtomicMoveNotSupportedException — 原子移动不支持"""
- pass
-
-
-class DirectoryIteratorException(FileSystemException):
- """DirectoryIteratorException — 目录迭代异常"""
- pass
-
-
-class DirectoryNotEmptyException(FileSystemException):
- """DirectoryNotEmptyException — 目录非空"""
- pass
-
-
-class FileSystemOperationException(FileSystemException):
- """FileSystemOperationException — 文件系统操作异常"""
- pass
-
-
-class InvalidPathException(FileSystemException):
- """InvalidPathException — 路径无效"""
- pass
-
-
-class ProviderMismatchException(FileSystemException):
- """ProviderMismatchException — 提供器不匹配"""
- pass
-
-
-class ProviderNotFoundException(FileSystemException):
- """ProviderNotFoundException — 提供器未找到"""
- pass
-
-
-class ReadOnlyFileSystemException(FileSystemException):
- """ReadOnlyFileSystemException — 只读文件系统"""
- pass
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileStatus / FileAccess / FileAccessModes
-# ═══════════════════════════════════════════════════════════════
-
-class FileStatus(Stub):
- """FileStatus — 文件状态"""
-
- def __init__(self, type_: int = FILE_TYPE_UNKNOWN,
- size: int = 0, lastModified: int = 0,
- lastAccess: int = 0, creationTime: int = 0,
- isSymbolicLink: bool = False,
- device: int = 0, inode: int = 0,
- mode: int = 0, uid: int = 0, gid: int = 0):
- super().__init__()
- self._type = type_
- self._size = size
- self._last_modified = lastModified
- self._last_access = lastAccess
- self._creation_time = creationTime
- self._is_symlink = isSymbolicLink
- self._device = device
- self._inode = inode
- self._mode = mode
- self._uid = uid
- self._gid = gid
-
- def getType(self) -> int:
- return self._type
-
- def getSize(self) -> int:
- return self._size
-
- def getLastModified(self) -> int:
- return self._last_modified
-
- def getLastAccess(self) -> int:
- return self._last_access
-
- def getCreationTime(self) -> int:
- return self._creation_time
-
- def isSymbolicLink(self) -> bool:
- return self._is_symlink
-
- def getDevice(self) -> int:
- return self._device
-
- def getInode(self) -> int:
- return self._inode
-
- def getMode(self) -> int:
- return self._mode
-
- def getUid(self) -> int:
- return self._uid
-
- def getGid(self) -> int:
- return self._gid
-
- def toString(self) -> str:
- return f"FileStatus(type={self._type}, size={self._size})"
-
-
-class FileAccess(Stub):
- """FileAccess — 文件访问"""
-
- def __init__(self, canRead: bool = True, canWrite: bool = True,
- canExecute: bool = False):
- super().__init__()
- self._can_read = canRead
- self._can_write = canWrite
- self._can_execute = canExecute
-
- def canRead(self) -> bool:
- return self._can_read
-
- def canWrite(self) -> bool:
- return self._can_write
-
- def canExecute(self) -> bool:
- return self._can_execute
-
- def toString(self) -> str:
- return f"FileAccess(r={self._can_read}, w={self._can_write}, x={self._can_execute})"
-
-
-class FileAccessModes(Stub):
- """FileAccessModes — 文件访问模式"""
-
- def __init__(self, read: bool = False, write: bool = False,
- append: bool = False, truncate: bool = False):
- super().__init__()
- self._read = read
- self._write = write
- self._append = append
- self._truncate = truncate
-
- def isRead(self) -> bool:
- return self._read
-
- def isWrite(self) -> bool:
- return self._write
-
- def isAppend(self) -> bool:
- return self._append
-
- def isTruncate(self) -> bool:
- return self._truncate
-
- def toString(self) -> str:
- return f"FileAccessModes(r={self._read}, w={self._write})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileDescriptor (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class FileDescriptor(Stub):
- """FileDescriptor — 文件描述符 (完整版)"""
-
- _in: Optional["FileDescriptor"] = None
- _out: Optional["FileDescriptor"] = None
- _err: Optional["FileDescriptor"] = None
-
- @staticmethod
- def in_() -> "FileDescriptor":
- if FileDescriptor._in is None:
- fd = FileDescriptor()
- fd._fd = 0
- FileDescriptor._in = fd
- return FileDescriptor._in
-
- @staticmethod
- def out() -> "FileDescriptor":
- if FileDescriptor._out is None:
- fd = FileDescriptor()
- fd._fd = 1
- FileDescriptor._out = fd
- return FileDescriptor._out
-
- @staticmethod
- def err() -> "FileDescriptor":
- if FileDescriptor._err is None:
- fd = FileDescriptor()
- fd._fd = 2
- FileDescriptor._err = fd
- return FileDescriptor._err
-
- def __init__(self):
- super().__init__()
- self._fd: int = -1
- self._closed = False
- self._readonly = False
-
- def valid(self) -> bool:
- return self._fd >= 0 and not self._closed
-
- def getInt(self) -> int:
- return self._fd
-
- def setInt(self, fd: int):
- self._fd = fd
- self._closed = False
-
- def close(self):
- if self.valid():
- try:
- os.close(self._fd)
- except Exception:
- pass
- self._closed = True
- self._fd = -1
-
- def isClosed(self) -> bool:
- return self._closed
-
- def sync(self):
- if self.valid():
- try:
- os.fsync(self._fd)
- except Exception:
- pass
-
- def toString(self) -> str:
- return f"FileDescriptor(fd={self._fd})"
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, FileDescriptor):
- return False
- return self._fd == other._fd
-
- def hashCode(self) -> int:
- return self._fd & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileInputStream (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class FileInputStream(Stub):
- """FileInputStream — 文件输入流 (完整版)"""
-
- def __init__(self, file: Any):
- super().__init__()
- if isinstance(file, int):
- self._fd = FileDescriptor()
- self._fd.setInt(file)
- self._native_fd = file
- elif isinstance(file, FileDescriptor):
- self._fd = file
- self._native_fd = file.getInt()
- elif isinstance(file, str):
- self._fd = FileDescriptor()
- self._native_fd = os.open(file, os.O_RDONLY)
- self._fd.setInt(self._native_fd)
- else:
- path = str(file) if hasattr(file, 'getPath') else str(file)
- self._fd = FileDescriptor()
- self._native_fd = os.open(path, os.O_RDONLY)
- self._fd.setInt(self._native_fd)
- self._closed = False
- self._pos = 0
-
- def read(self) -> int:
- if self._closed or self._native_fd < 0:
- return -1
- try:
- data = os.read(self._native_fd, 1)
- if not data:
- return -1
- self._pos += 1
- return data[0]
- except Exception:
- return -1
-
- def readBytes(self, b: bytearray, off: int, len_: int) -> int:
- if self._closed or self._native_fd < 0:
- return -1
- try:
- data = os.read(self._native_fd, len_)
- if not data:
- return -1
- actual = len(data)
- b[off:off + actual] = data
- self._pos += actual
- return actual
- except Exception:
- return -1
-
- def available(self) -> int:
- return 0
-
- def skip(self, n: int) -> int:
- if self._closed or self._native_fd < 0:
- return 0
- try:
- os.lseek(self._native_fd, n, os.SEEK_CUR)
- self._pos += n
- return n
- except Exception:
- return 0
-
- def close(self):
- if not self._closed:
- self._closed = True
- if self._native_fd >= 0:
- try:
- os.close(self._native_fd)
- except Exception:
- pass
- self._fd.close()
-
- def getFD(self) -> Optional[FileDescriptor]:
- return self._fd if self._fd.valid() else None
-
- def getChannel(self) -> "FileChannel":
- return FileChannel(fd=self._native_fd, mode="r")
-
- def isClosed(self) -> bool:
- return self._closed
-
- def toString(self) -> str:
- return f"FileInputStream(fd={self._native_fd})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileOutputStream (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class FileOutputStream(Stub):
- """FileOutputStream — 文件输出流 (完整版)"""
-
- def __init__(self, file: Any, append: bool = False):
- super().__init__()
- flags = os.O_WRONLY | os.O_CREAT
- if append:
- flags |= os.O_APPEND
- else:
- flags |= os.O_TRUNC
-
- if isinstance(file, int):
- self._fd = FileDescriptor()
- self._fd.setInt(file)
- self._native_fd = file
- elif isinstance(file, FileDescriptor):
- self._fd = file
- self._native_fd = file.getInt()
- elif isinstance(file, str):
- self._fd = FileDescriptor()
- self._native_fd = os.open(file, flags, 0o644)
- self._fd.setInt(self._native_fd)
- else:
- path = str(file) if hasattr(file, 'getPath') else str(file)
- self._fd = FileDescriptor()
- self._native_fd = os.open(path, flags, 0o644)
- self._fd.setInt(self._native_fd)
- self._closed = False
- self._append_mode = append
-
- def write(self, b: Union[int, bytes, bytearray]):
- if self._closed or self._native_fd < 0:
- return
- if isinstance(b, int):
- os.write(self._native_fd, bytes([b]))
- else:
- os.write(self._native_fd, bytes(b))
-
- def writeBytes(self, b: bytes, off: int, len_: int):
- if self._closed or self._native_fd < 0:
- return
- os.write(self._native_fd, b[off:off + len_])
-
- def flush(self):
- pass
-
- def close(self):
- if not self._closed:
- self._closed = True
- if self._native_fd >= 0:
- try:
- os.close(self._native_fd)
- except Exception:
- pass
- self._fd.close()
-
- def getFD(self) -> Optional[FileDescriptor]:
- return self._fd if self._fd.valid() else None
-
- def getChannel(self) -> "FileChannel":
- return FileChannel(fd=self._native_fd, mode="rw")
-
- def isClosed(self) -> bool:
- return self._closed
-
- def toString(self) -> str:
- return f"FileOutputStream(fd={self._native_fd})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# RandomAccessFile
-# ═══════════════════════════════════════════════════════════════
-
-class RandomAccessFile(Stub):
- """RandomAccessFile — 随机访问文件"""
-
- def __init__(self, file: Any, mode: str = "r"):
- super().__init__()
- self._mode = mode
- if isinstance(file, str):
- self._path = file
- elif hasattr(file, 'getPath'):
- self._path = file.getPath()
- else:
- self._path = str(file)
-
- if "r" in mode and "w" in mode:
- flags = os.O_RDWR | os.O_CREAT
- elif "w" in mode:
- flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
- elif "rws" in mode:
- flags = os.O_RDWR | os.O_SYNC
- elif "rwd" in mode:
- flags = os.O_RDWR | os.O_DSYNC
- else:
- flags = os.O_RDONLY
-
- self._fd = os.open(self._path, flags, 0o644)
- self._file_descriptor = FileDescriptor()
- self._file_descriptor.setInt(self._fd)
- self._closed = False
-
- def read(self) -> int:
- if self._closed:
- return -1
- try:
- data = os.read(self._fd, 1)
- return data[0] if data else -1
- except Exception:
- return -1
-
- def readBytes(self, b: bytearray, off: int, len_: int) -> int:
- if self._closed:
- return -1
- try:
- data = os.read(self._fd, len_)
- if not data:
- return -1
- b[off:off + len(data)] = data
- return len(data)
- except Exception:
- return -1
-
- def write(self, b: Union[int, bytes, bytearray]):
- if self._closed:
- return
- if isinstance(b, int):
- os.write(self._fd, bytes([b]))
- else:
- os.write(self._fd, bytes(b))
-
- def writeBytes(self, b: bytes, off: int, len_: int):
- if not self._closed:
- os.write(self._fd, b[off:off + len_])
-
- def getFilePointer(self) -> int:
- return os.lseek(self._fd, 0, os.SEEK_CUR)
-
- def seek(self, pos: int):
- os.lseek(self._fd, pos, os.SEEK_SET)
-
- def length(self) -> int:
- return os.lseek(self._fd, 0, os.SEEK_END)
-
- def setLength(self, newLength: int):
- os.truncate(self._fd, newLength)
-
- def skipBytes(self, n: int) -> int:
- try:
- current = os.lseek(self._fd, 0, os.SEEK_CUR)
- file_size = os.lseek(self._fd, 0, os.SEEK_END)
- os.lseek(self._fd, current, os.SEEK_SET)
- actual = min(n, file_size - current)
- os.lseek(self._fd, actual, os.SEEK_CUR)
- return max(0, actual)
- except Exception:
- return 0
-
- def close(self):
- if not self._closed:
- self._closed = True
- try:
- os.close(self._fd)
- except Exception:
- pass
-
- def getFD(self) -> FileDescriptor:
- return self._file_descriptor
-
- def getChannel(self) -> "FileChannel":
- return FileChannel(fd=self._fd, mode=self._mode)
-
- def readLine(self) -> Optional[str]:
- if self._closed:
- return None
- result = []
- while True:
- try:
- b = os.read(self._fd, 1)
- if not b:
- break
- c = b[0]
- if c == ord('\n'):
- break
- if c == ord('\r'):
- b2 = os.read(self._fd, 1)
- if b2 and b2[0] != ord('\n'):
- os.lseek(self._fd, -1, os.SEEK_CUR)
- break
- result.append(chr(c))
- except Exception:
- break
- return "".join(result) if result else None
-
- def toString(self) -> str:
- return f"RandomAccessFile(path={self._path}, mode={self._mode})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileLock
-# ═══════════════════════════════════════════════════════════════
-
-class FileLock(Stub):
- """FileLock — 文件锁"""
-
- def __init__(self, channel: "FileChannel", position: int = 0,
- size: int = 0, shared: bool = False):
- super().__init__()
- self._channel = channel
- self._position = position
- self._size = size
- self._shared = shared
- self._valid = True
-
- def position(self) -> int:
- return self._position
-
- def size(self) -> int:
- return self._size
-
- def isShared(self) -> bool:
- return self._shared
-
- def isValid(self) -> bool:
- return self._valid
-
- def release(self):
- self._valid = False
-
- def close(self):
- self.release()
-
- def channel(self) -> "FileChannel":
- return self._channel
-
- def toString(self) -> str:
- return f"FileLock(pos={self._position}, shared={self._shared})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileChannel (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class FileChannel(Stub):
- """FileChannel — 文件通道 (完整版)"""
-
- def __init__(self, fd: int = -1, mode: str = "r",
- path: str = ""):
- super().__init__()
- self._fd = fd
- self._mode = mode
- self._path = path
- self._open = fd >= 0
- self._position = 0
-
- def read(self, dst: bytearray, offset: int = 0, length: int = 0) -> int:
- if not self._open:
- return -1
- if length <= 0:
- length = len(dst) - offset
- try:
- data = os.read(self._fd, length)
- if not data:
- return -1
- dst[offset:offset + len(data)] = data
- self._position += len(data)
- return len(data)
- except Exception:
- return -1
-
- def write(self, src: Union[bytes, bytearray], offset: int = 0, length: int = 0) -> int:
- if not self._open:
- return 0
- if length <= 0:
- data = bytes(src)
- else:
- data = bytes(src[offset:offset + length])
- try:
- written = os.write(self._fd, data)
- self._position += written
- return written
- except Exception:
- return 0
-
- def position(self) -> int:
- return self._position
-
- def setPosition(self, newPosition: int) -> "FileChannel":
- if self._open:
- os.lseek(self._fd, newPosition, os.SEEK_SET)
- self._position = newPosition
- return self
-
- def size(self) -> int:
- if not self._open:
- return 0
- current = os.lseek(self._fd, 0, os.SEEK_CUR)
- size_ = os.lseek(self._fd, 0, os.SEEK_END)
- os.lseek(self._fd, current, os.SEEK_SET)
- return size_
-
- def truncate(self, newSize: int) -> "FileChannel":
- if self._open:
- os.truncate(self._fd, newSize)
- return self
-
- def force(self, metaData: bool):
- if self._open:
- os.fsync(self._fd)
-
- def close(self):
- if self._open:
- self._open = False
- try:
- os.close(self._fd)
- except Exception:
- pass
-
- def isOpen(self) -> bool:
- return self._open
-
- def lock(self, position: int = 0, size: int = 0, shared: bool = False) -> FileLock:
- return FileLock(channel=self, position=position, size=size, shared=shared)
-
- def tryLock(self, position: int = 0, size: int = 0, shared: bool = False) -> Optional[FileLock]:
- return FileLock(channel=self, position=position, size=size, shared=shared)
-
- def transferTo(self, position: int, count: int, target: "FileChannel") -> int:
- return 0
-
- def transferFrom(self, src: "FileChannel", position: int, count: int) -> int:
- return 0
-
- def map(self, mode: int, position: int, size: int) -> Any:
- return None
-
- def toString(self) -> str:
- return f"FileChannel(fd={self._fd}, open={self._open})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FilePermission (扩展)
-# ═══════════════════════════════════════════════════════════════
-
-class FilePermission(Stub):
- """FilePermission — 文件权限"""
-
- def __init__(self, path: str = "", actions: str = ""):
- super().__init__()
- self._path = path
- self._actions = actions
- self._action_set: Set[str] = set(actions.split(",")) if actions else set()
-
- def getPath(self) -> str:
- return self._path
-
- def getActions(self) -> str:
- return self._actions
-
- def implies(self, permission: "FilePermission") -> bool:
- return self._action_set.issuperset(permission._action_set)
-
- def impliesByPath(self, path: str) -> bool:
- return self._path == path
-
- def toString(self) -> str:
- return f'FilePermission("{self._path}", "{self._actions}")'
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, FilePermission):
- return False
- return self._path == other._path and self._actions == other._actions
-
- def hashCode(self) -> int:
- return hash((self._path, self._actions)) & 0x7FFFFFFF
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileFilter / FileNameFilter
-# ═══════════════════════════════════════════════════════════════
-
-class FileFilter(Stub):
- """FileFilter — 文件过滤器"""
-
- def accept(self, pathname: Any) -> bool:
- return True
-
- def toString(self) -> str:
- return f"FileFilter@{hex(id(self))}"
-
-
-class FileNameFilter(Stub):
- """FileNameFilter — 文件名过滤器"""
-
- def accept(self, dir_: Any, name: str) -> bool:
- return True
-
- def toString(self) -> str:
- return f"FileNameFilter@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileVisitOption / FileVisitResult / FileVisitor / SimpleFileVisitor
-# ═══════════════════════════════════════════════════════════════
-
-class FileVisitOption(Stub):
- """FileVisitOption — 文件访问选项"""
- FOLLOW_LINKS = 0
-
- def __init__(self, value: int = FOLLOW_LINKS):
- super().__init__()
- self._value = value
-
- def getValue(self) -> int:
- return self._value
-
-
-class FileVisitResult(Stub):
- """FileVisitResult — 文件访问结果"""
- CONTINUE = 0
- TERMINATE = 1
- SKIP_SUBTREE = 2
- SKIP_SIBLINGS = 3
-
- def __init__(self, value: int = CONTINUE):
- super().__init__()
- self._value = value
-
- def getValue(self) -> int:
- return self._value
-
-
-class FileVisitor(Stub):
- """FileVisitor — 文件访问器接口"""
-
- def preVisitDirectory(self, dir_: Any, attrs: Any) -> FileVisitResult:
- return FileVisitResult(FileVisitResult.CONTINUE)
-
- def visitFile(self, file_: Any, attrs: Any) -> FileVisitResult:
- return FileVisitResult(FileVisitResult.CONTINUE)
-
- def visitFileFailed(self, file_: Any, exc: Exception) -> FileVisitResult:
- return FileVisitResult(FileVisitResult.CONTINUE)
-
- def postVisitDirectory(self, dir_: Any, exc: Optional[Exception]) -> FileVisitResult:
- return FileVisitResult(FileVisitResult.CONTINUE)
-
- def toString(self) -> str:
- return f"FileVisitor@{hex(id(self))}"
-
-
-class SimpleFileVisitor(FileVisitor):
- """SimpleFileVisitor — 简单文件访问器"""
-
- def preVisitDirectory(self, dir_: Any, attrs: Any) -> FileVisitResult:
- return FileVisitResult(FileVisitResult.CONTINUE)
-
- def visitFile(self, file_: Any, attrs: Any) -> FileVisitResult:
- return FileVisitResult(FileVisitResult.CONTINUE)
-
- def visitFileFailed(self, file_: Any, exc: Exception) -> FileVisitResult:
- return FileVisitResult(FileVisitResult.CONTINUE)
-
- def postVisitDirectory(self, dir_: Any, exc: Optional[Exception]) -> FileVisitResult:
- return FileVisitResult(FileVisitResult.CONTINUE)
-
- def toString(self) -> str:
- return f"SimpleFileVisitor@{hex(id(self))}"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileTreeWalker / FileTypeDetector / FileSystemProvider
-# ═══════════════════════════════════════════════════════════════
-
-class FileTreeWalker(Stub):
- """FileTreeWalker — 文件树遍历器"""
-
- def __init__(self, visitor: Optional[FileVisitor] = None,
- options: List[FileVisitOption] = None,
- maxDepth: int = WALK_MAX_DEPTH_UNLIMITED):
- super().__init__()
- self._visitor = visitor or SimpleFileVisitor()
- self._options = options or []
- self._max_depth = maxDepth
-
- def walk(self, start: Any):
- self._walk_recursive(str(start), 0)
-
- def _walk_recursive(self, path: str, depth: int):
- if self._max_depth >= 0 and depth > self._max_depth:
- return
- if not os.path.exists(path):
- return
- if os.path.isdir(path):
- result = self._visitor.preVisitDirectory(path, None)
- if result.getValue() == FileVisitResult.TERMINATE:
- return
- if result.getValue() != FileVisitResult.SKIP_SUBTREE:
- try:
- for entry in sorted(os.listdir(path)):
- child = os.path.join(path, entry)
- self._walk_recursive(child, depth + 1)
- except Exception as e:
- self._visitor.visitFileFailed(path, e)
- self._visitor.postVisitDirectory(path, None)
- else:
- try:
- self._visitor.visitFile(path, None)
- except Exception as e:
- self._visitor.visitFileFailed(path, e)
-
- def toString(self) -> str:
- return f"FileTreeWalker(maxDepth={self._max_depth})"
-
-
-class FileTypeDetector(Stub):
- """FileTypeDetector — 文件类型检测器"""
-
- def probeContentType(self, path: Any) -> Optional[str]:
- return None
-
- def toString(self) -> str:
- return f"FileTypeDetector@{hex(id(self))}"
-
-
-class FileSystemProvider(Stub):
- """FileSystemProvider — 文件系统提供器"""
-
- SCHEME_FILE = "file"
-
- def __init__(self, scheme: str = SCHEME_FILE):
- super().__init__()
- self._scheme = scheme
-
- def getScheme(self) -> str:
- return self._scheme
-
- def newFileSystem(self, uri: Any, env: Dict[str, Any] = None) -> Any:
- return None
-
- def getFileSystem(self, uri: Any) -> Any:
- return None
-
- def getPath(self, uri: Any) -> str:
- return str(uri)
-
- def newFileChannel(self, path: Any, options: Set[str] = None,
- attrs: List[Any] = None) -> Optional[FileChannel]:
- return None
-
- def newInputStream(self, path: Any, options: Set[str] = None) -> Optional[FileInputStream]:
- return None
-
- def newOutputStream(self, path: Any, options: Set[str] = None) -> Optional[FileOutputStream]:
- return None
-
- def toString(self) -> str:
- return f"FileSystemProvider(scheme={self._scheme})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileStore / FileStoreAttributeView / FileAttribute / FileAttributeView
-# ═══════════════════════════════════════════════════════════════
-
-class FileAttribute(Stub):
- """FileAttribute — 文件属性"""
-
- def __init__(self, name: str = "", value: Any = None):
- super().__init__()
- self._name = name
- self._value = value
-
- def name(self) -> str:
- return self._name
-
- def value(self) -> Any:
- return self._value
-
- def toString(self) -> str:
- return f"FileAttribute(name={self._name})"
-
-
-class FileAttributeView(Stub):
- """FileAttributeView — 文件属性视图基类"""
-
- def name(self) -> str:
- return "basic"
-
- def toString(self) -> str:
- return f"FileAttributeView(name={self.name()})"
-
-
-class FileStoreAttributeView(Stub):
- """FileStoreAttributeView — 文件存储属性视图基类"""
-
- def name(self) -> str:
- return "basic"
-
- def toString(self) -> str:
- return f"FileStoreAttributeView(name={self.name()})"
-
-
-class FileStore(Stub):
- """FileStore — 文件存储"""
-
- def __init__(self, path: str = "/",
- type_: str = "ext4",
- isReadOnly: bool = False):
- super().__init__()
- self._path = path
- self._type = type_
- self._is_read_only = isReadOnly
-
- def name(self) -> str:
- return self._path
-
- def type(self) -> str:
- return self._type
-
- def isReadOnly(self) -> bool:
- return self._is_read_only
-
- def getTotalSpace(self) -> int:
- try:
- st = os.statvfs(self._path)
- return st.f_frsize * st.f_blocks
- except Exception:
- return 0
-
- def getUsableSpace(self) -> int:
- try:
- st = os.statvfs(self._path)
- return st.f_frsize * st.f_bavail
- except Exception:
- return 0
-
- def getUnallocatedSpace(self) -> int:
- try:
- st = os.statvfs(self._path)
- return st.f_frsize * st.f_bfree
- except Exception:
- return 0
-
- def getFileStoreAttributeView(self, viewType: Any) -> Optional[FileStoreAttributeView]:
- return None
-
- def supportsFileAttributeView(self, viewType: Any) -> bool:
- return True
-
- def toString(self) -> str:
- return f"FileStore(path={self._path}, type={self._type})"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileSystem (扩展) / UnixFileSystem / WinNTFileSystem
-# ═══════════════════════════════════════════════════════════════
-
-class FileSystem(Stub):
- """FileSystem — 文件系统 (扩展版)"""
-
- def __init__(self):
- super().__init__()
- self._separator = os.sep
- self._path_separator = os.pathsep
- self._normalized_separator = "/" if os.sep == "/" else "\\"
-
- def getSeparator(self) -> str:
- return self._separator
-
- def getPathSeparator(self) -> str:
- return self._path_separator
-
- def normalize(self, path: str) -> str:
- return os.path.normpath(path)
-
- def resolve(self, parent: str, child: str) -> str:
- return os.path.join(parent, child)
-
- def getLength(self, path: str) -> int:
- try:
- return os.path.getsize(path)
- except Exception:
- return 0
-
- def getLastModifiedTime(self, path: str) -> int:
- try:
- return int(os.path.getmtime(path) * 1000)
- except Exception:
- return 0
-
- def getLastAccessTime(self, path: str) -> int:
- try:
- st = os.stat(path)
- return int(st.st_atime * 1000)
- except Exception:
- return 0
-
- def getCreationTime(self, path: str) -> int:
- try:
- st = os.stat(path)
- if hasattr(st, 'st_birthtime'):
- return int(st.st_birthtime * 1000)
- return int(st.st_ctime * 1000)
- except Exception:
- return 0
-
- def isDirectory(self, path: str) -> bool:
- return os.path.isdir(path)
-
- def isFile(self, path: str) -> bool:
- return os.path.isfile(path)
-
- def exists(self, path: str) -> bool:
- return os.path.exists(path)
-
- def canRead(self, path: str) -> bool:
- return os.access(path, os.R_OK)
-
- def canWrite(self, path: str) -> bool:
- return os.access(path, os.W_OK)
-
- def canExecute(self, path: str) -> bool:
- return os.access(path, os.X_OK)
-
- def isAbsolute(self, path: str) -> bool:
- return os.path.isabs(path)
-
- def list(self, path: str) -> List[str]:
- try:
- return os.listdir(path)
- except Exception:
- return []
-
- def mkdir(self, path: str) -> bool:
- try:
- os.mkdir(path)
- return True
- except Exception:
- return False
-
- def mkdirs(self, path: str) -> bool:
- try:
- os.makedirs(path, exist_ok=True)
- return True
- except Exception:
- return False
-
- def rename(self, src: str, dst: str) -> bool:
- try:
- os.rename(src, dst)
- return True
- except Exception:
- return False
-
- def delete(self, path: str) -> bool:
- try:
- if os.path.isdir(path):
- os.rmdir(path)
- else:
- os.unlink(path)
- return True
- except Exception:
- return False
-
- def getStatus(self, path: str) -> Optional[FileStatus]:
- try:
- st = os.stat(path)
- return FileStatus(
- type_=FILE_TYPE_DIRECTORY if stat.S_ISDIR(st.st_mode)
- else FILE_TYPE_REGULAR if stat.S_ISREG(st.st_mode)
- else FILE_TYPE_SYMBOLIC_LINK if stat.S_ISLNK(st.st_mode)
- else FILE_TYPE_UNKNOWN,
- size=st.st_size,
- lastModified=int(st.st_mtime * 1000),
- lastAccess=int(st.st_atime * 1000),
- creationTime=int(st.st_ctime * 1000),
- isSymbolicLink=os.path.islink(path),
- device=st.st_dev,
- inode=st.st_ino,
- mode=st.st_mode,
- uid=st.st_uid,
- gid=st.st_gid,
- )
- except Exception:
- return None
-
- def getSpace(self, path: str) -> Tuple[int, int, int]:
- try:
- st = os.statvfs(path)
- total = st.f_frsize * st.f_blocks
- free = st.f_frsize * st.f_bfree
- available = st.f_frsize * st.f_bavail
- return (total, free, available)
- except Exception:
- return (0, 0, 0)
-
- def toString(self) -> str:
- return f"FileSystem(sep={self._separator})"
-
- def equals(self, other: Any) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return id(self) & 0x7FFFFFFF
-
-
-class UnixFileSystem(FileSystem):
- """UnixFileSystem — Unix 文件系统"""
-
- def __init__(self):
- super().__init__()
- self._separator = "/"
- self._path_separator = ":"
-
- def normalize(self, path: str) -> str:
- return os.path.normpath(path)
-
- def resolve(self, parent: str, child: str) -> str:
- if not parent:
- return child
- if not child:
- return parent
- return f"{parent.rstrip('/')}/{child.lstrip('/')}"
-
- def toString(self) -> str:
- return "UnixFileSystem"
-
-
-class WinNTFileSystem(FileSystem):
- """WinNTFileSystem — Windows NT 文件系统"""
-
- def __init__(self):
- super().__init__()
- self._separator = "\\"
- self._path_separator = ";"
- self._normalized_separator = "\\"
-
- def normalize(self, path: str) -> str:
- return path.replace("/", "\\")
-
- def resolve(self, parent: str, child: str) -> str:
- if not parent:
- return child
- if not child:
- return parent
- sep = "\\"
- parent_clean = parent.rstrip(sep)
- child_clean = child.lstrip(sep)
- return f"{parent_clean}{sep}{child_clean}"
-
- def toString(self) -> str:
- return "WinNTFileSystem"
-
-
-# ═══════════════════════════════════════════════════════════════
-# UserPrincipal / GroupPrincipal / UserPrincipalLookupService
-# ═══════════════════════════════════════════════════════════════
-
-class UserPrincipal(Stub):
- """UserPrincipal — 用户主体"""
-
- def __init__(self, name: str = ""):
- super().__init__()
- self._name = name
-
- def getName(self) -> str:
- return self._name
-
- def toString(self) -> str:
- return self._name
-
- def equals(self, other: Any) -> bool:
- if not isinstance(other, UserPrincipal):
- return False
- return self._name == other._name
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
-
-class GroupPrincipal(UserPrincipal):
- """GroupPrincipal — 组主体"""
-
- def __init__(self, name: str = ""):
- super().__init__(name=name)
-
- def toString(self) -> str:
- return f"Group({self._name})"
-
-
-class UserPrincipalLookupService(Stub):
- """UserPrincipalLookupService — 用户主体查找服务"""
-
- def lookupPrincipalByName(self, name: str) -> UserPrincipal:
- return UserPrincipal(name=name)
-
- def lookupPrincipalByGroupName(self, name: str) -> GroupPrincipal:
- return GroupPrincipal(name=name)
-
- def toString(self) -> str:
- return "UserPrincipalLookupService"
-
-
-# ═══════════════════════════════════════════════════════════════
-# FileSystems (工厂)
-# ═══════════════════════════════════════════════════════════════
-
-class FileSystems(Stub):
- """FileSystems — 文件系统工厂"""
-
- _default: Optional[FileSystem] = None
- _unix_default: Optional[UnixFileSystem] = None
-
- @staticmethod
- def getDefault() -> FileSystem:
- if sys.platform == "win32":
- if FileSystems._default is None:
- FileSystems._default = WinNTFileSystem()
- return FileSystems._default
- else:
- if FileSystems._unix_default is None:
- FileSystems._unix_default = UnixFileSystem()
- return FileSystems._unix_default
-
- @staticmethod
- def newFileSystem(uri: Any, env: Dict[str, Any] = None) -> Any:
- return None
-
- @staticmethod
- def newFileSystemFromPath(path: Any, loader: Any = None) -> Any:
- return None
-
- def toString(self) -> str:
- return "FileSystems"
\ No newline at end of file
diff --git a/android_pyapi/java/lang.py b/android_pyapi/java/lang.py
deleted file mode 100644
index d296fe2..0000000
--- a/android_pyapi/java/lang.py
+++ /dev/null
@@ -1,2128 +0,0 @@
-"""
-Java lang standard library APIs implemented in Python.
-java.lang package - String, Integer, Math, Thread, System, Object, etc.
-"""
-
-from .._core import Stub, AndroidOnlyError
-import re as _re
-import math as _py_math
-import sys as _sys
-import os as _os
-import platform
-import time as _time
-import threading as _threading
-import inspect as _inspect
-import math
-import random
-import time
-from datetime import datetime as _datetime
-
-__all__ = [
- "Object", "Throwable", "Exception", "RuntimeException", "Error",
- "NullPointerException", "IllegalArgumentException", "IllegalStateException",
- "IndexOutOfBoundsException", "ArrayIndexOutOfBoundsException",
- "StringIndexOutOfBoundsException", "ClassCastException",
- "UnsupportedOperationException", "ArithmeticException",
- "NumberFormatException", "SecurityException",
- "ConcurrentModificationException", "NegativeArraySizeException",
- "NoSuchFieldException", "NoSuchMethodException", "InterruptedException",
- "CloneNotSupportedException", "IllegalMonitorStateException",
- "IllegalThreadStateException", "EnumConstantNotPresentException",
- "TypeNotPresentException",
- "ClassNotFoundException", "IllegalAccessException", "InstantiationException",
- "InvocationTargetException", "NoSuchElementException",
- "AssertionError", "OutOfMemoryError", "StackOverflowError",
- "NoClassDefFoundError", "UnsatisfiedLinkError", "LinkageError",
- "VerifyError", "AbstractMethodError", "IncompatibleClassChangeError",
- "ExceptionInInitializerError",
- "String", "Integer", "Long", "Short", "Byte", "Float", "Double",
- "Boolean", "Character", "Math", "StrictMath", "System",
- "Thread", "ThreadLocal", "StringBuilder", "StringBuffer",
- "Class", "Void", "VoidType",
- "Stub", "Comparable", "CharSequence", "Iterable", "Appendable",
- "Readable", "AutoCloseable", "Cloneable", "Runnable",
- "StackTraceElement", "Number", "SuppressWarnings", "Deprecated",
- "Override", "FunctionalInterface",
-]
-
-
-# ============================================================
-# Interfaces
-# ============================================================
-
-class Comparable(Stub):
- def compareTo(self, other):
- raise NotImplementedError
-
-class Iterable(Stub):
- def iterator(self):
- raise NotImplementedError
-
-class AutoCloseable(Stub):
- def close(self):
- raise NotImplementedError
-
-class Cloneable(Stub):
- def clone(self):
- return self.__class__()
-
-class CharSequence(Stub):
- def length(self):
- raise NotImplementedError
- def charAt(self, index):
- raise NotImplementedError
- def subSequence(self, start, end):
- raise NotImplementedError
- def toString(self):
- raise NotImplementedError
-
-class Appendable(Stub):
- def append(self, c):
- raise NotImplementedError
-
-class Readable(Stub):
- def read(self, cb):
- raise NotImplementedError
-
-class Runnable(Stub):
- def run(self):
- pass
-
-
-# ============================================================
-# Throwable hierarchy
-# ============================================================
-
-class Throwable(Exception, Stub):
- def __init__(self, message=None, cause=None):
- super().__init__(message or "")
- self._detail_message = str(message) if message else None
- self._cause = cause
- self._stack_trace = []
- self._suppressed = []
- self._fill_in_stack()
-
- def _fill_in_stack(self):
- import traceback
- stack = traceback.extract_stack()
- self._stack_trace = [
- StackTraceElement(
- frame.filename, frame.name, frame.filename, frame.lineno, False
- )
- for frame in stack[:-1]
- ]
-
- def getMessage(self):
- return self._detail_message
-
- def getLocalizedMessage(self):
- return self._detail_message
-
- def getCause(self):
- return self._cause
-
- def initCause(self, cause):
- self._cause = cause
- return self
-
- def toString(self):
- msg = self._detail_message or ""
- return f"{self.__class__.__name__}: {msg}" if msg else self.__class__.__name__
-
- def printStackTrace(self, file=None):
- import traceback
- if file is None:
- file = _sys.stderr
- traceback.print_exc(file=file)
-
- def fillInStackTrace(self):
- self._fill_in_stack()
- return self
-
- def getStackTrace(self):
- return self._stack_trace
-
- def setStackTrace(self, stack_trace):
- self._stack_trace = stack_trace
-
- def addSuppressed(self, exception):
- self._suppressed.append(exception)
-
- def getSuppressed(self):
- return self._suppressed
-
- def __str__(self):
- return self.toString()
-
-
-class Exception(Throwable):
- pass
-
-class RuntimeException(Exception):
- pass
-
-class Error(Throwable):
- pass
-
-
-class NullPointerException(RuntimeException):
- pass
-
-class IllegalArgumentException(RuntimeException):
- pass
-
-class IllegalStateException(RuntimeException):
- pass
-
-class IndexOutOfBoundsException(RuntimeException):
- pass
-
-class ArrayIndexOutOfBoundsException(IndexOutOfBoundsException):
- pass
-
-class StringIndexOutOfBoundsException(IndexOutOfBoundsException):
- pass
-
-class ClassCastException(RuntimeException):
- pass
-
-class UnsupportedOperationException(RuntimeException):
- pass
-
-class ArithmeticException(RuntimeException):
- pass
-
-class NumberFormatException(IllegalArgumentException):
- pass
-
-class SecurityException(RuntimeException):
- pass
-
-class ConcurrentModificationException(RuntimeException):
- pass
-
-class NegativeArraySizeException(RuntimeException):
- pass
-
-class NoSuchFieldException(Exception):
- pass
-
-class NoSuchMethodException(Exception):
- pass
-
-class InterruptedException(Exception):
- pass
-
-class CloneNotSupportedException(Exception):
- pass
-
-class IllegalMonitorStateException(RuntimeException):
- pass
-
-class IllegalThreadStateException(IllegalArgumentException):
- pass
-
-class EnumConstantNotPresentException(RuntimeException):
- def __init__(self, e, constant):
- super().__init__(f"{e}.{constant}")
- self.enumType = e
- self.constantName = constant
-
-class TypeNotPresentException(RuntimeException):
- def __init__(self, typeName, cause=None):
- super().__init__(f"Type {typeName} not present", cause)
- self.typeName = typeName
-
-
-# ===== 缺失的 Exception 子类 =====
-class ClassNotFoundException(Exception):
- def __init__(self, message="", cause=None):
- super().__init__(message, cause)
- self.ex = message
-
-class IllegalAccessException(Exception):
- def __init__(self, message=""):
- super().__init__(message)
-
-class InstantiationException(Exception):
- def __init__(self, message=""):
- super().__init__(message)
-
-class InvocationTargetException(Exception):
- def __init__(self, target=None, cause=None):
- if target is not None and cause is None:
- super().__init__(str(target))
- self.target = target
- else:
- super().__init__(str(target) if target else "", cause)
- self.target = target
-
-class NoSuchElementException(RuntimeException):
- def __init__(self, message=""):
- super().__init__(message)
-
-# ===== 缺失的 Error 类 =====
-class AssertionError(Error):
- def __init__(self, message=None):
- if message is None:
- super().__init__("Assertion failed")
- else:
- super().__init__(str(message))
-
-class OutOfMemoryError(Error):
- def __init__(self, message=""):
- super().__init__(message)
-
-class StackOverflowError(Error):
- def __init__(self, message=""):
- super().__init__(message)
-
-class NoClassDefFoundError(Error):
- def __init__(self, message=""):
- super().__init__(message)
-
-class UnsatisfiedLinkError(Error):
- def __init__(self, message=""):
- super().__init__(message)
-
-class LinkageError(Error):
- def __init__(self, message=""):
- super().__init__(message)
-
-class VerifyError(LinkageError):
- def __init__(self, message=""):
- super().__init__(message)
-
-class AbstractMethodError(LinkageError):
- def __init__(self, message=""):
- super().__init__(message)
-
-class IncompatibleClassChangeError(LinkageError):
- def __init__(self, message=""):
- super().__init__(message)
-
-class ExceptionInInitializerError(LinkageError):
- def __init__(self, message="", cause=None):
- super().__init__(message)
- self._cause = cause
- self.exception = cause
-
-
-# ============================================================
-# StackTraceElement
-# ============================================================
-
-class StackTraceElement(Stub):
- def __init__(self, declaring_class, method_name, file_name, line_number, native_method):
- super().__init__()
- self._class = declaring_class
- self._method = method_name
- self._file = file_name
- self._line = line_number
- self._native = native_method
-
- def getClassName(self):
- return self._class
-
- def getMethodName(self):
- return self._method
-
- def getFileName(self):
- return self._file
-
- def getLineNumber(self):
- return self._line
-
- def isNativeMethod(self):
- return self._native
-
- def toString(self):
- return f"{self._class}.{self._method}({self._file}:{self._line})"
-
-
-# ============================================================
-# Object
-# ============================================================
-
-class Object(Stub):
- def __init__(self):
- super().__init__()
-
- def getClass(self):
- return self.__class__
-
- def hashCode(self):
- return hash(self) & 0x7FFFFFFF
-
- def equals(self, other):
- return self is other
-
- def toString(self):
- return f"{self.__class__.__name__}@{hex(id(self))}"
-
- def notify(self):
- pass
-
- def notifyAll(self):
- pass
-
- def wait(self, timeout=None):
- pass
-
- def clone(self):
- return self.__class__()
-
- def finalize(self):
- pass
-
-
-# ============================================================
-# String
-# ============================================================
-
-class String(CharSequence):
- def __init__(self, value=None):
- super().__init__()
- if value is None:
- self._str = ""
- elif isinstance(value, bytes):
- self._str = value.decode("utf-8", errors="replace")
- else:
- self._str = str(value)
-
- def charAt(self, index):
- return self._str[index]
-
- def codePointAt(self, index):
- return ord(self._str[index])
-
- def codePointBefore(self, index):
- return ord(self._str[index - 1]) if index > 0 else -1
-
- def codePointCount(self, beginIndex, endIndex):
- return endIndex - beginIndex
-
- def compareTo(self, other):
- if isinstance(other, String):
- return (self._str > other._str) - (self._str < other._str)
- return -1
-
- def compareToIgnoreCase(self, other):
- if isinstance(other, String):
- return (self._str.lower() > other._str.lower()) - (self._str.lower() < other._str.lower())
- return -1
-
- def concat(self, s):
- return String(self._str + str(s))
-
- def contains(self, s):
- return str(s) in self._str
-
- def contentEquals(self, cs):
- return self._str == str(cs)
-
- def endsWith(self, suffix):
- return self._str.endswith(suffix)
-
- def equals(self, other):
- if isinstance(other, String):
- return self._str == other._str
- return False
-
- def equalsIgnoreCase(self, other):
- if isinstance(other, String):
- return self._str.lower() == other._str.lower()
- return False
-
- def getBytes(self, charset="UTF-8"):
- return self._str.encode(charset, errors="replace")
-
- def hashCode(self) -> int:
- h = 0
- for i in range(len(self._str)):
- h = 31 * h + ord(self._str[i])
- return h & 0x7FFFFFFF
-
- def indexOf(self, ch, fromIndex=0):
- if isinstance(ch, int):
- ch = chr(ch)
- return self._str.index(str(ch), fromIndex) if str(ch) in self._str[fromIndex:] else -1
-
- def intern(self):
- return self
-
- def isEmpty(self):
- return len(self._str) == 0
-
- def lastIndexOf(self, ch, fromIndex=None):
- if isinstance(ch, int):
- ch = chr(ch)
- if fromIndex is None:
- fromIndex = len(self._str) - 1
- search_in = self._str[:fromIndex + 1]
- return search_in.rfind(str(ch)) if str(ch) in search_in else -1
-
- def length(self):
- return len(self._str)
-
- def matches(self, regex):
- return bool(_re.fullmatch(regex, self._str))
-
- def offsetByCodePoints(self, index, codePointOffset):
- return index + codePointOffset
-
- def regionMatches(self, ignoreCase, toffset, other, ooffset, length):
- if ignoreCase:
- return self._str[toffset:toffset+length].lower() == other._str[ooffset:ooffset+length].lower()
- return self._str[toffset:toffset+length] == other._str[ooffset:ooffset+length]
-
- def replace(self, oldChar, newChar):
- if isinstance(oldChar, int):
- oldChar = chr(oldChar)
- if isinstance(newChar, int):
- newChar = chr(newChar)
- return String(self._str.replace(oldChar, newChar))
-
- def replaceAll(self, regex, replacement):
- return String(_re.sub(regex, replacement, self._str))
-
- def replaceFirst(self, regex, replacement):
- return String(_re.sub(regex, replacement, self._str, count=1))
-
- def split(self, regex, limit=0):
- if limit <= 0:
- parts = _re.split(regex, self._str)
- if limit == 0:
- while parts and parts[-1] == "":
- parts.pop()
- else:
- parts = _re.split(regex, self._str, maxsplit=limit - 1)
- while len(parts) < limit:
- parts.append("")
- return [String(p) for p in parts]
-
- def startsWith(self, prefix):
- return self._str.startswith(prefix)
-
- def substring(self, beginIndex, endIndex=None):
- if endIndex is None:
- return String(self._str[beginIndex:])
- return String(self._str[beginIndex:endIndex])
-
- def toCharArray(self):
- return list(self._str)
-
- def toLowerCase(self):
- return String(self._str.lower())
-
- def toUpperCase(self):
- return String(self._str.upper())
-
- def trim(self):
- return String(self._str.strip())
-
- def strip(self):
- return String(self._str.strip())
-
- def stripLeading(self):
- return String(self._str.lstrip())
-
- def stripTrailing(self):
- return String(self._str.rstrip())
-
- def isBlank(self):
- return self._str.strip() == ""
-
- def repeat(self, count):
- return String(self._str * count)
-
- def lines(self):
- from .util import ArrayList
- result = ArrayList()
- for line in self._str.splitlines():
- result.add(String(line))
- return result
-
- def subSequence(self, start, end):
- return self.substring(start, end)
-
- def getChars(self, srcBegin, srcEnd, dst, dstBegin):
- chars = self._str[srcBegin:srcEnd]
- for i, c in enumerate(chars):
- dst[dstBegin + i] = c
-
- def chars(self):
- return [ord(c) for c in self._str]
-
- def formatted(self, *args):
- return String(self._str.format(*args))
-
- def translateEscapes(self):
- result = []
- s = self._str
- i = 0
- n = len(s)
- while i < n:
- c = s[i]
- if c == '\\' and i + 1 < n:
- nxt = s[i + 1]
- if nxt == 'b':
- result.append('\b'); i += 2
- elif nxt == 't':
- result.append('\t'); i += 2
- elif nxt == 'n':
- result.append('\n'); i += 2
- elif nxt == 'f':
- result.append('\f'); i += 2
- elif nxt == 'r':
- result.append('\r'); i += 2
- elif nxt == 's':
- result.append(' '); i += 2
- elif nxt == '"':
- result.append('"'); i += 2
- elif nxt == "'":
- result.append("'"); i += 2
- elif nxt == '\\':
- result.append('\\'); i += 2
- elif nxt in '01234567':
- octal = nxt
- i += 2
- max_digits = 2 if nxt in '0123' else 1
- while len(octal) < max_digits + 1 and i < n and s[i] in '01234567':
- octal += s[i]
- i += 1
- result.append(chr(int(octal, 8)))
- elif nxt == '\n':
- i += 2
- elif nxt == '\r':
- i += 2
- if i < n and s[i] == '\n':
- i += 1
- else:
- result.append(nxt); i += 2
- else:
- result.append(c); i += 1
- return String(''.join(result))
-
- @staticmethod
- def valueOf(obj):
- return String(str(obj))
-
- @staticmethod
- def copyValueOf(data, offset=0, count=None):
- if count is None:
- return String("".join(data))
- return String("".join(data[offset:offset+count]))
-
- @staticmethod
- def format(fmt, *args):
- return String(str(fmt) % args if args else str(fmt))
-
- @staticmethod
- def join(delimiter, *elements):
- if hasattr(elements[0], '__iter__') and not isinstance(elements[0], (str, bytes)):
- elements = elements[0]
- return String(str(delimiter).join(str(s) for s in elements))
-
- def toString(self):
- return self._str
-
- def __str__(self):
- return self._str
-
- def __repr__(self):
- return f"String({self._str!r})"
-
- def __len__(self):
- return len(self._str)
-
- def __getitem__(self, idx):
- return self._str[idx]
-
- def __add__(self, other):
- return String(self._str + str(other))
-
- def __eq__(self, other):
- if isinstance(other, String):
- return self._str == other._str
- return NotImplemented
-
-
-# ============================================================
-# Number
-# ============================================================
-
-class Number(Stub):
- def intValue(self):
- raise NotImplementedError
- def longValue(self):
- raise NotImplementedError
- def floatValue(self):
- raise NotImplementedError
- def doubleValue(self):
- raise NotImplementedError
- def byteValue(self):
- return self.intValue() & 0xFF
- def shortValue(self):
- return self.intValue() & 0xFFFF
-
-
-# ============================================================
-# Integer
-# ============================================================
-
-class Integer(Number, Comparable):
- MAX_VALUE = 2147483647
- MIN_VALUE = -2147483648
- SIZE = 32
- BYTES = 4
- TYPE = int
-
- def __init__(self, value=0):
- super().__init__()
- if isinstance(value, str):
- self._value = Integer.parseInt(value)
- else:
- self._value = int(value)
-
- @staticmethod
- def parseInt(s, radix=10):
- if isinstance(s, String):
- s = str(s)
- if radix == 10:
- return int(str(s))
- return int(str(s), radix)
-
- @staticmethod
- def toString(i, radix=10):
- if radix == 10:
- return String(str(i))
- if radix == 2:
- return String(bin(i)[2:])
- if radix == 8:
- return String(oct(i)[2:])
- if radix == 16:
- return String(hex(i)[2:])
- return String(str(i))
-
- @staticmethod
- def toBinaryString(i):
- if i >= 0:
- return String(bin(i)[2:])
- return String(bin(i & 0xFFFFFFFF)[2:])
-
- @staticmethod
- def toHexString(i):
- if i >= 0:
- return String(hex(i)[2:])
- return String(hex(i & 0xFFFFFFFF)[2:])
-
- @staticmethod
- def toOctalString(i):
- if i >= 0:
- return String(oct(i)[2:])
- return String(oct(i & 0xFFFFFFFF)[2:])
-
- @staticmethod
- def valueOf(i, radix=10):
- if isinstance(i, str):
- return Integer(Integer.parseInt(i, radix))
- return Integer(i)
-
- def intValue(self):
- return self._value
-
- def compareTo(self, other):
- if isinstance(other, Integer):
- return (self._value > other._value) - (self._value < other._value)
- return -1
-
- def equals(self, other):
- if isinstance(other, Integer):
- return self._value == other._value
- return False
-
- def byteValue(self):
- return self._value & 0xFF
-
- def shortValue(self):
- return self._value & 0xFFFF
-
- def longValue(self):
- return self._value
-
- def floatValue(self):
- return float(self._value)
-
- def doubleValue(self):
- return float(self._value)
-
- @staticmethod
- def bitCount(i):
- return bin(i & 0xFFFFFFFF).count("1")
-
- @staticmethod
- def highestOneBit(i):
- if i == 0:
- return 0
- return 1 << (i.bit_length() - 1)
-
- @staticmethod
- def lowestOneBit(i):
- return i & -i
-
- @staticmethod
- def numberOfLeadingZeros(i):
- if i == 0:
- return 32
- return 32 - i.bit_length()
-
- @staticmethod
- def numberOfTrailingZeros(i):
- if i == 0:
- return 32
- return (i & -i).bit_length() - 1
-
- @staticmethod
- def reverse(i):
- v = i & 0xFFFFFFFF
- result = 0
- for _ in range(32):
- result = (result << 1) | (v & 1)
- v >>= 1
- return result
-
- @staticmethod
- def reverseBytes(i):
- v = i & 0xFFFFFFFF
- return ((v >> 24) & 0xFF) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000)
-
- @staticmethod
- def rotateLeft(i, distance):
- v = i & 0xFFFFFFFF
- d = distance & 31
- return ((v << d) | (v >> (32 - d))) & 0xFFFFFFFF
-
- @staticmethod
- def rotateRight(i, distance):
- v = i & 0xFFFFFFFF
- d = distance & 31
- return ((v >> d) | (v << (32 - d))) & 0xFFFFFFFF
-
- @staticmethod
- def signum(i):
- if i > 0:
- return 1
- if i < 0:
- return -1
- return 0
-
- @staticmethod
- def decode(nm):
- if nm.startswith("0x") or nm.startswith("0X"):
- return Integer(int(nm, 16))
- if nm.startswith("0") and len(nm) > 1:
- return Integer(int(nm, 8))
- if nm.startswith("#"):
- return Integer(int(nm[1:], 16))
- return Integer(int(nm))
-
- @staticmethod
- def getInteger(nm, val=None):
- env_val = _os.environ.get(nm)
- if env_val is not None:
- return Integer(int(env_val))
- return Integer(val) if val is not None else None
-
- @staticmethod
- def compare(x, y):
- return -1 if x < y else (1 if x > y else 0)
-
- @staticmethod
- def compareUnsigned(x, y):
- ux = x & 0xFFFFFFFF if x < 0 else x
- uy = y & 0xFFFFFFFF if y < 0 else y
- return -1 if ux < uy else (1 if ux > uy else 0)
-
- @staticmethod
- def divideUnsigned(dividend, divisor):
- ux = dividend & 0xFFFFFFFF if dividend < 0 else dividend
- uy = divisor & 0xFFFFFFFF if divisor < 0 else divisor
- return ux // uy
-
- @staticmethod
- def remainderUnsigned(dividend, divisor):
- ux = dividend & 0xFFFFFFFF if dividend < 0 else dividend
- uy = divisor & 0xFFFFFFFF if divisor < 0 else divisor
- return ux % uy
-
- @staticmethod
- def parseUnsignedInt(s, radix=10):
- return int(s, radix)
-
- @staticmethod
- def toUnsignedString(i, radix=10):
- if i < 0:
- i = i & 0xFFFFFFFF
- if radix == 10:
- return str(i)
- elif radix == 16:
- return format(i, 'x')
- elif radix == 2:
- return format(i, 'b')
- elif radix == 8:
- return format(i, 'o')
- return str(i)
-
- @staticmethod
- def toUnsignedLong(i):
- return i & 0xFFFFFFFF
-
- @staticmethod
- def sum(a, b):
- return a + b
-
- @staticmethod
- def max(a, b):
- return a if a > b else b
-
- @staticmethod
- def min(a, b):
- return a if a < b else b
-
- def toString(self):
- return String(str(self._value))
-
- def __str__(self):
- return str(self._value)
-
- def __int__(self):
- return self._value
-
-
-# ============================================================
-# Long
-# ============================================================
-
-class Long(Number, Comparable):
- MAX_VALUE = 9223372036854775807
- MIN_VALUE = -9223372036854775808
- SIZE = 64
- BYTES = 8
- TYPE = int
-
- def __init__(self, value=0):
- super().__init__()
- if isinstance(value, str):
- self._value = Long.parseLong(value)
- else:
- self._value = int(value)
-
- @staticmethod
- def parseLong(s, radix=10):
- if isinstance(s, String):
- s = str(s)
- if radix == 10:
- return int(str(s))
- return int(str(s), radix)
-
- @staticmethod
- def toString(i, radix=10):
- if radix == 10:
- return String(str(i))
- return String(str(i))
-
- @staticmethod
- def toBinaryString(i):
- if i >= 0:
- return String(bin(i)[2:])
- return String(bin(i & 0xFFFFFFFFFFFFFFFF)[2:])
-
- @staticmethod
- def toHexString(i):
- if i >= 0:
- return String(hex(i)[2:])
- return String(hex(i & 0xFFFFFFFFFFFFFFFF)[2:])
-
- @staticmethod
- def toOctalString(i):
- if i >= 0:
- return String(oct(i)[2:])
- return String(oct(i & 0xFFFFFFFFFFFFFFFF)[2:])
-
- @staticmethod
- def valueOf(i, radix=10):
- if isinstance(i, str):
- return Long(Long.parseLong(i, radix))
- return Long(i)
-
- def longValue(self):
- return self._value
-
- def intValue(self):
- return int(self._value)
-
- def floatValue(self):
- return float(self._value)
-
- def doubleValue(self):
- return float(self._value)
-
- def compareTo(self, other):
- if isinstance(other, Long):
- return (self._value > other._value) - (self._value < other._value)
- return -1
-
- def equals(self, other):
- if isinstance(other, Long):
- return self._value == other._value
- return False
-
- def toString(self):
- return String(str(self._value))
-
- def __str__(self):
- return str(self._value)
-
-
-# ============================================================
-# Short, Byte
-# ============================================================
-
-class Short(Number, Comparable):
- MAX_VALUE = 32767
- MIN_VALUE = -32768
- SIZE = 16
- BYTES = 2
- TYPE = int
-
- def __init__(self, value=0):
- super().__init__()
- if isinstance(value, str):
- self._value = Short.parseShort(value)
- else:
- self._value = int(value) & 0xFFFF
-
- @staticmethod
- def parseShort(s, radix=10):
- return int(str(s), radix)
-
- @staticmethod
- def valueOf(i, radix=10):
- if isinstance(i, str):
- return Short(Short.parseShort(i, radix))
- return Short(i)
-
- def shortValue(self):
- return self._value
-
- def intValue(self):
- return self._value
-
- def longValue(self):
- return self._value
-
- def floatValue(self):
- return float(self._value)
-
- def doubleValue(self):
- return float(self._value)
-
- def compareTo(self, other):
- if isinstance(other, Short):
- return (self._value > other._value) - (self._value < other._value)
- return -1
-
- def equals(self, other):
- if isinstance(other, Short):
- return self._value == other._value
- return False
-
- def toString(self):
- return String(str(self._value))
-
-
-class Byte(Number, Comparable):
- MAX_VALUE = 127
- MIN_VALUE = -128
- SIZE = 8
- BYTES = 1
- TYPE = int
-
- def __init__(self, value=0):
- super().__init__()
- if isinstance(value, str):
- self._value = Byte.parseByte(value)
- else:
- self._value = int(value) & 0xFF
- if self._value > 127:
- self._value -= 256
-
- @staticmethod
- def parseByte(s, radix=10):
- return int(str(s), radix)
-
- @staticmethod
- def valueOf(i, radix=10):
- if isinstance(i, str):
- return Byte(Byte.parseByte(i, radix))
- return Byte(i)
-
- def byteValue(self):
- return self._value
-
- def intValue(self):
- return self._value
-
- def longValue(self):
- return self._value
-
- def compareTo(self, other):
- if isinstance(other, Byte):
- return (self._value > other._value) - (self._value < other._value)
- return -1
-
- def equals(self, other):
- if isinstance(other, Byte):
- return self._value == other._value
- return False
-
- def toString(self):
- return String(str(self._value))
-
-
-# ============================================================
-# Float
-# ============================================================
-
-class Float(Number, Comparable):
- MAX_VALUE = 3.4028235e38
- MIN_VALUE = 1.4e-45
- MIN_NORMAL = 1.17549435e-38
- MAX_EXPONENT = 127
- MIN_EXPONENT = -126
- SIZE = 32
- BYTES = 4
- TYPE = float
- NaN = float("nan")
- POSITIVE_INFINITY = float("inf")
- NEGATIVE_INFINITY = float("-inf")
-
- def __init__(self, value=0.0):
- super().__init__()
- if isinstance(value, str):
- self._value = Float.parseFloat(value)
- else:
- self._value = float(value)
-
- @staticmethod
- def parseFloat(s):
- if isinstance(s, String):
- s = str(s)
- s = str(s).strip()
- if s == "NaN":
- return float("nan")
- if s == "Infinity" or s == "Inf":
- return float("inf")
- if s == "-Infinity" or s == "-Inf":
- return float("-inf")
- return float(s)
-
- @staticmethod
- def toString(f):
- return String(str(f))
-
- @staticmethod
- def valueOf(f):
- if isinstance(f, str):
- return Float(Float.parseFloat(f))
- return Float(f)
-
- def floatValue(self):
- return self._value
-
- def intValue(self):
- return int(self._value)
-
- def longValue(self):
- return int(self._value)
-
- def doubleValue(self):
- return float(self._value)
-
- def compareTo(self, other):
- if isinstance(other, Float):
- a, b = self._value, other._value
- if _py_math.isnan(a) and _py_math.isnan(b):
- return 0
- if _py_math.isnan(a):
- return 1
- if _py_math.isnan(b):
- return -1
- return (a > b) - (a < b)
- return -1
-
- def isNaN(self):
- return _py_math.isnan(self._value)
-
- def isInfinite(self):
- return _py_math.isinf(self._value)
-
- def equals(self, other):
- if isinstance(other, Float):
- if _py_math.isnan(self._value) and _py_math.isnan(other._value):
- return True
- return self._value == other._value
- return False
-
- def hashCode(self):
- return _struct.pack(">f", self._value)
-
- def toString(self):
- return String(str(self._value))
-
- def __str__(self):
- return str(self._value)
-
-import struct as _struct
-
-
-# ============================================================
-# Double
-# ============================================================
-
-class Double(Number, Comparable):
- MAX_VALUE = 1.7976931348623157e308
- MIN_VALUE = 4.9e-324
- MIN_NORMAL = 2.2250738585072014e-308
- MAX_EXPONENT = 1023
- MIN_EXPONENT = -1022
- SIZE = 64
- BYTES = 8
- TYPE = float
- NaN = float("nan")
- POSITIVE_INFINITY = float("inf")
- NEGATIVE_INFINITY = float("-inf")
-
- def __init__(self, value=0.0):
- super().__init__()
- if isinstance(value, str):
- self._value = Double.parseDouble(value)
- else:
- self._value = float(value)
-
- @staticmethod
- def parseDouble(s):
- if isinstance(s, String):
- s = str(s)
- s = str(s).strip()
- if s == "NaN":
- return float("nan")
- if s == "Infinity" or s == "Inf":
- return float("inf")
- if s == "-Infinity" or s == "-Inf":
- return float("-inf")
- return float(s)
-
- @staticmethod
- def toString(d):
- return String(str(d))
-
- @staticmethod
- def valueOf(d):
- if isinstance(d, str):
- return Double(Double.parseDouble(d))
- return Double(d)
-
- def doubleValue(self):
- return self._value
-
- def intValue(self):
- return int(self._value)
-
- def longValue(self):
- return int(self._value)
-
- def floatValue(self):
- return float(self._value)
-
- def compareTo(self, other):
- if isinstance(other, Double):
- a, b = self._value, other._value
- if _py_math.isnan(a) and _py_math.isnan(b):
- return 0
- if _py_math.isnan(a):
- return 1
- if _py_math.isnan(b):
- return -1
- return (a > b) - (a < b)
- return -1
-
- def isNaN(self):
- return _py_math.isnan(self._value)
-
- def isInfinite(self):
- return _py_math.isinf(self._value)
-
- def equals(self, other):
- if isinstance(other, Double):
- if _py_math.isnan(self._value) and _py_math.isnan(other._value):
- return True
- return self._value == other._value
- return False
-
- def toString(self):
- return String(str(self._value))
-
- def __str__(self):
- return str(self._value)
-
-
-# ============================================================
-# Boolean
-# ============================================================
-
-class Boolean(Stub):
- TRUE = "true"
- FALSE = "false"
- TYPE = bool
-
- def __init__(self, value=False):
- super().__init__()
- if isinstance(value, str):
- self._value = Boolean.parseBoolean(value)
- elif isinstance(value, bool):
- self._value = value
- else:
- self._value = bool(value)
-
- @staticmethod
- def parseBoolean(s):
- return str(s).lower() == "true"
-
- @staticmethod
- def toString(b):
- return String(str(b).lower())
-
- @staticmethod
- def valueOf(b):
- if isinstance(b, str):
- return Boolean(Boolean.parseBoolean(b))
- return Boolean(b)
-
- def booleanValue(self):
- return self._value
-
- @staticmethod
- def logicalAnd(a, b):
- return a and b
-
- @staticmethod
- def logicalOr(a, b):
- return a or b
-
- @staticmethod
- def logicalXor(a, b):
- return a ^ b
-
- def compareTo(self, other):
- if isinstance(other, Boolean):
- return (self._value > other._value) - (self._value < other._value)
- return -1
-
- def equals(self, other):
- if isinstance(other, Boolean):
- return self._value == other._value
- return False
-
- def toString(self):
- return String("true" if self._value else "false")
-
- def __str__(self):
- return "true" if self._value else "false"
-
- def __bool__(self):
- return self._value
-
-
-# ============================================================
-# Character
-# ============================================================
-
-class Character(Stub):
- MAX_VALUE = 65535
- MIN_VALUE = 0
- SIZE = 16
- BYTES = 2
- TYPE = str
-
- def __init__(self, value=""):
- super().__init__()
- if isinstance(value, int):
- self._value = chr(value)
- else:
- self._value = str(value)[0] if value else ""
-
- def charValue(self):
- return self._value
-
- @staticmethod
- def isDigit(ch):
- return str(ch).isdigit()
-
- @staticmethod
- def isLetter(ch):
- return str(ch).isalpha()
-
- @staticmethod
- def isLetterOrDigit(ch):
- return str(ch).isalnum()
-
- @staticmethod
- def isLowerCase(ch):
- return str(ch).islower()
-
- @staticmethod
- def isUpperCase(ch):
- return str(ch).isupper()
-
- @staticmethod
- def isWhitespace(ch):
- return str(ch).isspace()
-
- @staticmethod
- def isSpaceChar(ch):
- return str(ch) in " \t\n\r\f\u000B"
-
- @staticmethod
- def isISOControl(ch):
- c = ord(ch) if isinstance(ch, str) else ch
- return c < 0x20 or c == 0x7F
-
- @staticmethod
- def isJavaIdentifierPart(ch):
- c = str(ch)
- return c.isalnum() or c == "_" or c == "$"
-
- @staticmethod
- def isJavaIdentifierStart(ch):
- c = str(ch)
- return c.isalpha() or c == "_" or c == "$"
-
- @staticmethod
- def isJavaLetter(ch):
- return Character.isJavaIdentifierStart(ch)
-
- @staticmethod
- def isJavaLetterOrDigit(ch):
- return Character.isJavaIdentifierPart(ch)
-
- @staticmethod
- def toLowerCase(ch):
- return str(ch).lower()
-
- @staticmethod
- def toUpperCase(ch):
- return str(ch).upper()
-
- @staticmethod
- def toTitleCase(ch):
- return str(ch).upper()
-
- @staticmethod
- def getNumericValue(ch):
- s = str(ch)
- if s.isdigit():
- return int(s)
- if "a" <= s <= "z":
- return ord(s) - ord("a") + 10
- if "A" <= s <= "Z":
- return ord(s) - ord("A") + 10
- return -1
-
- @staticmethod
- def digit(ch, radix):
- val = Character.getNumericValue(ch)
- return val if val < radix else -1
-
- @staticmethod
- def forDigit(digit, radix):
- if digit >= radix:
- return "\0"
- return str(digit) if digit < 10 else chr(ord("a") + digit - 10)
-
- @staticmethod
- def getType(ch):
- return 0
-
- @staticmethod
- def getDirectionality(ch):
- return 0
-
- @staticmethod
- def getName(ch):
- return f"CHARACTER {ord(ch)}"
-
- @staticmethod
- def charCount(codePoint):
- return 1 if codePoint < 0x10000 else 2
-
- @staticmethod
- def isBmpCodePoint(cp):
- return cp <= 0xFFFF
-
- @staticmethod
- def isHighSurrogate(ch):
- c = ord(ch) if isinstance(ch, str) else ch
- return 0xD800 <= c <= 0xDBFF
-
- @staticmethod
- def isLowSurrogate(ch):
- c = ord(ch) if isinstance(ch, str) else ch
- return 0xDC00 <= c <= 0xDFFF
-
- @staticmethod
- def isSupplementaryCodePoint(cp):
- return 0x10000
-
-
-class Math:
- """java.lang.Math — 数学运算"""
- E = 2.718281828459045
- PI = 3.141592653589793
-
- @staticmethod
- def abs(a): return abs(a)
- @staticmethod
- def ceil(a): return int(math.ceil(a))
- @staticmethod
- def floor(a): return int(math.floor(a))
- @staticmethod
- def round(a: float) -> int:
- return int(math.floor(a + 0.5))
- @staticmethod
- def min(a, b): return a if a < b else b
- @staticmethod
- def max(a, b): return a if a > b else b
- @staticmethod
- def sqrt(a): return math.sqrt(a)
- @staticmethod
- def cbrt(a): return math.cbrt(a)
- @staticmethod
- def pow(a, b): return math.pow(a, b)
- @staticmethod
- def exp(a): return math.exp(a)
- @staticmethod
- def log(a): return math.log(a)
- @staticmethod
- def log10(a): return math.log10(a)
- @staticmethod
- def sin(a): return math.sin(a)
- @staticmethod
- def cos(a): return math.cos(a)
- @staticmethod
- def tan(a): return math.tan(a)
- @staticmethod
- def asin(a): return math.asin(a)
- @staticmethod
- def acos(a): return math.acos(a)
- @staticmethod
- def atan(a): return math.atan(a)
- @staticmethod
- def atan2(y, x): return math.atan2(y, x)
- @staticmethod
- def toDegrees(r): return math.degrees(r)
- @staticmethod
- def toRadians(d): return math.radians(d)
- @staticmethod
- def hypot(x, y): return math.hypot(x, y)
- @staticmethod
- def sinh(x): return math.sinh(x)
- @staticmethod
- def cosh(x): return math.cosh(x)
- @staticmethod
- def tanh(x): return math.tanh(x)
- @staticmethod
- def signum(x): return 0.0 if x == 0 else (1.0 if x > 0 else -1.0)
- @staticmethod
- def random(): return random.random()
- @staticmethod
- def addExact(x, y):
- result = x + y
- if (x > 0 and y > 0 and result < 0) or (x < 0 and y < 0 and result > 0):
- raise ArithmeticError("integer overflow")
- return result
- @staticmethod
- def copySign(m, s): return abs(m) * (1 if s >= 0 else -1)
- @staticmethod
- def floorDiv(x, y):
- return math.floor(x / y) if y != 0 else 0
- @staticmethod
- def floorMod(x, y):
- return x - Math.floorDiv(x, y) * y
- @staticmethod
- def subtractExact(x, y):
- result = x - y
- if isinstance(x, int) and isinstance(y, int):
- if result > 0 and x < 0 and y > 0:
- raise ArithmeticException("integer overflow")
- if result < 0 and x > 0 and y < 0:
- raise ArithmeticException("integer overflow")
- return result
- @staticmethod
- def multiplyExact(x, y):
- result = x * y
- if isinstance(x, int) and isinstance(y, int):
- if result // y != x:
- raise ArithmeticException("integer overflow")
- return result
- @staticmethod
- def incrementExact(a):
- if a == 2147483647:
- raise ArithmeticException("integer overflow")
- return a + 1
- @staticmethod
- def decrementExact(a):
- if a == -2147483648:
- raise ArithmeticException("integer overflow")
- return a - 1
- @staticmethod
- def negateExact(a):
- if a == -2147483648:
- raise ArithmeticException("integer overflow")
- return -a
- @staticmethod
- def toIntExact(value):
- if value < -2147483648 or value > 2147483647:
- raise ArithmeticException("integer overflow")
- return int(value)
- @staticmethod
- def log1p(x):
- return math.log1p(x)
- @staticmethod
- def expm1(x):
- return math.expm1(x)
- @staticmethod
- def ulp(x):
- return math.ulp(x) if hasattr(math, 'ulp') else abs(x) * 2.220446049250313e-16
- @staticmethod
- def getExponent(x):
- return math.frexp(x)[1] - 1
- @staticmethod
- def nextAfter(start, direction):
- return math.nextafter(start, direction)
- @staticmethod
- def nextUp(x):
- return math.nextafter(x, math.inf)
- @staticmethod
- def nextDown(x):
- return math.nextafter(x, -math.inf)
- @staticmethod
- def rint(x):
- return math.rint(x) if hasattr(math, 'rint') else float(math.floor(x + 0.5))
- @staticmethod
- def IEEEremainder(x, y):
- return math.remainder(x, y) if hasattr(math, 'remainder') else x - y * math.floor(x / y)
- @staticmethod
- def compareUnsigned(x, y):
- ux = x & 0xFFFFFFFF if x < 0 else x
- uy = y & 0xFFFFFFFF if y < 0 else y
- return -1 if ux < uy else (1 if ux > uy else 0)
- @staticmethod
- def divideUnsigned(dividend, divisor):
- ux = dividend & 0xFFFFFFFF if dividend < 0 else dividend
- uy = divisor & 0xFFFFFFFF if divisor < 0 else divisor
- return ux // uy
- @staticmethod
- def remainderUnsigned(dividend, divisor):
- ux = dividend & 0xFFFFFFFF if dividend < 0 else dividend
- uy = divisor & 0xFFFFFFFF if divisor < 0 else divisor
- return ux % uy
- @staticmethod
- def fma(a, b, c):
- return a * b + c
-
-
-class StrictMath(Math):
- """java.lang.StrictMath"""
- pass
-
-
-class _Console:
- """java.io.Console 简化实现,供 System.console() 使用"""
- def readLine(self, fmt=None, *args):
- if fmt is not None:
- try:
- _sys.stdout.write(str(fmt) % args if args else str(fmt))
- except Exception:
- _sys.stdout.write(str(fmt))
- _sys.stdout.flush()
- line = _sys.stdin.readline()
- if line == "":
- return None
- return line.rstrip("\r\n")
-
- def readPassword(self, fmt=None, *args):
- import getpass
- if fmt is not None:
- try:
- _sys.stderr.write(str(fmt) % args if args else str(fmt))
- except Exception:
- _sys.stderr.write(str(fmt))
- _sys.stderr.flush()
- pwd = getpass.getpass("")
- return list(pwd) if pwd is not None else None
-
- def printf(self, fmt, *args):
- try:
- _sys.stdout.write(str(fmt) % args if args else str(fmt))
- except Exception:
- _sys.stdout.write(str(fmt))
- return self
-
- def format(self, fmt, *args):
- try:
- _sys.stdout.write(str(fmt) % args if args else str(fmt))
- except Exception:
- _sys.stdout.write(str(fmt))
- return self
-
- def flush(self):
- _sys.stdout.flush()
-
- def writer(self):
- return _sys.stdout
-
- def reader(self):
- return _sys.stdin
-
-
-class System:
- """java.lang.System"""
- _console = None
- @staticmethod
- def currentTimeMillis(): return int(time.time() * 1000)
- @staticmethod
- def nanoTime(): return time.perf_counter_ns()
- @staticmethod
- def arraycopy(src, srcPos, dest, destPos, length):
- if isinstance(src, (list, bytearray)):
- dest[destPos:destPos+length] = src[srcPos:srcPos+length]
- else:
- raise TypeError("Unsupported type for arraycopy")
- @staticmethod
- def identityHashCode(obj): return id(obj) & 0x7FFFFFFF
- @staticmethod
- def gc(): pass
- @staticmethod
- def exit(status): raise SystemExit(status)
- @staticmethod
- def getProperty(key, default=None):
- import os
- return os.environ.get(key, default)
- @staticmethod
- def setProperty(key, value):
- import os
- os.environ[key] = value
- return value
- @staticmethod
- def clearProperty(key):
- return _os.environ.pop(key, None)
- @staticmethod
- def getenv(name=None):
- if name is None:
- return dict(_os.environ)
- return _os.environ.get(name)
- @staticmethod
- def console():
- if System._console is None:
- System._console = _Console()
- return System._console
- @staticmethod
- def setIn(in_stream):
- System.in_ = in_stream
- @staticmethod
- def setOut(out_stream):
- System.out = out_stream
- @staticmethod
- def setErr(err_stream):
- System.err = err_stream
- @staticmethod
- def lineSeparator(): return _os.linesep
- @staticmethod
- def getProperties():
- return {
- "java.version": "1.8.0",
- "java.vendor": "Android-pyApi",
- "java.vendor.url": "https://gitee.com/shuiyu1123/Android-pyApi",
- "java.home": _os.environ.get("JAVA_HOME", ""),
- "java.class.version": "52.0",
- "os.name": platform.system(),
- "os.arch": platform.machine(),
- "os.version": platform.release(),
- "file.separator": _os.sep,
- "path.separator": _os.pathsep,
- "line.separator": _os.linesep,
- "user.name": _os.environ.get("USER", _os.environ.get("USERNAME", "")),
- "user.home": _os.path.expanduser("~"),
- "user.dir": _os.getcwd(),
- }
- @staticmethod
- def setProperties(props):
- System._properties = props
- @staticmethod
- def mapLibraryName(libname):
- if platform.system() == "Windows":
- return libname + ".dll"
- elif platform.system() == "Darwin":
- return "lib" + libname + ".dylib"
- else:
- return "lib" + libname + ".so"
- @staticmethod
- def getLogger(name):
- import logging
- return logging.getLogger(name)
- in_ = _sys.stdin
- out = _sys.stdout
- err = _sys.stderr
-
-
-class Thread(Runnable):
- """java.lang.Thread"""
- MIN_PRIORITY = 1
- NORM_PRIORITY = 5
- MAX_PRIORITY = 10
-
- # Thread.State 常量(java.lang.Thread.State)
- NEW = "NEW"
- RUNNABLE = "RUNNABLE"
- BLOCKED = "BLOCKED"
- WAITING = "WAITING"
- TIMED_WAITING = "TIMED_WAITING"
- TERMINATED = "TERMINATED"
-
- # 按 Python 线程 ident 缓存 Thread 对象,供 currentThread() 复用
- _thread_cache = {}
- _default_uncaught_exception_handler = None
-
- def __init__(self, target=None, name=None):
- super().__init__()
- self._target = target
- self._name = name or f"Thread-{id(self)}"
- self._alive = False
- self._daemon = False
- self._interrupted = False
- self._priority = Thread.NORM_PRIORITY
- self._state = Thread.NEW
- self._py_thread = None
- self._id = _threading.get_ident()
-
- def start(self):
- self._alive = True
- self._state = Thread.RUNNABLE
- self._py_thread = _threading.Thread(
- target=self._run_wrapper, daemon=self._daemon, name=self._name
- )
- self._py_thread.start()
- self._id = self._py_thread.ident
-
- def _run_wrapper(self):
- tid = _threading.get_ident()
- self._id = tid
- Thread._thread_cache[tid] = self
- try:
- self.run()
- except (SystemExit, KeyboardInterrupt):
- raise
- except BaseException as e:
- # 注意:模块内 Exception 已被 java.lang.Exception 覆盖,
- # 这里用 BaseException 捕获 Python 原生异常并转发给未捕获异常处理器
- handler = Thread._default_uncaught_exception_handler
- if handler is not None:
- try:
- handler.uncaughtException(self, e)
- except BaseException:
- pass
- finally:
- self._alive = False
- self._state = Thread.TERMINATED
- Thread._thread_cache.pop(tid, None)
-
- def run(self):
- if self._target:
- self._target()
-
- def join(self, millis=0):
- if self._py_thread is not None:
- if millis and millis > 0:
- self._py_thread.join(millis / 1000.0)
- else:
- self._py_thread.join()
-
- def interrupt(self):
- self._interrupted = True
-
- def isInterrupted(self):
- return self._interrupted
-
- @staticmethod
- def interrupted():
- tid = _threading.get_ident()
- t = Thread._thread_cache.get(tid)
- if t is not None:
- status = t._interrupted
- t._interrupted = False
- return status
- return False
-
- def isAlive(self):
- if self._py_thread is not None:
- return self._py_thread.is_alive()
- return self._alive
-
- def getState(self):
- if self._py_thread is not None:
- if self._py_thread.is_alive():
- return Thread.RUNNABLE
- return Thread.TERMINATED
- return self._state
-
- def getPriority(self):
- return self._priority
-
- def setPriority(self, priority):
- if Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY:
- self._priority = priority
-
- def getId(self):
- return self._id
-
- def getName(self): return self._name
- def setName(self, n): self._name = n
- def setDaemon(self, d): self._daemon = d
- def isDaemon(self): return self._daemon
-
- @staticmethod
- def currentThread():
- tid = _threading.get_ident()
- t = Thread._thread_cache.get(tid)
- if t is not None:
- return t
- # 未缓存的线程(如主线程):创建并缓存一个代表对象
- try:
- is_main = (tid == _threading.main_thread().ident)
- except Exception:
- is_main = False
- t = Thread(name="main" if is_main else f"Thread-{tid}")
- t._state = Thread.RUNNABLE
- t._alive = True
- t._id = tid
- Thread._thread_cache[tid] = t
- return t
-
- @staticmethod
- def sleep(millis):
- _time.sleep(millis / 1000.0)
-
- @staticmethod
- def yield_():
- _time.sleep(0)
-
- @staticmethod
- def setDefaultUncaughtExceptionHandler(handler):
- Thread._default_uncaught_exception_handler = handler
-
- @staticmethod
- def getDefaultUncaughtExceptionHandler():
- return Thread._default_uncaught_exception_handler
-
- def getUncaughtExceptionHandler(self):
- return getattr(self, '_uncaught_handler', Thread._default_uncaught_exception_handler)
-
- def setUncaughtExceptionHandler(self, handler):
- self._uncaught_handler = handler
-
- @staticmethod
- def getAllStackTraces():
- import traceback
- result = {}
- # 只返回当前线程
- result[Thread.currentThread()] = traceback.extract_stack()
- return result
-
- def getStackTrace(self):
- import traceback
- return traceback.extract_stack()
-
- @staticmethod
- def enumerate(array):
- # 返回活动线程数
- return 0
-
- @staticmethod
- def activeCount():
- import threading
- return threading.active_count()
-
- def getContextClassLoader(self):
- return getattr(self, '_context_classloader', None)
-
- def setContextClassLoader(self, cl):
- self._context_classloader = cl
-
- def getThreadGroup(self):
- return getattr(self, '_thread_group', None)
-
- @staticmethod
- def holdLock(obj):
- return False
-
- @staticmethod
- def dumpStack():
- import traceback
- traceback.print_stack()
-
- @staticmethod
- def onSpinWait():
- pass
-
- def isVirtual(self):
- return False
-
- @staticmethod
- def ofVirtual():
- """创建虚拟线程 (Java 21+)"""
- t = Thread(target=lambda: None)
- t._virtual = True
- return t
-
-
-class ThreadLocal(Stub):
- """java.lang.ThreadLocal"""
- def __init__(self):
- super().__init__()
- self._data = {}
-
- def get(self):
- tid = _threading.get_ident()
- return self._data.get(tid, None)
- def set(self, value):
- self._data[_threading.get_ident()] = value
- def remove(self):
- self._data.pop(_threading.get_ident(), None)
-
-
-class StringBuilder(Stub):
- """java.lang.StringBuilder — 可变字符序列"""
- def __init__(self, s=""):
- super().__init__()
- self._buf = list(str(s))
-
- def append(self, obj):
- if isinstance(obj, bool):
- self._buf.append("true" if obj else "false")
- else:
- self._buf.append(str(obj))
- return self
-
- def insert(self, offset, obj):
- self._buf[offset:offset] = list(str(obj))
- return self
-
- def delete(self, start, end):
- del self._buf[start:end]
- return self
-
- def deleteCharAt(self, index):
- del self._buf[index]
- return self
-
- def replace(self, start, end, s):
- self._buf[start:end] = list(s)
- return self
-
- def reverse(self):
- self._buf.reverse()
- return self
-
- def toString(self): return "".join(self._buf)
- def length(self): return len(self._buf)
- def capacity(self): return len(self._buf) + 16
- def charAt(self, i): return self._buf[i]
- def setCharAt(self, i, c): self._buf[i] = c
- def substring(self, s, e=None):
- return "".join(self._buf[s:e])
- def indexOf(self, s, f=0):
- return self.toString().find(s, f)
- def lastIndexOf(self, s, f=None):
- return self.toString().rfind(s)
-
- def ensureCapacity(self, minimumCapacity):
- pass # Python list 自动扩容
-
- def trimToSize(self):
- pass
-
- def setLength(self, newLength):
- current = len(self._buf)
- if newLength < current:
- del self._buf[newLength:]
- else:
- self._buf.extend([" "] * (newLength - current))
-
- def subSequence(self, start, end):
- return "".join(self._buf[start:end])
-
- def getChars(self, srcBegin, srcEnd, dst, dstBegin):
- for i in range(srcBegin, srcEnd):
- dst[dstBegin + i - srcBegin] = self._buf[i]
-
- def codePointAt(self, index):
- return ord(self._buf[index])
-
- def codePointBefore(self, index):
- return ord(self._buf[index - 1])
-
- def codePointCount(self, beginIndex, endIndex):
- return endIndex - beginIndex
-
-
-class StringBuffer(StringBuilder):
- """java.lang.StringBuffer — 线程安全的可变字符序列"""
- pass
-
-
-class Class(Stub):
- """java.lang.Class"""
- def __init__(self, cls):
- super().__init__()
- self._cls = cls
- def getName(self): return self._cls.__name__
- def getSimpleName(self): return self._cls.__name__
- def getCanonicalName(self): return self._cls.__name__
- def isInterface(self): return isinstance(self._cls, type)
- def isArray(self): return self._cls is list
- def isPrimitive(self): return self._cls in (int, float, bool, str, bytes)
- def getSuperclass(self): return Class(self._cls.__base__) if self._cls.__base__ else None
- def cast(self, obj): return obj
-
-
-class Void(Stub):
- """java.lang.Void"""
- TYPE = None
-
-
-class VoidType(Stub):
- """java.lang.Void (inner type)"""
- pass
-
-
-# 注解类
-class SuppressWarnings(Stub):
- pass
-class Deprecated(Stub):
- pass
-class Override(Stub):
- pass
-class FunctionalInterface(Stub):
- pass
\ No newline at end of file
diff --git a/android_pyapi/java/lang_annotation.py b/android_pyapi/java/lang_annotation.py
deleted file mode 100644
index 7fe12cf..0000000
--- a/android_pyapi/java/lang_annotation.py
+++ /dev/null
@@ -1,303 +0,0 @@
-"""
-Java java.lang.annotation APIs implemented in Python.
-java.lang.annotation package - Annotation, Retention, Target, Documented, Inherited, etc.
-Desktop wrapper classes mirroring the Java annotation framework.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-from ..java.lang import Error
-
-__all__ = [
- "Annotation", "Documented", "Inherited", "Repeatable", "Retention",
- "RetentionPolicy", "Target", "ElementType", "Native",
- "IncompleteAnnotationException", "AnnotationFormatError",
-]
-
-
-# ============================================================
-# RetentionPolicy enum
-# ============================================================
-
-class RetentionPolicy(Stub):
- """
- java.lang.annotation.RetentionPolicy
- Enum-like class for annotation retention policies.
- """
- SOURCE: "RetentionPolicy" = None
- CLASS: "RetentionPolicy" = None
- RUNTIME: "RetentionPolicy" = None
-
- def __init__(self, name: str):
- super().__init__()
- self._name = name
-
- def name(self) -> str:
- return self._name
-
- def toString(self) -> str:
- return self._name
-
- def equals(self, other) -> bool:
- if isinstance(other, RetentionPolicy):
- return self._name == other._name
- return False
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
- def ordinal(self) -> int:
- return ["SOURCE", "CLASS", "RUNTIME"].index(self._name)
-
-
-RetentionPolicy.SOURCE = RetentionPolicy("SOURCE")
-RetentionPolicy.CLASS = RetentionPolicy("CLASS")
-RetentionPolicy.RUNTIME = RetentionPolicy("RUNTIME")
-
-
-# ============================================================
-# ElementType enum
-# ============================================================
-
-class ElementType(Stub):
- """
- java.lang.annotation.ElementType
- Enum-like class for annotation target element types.
- """
- TYPE: "ElementType" = None
- FIELD: "ElementType" = None
- METHOD: "ElementType" = None
- PARAMETER: "ElementType" = None
- CONSTRUCTOR: "ElementType" = None
- LOCAL_VARIABLE: "ElementType" = None
- ANNOTATION_TYPE: "ElementType" = None
- PACKAGE: "ElementType" = None
- TYPE_PARAMETER: "ElementType" = None
- TYPE_USE: "ElementType" = None
- MODULE: "ElementType" = None
- RECORD_COMPONENT: "ElementType" = None
-
- def __init__(self, name: str):
- super().__init__()
- self._name = name
-
- def name(self) -> str:
- return self._name
-
- def toString(self) -> str:
- return self._name
-
- def equals(self, other) -> bool:
- if isinstance(other, ElementType):
- return self._name == other._name
- return False
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
- def ordinal(self) -> int:
- return [
- "TYPE", "FIELD", "METHOD", "PARAMETER", "CONSTRUCTOR",
- "LOCAL_VARIABLE", "ANNOTATION_TYPE", "PACKAGE",
- "TYPE_PARAMETER", "TYPE_USE", "MODULE", "RECORD_COMPONENT",
- ].index(self._name)
-
-
-ElementType.TYPE = ElementType("TYPE")
-ElementType.FIELD = ElementType("FIELD")
-ElementType.METHOD = ElementType("METHOD")
-ElementType.PARAMETER = ElementType("PARAMETER")
-ElementType.CONSTRUCTOR = ElementType("CONSTRUCTOR")
-ElementType.LOCAL_VARIABLE = ElementType("LOCAL_VARIABLE")
-ElementType.ANNOTATION_TYPE = ElementType("ANNOTATION_TYPE")
-ElementType.PACKAGE = ElementType("PACKAGE")
-ElementType.TYPE_PARAMETER = ElementType("TYPE_PARAMETER")
-ElementType.TYPE_USE = ElementType("TYPE_USE")
-ElementType.MODULE = ElementType("MODULE")
-ElementType.RECORD_COMPONENT = ElementType("RECORD_COMPONENT")
-
-
-# ============================================================
-# Annotation (interface)
-# ============================================================
-
-class Annotation(Stub):
- """
- java.lang.annotation.Annotation
- The common interface for all annotation types.
- """
-
- def __init__(self):
- super().__init__()
-
- def annotationType(self) -> type:
- """Returns the annotation type of this annotation."""
- return self.__class__
-
- def toString(self) -> str:
- return f"@{self.__class__.__name__}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self.__class__.__name__) & 0x7FFFFFFF
-
-
-# ============================================================
-# Documented
-# ============================================================
-
-class Documented(Annotation):
- """
- java.lang.annotation.Documented
- Indicates that annotations with a type are to be documented by javadoc.
- """
- def __init__(self):
- super().__init__()
-
-
-# ============================================================
-# Inherited
-# ============================================================
-
-class Inherited(Annotation):
- """
- java.lang.annotation.Inherited
- Indicates that an annotation type is automatically inherited.
- """
- def __init__(self):
- super().__init__()
-
-
-# ============================================================
-# Repeatable
-# ============================================================
-
-class Repeatable(Annotation):
- """
- java.lang.annotation.Repeatable
- Indicates that the annotation type can be applied more than once.
- """
- def __init__(self, value: type = None):
- super().__init__()
- self._value = value
-
- def value(self) -> type:
- return self._value
-
- def toString(self) -> str:
- return f"@Repeatable(value={self._value})" if self._value else "@Repeatable"
-
-
-# ============================================================
-# Retention
-# ============================================================
-
-class Retention(Annotation):
- """
- java.lang.annotation.Retention
- Indicates how long annotations with the annotated type are to be retained.
- """
- def __init__(self, value: RetentionPolicy = RetentionPolicy.CLASS):
- super().__init__()
- self._value = value
-
- def value(self) -> RetentionPolicy:
- return self._value
-
- def toString(self) -> str:
- return f"@Retention(value={self._value})"
-
-
-# ============================================================
-# Target
-# ============================================================
-
-class Target(Annotation):
- """
- java.lang.annotation.Target
- Indicates the contexts in which an annotation type is applicable.
- """
- def __init__(self, value=None):
- super().__init__()
- self._value = value if value is not None else []
-
- def value(self):
- """Returns the element types this annotation can be applied to."""
- return self._value
-
- def toString(self) -> str:
- return f"@Target(value={self._value})"
-
-
-# ============================================================
-# Native
-# ============================================================
-
-class Native(Annotation):
- """
- java.lang.annotation.Native
- Indicates that a field defining a constant value may be referenced from native code.
- """
- def __init__(self):
- super().__init__()
-
-
-# ============================================================
-# IncompleteAnnotationException
-# ============================================================
-
-class IncompleteAnnotationException(Exception, Stub):
- """
- java.lang.annotation.IncompleteAnnotationException
- Thrown when a program attempts to access an annotation with missing elements.
- """
- def __init__(self, annotation_type: type = None, element_name: str = None):
- super().__init__(f"Annotation {annotation_type} is missing element '{element_name}'")
- self._annotation_type = annotation_type
- self._element_name = element_name
-
- def annotationType(self) -> type:
- return self._annotation_type
-
- def elementName(self) -> str:
- return self._element_name
-
- def toString(self) -> str:
- return f"IncompleteAnnotationException: {self._annotation_type} missing '{self._element_name}'"
-
- def equals(self, other) -> bool:
- if not isinstance(other, IncompleteAnnotationException):
- return False
- return self._annotation_type == other._annotation_type and self._element_name == other._element_name
-
- def hashCode(self) -> int:
- return hash((str(self._annotation_type), self._element_name)) & 0x7FFFFFFF
-
-
-# ============================================================
-# AnnotationFormatError
-# ============================================================
-
-class AnnotationFormatError(Error, Stub):
- """
- java.lang.annotation.AnnotationFormatError
- Thrown when the annotation parser attempts to read an annotation from a class file
- and determines that the annotation is malformed.
- """
- def __init__(self, message: str = None, cause: Exception = None):
- super().__init__(message, cause)
- self._message = message
-
- def toString(self) -> str:
- return f"AnnotationFormatError: {self._message}"
-
- def equals(self, other) -> bool:
- if not isinstance(other, AnnotationFormatError):
- return False
- return self._message == other._message
-
- def hashCode(self) -> int:
- return hash(self._message) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/java/lang_invoke.py b/android_pyapi/java/lang_invoke.py
deleted file mode 100644
index c4af1c0..0000000
--- a/android_pyapi/java/lang_invoke.py
+++ /dev/null
@@ -1,766 +0,0 @@
-"""
-Java java.lang.invoke standard library APIs implemented in Python.
-java.lang.invoke package - MethodHandle, MethodType, MethodHandles, CallSite, VarHandle, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub
-from ..java.lang import RuntimeException, Exception as _JavaException
-import typing as _typing
-import types as _py_types
-import inspect as _inspect
-import functools as _functools
-
-__all__ = [
- "MethodHandle", "MethodType", "MethodHandles", "MethodHandles_Lookup",
- "CallSite", "ConstantCallSite", "MutableCallSite", "VolatileCallSite",
- "SwitchPoint", "VarHandle", "VarHandle_AccessMode",
- "MethodHandleInfo", "MethodHandleProxies",
- "SerializedLambda", "LambdaMetafactory", "StringConcatFactory",
- "REF_GET_FIELD", "REF_GET_STATIC", "REF_PUT_FIELD",
- "REF_PUT_STATIC", "REF_INVOKE_VIRTUAL", "REF_INVOKE_STATIC",
- "REF_INVOKE_SPECIAL", "REF_NEW_INVOKE_SPECIAL",
- "REF_INVOKE_INTERFACE",
- "LT_GLOBAL", "LT_NEW",
-]
-
-# ============================================================
-# Reference Constants
-# ============================================================
-
-REF_GET_FIELD = 1
-REF_GET_STATIC = 2
-REF_PUT_FIELD = 3
-REF_PUT_STATIC = 4
-REF_INVOKE_VIRTUAL = 5
-REF_INVOKE_STATIC = 6
-REF_INVOKE_SPECIAL = 7
-REF_NEW_INVOKE_SPECIAL = 8
-REF_INVOKE_INTERFACE = 9
-
-LT_GLOBAL = "global"
-LT_NEW = "new"
-
-
-# ============================================================
-# MethodType
-# ============================================================
-
-class MethodType(Stub):
- """java.lang.invoke.MethodType"""
- def __init__(self, return_type, param_types=None):
- super().__init__()
- self._return_type = return_type
- self._param_types = list(param_types or [])
-
- def returnType(self):
- return self._return_type
-
- def parameterCount(self):
- return len(self._param_types)
-
- def parameterType(self, index):
- return self._param_types[index]
-
- def parameterList(self):
- return list(self._param_types)
-
- def parameterArray(self):
- return list(self._param_types)
-
- def appendParameterTypes(self, *types):
- return MethodType(self._return_type, self._param_types + list(types))
-
- def changeReturnType(self, return_type):
- return MethodType(return_type, self._param_types)
-
- def changeParameterType(self, index, param_type):
- new_params = list(self._param_types)
- new_params[index] = param_type
- return MethodType(self._return_type, new_params)
-
- def dropParameterTypes(self, start, end):
- new_params = self._param_types[:start] + self._param_types[end:]
- return MethodType(self._return_type, new_params)
-
- def insertParameterTypes(self, index, *types):
- new_params = self._param_types[:index] + list(types) + self._param_types[index:]
- return MethodType(self._return_type, new_params)
-
- def genericMethodType(self, object_count, final_array=False):
- return MethodType(object, [object] * object_count)
-
- @staticmethod
- def methodType(return_type, *param_types):
- return MethodType(return_type, list(param_types))
-
- @staticmethod
- def genericMethodType(object_count, final_array=False):
- return MethodType(object, [object] * object_count)
-
- def toString(self):
- params = ", ".join(str(t) for t in self._param_types)
- return f"({params}) -> {self._return_type}"
-
- def equals(self, other):
- if not isinstance(other, MethodType):
- return False
- return (self._return_type == other._return_type
- and self._param_types == other._param_types)
-
- def hashCode(self):
- return hash((self._return_type, tuple(self._param_types)))
-
- def wrap(self):
- return self
-
- def unwrap(self):
- return self
-
-
-# ============================================================
-# MethodHandle
-# ============================================================
-
-class MethodHandle(Stub):
- """java.lang.invoke.MethodHandle"""
- def __init__(self, method_type=None, target=None):
- super().__init__()
- self._type = method_type or MethodType(object, [])
- self._target = target
-
- def type(self):
- return self._type
-
- def invoke(self, *args):
- if self._target is None:
- return None
- return self._target(*args)
-
- def invokeExact(self, *args):
- return self.invoke(*args)
-
- def invokeWithArguments(self, *args):
- return self.invoke(*args)
-
- def asType(self, new_type):
- return self._target
-
- def asCollector(self, array_type, array_length):
- return self
-
- def asSpreader(self, array_type, array_length):
- return self
-
- def bindTo(self, argument):
- bound_target = None
- if self._target is not None:
- bound_target = _functools.partial(self._target, argument)
- return MethodHandle(self._type.dropParameterTypes(0, 1), bound_target)
-
- def toString(self):
- return f"MethodHandle{self._type}"
-
-
-# ============================================================
-# MethodHandles / Lookup
-# ============================================================
-
-class MethodHandles_Lookup(Stub):
- """java.lang.invoke.MethodHandles.Lookup"""
- def __init__(self, lookup_class=None):
- super().__init__()
- self._lookup_class = lookup_class
-
- def lookupClass(self):
- return self._lookup_class
-
- def findStatic(self, refc, name, type_):
- return MethodHandle(type_)
-
- def findVirtual(self, refc, name, type_):
- return MethodHandle(type_)
-
- def findConstructor(self, refc, type_):
- return MethodHandle(type_)
-
- def findSpecial(self, refc, name, type_, special_caller):
- return MethodHandle(type_)
-
- def findGetter(self, refc, name, type_):
- return MethodHandle(type_)
-
- def findSetter(self, refc, name, type_):
- return MethodHandle(type_)
-
- def findStaticGetter(self, refc, name, type_):
- return MethodHandle(type_)
-
- def findStaticSetter(self, refc, name, type_):
- return MethodHandle(type_)
-
- def bind(self, receiver, name, type_):
- return MethodHandle(type_)
-
- def unreflect(self, method):
- return MethodHandle(MethodType(object, []))
-
- def unreflectConstructor(self, constructor):
- return MethodHandle(MethodType(object, []))
-
- def unreflectGetter(self, field):
- return MethodHandle(MethodType(object, []))
-
- def unreflectSetter(self, field):
- return MethodHandle(MethodType(object, []))
-
- def dropLookupMode(self, mode_to_drop):
- return MethodHandles_Lookup(self._lookup_class)
-
- def toString(self):
- return f"Lookup[{self._lookup_class}]"
-
- PACKAGE = 8
- PRIVATE = 4
- PROTECTED = 2
- PUBLIC = 1
-
-
-class MethodHandles(Stub):
- """java.lang.invoke.MethodHandles"""
- @staticmethod
- def lookup():
- return MethodHandles_Lookup()
-
- @staticmethod
- def publicLookup():
- return MethodHandles_Lookup(object)
-
- @staticmethod
- def arrayElementGetter(array_class):
- return MethodHandle(MethodType(object, [array_class, int]))
-
- @staticmethod
- def arrayElementSetter(array_class):
- return MethodHandle(MethodType(None, [array_class, int, object]))
-
- @staticmethod
- def identity(type_):
- return MethodHandle(MethodType(type_, [type_]))
-
- @staticmethod
- def constant(type_, value):
- return MethodHandle(MethodType(type_, []))
-
- @staticmethod
- def zero(type_):
- return MethodHandle(MethodType(type_, []))
-
- @staticmethod
- def filterReturnValue(target, filter_):
- return target
-
- @staticmethod
- def filterArguments(target, pos, *filters):
- return target
-
- @staticmethod
- def collectArguments(target, pos, filter_):
- return target
-
- @staticmethod
- def foldArguments(target, combiner):
- return target
-
- @staticmethod
- def guardWithTest(test, target, fallback):
- class Guarded(MethodHandle):
- def invoke(self, *args):
- if test.invoke(*args):
- return target.invoke(*args)
- return fallback.invoke(*args)
- return Guarded(MethodType(object, []))
-
- @staticmethod
- def throwException(return_type, ex_type):
- return MethodHandle(MethodType(return_type, [ex_type]))
-
- @staticmethod
- def spreadInvoker(type_, leading_arg_count):
- return MethodHandle(type_)
-
- @staticmethod
- def explicitCastArguments(target, new_type):
- return target
-
- @staticmethod
- def permuteArguments(target, new_type, *reorder):
- return target
-
- @staticmethod
- def catchException(target, ex_type, handler):
- return target
-
- @staticmethod
- def tryFinally(target, cleanup):
- return target
-
- @staticmethod
- def loop(loop_handles):
- return MethodHandle(MethodType(object, []))
-
-
-# ============================================================
-# CallSite / ConstantCallSite / MutableCallSite / VolatileCallSite
-# ============================================================
-
-class CallSite(Stub):
- """java.lang.invoke.CallSite"""
- def __init__(self, target=None):
- super().__init__()
- self._target = target
-
- def type(self):
- if self._target:
- return self._target.type()
- return MethodType(object, [])
-
- def target(self):
- return self._target
-
- def setTarget(self, new_target):
- self._target = new_target
-
- def dynamicInvoker(self):
- return self._target
-
-
-class ConstantCallSite(CallSite):
- """java.lang.invoke.ConstantCallSite"""
- def __init__(self, target):
- super().__init__(target)
-
- def setTarget(self, new_target):
- raise UnsupportedOperationException("ConstantCallSite target is immutable")
-
-
-class MutableCallSite(CallSite):
- """java.lang.invoke.MutableCallSite"""
- def __init__(self, target_or_type):
- if isinstance(target_or_type, MethodType):
- super().__init__(MethodHandle(target_or_type))
- else:
- super().__init__(target_or_type)
-
- def syncAll(self, sites):
- pass
-
- def setTarget(self, new_target):
- if hasattr(self, '_target'):
- self._target = new_target
-
-
-class VolatileCallSite(MutableCallSite):
- """java.lang.invoke.VolatileCallSite"""
- def __init__(self, target_or_type):
- super().__init__(target_or_type)
-
- def setTarget(self, new_target):
- super().setTarget(new_target)
-
- def target(self):
- return self._target
-
-
-# ============================================================
-# SwitchPoint
-# ============================================================
-
-class SwitchPoint(Stub):
- """java.lang.invoke.SwitchPoint"""
- def __init__(self):
- super().__init__()
- self._has_been_invalidated = False
-
- def hasBeenInvalidated(self):
- return self._has_been_invalidated
-
- def invalidateAll(self):
- self._has_been_invalidated = True
-
- @staticmethod
- def guardWithTest(switch_point, target, fallback):
- class GuardedSwitch(MethodHandle):
- def invoke(self, *args):
- if switch_point.hasBeenInvalidated():
- return fallback.invoke(*args)
- return target.invoke(*args)
- return GuardedSwitch(MethodType(object, []))
-
-
-# ============================================================
-# VarHandle
-# ============================================================
-
-class VarHandle_AccessMode(Stub):
- """java.lang.invoke.VarHandle.AccessMode"""
- def __init__(self, name):
- super().__init__()
- self._name = name
-
- def name(self):
- return self._name
-
- def toString(self):
- return self._name
-
- # Access mode constants
- GET = None
- SET = None
- GET_VOLATILE = None
- SET_VOLATILE = None
- GET_ACQUIRE = None
- SET_RELEASE = None
- GET_OPAQUE = None
- SET_OPAQUE = None
- COMPARE_AND_SET = None
- COMPARE_AND_EXCHANGE = None
- COMPARE_AND_EXCHANGE_ACQUIRE = None
- COMPARE_AND_EXCHANGE_RELEASE = None
- WEAK_COMPARE_AND_SET = None
- WEAK_COMPARE_AND_SET_ACQUIRE = None
- WEAK_COMPARE_AND_SET_RELEASE = None
- GET_AND_SET = None
- GET_AND_SET_ACQUIRE = None
- GET_AND_SET_RELEASE = None
- GET_AND_ADD = None
- GET_AND_ADD_ACQUIRE = None
- GET_AND_ADD_RELEASE = None
- GET_AND_BITWISE_OR = None
- GET_AND_BITWISE_OR_ACQUIRE = None
- GET_AND_BITWISE_OR_RELEASE = None
- GET_AND_BITWISE_AND = None
- GET_AND_BITWISE_AND_ACQUIRE = None
- GET_AND_BITWISE_AND_RELEASE = None
- GET_AND_BITWISE_XOR = None
- GET_AND_BITWISE_XOR_ACQUIRE = None
- GET_AND_BITWISE_XOR_RELEASE = None
- GET = None
-
-
-class VarHandle(Stub):
- """java.lang.invoke.VarHandle"""
- def __init__(self, var_type=None, coordinate_types=None):
- super().__init__()
- self._var_type = var_type or object
- self._coordinate_types = list(coordinate_types or [])
- self._access_modes = {}
-
- def get(self, *coordinates):
- return None
-
- def set(self, *coordinates_and_value):
- pass
-
- def getVolatile(self, *coordinates):
- return self.get(*coordinates)
-
- def setVolatile(self, *coordinates_and_value):
- self.set(*coordinates_and_value)
-
- def getAcquire(self, *coordinates):
- return self.get(*coordinates)
-
- def setRelease(self, *coordinates_and_value):
- self.set(*coordinates_and_value)
-
- def getOpaque(self, *coordinates):
- return self.get(*coordinates)
-
- def setOpaque(self, *coordinates_and_value):
- self.set(*coordinates_and_value)
-
- def compareAndSet(self, *args):
- return True
-
- def compareAndExchange(self, *args):
- return args[-2]
-
- def compareAndExchangeAcquire(self, *args):
- return self.compareAndExchange(*args)
-
- def compareAndExchangeRelease(self, *args):
- return self.compareAndExchange(*args)
-
- def weakCompareAndSet(self, *args):
- return True
-
- def weakCompareAndSetAcquire(self, *args):
- return True
-
- def weakCompareAndSetRelease(self, *args):
- return True
-
- def getAndSet(self, *coordinates_and_value):
- return None
-
- def getAndSetAcquire(self, *coordinates_and_value):
- return self.getAndSet(*coordinates_and_value)
-
- def getAndSetRelease(self, *coordinates_and_value):
- return self.getAndSet(*coordinates_and_value)
-
- def getAndAdd(self, *coordinates_and_value):
- return 0
-
- def getAndAddAcquire(self, *coordinates_and_value):
- return self.getAndAdd(*coordinates_and_value)
-
- def getAndAddRelease(self, *coordinates_and_value):
- return self.getAndAdd(*coordinates_and_value)
-
- def getAndBitwiseOr(self, *coordinates_and_value):
- return 0
-
- def getAndBitwiseAnd(self, *coordinates_and_value):
- return 0
-
- def getAndBitwiseXor(self, *coordinates_and_value):
- return 0
-
- def varType(self):
- return self._var_type
-
- def coordinateTypes(self):
- return self._coordinate_types
-
- def toMethodHandle(self, access_mode):
- return MethodHandle(MethodType(self._var_type, self._coordinate_types))
-
- def getAccessModes(self):
- return list(self._access_modes.values())
-
- def isAccessModeSupported(self, access_mode):
- return True
-
- AccessMode = VarHandle_AccessMode
-
- def toString(self):
- return f"VarHandle[{self._var_type}]"
-
-
-# ============================================================
-# Initialize VarHandle_AccessMode constants
-# ============================================================
-
-VarHandle_AccessMode.GET = VarHandle_AccessMode("GET")
-VarHandle_AccessMode.SET = VarHandle_AccessMode("SET")
-VarHandle_AccessMode.GET_VOLATILE = VarHandle_AccessMode("GET_VOLATILE")
-VarHandle_AccessMode.SET_VOLATILE = VarHandle_AccessMode("SET_VOLATILE")
-VarHandle_AccessMode.GET_ACQUIRE = VarHandle_AccessMode("GET_ACQUIRE")
-VarHandle_AccessMode.SET_RELEASE = VarHandle_AccessMode("SET_RELEASE")
-VarHandle_AccessMode.GET_OPAQUE = VarHandle_AccessMode("GET_OPAQUE")
-VarHandle_AccessMode.SET_OPAQUE = VarHandle_AccessMode("SET_OPAQUE")
-VarHandle_AccessMode.COMPARE_AND_SET = VarHandle_AccessMode("COMPARE_AND_SET")
-VarHandle_AccessMode.COMPARE_AND_EXCHANGE = VarHandle_AccessMode("COMPARE_AND_EXCHANGE")
-VarHandle_AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE = VarHandle_AccessMode("COMPARE_AND_EXCHANGE_ACQUIRE")
-VarHandle_AccessMode.COMPARE_AND_EXCHANGE_RELEASE = VarHandle_AccessMode("COMPARE_AND_EXCHANGE_RELEASE")
-VarHandle_AccessMode.WEAK_COMPARE_AND_SET = VarHandle_AccessMode("WEAK_COMPARE_AND_SET")
-VarHandle_AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE = VarHandle_AccessMode("WEAK_COMPARE_AND_SET_ACQUIRE")
-VarHandle_AccessMode.WEAK_COMPARE_AND_SET_RELEASE = VarHandle_AccessMode("WEAK_COMPARE_AND_SET_RELEASE")
-VarHandle_AccessMode.GET_AND_SET = VarHandle_AccessMode("GET_AND_SET")
-VarHandle_AccessMode.GET_AND_SET_ACQUIRE = VarHandle_AccessMode("GET_AND_SET_ACQUIRE")
-VarHandle_AccessMode.GET_AND_SET_RELEASE = VarHandle_AccessMode("GET_AND_SET_RELEASE")
-VarHandle_AccessMode.GET_AND_ADD = VarHandle_AccessMode("GET_AND_ADD")
-VarHandle_AccessMode.GET_AND_ADD_ACQUIRE = VarHandle_AccessMode("GET_AND_ADD_ACQUIRE")
-VarHandle_AccessMode.GET_AND_ADD_RELEASE = VarHandle_AccessMode("GET_AND_ADD_RELEASE")
-VarHandle_AccessMode.GET_AND_BITWISE_OR = VarHandle_AccessMode("GET_AND_BITWISE_OR")
-VarHandle_AccessMode.GET_AND_BITWISE_OR_ACQUIRE = VarHandle_AccessMode("GET_AND_BITWISE_OR_ACQUIRE")
-VarHandle_AccessMode.GET_AND_BITWISE_OR_RELEASE = VarHandle_AccessMode("GET_AND_BITWISE_OR_RELEASE")
-VarHandle_AccessMode.GET_AND_BITWISE_AND = VarHandle_AccessMode("GET_AND_BITWISE_AND")
-VarHandle_AccessMode.GET_AND_BITWISE_AND_ACQUIRE = VarHandle_AccessMode("GET_AND_BITWISE_AND_ACQUIRE")
-VarHandle_AccessMode.GET_AND_BITWISE_AND_RELEASE = VarHandle_AccessMode("GET_AND_BITWISE_AND_RELEASE")
-VarHandle_AccessMode.GET_AND_BITWISE_XOR = VarHandle_AccessMode("GET_AND_BITWISE_XOR")
-VarHandle_AccessMode.GET_AND_BITWISE_XOR_ACQUIRE = VarHandle_AccessMode("GET_AND_BITWISE_XOR_ACQUIRE")
-VarHandle_AccessMode.GET_AND_BITWISE_XOR_RELEASE = VarHandle_AccessMode("GET_AND_BITWISE_XOR_RELEASE")
-
-
-# ============================================================
-# MethodHandleInfo
-# ============================================================
-
-class MethodHandleInfo(Stub):
- """java.lang.invoke.MethodHandleInfo"""
- def __init__(self, reference_kind=0, declaring_class=None, name="", method_type=None):
- super().__init__()
- self._reference_kind = reference_kind
- self._declaring_class = declaring_class
- self._name = name
- self._method_type = method_type or MethodType(object, [])
-
- def getReferenceKind(self):
- return self._reference_kind
-
- def getDeclaringClass(self):
- return self._declaring_class
-
- def getName(self):
- return self._name
-
- def getMethodType(self):
- return self._method_type
-
- def isVarArgs(self):
- return False
-
- def reflectAs(self, expected_type, lookup):
- return None
-
- def toString(self):
- return (f"MethodHandleInfo[{self._name}, kind={self._reference_kind}, "
- f"class={self._declaring_class}, type={self._method_type}]")
-
- # Reference kind constants
- REF_getField = REF_GET_FIELD
- REF_getStatic = REF_GET_STATIC
- REF_putField = REF_PUT_FIELD
- REF_putStatic = REF_PUT_STATIC
- REF_invokeVirtual = REF_INVOKE_VIRTUAL
- REF_invokeStatic = REF_INVOKE_STATIC
- REF_invokeSpecial = REF_INVOKE_SPECIAL
- REF_newInvokeSpecial = REF_NEW_INVOKE_SPECIAL
- REF_invokeInterface = REF_INVOKE_INTERFACE
-
-
-# ============================================================
-# MethodHandleProxies
-# ============================================================
-
-class MethodHandleProxies(Stub):
- """java.lang.invoke.MethodHandleProxies"""
- @staticmethod
- def asInterfaceInstance(iface, target):
- return target
-
- @staticmethod
- def isWrapperClass(cls):
- return False
-
- @staticmethod
- def wrapperInstanceTarget(proxy):
- return None
-
- @staticmethod
- def wrapperInstanceType(proxy):
- return None
-
-
-# ============================================================
-# SerializedLambda
-# ============================================================
-
-class SerializedLambda(Stub):
- """java.lang.invoke.SerializedLambda"""
- def __init__(self):
- super().__init__()
- self._capturing_class = ""
- self._functional_interface_class_name = ""
- self._functional_interface_method_name = ""
- self._functional_interface_method_signature = ""
- self._impl_class = ""
- self._impl_method_name = ""
- self._impl_method_signature = ""
- self._impl_method_kind = 0
- self._captured_args = []
- self._instantiated_method_type = ""
- self._captured_arg_count = 0
-
- def getCapturingClass(self):
- return self._capturing_class
-
- def getFunctionalInterfaceClassName(self):
- return self._functional_interface_class_name
-
- def getFunctionalInterfaceMethodName(self):
- return self._functional_interface_method_name
-
- def getFunctionalInterfaceMethodSignature(self):
- return self._functional_interface_method_signature
-
- def getImplClass(self):
- return self._impl_class
-
- def getImplMethodName(self):
- return self._impl_method_name
-
- def getImplMethodSignature(self):
- return self._impl_method_signature
-
- def getImplMethodKind(self):
- return self._impl_method_kind
-
- def getCapturedArgCount(self):
- return self._captured_arg_count
-
- def getCapturedArg(self, i):
- return self._captured_args[i] if i < len(self._captured_args) else None
-
- def getInstantiatedMethodType(self):
- return self._instantiated_method_type
-
-
-# ============================================================
-# LambdaMetafactory
-# ============================================================
-
-class LambdaMetafactory(Stub):
- """java.lang.invoke.LambdaMetafactory"""
- FLAG_SERIALIZABLE = 1
- FLAG_MARKERS = 2
- FLAG_BRIDGES = 4
-
- @staticmethod
- def metafactory(caller, invoked_name, invoked_type, sam_method_type,
- impl_method, instantiated_method_type, *args):
- return MethodHandle(instantiated_method_type)
-
- @staticmethod
- def altMetafactory(caller, invoked_name, invoked_type, *args):
- return MethodHandle(MethodType(object, []))
-
-
-# ============================================================
-# StringConcatFactory
-# ============================================================
-
-class StringConcatFactory(Stub):
- """java.lang.invoke.StringConcatFactory"""
- @staticmethod
- def makeConcatWithConstants(lookup, name, concat_type, recipe, *constants):
- return MethodHandle(concat_type)
-
- @staticmethod
- def makeConcat(lookup, name, concat_type):
- class ConcatHandle(MethodHandle):
- def invoke(self, *args):
- return "".join(str(a) for a in args)
- return ConcatHandle(concat_type, lambda *args: "".join(str(a) for a in args))
-
-
-# ============================================================
-# UnsupportedOperationException
-# ============================================================
-
-class UnsupportedOperationException(RuntimeException):
- """java.lang.UnsupportedOperationException"""
- pass
-
-
-# ============================================================
-# Alias for MethodHandles.Lookup
-# ============================================================
-
-MethodHandles_Lookup = MethodHandles_Lookup
-MethodHandles.Lookup = MethodHandles_Lookup
-VarHandle.AccessMode = VarHandle_AccessMode
\ No newline at end of file
diff --git a/android_pyapi/java/lang_management.py b/android_pyapi/java/lang_management.py
deleted file mode 100644
index f947ef3..0000000
--- a/android_pyapi/java/lang_management.py
+++ /dev/null
@@ -1,830 +0,0 @@
-"""
-Java java.lang.management standard library APIs implemented in Python.
-java.lang.management package - ManagementFactory, MXBeans, ThreadInfo, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub
-from ..java.lang import RuntimeException, StackTraceElement
-import typing as _typing
-import time as _time
-import os as _os
-import sys as _sys
-import threading as _threading
-import platform as _platform
-
-__all__ = [
- "ManagementFactory", "MemoryMXBean", "MemoryUsage", "MemoryType",
- "MemoryPoolMXBean", "MemoryManagerMXBean", "GarbageCollectorMXBean",
- "ThreadMXBean", "RuntimeMXBean", "ClassLoadingMXBean",
- "OperatingSystemMXBean", "CompilationMXBean",
- "PlatformLoggingMXBean", "PlatformManagedObject",
- "ManagementPermission", "LockInfo", "MonitorInfo", "ThreadInfo",
-]
-
-
-# ============================================================
-# ManagementPermission
-# ============================================================
-
-class ManagementPermission(Stub):
- """java.lang.management.ManagementPermission"""
- def __init__(self, name, actions=None):
- super().__init__()
- self._name = name
- self._actions = actions
-
- def getName(self):
- return self._name
-
- def getActions(self):
- return self._actions or ""
-
- def implies(self, permission):
- return True
-
-
-# ============================================================
-# MemoryType
-# ============================================================
-
-class MemoryType(Stub):
- """java.lang.management.MemoryType"""
- def __init__(self, name):
- super().__init__()
- self._name = name
-
- def toString(self):
- return self._name
-
- HEAP = None
- NON_HEAP = None
-
-
-MemoryType.HEAP = MemoryType("HEAP")
-MemoryType.NON_HEAP = MemoryType("NON_HEAP")
-
-
-# ============================================================
-# MemoryUsage
-# ============================================================
-
-class MemoryUsage(Stub):
- """java.lang.management.MemoryUsage"""
- def __init__(self, init, used, committed, max_val):
- super().__init__()
- self._init = init
- self._used = used
- self._committed = committed
- self._max = max_val
-
- def getInit(self):
- return self._init
-
- def getUsed(self):
- return self._used
-
- def getCommitted(self):
- return self._committed
-
- def getMax(self):
- return self._max
-
- def toString(self):
- return (f"init={self._init} used={self._used} "
- f"committed={self._committed} max={self._max}")
-
-
-# ============================================================
-# LockInfo
-# ============================================================
-
-class LockInfo(Stub):
- """java.lang.management.LockInfo"""
- def __init__(self, class_name, identity_hash_code):
- super().__init__()
- self._class_name = class_name
- self._identity_hash_code = identity_hash_code
-
- def getClassName(self):
- return self._class_name
-
- def getIdentityHashCode(self):
- return self._identity_hash_code
-
- def toString(self):
- return f"{self._class_name}@{self._identity_hash_code:x}"
-
-
-# ============================================================
-# MonitorInfo
-# ============================================================
-
-class MonitorInfo(LockInfo):
- """java.lang.management.MonitorInfo"""
- def __init__(self, class_name, identity_hash_code,
- locked_stack_depth, locked_stack_frame):
- super().__init__(class_name, identity_hash_code)
- self._locked_stack_depth = locked_stack_depth
- self._locked_stack_frame = locked_stack_frame
-
- def getLockedStackDepth(self):
- return self._locked_stack_depth
-
- def getLockedStackFrame(self):
- return self._locked_stack_frame
-
- def toString(self):
- return (f"MonitorInfo[{self._class_name}@{self._identity_hash_code:x}, "
- f"depth={self._locked_stack_depth}]")
-
-
-# ============================================================
-# ThreadInfo
-# ============================================================
-
-class ThreadInfo(Stub):
- """java.lang.management.ThreadInfo"""
- def __init__(self, thread_id=0, thread_name="", thread_state="RUNNABLE",
- blocked_count=0, blocked_time=-1, waited_count=0, waited_time=-1,
- lock_name=None, lock_owner_id=-1, lock_owner_name=None,
- in_native=False, suspended=False, stack_trace=None,
- locked_monitors=None, locked_synchronizers=None,
- daemon=False, priority=5):
- super().__init__()
- self._thread_id = thread_id
- self._thread_name = thread_name
- self._thread_state = thread_state
- self._blocked_count = blocked_count
- self._blocked_time = blocked_time
- self._waited_count = waited_count
- self._waited_time = waited_time
- self._lock_name = lock_name
- self._lock_owner_id = lock_owner_id
- self._lock_owner_name = lock_owner_name
- self._in_native = in_native
- self._suspended = suspended
- self._stack_trace = stack_trace or []
- self._locked_monitors = locked_monitors or []
- self._locked_synchronizers = locked_synchronizers or []
- self._daemon = daemon
- self._priority = priority
-
- def getThreadId(self):
- return self._thread_id
-
- def getThreadName(self):
- return self._thread_name
-
- def getThreadState(self):
- return self._thread_state
-
- def getBlockedCount(self):
- return self._blocked_count
-
- def getBlockedTime(self):
- return self._blocked_time
-
- def getWaitedCount(self):
- return self._waited_count
-
- def getWaitedTime(self):
- return self._waited_time
-
- def getLockName(self):
- return self._lock_name
-
- def getLockOwnerId(self):
- return self._lock_owner_id
-
- def getLockOwnerName(self):
- return self._lock_owner_name
-
- def isInNative(self):
- return self._in_native
-
- def isSuspended(self):
- return self._suspended
-
- def getStackTrace(self):
- return self._stack_trace
-
- def getLockedMonitors(self):
- return self._locked_monitors
-
- def getLockedSynchronizers(self):
- return self._locked_synchronizers
-
- def isDaemon(self):
- return self._daemon
-
- def getPriority(self):
- return self._priority
-
- def toString(self):
- return (f"ThreadInfo[id={self._thread_id}, name={self._thread_name}, "
- f"state={self._thread_state}]")
-
-
-# ============================================================
-# PlatformManagedObject
-# ============================================================
-
-class PlatformManagedObject(Stub):
- """java.lang.management.PlatformManagedObject"""
- def getObjectName(self):
- return None
-
-
-# ============================================================
-# MemoryMXBean
-# ============================================================
-
-class MemoryMXBean(PlatformManagedObject):
- """java.lang.management.MemoryMXBean"""
- def __init__(self):
- super().__init__()
- import psutil as _psutil
- self._psutil_available = False
- try:
- import psutil
- self._psutil = psutil
- self._psutil_available = True
- except ImportError:
- self._psutil_available = False
-
- def getHeapMemoryUsage(self):
- if self._psutil_available:
- mem = self._psutil.virtual_memory()
- return MemoryUsage(mem.total, mem.used, mem.available, mem.total)
- return MemoryUsage(0, 0, 0, 0)
-
- def getNonHeapMemoryUsage(self):
- return MemoryUsage(0, 0, 0, 0)
-
- def getObjectPendingFinalizationCount(self):
- return 0
-
- def isVerbose(self):
- return False
-
- def setVerbose(self, value):
- pass
-
- def gc(self):
- import gc
- gc.collect()
-
-
-# ============================================================
-# MemoryPoolMXBean
-# ============================================================
-
-class MemoryPoolMXBean(PlatformManagedObject):
- """java.lang.management.MemoryPoolMXBean"""
- def __init__(self, name="", pool_type=MemoryType.HEAP):
- super().__init__()
- self._name = name
- self._type = pool_type
- self._usage = MemoryUsage(0, 0, 0, 0)
- self._peak_usage = MemoryUsage(0, 0, 0, 0)
- self._collection_usage = None
- self._valid = True
- self._threshold = 0
- self._collection_threshold = 0
- self._threshold_supported = False
- self._collection_threshold_supported = False
-
- def getName(self):
- return self._name
-
- def getType(self):
- return self._type
-
- def getUsage(self):
- import psutil
- try:
- mem = psutil.virtual_memory()
- self._usage = MemoryUsage(mem.total, mem.used, mem.available, mem.total)
- except ImportError:
- pass
- return self._usage
-
- def getPeakUsage(self):
- return self._peak_usage
-
- def resetPeakUsage(self):
- self._peak_usage = MemoryUsage(0, 0, 0, 0)
-
- def isValid(self):
- return self._valid
-
- def getCollectionUsage(self):
- return self._collection_usage
-
- def getUsageThreshold(self):
- return self._threshold
-
- def setUsageThreshold(self, threshold):
- self._threshold = threshold
- self._threshold_supported = True
-
- def isUsageThresholdSupported(self):
- return self._threshold_supported
-
- def isUsageThresholdExceeded(self):
- return self._usage.getUsed() > self._threshold if self._threshold > 0 else False
-
- def getUsageThresholdCount(self):
- return 0
-
- def getCollectionUsageThreshold(self):
- return self._collection_threshold
-
- def setCollectionUsageThreshold(self, threshold):
- self._collection_threshold = threshold
- self._collection_threshold_supported = True
-
- def isCollectionUsageThresholdSupported(self):
- return self._collection_threshold_supported
-
- def isCollectionUsageThresholdExceeded(self):
- return False
-
- def getCollectionUsageThresholdCount(self):
- return 0
-
- def getMemoryManagerNames(self):
- return []
-
- def toString(self):
- return f"MemoryPoolMXBean[name={self._name}, type={self._type}]"
-
-
-# ============================================================
-# MemoryManagerMXBean
-# ============================================================
-
-class MemoryManagerMXBean(PlatformManagedObject):
- """java.lang.management.MemoryManagerMXBean"""
- def __init__(self, name=""):
- super().__init__()
- self._name = name
- self._valid = True
- self._pool_names = []
-
- def getName(self):
- return self._name
-
- def isValid(self):
- return self._valid
-
- def getMemoryPoolNames(self):
- return self._pool_names
-
- def toString(self):
- return f"MemoryManagerMXBean[name={self._name}]"
-
-
-# ============================================================
-# GarbageCollectorMXBean
-# ============================================================
-
-class GarbageCollectorMXBean(MemoryManagerMXBean):
- """java.lang.management.GarbageCollectorMXBean"""
- def __init__(self, name=""):
- super().__init__(name)
- self._collection_count = 0
- self._collection_time = 0
-
- def getCollectionCount(self):
- return self._collection_count
-
- def getCollectionTime(self):
- return self._collection_time
-
- def toString(self):
- return (f"GarbageCollectorMXBean[name={self._name}, "
- f"collections={self._collection_count}, "
- f"time={self._collection_time}ms]")
-
-
-# ============================================================
-# ThreadMXBean
-# ============================================================
-
-class ThreadMXBean(PlatformManagedObject):
- """java.lang.management.ThreadMXBean"""
- def __init__(self):
- super().__init__()
- self._thread_contention_monitoring_enabled = False
- self._thread_cpu_time_enabled = False
- self._thread_allocated_memory_enabled = False
-
- def getThreadCount(self):
- return _threading.active_count()
-
- def getPeakThreadCount(self):
- return _threading.active_count()
-
- def getTotalStartedThreadCount(self):
- return _threading.active_count()
-
- def getDaemonThreadCount(self):
- return 0
-
- def getAllThreadIds(self):
- return [t.ident for t in _threading.enumerate() if t.ident is not None]
-
- def getThreadInfo(self, thread_id_or_ids, max_depth=None):
- if isinstance(thread_id_or_ids, (list, tuple)):
- return [self._build_thread_info(tid) for tid in thread_id_or_ids]
- return self._build_thread_info(thread_id_or_ids)
-
- def _build_thread_info(self, thread_id):
- for t in _threading.enumerate():
- if t.ident == thread_id:
- return ThreadInfo(
- thread_id=thread_id,
- thread_name=t.name or "",
- thread_state=t.name or "RUNNABLE",
- )
- return ThreadInfo(thread_id=thread_id, thread_name="")
-
- def isThreadContentionMonitoringSupported(self):
- return True
-
- def isThreadContentionMonitoringEnabled(self):
- return self._thread_contention_monitoring_enabled
-
- def setThreadContentionMonitoringEnabled(self, enable):
- self._thread_contention_monitoring_enabled = enable
-
- def isCurrentThreadCpuTimeSupported(self):
- return True
-
- def isThreadCpuTimeEnabled(self):
- return self._thread_cpu_time_enabled
-
- def setThreadCpuTimeEnabled(self, enable):
- self._thread_cpu_time_enabled = enable
-
- def getCurrentThreadCpuTime(self):
- return 0
-
- def getCurrentThreadUserTime(self):
- return 0
-
- def getThreadCpuTime(self, thread_id):
- return 0
-
- def getThreadUserTime(self, thread_id):
- return 0
-
- def isObjectMonitorUsageSupported(self):
- return True
-
- def isSynchronizerUsageSupported(self):
- return True
-
- def findMonitorDeadlockedThreads(self):
- return None
-
- def findDeadlockedThreads(self):
- return None
-
- def resetPeakThreadCount(self):
- pass
-
- def getThreadAllocatedBytes(self, thread_id_or_ids):
- if isinstance(thread_id_or_ids, (list, tuple)):
- return [0] * len(thread_id_or_ids)
- return 0
-
- def isThreadAllocatedMemorySupported(self):
- return True
-
- def isThreadAllocatedMemoryEnabled(self):
- return self._thread_allocated_memory_enabled
-
- def setThreadAllocatedMemoryEnabled(self, enable):
- self._thread_allocated_memory_enabled = enable
-
- def getTotalThreadAllocatedBytes(self):
- return 0
-
-
-# ============================================================
-# RuntimeMXBean
-# ============================================================
-
-class RuntimeMXBean(PlatformManagedObject):
- """java.lang.management.RuntimeMXBean"""
- def __init__(self):
- super().__init__()
- self._start_time = _time.time() * 1000
-
- def getName(self):
- return f"{_os.getpid()}@{_platform.node()}"
-
- getVmName = lambda self: _platform.python_implementation()
- getVmVersion = lambda self: _platform.python_version()
- getVmVendor = lambda self: "Python Software Foundation"
- getSpecName = lambda self: "Python Virtual Machine Specification"
- getSpecVersion = lambda self: _sys.version
- getSpecVendor = lambda self: "Python Software Foundation"
-
- def getManagementSpecVersion(self):
- return "1.0"
-
- def getStartTime(self):
- return self._start_time
-
- def getUptime(self):
- return (_time.time() * 1000) - self._start_time
-
- def getInputArguments(self):
- return _sys.argv[1:]
-
- def getClassPath(self):
- return _sys.path
-
- def getBootClassPath(self):
- return ""
-
- def getLibraryPath(self):
- return _os.environ.get("PATH", "")
-
- def getSystemProperties(self):
- return {
- "java.version": _platform.python_version(),
- "java.vendor": "Python",
- "java.vm.version": _platform.python_version(),
- "os.name": _platform.system(),
- "os.arch": _platform.machine(),
- "os.version": _platform.release(),
- "user.dir": _os.getcwd(),
- "user.home": _os.path.expanduser("~"),
- "user.name": _os.environ.get("USER", ""),
- "line.separator": "\n",
- "file.separator": _os.sep,
- "path.separator": _os.pathsep,
- }
-
- def isBootClassPathSupported(self):
- return False
-
-
-# ============================================================
-# ClassLoadingMXBean
-# ============================================================
-
-class ClassLoadingMXBean(PlatformManagedObject):
- """java.lang.management.ClassLoadingMXBean"""
- def __init__(self):
- super().__init__()
- self._verbose = False
-
- def getTotalLoadedClassCount(self):
- return 0
-
- def getLoadedClassCount(self):
- return 0
-
- def getUnloadedClassCount(self):
- return 0
-
- def isVerbose(self):
- return self._verbose
-
- def setVerbose(self, value):
- self._verbose = value
-
-
-# ============================================================
-# OperatingSystemMXBean
-# ============================================================
-
-class OperatingSystemMXBean(PlatformManagedObject):
- """java.lang.management.OperatingSystemMXBean"""
- def __init__(self):
- super().__init__()
- self._available = False
- try:
- import psutil
- self._psutil = psutil
- self._available = True
- except ImportError:
- self._available = False
-
- def getArch(self):
- return _platform.machine()
-
- def getAvailableProcessors(self):
- return _os.cpu_count() or 1
-
- def getSystemLoadAverage(self):
- if self._available:
- return self._psutil.getloadavg()[0]
- return -1.0
-
- def getName(self):
- return _platform.system()
-
- def getVersion(self):
- return _platform.release()
-
- def getProcessCpuTime(self):
- return 0
-
- def getCommittedVirtualMemorySize(self):
- return 0
-
- def getTotalSwapSpaceSize(self):
- if self._available:
- return self._psutil.swap_memory().total
- return 0
-
- def getFreeSwapSpaceSize(self):
- if self._available:
- return self._psutil.swap_memory().free
- return 0
-
- def getProcessCpuLoad(self):
- return 0.0
-
- def getSystemCpuLoad(self):
- if self._available:
- return self._psutil.cpu_percent(interval=0) / 100.0
- return 0.0
-
- def getTotalPhysicalMemorySize(self):
- if self._available:
- return self._psutil.virtual_memory().total
- return 0
-
- def getFreePhysicalMemorySize(self):
- if self._available:
- return self._psutil.virtual_memory().available
- return 0
-
- def getTotalDiskSpace(self):
- return 0
-
- def getFreeDiskSpace(self):
- return 0
-
- def getSystemUptime(self):
- return _time.time() - _time.monotonic() + _time.monotonic()
-
-
-# ============================================================
-# CompilationMXBean
-# ============================================================
-
-class CompilationMXBean(PlatformManagedObject):
- """java.lang.management.CompilationMXBean"""
- def getName(self):
- return "CPython"
-
- def isCompilationTimeMonitoringSupported(self):
- return False
-
- def getTotalCompilationTime(self):
- return 0
-
-
-# ============================================================
-# PlatformLoggingMXBean
-# ============================================================
-
-class PlatformLoggingMXBean(PlatformManagedObject):
- """java.lang.management.PlatformLoggingMXBean"""
- def getLoggerLevel(self, logger_name):
- return ""
-
- def setLoggerLevel(self, logger_name, level_name):
- pass
-
- def getParentLogger(self, logger_name):
- return ""
-
- def getLoggerNames(self):
- return []
-
-
-# ============================================================
-# ManagementFactory
-# ============================================================
-
-class ManagementFactory(Stub):
- """java.lang.management.ManagementFactory"""
- CLASS_LOADING_MXBEAN_NAME = "java.lang:type=ClassLoading"
- COMPILATION_MXBEAN_NAME = "java.lang:type=Compilation"
- GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE = "java.lang:type=GarbageCollector"
- MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE = "java.lang:type=MemoryManager"
- MEMORY_MXBEAN_NAME = "java.lang:type=Memory"
- MEMORY_POOL_MXBEAN_DOMAIN_TYPE = "java.lang:type=MemoryPool"
- OPERATING_SYSTEM_MXBEAN_NAME = "java.lang:type=OperatingSystem"
- RUNTIME_MXBEAN_NAME = "java.lang:type=Runtime"
- THREAD_MXBEAN_NAME = "java.lang:type=Threading"
- LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging"
-
- _memory_mxbean = None
- _runtime_mxbean = None
- _thread_mxbean = None
- _class_loading_mxbean = None
- _os_mxbean = None
- _compilation_mxbean = None
- _platform_logging_mxbean = None
- _memory_pools = None
- _memory_managers = None
- _gc_mxbeans = None
-
- @staticmethod
- def getMemoryMXBean():
- if ManagementFactory._memory_mxbean is None:
- ManagementFactory._memory_mxbean = MemoryMXBean()
- return ManagementFactory._memory_mxbean
-
- @staticmethod
- def getRuntimeMXBean():
- if ManagementFactory._runtime_mxbean is None:
- ManagementFactory._runtime_mxbean = RuntimeMXBean()
- return ManagementFactory._runtime_mxbean
-
- @staticmethod
- def getThreadMXBean():
- if ManagementFactory._thread_mxbean is None:
- ManagementFactory._thread_mxbean = ThreadMXBean()
- return ManagementFactory._thread_mxbean
-
- @staticmethod
- def getClassLoadingMXBean():
- if ManagementFactory._class_loading_mxbean is None:
- ManagementFactory._class_loading_mxbean = ClassLoadingMXBean()
- return ManagementFactory._class_loading_mxbean
-
- @staticmethod
- def getOperatingSystemMXBean():
- if ManagementFactory._os_mxbean is None:
- ManagementFactory._os_mxbean = OperatingSystemMXBean()
- return ManagementFactory._os_mxbean
-
- @staticmethod
- def getCompilationMXBean():
- if ManagementFactory._compilation_mxbean is None:
- ManagementFactory._compilation_mxbean = CompilationMXBean()
- return ManagementFactory._compilation_mxbean
-
- @staticmethod
- def getPlatformLoggingMXBean():
- if ManagementFactory._platform_logging_mxbean is None:
- ManagementFactory._platform_logging_mxbean = PlatformLoggingMXBean()
- return ManagementFactory._platform_logging_mxbean
-
- @staticmethod
- def getMemoryPoolMXBeans():
- if ManagementFactory._memory_pools is None:
- ManagementFactory._memory_pools = [
- MemoryPoolMXBean("Code Cache", MemoryType.NON_HEAP),
- MemoryPoolMXBean("Metaspace", MemoryType.NON_HEAP),
- MemoryPoolMXBean("Compressed Class Space", MemoryType.NON_HEAP),
- MemoryPoolMXBean("PS Eden Space", MemoryType.HEAP),
- MemoryPoolMXBean("PS Survivor Space", MemoryType.HEAP),
- MemoryPoolMXBean("PS Old Gen", MemoryType.HEAP),
- ]
- return ManagementFactory._memory_pools
-
- @staticmethod
- def getMemoryManagerMXBeans():
- if ManagementFactory._memory_managers is None:
- ManagementFactory._memory_managers = [
- MemoryManagerMXBean("CodeCacheManager"),
- MemoryManagerMXBean("Metaspace Manager"),
- MemoryManagerMXBean("PS Scavenge"),
- MemoryManagerMXBean("PS MarkSweep"),
- ]
- return ManagementFactory._memory_managers
-
- @staticmethod
- def getGarbageCollectorMXBeans():
- if ManagementFactory._gc_mxbeans is None:
- ManagementFactory._gc_mxbeans = [
- GarbageCollectorMXBean("PS Scavenge"),
- GarbageCollectorMXBean("PS MarkSweep"),
- ]
- return ManagementFactory._gc_mxbeans
-
- @staticmethod
- def getPlatformMXBeans(interface_class):
- return []
-
- @staticmethod
- def newPlatformMXBeanProxy(server_connection, mxbean_name, interface_class):
- return None
-
- @staticmethod
- def getPlatformManagedObject(object_name):
- return None
\ No newline at end of file
diff --git a/android_pyapi/java/lang_ref.py b/android_pyapi/java/lang_ref.py
deleted file mode 100644
index d8294ad..0000000
--- a/android_pyapi/java/lang_ref.py
+++ /dev/null
@@ -1,386 +0,0 @@
-"""
-Java java.lang.ref reference APIs implemented in Python.
-java.lang.ref package - Reference, ReferenceQueue, SoftReference, WeakReference, PhantomReference, Finalizer.
-Wraps Python weakref module.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-import weakref as _weakref
-import threading as _threading
-import gc as _gc
-
-__all__ = [
- "Reference", "SoftReference", "WeakReference", "PhantomReference",
- "ReferenceQueue", "Finalizer", "FinalizerReference", "FinalizationWatchdog",
-]
-
-
-# ============================================================
-# ReferenceQueue
-# ============================================================
-
-class ReferenceQueue(Stub):
- """
- java.lang.ref.ReferenceQueue
- A queue that References are appended to when they are enqueued.
- """
-
- def __init__(self):
- super().__init__()
- self._queue: list = []
- self._lock = _threading.Lock()
- self._cond = _threading.Condition(self._lock)
-
- def poll(self):
- """
- Polls to see if a reference object is available.
- Returns the reference if available, None otherwise.
- """
- with self._lock:
- if self._queue:
- return self._queue.pop(0)
- return None
-
- def remove(self, timeout: int = 0):
- """
- Removes the next reference object from this queue, blocking until one is available
- or the timeout expires.
- Args:
- timeout: timeout in milliseconds (0 = indefinite)
- Returns:
- The reference, or None if timeout expired.
- """
- with self._lock:
- if self._queue:
- return self._queue.pop(0)
- if timeout == 0:
- self._cond.wait()
- if self._queue:
- return self._queue.pop(0)
- return None
- else:
- self._cond.wait(timeout / 1000.0)
- if self._queue:
- return self._queue.pop(0)
- return None
-
- def enqueue(self, ref: "Reference") -> bool:
- """
- Enqueues a reference onto this queue.
- Returns True if successful.
- """
- with self._lock:
- self._queue.append(ref)
- self._cond.notify()
- return True
-
- def __len__(self):
- return len(self._queue)
-
-
-# ============================================================
-# Reference (abstract base)
-# ============================================================
-
-class Reference(Stub):
- """
- java.lang.ref.Reference
- Abstract base class for reference objects.
- """
-
- def __init__(self, referent=None, queue: ReferenceQueue = None):
- super().__init__()
- self._referent = referent
- self._queue = queue
- self._enqueued = False
- # Underlying weakref to track referent lifetime
- self._weak = None
- if referent is not None:
- self._weak = _weakref.ref(
- referent,
- self._on_referent_collected
- )
-
- def _on_referent_collected(self, weakref_obj):
- """Called when the referent is garbage collected."""
- if self._queue is not None and not self._enqueued:
- self._enqueued = True
- self._queue.enqueue(self)
-
- def get(self):
- """
- Returns this reference object's referent.
- If the referent has been garbage collected, returns None.
- """
- if self._weak is not None:
- return self._weak()
- return self._referent
-
- def clear(self):
- """Clears this reference object."""
- self._referent = None
- if self._weak is not None:
- self._weak = None
-
- def isEnqueued(self) -> bool:
- """Returns whether this reference object has been enqueued."""
- return self._enqueued
-
- def enqueue(self) -> bool:
- """Enqueues this reference object."""
- if self._queue is not None and not self._enqueued:
- self._enqueued = True
- return self._queue.enqueue(self)
- return False
-
- def clone(self):
- """Creates a shallow copy of this reference."""
- return self.__class__(self.get(), self._queue)
-
- def toString(self) -> str:
- return f"{self.__class__.__name__}@{hex(id(self))}[referent={self.get()}]"
-
- def equals(self, other) -> bool:
- if not isinstance(other, Reference):
- return False
- return self.get() is other.get()
-
- def hashCode(self) -> int:
- r = self.get()
- return hash(r) & 0x7FFFFFFF if r is not None else 0
-
-
-# ============================================================
-# SoftReference
-# ============================================================
-
-class SoftReference(Reference):
- """
- java.lang.ref.SoftReference
- Soft reference objects, cleared at the discretion of the GC.
- """
-
- def __init__(self, referent=None, queue: ReferenceQueue = None):
- super().__init__(referent, queue)
- self._clock = 0
-
- def get(self):
- """Returns the referent; on desktop, soft references are more resilient."""
- return super().get()
-
- def enqueue(self) -> bool:
- return super().enqueue()
-
- def clear(self):
- super().clear()
-
- def toString(self) -> str:
- return f"SoftReference@{hex(id(self))}[referent={self.get()}]"
-
-
-# ============================================================
-# WeakReference
-# ============================================================
-
-class WeakReference(Reference):
- """
- java.lang.ref.WeakReference
- Weak reference objects, cleared automatically by the GC.
- """
-
- def __init__(self, referent=None, queue: ReferenceQueue = None):
- super().__init__(referent, queue)
-
- def toString(self) -> str:
- return f"WeakReference@{hex(id(self))}[referent={self.get()}]"
-
-
-# ============================================================
-# PhantomReference
-# ============================================================
-
-class PhantomReference(Reference):
- """
- java.lang.ref.PhantomReference
- Phantom reference objects. get() always returns None.
- """
-
- def __init__(self, referent=None, queue: ReferenceQueue = None):
- super().__init__(referent, queue)
-
- def get(self):
- """
- Phantom references always return None.
- The referent is phantom-reachable and thus not accessible.
- """
- return None
-
- def toString(self) -> str:
- return f"PhantomReference@{hex(id(self))}[referent=phantom]"
-
-
-# ============================================================
-# FinalizerReference
-# ============================================================
-
-class FinalizerReference(Reference):
- """
- java.lang.ref.FinalizerReference
- Represents a finalizer reference used by the VM's finalization system.
- """
-
- def __init__(self, referent=None, queue: ReferenceQueue = None):
- super().__init__(referent, queue)
- self._finalized = False
- self._finalize_method = None
- if referent is not None and hasattr(referent, "finalize"):
- self._finalize_method = getattr(referent, "finalize", None)
-
- def finalize(self):
- """Invokes the referent's finalize method if it exists."""
- if not self._finalized and self._finalize_method is not None:
- try:
- self._finalize_method()
- except Exception:
- pass
- finally:
- self._finalized = True
-
- def isFinalized(self) -> bool:
- return self._finalized
-
- def toString(self) -> str:
- return f"FinalizerReference@{hex(id(self))}[finalized={self._finalized}]"
-
-
-# ============================================================
-# FinalizationWatchdog
-# ============================================================
-
-class FinalizationWatchdog(Stub):
- """
- java.lang.ref.FinalizationWatchdog
- A watchdog thread that ensures finalizations proceed.
- Desktop stub implementation.
- """
-
- _instance = None
- _running = False
- _thread = None
-
- def __init__(self):
- super().__init__()
- self._timeout = 10000 # 10 seconds
-
- @classmethod
- def getInstance(cls):
- if cls._instance is None:
- cls._instance = FinalizationWatchdog()
- return cls._instance
-
- def start(self):
- """Starts the watchdog thread."""
- if not self._running:
- self._running = True
- self._thread = _threading.Thread(target=self._run, daemon=True)
- self._thread.start()
-
- def stop(self):
- """Stops the watchdog thread."""
- self._running = False
-
- def _run(self):
- """Watchdog loop."""
- while self._running:
- _gc.collect()
- import time
- time.sleep(1)
-
- def setEnabled(self, enabled: bool):
- if enabled:
- self.start()
- else:
- self.stop()
-
- def toString(self) -> str:
- return f"FinalizationWatchdog@{hex(id(self))}[running={self._running}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Finalizer
-# ============================================================
-
-class Finalizer(Stub):
- """
- java.lang.ref.Finalizer
- Manages object finalization. Provides methods to run finalization.
- """
-
- _instance = None
-
- def __init__(self):
- super().__init__()
-
- @classmethod
- def runFinalization(cls):
- """
- Runs the finalization methods of any objects pending finalization.
- Equivalent to calling System.runFinalization().
- """
- _gc.collect()
- for obj in _gc.get_objects():
- if hasattr(obj, "finalize"):
- try:
- obj.finalize()
- except Exception:
- pass
-
- @classmethod
- def runFinalizersOnExit(cls, value: bool):
- """
- Sets whether finalization is enabled on exit.
- Deprecated in Java. Desktop stub.
- """
- if value:
- import atexit
- atexit.register(cls._finalize_all)
-
- @classmethod
- def _finalize_all(cls):
- """Finalize all objects on exit."""
- for obj in _gc.get_objects():
- if hasattr(obj, "finalize"):
- try:
- obj.finalize()
- except Exception:
- pass
-
- @classmethod
- def finalizeAllEnqueued(cls):
- """
- Finalizes all objects that have been enqueued for finalization.
- """
- _gc.collect()
- for obj in _gc.get_objects():
- if hasattr(obj, "finalize"):
- try:
- obj.finalize()
- except Exception:
- pass
-
- def toString(self) -> str:
- return f"Finalizer@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/java/lang_reflect.py b/android_pyapi/java/lang_reflect.py
deleted file mode 100644
index 0df5774..0000000
--- a/android_pyapi/java/lang_reflect.py
+++ /dev/null
@@ -1,968 +0,0 @@
-"""
-Java java.lang.reflect APIs implemented in Python.
-java.lang.reflect package - Field, Method, Constructor, Array, Modifier, Proxy, etc.
-Wraps Python inspect module.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-import inspect as _inspect
-import types as _types
-from typing import Any, List, Optional, Tuple
-
-__all__ = [
- "Field", "Method", "Constructor", "Array", "Modifier",
- "InvocationHandler", "Proxy", "Parameter",
- "AccessibleObject", "Executable",
- "GenericArrayType", "ParameterizedType", "TypeVariable",
- "WildcardType", "GenericDeclaration",
- "AnnotatedType", "AnnotatedArrayType", "AnnotatedParameterizedType",
- "AnnotatedTypeVariable", "AnnotatedWildcardType",
-]
-
-
-# ============================================================
-# Modifier
-# ============================================================
-
-class Modifier(Stub):
- """
- java.lang.reflect.Modifier
- Provides static methods and constants for decoding class and member access modifiers.
- Uses actual JVM modifier bit values.
- """
- PUBLIC: int = 0x0001
- PRIVATE: int = 0x0002
- PROTECTED: int = 0x0004
- STATIC: int = 0x0008
- FINAL: int = 0x0010
- SYNCHRONIZED: int = 0x0020
- VOLATILE: int = 0x0040
- TRANSIENT: int = 0x0080
- NATIVE: int = 0x0100
- INTERFACE: int = 0x0200
- ABSTRACT: int = 0x0400
- STRICT: int = 0x0800
-
- _MODIFIER_NAMES = {
- 0x0001: "public", 0x0002: "private", 0x0004: "protected",
- 0x0008: "static", 0x0010: "final", 0x0020: "synchronized",
- 0x0040: "volatile", 0x0080: "transient", 0x0100: "native",
- 0x0200: "interface", 0x0400: "abstract", 0x0800: "strictfp",
- }
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def isPublic(mod: int) -> bool:
- return (mod & Modifier.PUBLIC) != 0
-
- @staticmethod
- def isPrivate(mod: int) -> bool:
- return (mod & Modifier.PRIVATE) != 0
-
- @staticmethod
- def isProtected(mod: int) -> bool:
- return (mod & Modifier.PROTECTED) != 0
-
- @staticmethod
- def isStatic(mod: int) -> bool:
- return (mod & Modifier.STATIC) != 0
-
- @staticmethod
- def isFinal(mod: int) -> bool:
- return (mod & Modifier.FINAL) != 0
-
- @staticmethod
- def isSynchronized(mod: int) -> bool:
- return (mod & Modifier.SYNCHRONIZED) != 0
-
- @staticmethod
- def isVolatile(mod: int) -> bool:
- return (mod & Modifier.VOLATILE) != 0
-
- @staticmethod
- def isTransient(mod: int) -> bool:
- return (mod & Modifier.TRANSIENT) != 0
-
- @staticmethod
- def isNative(mod: int) -> bool:
- return (mod & Modifier.NATIVE) != 0
-
- @staticmethod
- def isInterface(mod: int) -> bool:
- return (mod & Modifier.INTERFACE) != 0
-
- @staticmethod
- def isAbstract(mod: int) -> bool:
- return (mod & Modifier.ABSTRACT) != 0
-
- @staticmethod
- def isStrict(mod: int) -> bool:
- return (mod & Modifier.STRICT) != 0
-
- @staticmethod
- def toString(mod: int) -> str:
- parts = []
- for bit, name in sorted(Modifier._MODIFIER_NAMES.items()):
- if mod & bit:
- parts.append(name)
- return " ".join(parts)
-
- @staticmethod
- def classModifiers() -> int:
- return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | \
- Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | Modifier.STRICT
-
- @staticmethod
- def constructorModifiers() -> int:
- return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE
-
- @staticmethod
- def fieldModifiers() -> int:
- return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | \
- Modifier.STATIC | Modifier.FINAL | Modifier.TRANSIENT | Modifier.VOLATILE
-
- @staticmethod
- def interfaceModifiers() -> int:
- return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | \
- Modifier.ABSTRACT | Modifier.STATIC | Modifier.STRICT
-
- @staticmethod
- def methodModifiers() -> int:
- return Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | \
- Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | \
- Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.STRICT
-
- @staticmethod
- def parameterModifiers() -> int:
- return Modifier.FINAL
-
-
-# ============================================================
-# AccessibleObject
-# ============================================================
-
-class AccessibleObject(Stub):
- """
- java.lang.reflect.AccessibleObject
- Base class for Field, Method, and Constructor.
- """
-
- def __init__(self):
- super().__init__()
- self._accessible = False
-
- def setAccessible(self, flag: bool):
- """Sets the accessible flag for this object."""
- self._accessible = flag
-
- def isAccessible(self) -> bool:
- """Returns the value of the accessible flag."""
- return self._accessible
-
- def getAnnotation(self, annotation_class: type) -> Optional[Stub]:
- """Returns the annotation for this element (if present)."""
- return None
-
- def getDeclaredAnnotations(self) -> List:
- """Returns all annotations directly present on this element."""
- return []
-
- def getAnnotations(self) -> List:
- """Returns all annotations on this element."""
- return []
-
- def getAnnotationsByType(self, annotation_class: type) -> List:
- """Returns annotations of the specified type on this element."""
- return []
-
- def isAnnotationPresent(self, annotation_class: type) -> bool:
- """Returns True if the specified annotation is present."""
- return False
-
- def toString(self) -> str:
- return f"{self.__class__.__name__}@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Field
-# ============================================================
-
-class Field(AccessibleObject):
- """
- java.lang.reflect.Field
- Provides information about, and dynamic access to, a single field of a class.
- """
-
- def __init__(self, declaring_class: type = None, name: str = None,
- field_type: type = None, modifiers: int = 0):
- super().__init__()
- self._declaring_class = declaring_class
- self._name = name
- self._field_type = field_type
- self._modifiers = modifiers
- self._generic_type = field_type
-
- def getName(self) -> str:
- return self._name or ""
-
- def getType(self) -> type:
- return self._field_type or object
-
- def getModifiers(self) -> int:
- return self._modifiers
-
- def get(self, obj: Any) -> Any:
- """Returns the value of the field on the given object."""
- if self._name is None:
- return None
- if obj is None and Modifier.isStatic(self._modifiers):
- # Static field access on the class
- if self._declaring_class and hasattr(self._declaring_class, self._name):
- return getattr(self._declaring_class, self._name)
- return None
- if obj is not None and hasattr(obj, self._name):
- return getattr(obj, self._name)
- return None
-
- def set(self, obj: Any, value: Any):
- """Sets the field on the given object to the given value."""
- if self._name is None:
- return
- if obj is None and Modifier.isStatic(self._modifiers):
- if self._declaring_class:
- setattr(self._declaring_class, self._name, value)
- return
- if obj is not None and hasattr(obj, self._name):
- setattr(obj, self._name, value)
-
- def setAccessible(self, flag: bool):
- self._accessible = flag
-
- def getDeclaringClass(self) -> type:
- return self._declaring_class
-
- def getGenericType(self):
- return self._generic_type
-
- def getAnnotation(self, annotation_class: type):
- return None
-
- def getDeclaredAnnotations(self) -> List:
- return []
-
- def isAccessible(self) -> bool:
- return self._accessible
-
- def isSynthetic(self) -> bool:
- return False
-
- def toGenericString(self) -> str:
- return f"{Modifier.toString(self._modifiers)} {self._field_type.__name__ if self._field_type else '?'} {self._name}"
-
- def getBoolean(self, obj: Any) -> bool:
- val = self.get(obj)
- return bool(val) if val is not None else False
-
- def getByte(self, obj: Any) -> int:
- val = self.get(obj)
- return int(val) if val is not None else 0
-
- def getChar(self, obj: Any) -> str:
- val = self.get(obj)
- return str(val)[0] if val else '\0'
-
- def getShort(self, obj: Any) -> int:
- val = self.get(obj)
- return int(val) if val is not None else 0
-
- def getInt(self, obj: Any) -> int:
- val = self.get(obj)
- return int(val) if val is not None else 0
-
- def getLong(self, obj: Any) -> int:
- val = self.get(obj)
- return int(val) if val is not None else 0
-
- def getFloat(self, obj: Any) -> float:
- val = self.get(obj)
- return float(val) if val is not None else 0.0
-
- def getDouble(self, obj: Any) -> float:
- val = self.get(obj)
- return float(val) if val is not None else 0.0
-
- def setBoolean(self, obj: Any, value: bool):
- self.set(obj, value)
-
- def setByte(self, obj: Any, value: int):
- self.set(obj, value)
-
- def setChar(self, obj: Any, value: str):
- self.set(obj, value)
-
- def setShort(self, obj: Any, value: int):
- self.set(obj, value)
-
- def setInt(self, obj: Any, value: int):
- self.set(obj, value)
-
- def setLong(self, obj: Any, value: int):
- self.set(obj, value)
-
- def setFloat(self, obj: Any, value: float):
- self.set(obj, value)
-
- def setDouble(self, obj: Any, value: float):
- self.set(obj, value)
-
- def toString(self) -> str:
- return self.toGenericString()
-
- def equals(self, other) -> bool:
- if not isinstance(other, Field):
- return False
- return (self._declaring_class == other._declaring_class and
- self._name == other._name and
- self._field_type == other._field_type)
-
- def hashCode(self) -> int:
- return hash((self._declaring_class, self._name)) & 0x7FFFFFFF
-
-
-# ============================================================
-# Executable (abstract base for Method & Constructor)
-# ============================================================
-
-class Executable(AccessibleObject):
- """
- java.lang.reflect.Executable
- Shared base for Method and Constructor.
- """
-
- def __init__(self, declaring_class: type = None, name: str = None,
- parameter_types: List[type] = None, exception_types: List[type] = None,
- modifiers: int = 0):
- super().__init__()
- self._declaring_class = declaring_class
- self._name = name
- self._parameter_types = parameter_types or []
- self._exception_types = exception_types or []
- self._modifiers = modifiers
-
- def getParameterTypes(self) -> List[type]:
- return list(self._parameter_types)
-
- def getParameterCount(self) -> int:
- return len(self._parameter_types)
-
- def getExceptionTypes(self) -> List[type]:
- return list(self._exception_types)
-
- def getModifiers(self) -> int:
- return self._modifiers
-
- def getDeclaringClass(self) -> type:
- return self._declaring_class
-
- def getName(self) -> str:
- return self._name or ""
-
- def getAnnotation(self, annotation_class: type):
- return None
-
- def getDeclaredAnnotations(self) -> List:
- return []
-
- def getParameterAnnotations(self) -> List[List]:
- return [[] for _ in self._parameter_types]
-
- def isVarArgs(self) -> bool:
- return False
-
- def isSynthetic(self) -> bool:
- return False
-
- def toGenericString(self) -> str:
- return f"{Modifier.toString(self._modifiers)} {self._name}({', '.join(t.__name__ for t in self._parameter_types)})"
-
- def toString(self) -> str:
- return self.toGenericString()
-
- def equals(self, other) -> bool:
- if not isinstance(other, Executable):
- return False
- return (self._declaring_class == other._declaring_class and
- self._name == other._name and
- self._parameter_types == other._parameter_types)
-
- def hashCode(self) -> int:
- return hash((self._declaring_class, self._name)) & 0x7FFFFFFF
-
-
-# ============================================================
-# Method
-# ============================================================
-
-class Method(Executable):
- """
- java.lang.reflect.Method
- Provides information about, and access to, a single method of a class.
- """
-
- def __init__(self, declaring_class: type = None, name: str = None,
- return_type: type = None, parameter_types: List[type] = None,
- exception_types: List[type] = None, modifiers: int = 0,
- impl_func: callable = None):
- super().__init__(declaring_class, name, parameter_types, exception_types, modifiers)
- self._return_type = return_type
- self._impl_func = impl_func
- self._generic_return_type = return_type
- self._generic_parameter_types = parameter_types or []
-
- def getReturnType(self) -> type:
- return self._return_type or type(None)
-
- def getGenericReturnType(self):
- return self._generic_return_type
-
- def getGenericParameterTypes(self) -> List:
- return list(self._generic_parameter_types)
-
- def invoke(self, obj: Any, *args) -> Any:
- """
- Invokes the underlying method on the given object with the given args.
- """
- if self._impl_func is not None:
- return self._impl_func(obj, *args)
-
- if self._name is None:
- return None
-
- # Try to call the method on the object
- if obj is not None and hasattr(obj, self._name):
- method = getattr(obj, self._name)
- if callable(method):
- return method(*args)
-
- # Static call on class
- if self._declaring_class and hasattr(self._declaring_class, self._name):
- method = getattr(self._declaring_class, self._name)
- if callable(method):
- return method(*args)
-
- return None
-
- def getDefaultValue(self):
- """Returns the default value for the annotation member."""
- return None
-
- def isBridge(self) -> bool:
- return False
-
- def toGenericString(self) -> str:
- ret = self._return_type.__name__ if self._return_type else "void"
- params = ', '.join(t.__name__ for t in self._parameter_types)
- return f"{Modifier.toString(self._modifiers)} {ret} {self._name}({params})"
-
- def toString(self) -> str:
- return self.toGenericString()
-
- def equals(self, other) -> bool:
- if not isinstance(other, Method):
- return False
- return (self._declaring_class == other._declaring_class and
- self._name == other._name and
- self._parameter_types == other._parameter_types)
-
- def hashCode(self) -> int:
- return hash((self._declaring_class, self._name)) & 0x7FFFFFFF
-
-
-# ============================================================
-# Constructor
-# ============================================================
-
-class Constructor(Executable):
- """
- java.lang.reflect.Constructor
- Provides information about, and access to, a single constructor of a class.
- """
-
- def __init__(self, declaring_class: type = None,
- parameter_types: List[type] = None,
- exception_types: List[type] = None,
- modifiers: int = 0):
- super().__init__(declaring_class, declaring_class.__name__ if declaring_class else "",
- parameter_types, exception_types, modifiers)
-
- def newInstance(self, *args) -> Any:
- """Creates a new instance of the declaring class."""
- if self._declaring_class is None:
- raise AndroidOnlyError("No declaring class for constructor")
- try:
- return self._declaring_class(*args)
- except Exception as e:
- raise AndroidOnlyError(f"Cannot instantiate {self._declaring_class}: {e}")
-
- def toGenericString(self) -> str:
- params = ', '.join(t.__name__ for t in self._parameter_types)
- return f"{Modifier.toString(self._modifiers)} {self._name}({params})"
-
- def toString(self) -> str:
- return self.toGenericString()
-
- def equals(self, other) -> bool:
- if not isinstance(other, Constructor):
- return False
- return (self._declaring_class == other._declaring_class and
- self._parameter_types == other._parameter_types)
-
- def hashCode(self) -> int:
- return hash((self._declaring_class, tuple(self._parameter_types))) & 0x7FFFFFFF
-
-
-# ============================================================
-# Array
-# ============================================================
-
-class Array(Stub):
- """
- java.lang.reflect.Array
- Provides static methods to dynamically create and access arrays.
- """
-
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def newInstance(component_type: type, *dimensions) -> Any:
- """Creates a new array with the specified component type and dimensions."""
- if len(dimensions) == 1:
- return [None] * dimensions[0]
- # Multi-dimensional
- result = []
- for _ in range(dimensions[0]):
- result.append(Array.newInstance(component_type, *dimensions[1:]))
- return result
-
- @staticmethod
- def getLength(array: Any) -> int:
- """Returns the length of the specified array."""
- return len(array)
-
- @staticmethod
- def get(array: Any, index: int) -> Any:
- """Returns the element at the specified index."""
- return array[index]
-
- @staticmethod
- def set(array: Any, index: int, value: Any):
- """Sets the element at the specified index."""
- array[index] = value
-
- @staticmethod
- def getBoolean(array: Any, index: int) -> bool:
- return bool(array[index])
-
- @staticmethod
- def getByte(array: Any, index: int) -> int:
- return int(array[index])
-
- @staticmethod
- def getChar(array: Any, index: int) -> str:
- return str(array[index])
-
- @staticmethod
- def getShort(array: Any, index: int) -> int:
- return int(array[index])
-
- @staticmethod
- def getInt(array: Any, index: int) -> int:
- return int(array[index])
-
- @staticmethod
- def getLong(array: Any, index: int) -> int:
- return int(array[index])
-
- @staticmethod
- def getFloat(array: Any, index: int) -> float:
- return float(array[index])
-
- @staticmethod
- def getDouble(array: Any, index: int) -> float:
- return float(array[index])
-
- @staticmethod
- def setBoolean(array: Any, index: int, value: bool):
- array[index] = value
-
- @staticmethod
- def setByte(array: Any, index: int, value: int):
- array[index] = value
-
- @staticmethod
- def setChar(array: Any, index: int, value: str):
- array[index] = value
-
- @staticmethod
- def setShort(array: Any, index: int, value: int):
- array[index] = value
-
- @staticmethod
- def setInt(array: Any, index: int, value: int):
- array[index] = value
-
- @staticmethod
- def setLong(array: Any, index: int, value: int):
- array[index] = value
-
- @staticmethod
- def setFloat(array: Any, index: int, value: float):
- array[index] = value
-
- @staticmethod
- def setDouble(array: Any, index: int, value: float):
- array[index] = value
-
-
-# ============================================================
-# Parameter
-# ============================================================
-
-class Parameter(AccessibleObject):
- """
- java.lang.reflect.Parameter
- Information about a method parameter.
- """
-
- def __init__(self, name: str = None, param_type: type = None,
- modifiers: int = 0, is_implicit: bool = False,
- is_name_present: bool = True):
- super().__init__()
- self._name = name or ""
- self._param_type = param_type or object
- self._modifiers = modifiers
- self._is_implicit = is_implicit
- self._is_name_present = is_name_present
- self._parameterized_type = param_type
-
- def getName(self) -> str:
- return self._name
-
- def getType(self) -> type:
- return self._param_type
-
- def getParameterizedType(self):
- return self._parameterized_type
-
- def getModifiers(self) -> int:
- return self._modifiers
-
- def isNamePresent(self) -> bool:
- return self._is_name_present
-
- def isImplicit(self) -> bool:
- return self._is_implicit
-
- def isSynthetic(self) -> bool:
- return False
-
- def isVarArgs(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"{Modifier.toString(self._modifiers)} {self._param_type.__name__} {self._name}"
-
- def equals(self, other) -> bool:
- if not isinstance(other, Parameter):
- return False
- return (self._name == other._name and
- self._param_type == other._param_type)
-
- def hashCode(self) -> int:
- return hash((self._name, self._param_type)) & 0x7FFFFFFF
-
-
-# ============================================================
-# InvocationHandler
-# ============================================================
-
-class InvocationHandler(Stub):
- """
- java.lang.reflect.InvocationHandler
- Interface for invocation handlers of proxy instances.
- """
-
- def invoke(self, proxy: Any, method: Any, args: List) -> Any:
- """Processes a method invocation on a proxy instance."""
- raise NotImplementedError("invoke must be implemented by subclass")
-
-
-# ============================================================
-# Proxy
-# ============================================================
-
-class Proxy(Stub):
- """
- java.lang.reflect.Proxy
- Provides static methods for creating dynamic proxy classes and instances.
- """
-
- _invocation_handler: InvocationHandler = None
-
- def __init__(self, handler: InvocationHandler = None):
- super().__init__()
- self._invocation_handler = handler
-
- @staticmethod
- def newProxyInstance(class_loader: Any, interfaces: List[type],
- handler: InvocationHandler) -> Stub:
- """Creates a proxy instance for the specified interfaces."""
- proxy = Proxy(handler)
- proxy._interfaces = interfaces
- return proxy
-
- @staticmethod
- def getInvocationHandler(proxy: Any) -> InvocationHandler:
- """Returns the invocation handler for the specified proxy instance."""
- if isinstance(proxy, Proxy):
- return proxy._invocation_handler
- return None
-
- @staticmethod
- def getProxyClass(class_loader: Any, interfaces: List[type]) -> type:
- """Returns the proxy class for the specified interfaces."""
- return Proxy
-
- @staticmethod
- def isProxyClass(cls: type) -> bool:
- """Returns True if the class is a proxy class."""
- return cls == Proxy or (hasattr(cls, '__bases__') and Proxy in cls.__bases__)
-
- def toString(self) -> str:
- return f"Proxy@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Generic Array Type (stub interface)
-# ============================================================
-
-class GenericArrayType(Stub):
- """
- java.lang.reflect.GenericArrayType
- Represents an array type whose component type is a parameterized type or type variable.
- """
- def __init__(self, generic_component_type=None):
- super().__init__()
- self._generic_component_type = generic_component_type
-
- def getGenericComponentType(self):
- return self._generic_component_type
-
- def toString(self) -> str:
- return f"{self._generic_component_type}[]"
-
-
-# ============================================================
-# ParameterizedType
-# ============================================================
-
-class ParameterizedType(Stub):
- """
- java.lang.reflect.ParameterizedType
- Represents a parameterized type, e.g. List.
- """
- def __init__(self, raw_type=None, actual_type_arguments=None, owner_type=None):
- super().__init__()
- self._raw_type = raw_type
- self._actual_type_arguments = actual_type_arguments or []
- self._owner_type = owner_type
-
- def getRawType(self):
- return self._raw_type
-
- def getActualTypeArguments(self):
- return list(self._actual_type_arguments)
-
- def getOwnerType(self):
- return self._owner_type
-
- def toString(self) -> str:
- args = ', '.join(str(a) for a in self._actual_type_arguments)
- return f"{self._raw_type}<{args}>"
-
-
-# ============================================================
-# TypeVariable
-# ============================================================
-
-class TypeVariable(Stub):
- """
- java.lang.reflect.TypeVariable
- Represents a type variable, like T in Foo.
- """
- def __init__(self, name: str = None, bounds: List = None,
- generic_declaration: Any = None):
- super().__init__()
- self._name = name or "T"
- self._bounds = bounds or [object]
- self._generic_declaration = generic_declaration
-
- def getName(self) -> str:
- return self._name
-
- def getBounds(self) -> List:
- return list(self._bounds)
-
- def getGenericDeclaration(self) -> Any:
- return self._generic_declaration
-
- def toString(self) -> str:
- return self._name
-
-
-# ============================================================
-# WildcardType
-# ============================================================
-
-class WildcardType(Stub):
- """
- java.lang.reflect.WildcardType
- Represents a wildcard type, like ?, ? extends T, ? super T.
- """
- def __init__(self, upper_bounds: List = None, lower_bounds: List = None):
- super().__init__()
- self._upper_bounds = upper_bounds or [object]
- self._lower_bounds = lower_bounds or []
-
- def getUpperBounds(self) -> List:
- return list(self._upper_bounds)
-
- def getLowerBounds(self) -> List:
- return list(self._lower_bounds)
-
- def toString(self) -> str:
- if self._lower_bounds:
- return f"? super {self._lower_bounds[0]}"
- if self._upper_bounds and self._upper_bounds[0] is not object:
- return f"? extends {self._upper_bounds[0]}"
- return "?"
-
-
-# ============================================================
-# GenericDeclaration
-# ============================================================
-
-class GenericDeclaration(Stub):
- """
- java.lang.reflect.GenericDeclaration
- Interface for entities that declare type variables.
- """
- def getTypeParameters(self) -> List[TypeVariable]:
- return []
-
- def toGenericString(self) -> str:
- return self.toString()
-
-
-# ============================================================
-# AnnotatedType interfaces
-# ============================================================
-
-class AnnotatedType(Stub):
- """
- java.lang.reflect.AnnotatedType
- Represents an annotated type.
- """
- def __init__(self, type_=None, annotations: List = None):
- super().__init__()
- self._type = type_
- self._annotations = annotations or []
-
- def getType(self):
- return self._type
-
- def getAnnotations(self) -> List:
- return list(self._annotations)
-
- def getAnnotation(self, annotation_class: type):
- for a in self._annotations:
- if isinstance(a, annotation_class):
- return a
- return None
-
- def toString(self) -> str:
- return str(self._type) if self._type else "?"
-
-
-class AnnotatedArrayType(AnnotatedType):
- """
- java.lang.reflect.AnnotatedArrayType
- Represents an annotated array type.
- """
- def __init__(self, annotated_generic_component_type=None, type_=None, annotations=None):
- super().__init__(type_, annotations)
- self._annotated_generic_component_type = annotated_generic_component_type
-
- def getAnnotatedGenericComponentType(self) -> AnnotatedType:
- return self._annotated_generic_component_type
-
-
-class AnnotatedParameterizedType(AnnotatedType):
- """
- java.lang.reflect.AnnotatedParameterizedType
- Represents an annotated parameterized type.
- """
- def __init__(self, annotated_actual_type_arguments=None, type_=None, annotations=None):
- super().__init__(type_, annotations)
- self._annotated_actual_type_arguments = annotated_actual_type_arguments or []
-
- def getAnnotatedActualTypeArguments(self) -> List[AnnotatedType]:
- return list(self._annotated_actual_type_arguments)
-
-
-class AnnotatedTypeVariable(AnnotatedType):
- """
- java.lang.reflect.AnnotatedTypeVariable
- Represents an annotated type variable.
- """
- def __init__(self, annotated_bounds=None, type_=None, annotations=None):
- super().__init__(type_, annotations)
- self._annotated_bounds = annotated_bounds or []
-
- def getAnnotatedBounds(self) -> List[AnnotatedType]:
- return list(self._annotated_bounds)
-
-
-class AnnotatedWildcardType(AnnotatedType):
- """
- java.lang.reflect.AnnotatedWildcardType
- Represents an annotated wildcard type.
- """
- def __init__(self, annotated_upper_bounds=None, annotated_lower_bounds=None,
- type_=None, annotations=None):
- super().__init__(type_, annotations)
- self._annotated_upper_bounds = annotated_upper_bounds or []
- self._annotated_lower_bounds = annotated_lower_bounds or []
-
- def getAnnotatedUpperBounds(self) -> List[AnnotatedType]:
- return list(self._annotated_upper_bounds)
-
- def getAnnotatedLowerBounds(self) -> List[AnnotatedType]:
- return list(self._annotated_lower_bounds)
\ No newline at end of file
diff --git a/android_pyapi/java/math.py b/android_pyapi/java/math.py
deleted file mode 100644
index bdbf2c7..0000000
--- a/android_pyapi/java/math.py
+++ /dev/null
@@ -1,683 +0,0 @@
-"""
-Java math standard library APIs implemented in Python.
-java.math package - BigInteger, BigDecimal, MathContext, RoundingMode.
-"""
-
-from .._core import Stub
-from .lang import Comparable
-from decimal import (
- Decimal as _Decimal,
- ROUND_DOWN as _DEC_ROUND_DOWN,
- ROUND_HALF_UP as _DEC_ROUND_HALF_UP,
- ROUND_HALF_EVEN as _DEC_ROUND_HALF_EVEN,
- ROUND_UP as _DEC_ROUND_UP,
- ROUND_CEILING as _DEC_ROUND_CEILING,
- ROUND_FLOOR as _DEC_ROUND_FLOOR,
- ROUND_HALF_DOWN as _DEC_ROUND_HALF_DOWN,
- localcontext as _local_context,
- getcontext as _get_context,
-)
-import random as _random
-import math as _py_math
-import sys as _sys
-
-__all__ = [
- "BigInteger", "BigDecimal", "MathContext", "RoundingMode",
-]
-
-
-# ============================================================
-# RoundingMode
-# ============================================================
-
-class RoundingMode(Stub):
- UP = 0
- DOWN = 1
- CEILING = 2
- FLOOR = 3
- HALF_UP = 4
- HALF_DOWN = 5
- HALF_EVEN = 6
- UNNECESSARY = 7
-
- _names = {
- 0: "UP", 1: "DOWN", 2: "CEILING", 3: "FLOOR",
- 4: "HALF_UP", 5: "HALF_DOWN", 6: "HALF_EVEN", 7: "UNNECESSARY",
- }
-
- _py_map = {
- 0: _DEC_ROUND_UP,
- 1: _DEC_ROUND_DOWN,
- 2: _DEC_ROUND_CEILING,
- 3: _DEC_ROUND_FLOOR,
- 4: _DEC_ROUND_HALF_UP,
- 5: _DEC_ROUND_HALF_DOWN,
- 6: _DEC_ROUND_HALF_EVEN,
- 7: _DEC_ROUND_HALF_EVEN, # closest approximation
- }
-
- def __init__(self, value):
- super().__init__()
- self._value = value
-
- def toString(self):
- return self._names.get(self._value, "UNKNOWN")
-
-
-# ============================================================
-# MathContext
-# ============================================================
-
-class MathContext(Stub):
- UNLIMITED = None
- DECIMAL32 = None
- DECIMAL64 = None
- DECIMAL128 = None
-
- def __init__(self, *args):
- super().__init__()
- if len(args) == 1:
- if isinstance(args[0], str):
- s = args[0].strip().lower()
- if s == "precision=7 roundingmode=half_even":
- self._precision = 7
- self._rounding_mode = RoundingMode.HALF_EVEN
- elif s == "precision=16 roundingmode=half_even":
- self._precision = 16
- self._rounding_mode = RoundingMode.HALF_EVEN
- elif s == "precision=34 roundingmode=half_even":
- self._precision = 34
- self._rounding_mode = RoundingMode.HALF_EVEN
- else:
- self._precision = 0
- self._rounding_mode = RoundingMode.HALF_UP
- else:
- self._precision = int(args[0])
- self._rounding_mode = RoundingMode.HALF_UP
- elif len(args) == 2:
- self._precision = int(args[0])
- self._rounding_mode = args[1]
-
- def getPrecision(self):
- return self._precision
-
- def getRoundingMode(self):
- return self._rounding_mode
-
- def equals(self, other):
- if isinstance(other, MathContext):
- return (self._precision == other._precision and
- self._rounding_mode == other._rounding_mode)
- return False
-
- def hashCode(self):
- return hash((self._precision, self._rounding_mode)) & 0x7FFFFFFF
-
- def toString(self):
- return f"precision={self._precision} roundingMode={self._rounding_mode.toString()}"
-
-
-MathContext.UNLIMITED = MathContext(0)
-MathContext.DECIMAL32 = MathContext(7, RoundingMode.HALF_EVEN)
-MathContext.DECIMAL64 = MathContext(16, RoundingMode.HALF_EVEN)
-MathContext.DECIMAL128 = MathContext(34, RoundingMode.HALF_EVEN)
-
-
-# ============================================================
-# BigInteger
-# ============================================================
-
-class BigInteger(Comparable):
- ZERO = None
- ONE = None
- TEN = None
-
- def __init__(self, *args):
- super().__init__()
- if len(args) == 0:
- self._value = 0
- elif len(args) == 1:
- if isinstance(args[0], str):
- self._value = int(str(args[0]))
- elif isinstance(args[0], bytes):
- self._value = int.from_bytes(args[0], byteorder="big", signed=True)
- elif isinstance(args[0], bytearray):
- self._value = int.from_bytes(bytes(args[0]), byteorder="big", signed=True)
- elif isinstance(args[0], int):
- self._value = args[0]
- elif isinstance(args[0], BigInteger):
- self._value = args[0]._value
- else:
- self._value = int(args[0])
- elif len(args) == 2:
- if isinstance(args[1], _random.Random):
- bit_length, rng = args
- self._value = rng.getrandbits(bit_length)
- elif isinstance(args[1], int):
- val_str, radix = args
- self._value = int(str(val_str), radix)
- else:
- self._value = int.from_bytes(bytes(args[0]), byteorder="big", signed=True)
- else:
- self._value = 0
-
- @staticmethod
- def valueOf(val):
- if isinstance(val, int):
- if val == 0:
- return BigInteger.ZERO
- if val == 1:
- return BigInteger.ONE
- if val == 10:
- return BigInteger.TEN
- return BigInteger(val)
-
- def add(self, other):
- if isinstance(other, BigInteger):
- return BigInteger(self._value + other._value)
- return BigInteger(self._value + int(other))
-
- def subtract(self, other):
- if isinstance(other, BigInteger):
- return BigInteger(self._value - other._value)
- return BigInteger(self._value - int(other))
-
- def multiply(self, other):
- if isinstance(other, BigInteger):
- return BigInteger(self._value * other._value)
- return BigInteger(self._value * int(other))
-
- def divide(self, other):
- if isinstance(other, BigInteger):
- return BigInteger(self._value // other._value)
- return BigInteger(self._value // int(other))
-
- def pow(self, exponent):
- return BigInteger(self._value ** exponent)
-
- def gcd(self, other):
- return BigInteger(_py_math.gcd(self._value, other._value if isinstance(other, BigInteger) else int(other)))
-
- def abs(self):
- return BigInteger(abs(self._value))
-
- def negate(self):
- return BigInteger(-self._value)
-
- def signum(self):
- if self._value > 0:
- return 1
- if self._value < 0:
- return -1
- return 0
-
- def mod(self, m):
- if isinstance(m, BigInteger):
- return BigInteger(self._value % m._value)
- return BigInteger(self._value % int(m))
-
- def remainder(self, other):
- if isinstance(other, BigInteger):
- return BigInteger(self._value % other._value)
- return BigInteger(self._value % int(other))
-
- def and_(self, other):
- return BigInteger(self._value & (other._value if isinstance(other, BigInteger) else int(other)))
-
- def or_(self, other):
- return BigInteger(self._value | (other._value if isinstance(other, BigInteger) else int(other)))
-
- def xor(self, other):
- return BigInteger(self._value ^ (other._value if isinstance(other, BigInteger) else int(other)))
-
- def not_(self):
- return BigInteger(~self._value)
-
- def andNot(self, other):
- return BigInteger(self._value & ~(other._value if isinstance(other, BigInteger) else int(other)))
-
- def shiftLeft(self, n):
- return BigInteger(self._value << n)
-
- def shiftRight(self, n):
- return BigInteger(self._value >> n)
-
- def getLowestSetBit(self):
- if self._value == 0:
- return -1
- return (self._value & -self._value).bit_length() - 1
-
- def bitLength(self):
- if self._value == 0:
- return 0
- return self._value.bit_length()
-
- def bitCount(self):
- return bin(self._value & ((1 << self.bitLength()) - 1) if self._value >= 0 else self._value).count("1")
-
- def isProbablePrime(self, certainty):
- if abs(self._value) < 2:
- return False
- if abs(self._value) == 2 or abs(self._value) == 3:
- return True
- if self._value % 2 == 0:
- return False
- d = self._value - 1
- s = 0
- while d % 2 == 0:
- d //= 2
- s += 1
- for _ in range(min(certainty, 20)):
- a = _random.randrange(2, min(self._value - 1, 1000000))
- x = pow(a, d, self._value)
- if x == 1 or x == self._value - 1:
- continue
- for _ in range(s - 1):
- x = pow(x, 2, self._value)
- if x == self._value - 1:
- break
- else:
- return False
- return True
-
- def nextProbablePrime(self):
- v = self._value + 1
- if v < 3:
- return BigInteger(2) if v <= 2 else BigInteger(3)
- while True:
- if v % 2 == 0:
- v += 1
- for i in range(3, int(_py_math.sqrt(v)) + 1, 2):
- if v % i == 0:
- break
- else:
- return BigInteger(v)
- v += 2
-
- def compareTo(self, other):
- if isinstance(other, BigInteger):
- return (self._value > other._value) - (self._value < other._value)
- return -1
-
- def equals(self, other):
- if isinstance(other, BigInteger):
- return self._value == other._value
- return False
-
- def toByteArray(self):
- if self._value == 0:
- return b"\x00"
- byte_length = (self._value.bit_length() + 8) // 8
- return self._value.to_bytes(byte_length, byteorder="big", signed=True)
-
- def toString(self, radix=10):
- if radix == 10:
- return str(self._value)
- if radix == 16:
- return hex(self._value)[2:]
- if radix == 8:
- return oct(self._value)[2:]
- if radix == 2:
- return bin(self._value)[2:]
- return str(self._value)
-
- def intValue(self):
- return self._value & 0xFFFFFFFF
-
- def longValue(self):
- return self._value
-
- def floatValue(self):
- return float(self._value)
-
- def doubleValue(self):
- return float(self._value)
-
- def min(self, other):
- return BigInteger(min(self._value, other._value if isinstance(other, BigInteger) else int(other)))
-
- def max(self, other):
- return BigInteger(max(self._value, other._value if isinstance(other, BigInteger) else int(other)))
-
- def modPow(self, exponent, m):
- if isinstance(exponent, BigInteger):
- exp_val = exponent._value
- else:
- exp_val = int(exponent)
- mod_val = m._value if isinstance(m, BigInteger) else int(m)
- return BigInteger(pow(self._value, exp_val, mod_val))
-
- def modInverse(self, m):
- mod_val = m._value if isinstance(m, BigInteger) else int(m)
- return BigInteger(pow(self._value, -1, mod_val))
-
- def divideAndRemainder(self, other):
- if isinstance(other, BigInteger):
- divisor = other._value
- else:
- divisor = int(other)
- q = self._value // divisor
- r = self._value % divisor
- return [BigInteger(q), BigInteger(r)]
-
- def __int__(self):
- return self._value
-
- def __str__(self):
- return str(self._value)
-
- def __neg__(self):
- return self.negate()
-
- def __abs__(self):
- return self.abs()
-
- def __add__(self, other):
- return self.add(other)
-
- def __sub__(self, other):
- return self.subtract(other)
-
- def __mul__(self, other):
- return self.multiply(other)
-
- def __truediv__(self, other):
- return self.divide(other)
-
- def __floordiv__(self, other):
- return self.divide(other)
-
- def __mod__(self, other):
- return self.mod(other)
-
- def __pow__(self, other):
- return self.pow(other)
-
- def __and__(self, other):
- return self.and_(other)
-
- def __or__(self, other):
- return self.or_(other)
-
- def __xor__(self, other):
- return self.xor(other)
-
- def __invert__(self):
- return self.not_()
-
- def __lshift__(self, n):
- return self.shiftLeft(n)
-
- def __rshift__(self, n):
- return self.shiftRight(n)
-
-
-BigInteger.ZERO = BigInteger(0)
-BigInteger.ONE = BigInteger(1)
-BigInteger.TEN = BigInteger(10)
-
-
-# ============================================================
-# BigDecimal
-# ============================================================
-
-class BigDecimal(Comparable):
- ZERO = None
- ONE = None
- TEN = None
-
- ROUND_UP = 0
- ROUND_DOWN = 1
- ROUND_CEILING = 2
- ROUND_FLOOR = 3
- ROUND_HALF_UP = 4
- ROUND_HALF_DOWN = 5
- ROUND_HALF_EVEN = 6
- ROUND_UNNECESSARY = 7
-
- _round_map = {
- 0: _DEC_ROUND_UP,
- 1: _DEC_ROUND_DOWN,
- 2: _DEC_ROUND_CEILING,
- 3: _DEC_ROUND_FLOOR,
- 4: _DEC_ROUND_HALF_UP,
- 5: _DEC_ROUND_HALF_DOWN,
- 6: _DEC_ROUND_HALF_EVEN,
- 7: _DEC_ROUND_HALF_EVEN,
- }
-
- def __init__(self, *args):
- super().__init__()
- if len(args) == 1:
- val = args[0]
- if isinstance(val, str):
- self._dec = _Decimal(str(val))
- elif isinstance(val, float):
- self._dec = _Decimal(repr(val))
- elif isinstance(val, int):
- self._dec = _Decimal(val)
- elif isinstance(val, BigInteger):
- self._dec = _Decimal(val._value)
- elif isinstance(val, BigDecimal):
- self._dec = _Decimal(val._dec)
- elif isinstance(val, _Decimal):
- self._dec = val
- else:
- self._dec = _Decimal(str(val))
- elif len(args) == 2:
- val, mc = args
- if isinstance(val, str):
- self._dec = _Decimal(str(val))
- elif isinstance(val, float):
- self._dec = _Decimal(repr(val))
- else:
- self._dec = _Decimal(val)
- if mc and hasattr(mc, 'getPrecision') and mc.getPrecision() > 0:
- self._dec = +self._dec
-
- @staticmethod
- def valueOf(val):
- if isinstance(val, int):
- if val == 0:
- return BigDecimal.ZERO
- if val == 1:
- return BigDecimal.ONE
- if val == 10:
- return BigDecimal.TEN
- if isinstance(val, float):
- return BigDecimal(repr(val))
- return BigDecimal(val)
-
- def add(self, other):
- if isinstance(other, BigDecimal):
- return BigDecimal(self._dec + other._dec)
- return BigDecimal(self._dec + _Decimal(str(other)))
-
- def subtract(self, other):
- if isinstance(other, BigDecimal):
- return BigDecimal(self._dec - other._dec)
- return BigDecimal(self._dec - _Decimal(str(other)))
-
- def multiply(self, other):
- if isinstance(other, BigDecimal):
- return BigDecimal(self._dec * other._dec)
- return BigDecimal(self._dec * _Decimal(str(other)))
-
- def divide(self, *args):
- if len(args) == 1:
- other = args[0]
- if isinstance(other, BigDecimal):
- return BigDecimal(self._dec / other._dec)
- return BigDecimal(self._dec / _Decimal(str(other)))
- elif len(args) == 2:
- other, rounding_mode = args
- if isinstance(other, BigDecimal):
- result = self._dec / other._dec
- else:
- result = self._dec / _Decimal(str(other))
- return BigDecimal(result)
- elif len(args) == 3:
- other, scale, rounding_mode = args
- if isinstance(other, BigDecimal):
- result = self._dec / other._dec
- else:
- result = self._dec / _Decimal(str(other))
- rounded = BigDecimal(result)
- return rounded.setScale(scale, rounding_mode)
-
- def divideToIntegralValue(self, other):
- if isinstance(other, BigDecimal):
- return BigDecimal(int(self._dec / other._dec))
- return BigDecimal(int(self._dec / _Decimal(str(other))))
-
- def remainder(self, other):
- if isinstance(other, BigDecimal):
- return BigDecimal(self._dec % other._dec)
- return BigDecimal(self._dec % _Decimal(str(other)))
-
- def pow(self, n):
- return BigDecimal(self._dec ** n)
-
- def abs(self):
- return BigDecimal(abs(self._dec))
-
- def negate(self):
- return BigDecimal(-self._dec)
-
- def signum(self):
- if self._dec > 0:
- return 1
- if self._dec < 0:
- return -1
- return 0
-
- def scale(self):
- return abs(self._dec.as_tuple().exponent)
-
- def precision(self):
- return len(self._dec.as_tuple().digits)
-
- def round(self, mc):
- if mc.getPrecision() > 0:
- with _local_context() as ctx:
- ctx.prec = mc.getPrecision()
- return BigDecimal(+self._dec)
- return BigDecimal(self._dec)
-
- def setScale(self, new_scale, rounding_mode=None):
- if rounding_mode is None:
- qe = _Decimal(10) ** (-new_scale)
- return BigDecimal(self._dec.quantize(qe))
- py_mode = self._round_map.get(rounding_mode, _DEC_ROUND_HALF_UP)
- qe = _Decimal(10) ** (-new_scale)
- return BigDecimal(self._dec.quantize(qe, rounding=py_mode))
-
- def ulp(self):
- exponent = self._dec.as_tuple().exponent
- return BigDecimal(_Decimal(10) ** exponent)
-
- def unscaledValue(self):
- t = self._dec.as_tuple()
- digits = t.digits
- val = int("".join(str(d) for d in digits))
- return BigInteger(-val if t.sign else val)
-
- def byteValueExact(self):
- val = self.intValueExact()
- if val < -128 or val > 127:
- raise ArithmeticError("Overflow")
- return val
-
- def shortValueExact(self):
- val = self.intValueExact()
- if val < -32768 or val > 32767:
- raise ArithmeticError("Overflow")
- return val
-
- def intValueExact(self):
- if self._dec != int(self._dec):
- raise ArithmeticError("Rounding necessary")
- return int(self._dec)
-
- def longValueExact(self):
- if self._dec != int(self._dec):
- raise ArithmeticError("Rounding necessary")
- return int(self._dec)
-
- def floatValue(self):
- return float(self._dec)
-
- def doubleValue(self):
- return float(self._dec)
-
- def intValue(self):
- return int(self._dec)
-
- def longValue(self):
- return int(self._dec)
-
- def toString(self):
- return str(self._dec)
-
- def toEngineeringString(self):
- return format(self._dec, "e")
-
- def toPlainString(self):
- return format(self._dec, "f")
-
- def compareTo(self, other):
- if isinstance(other, BigDecimal):
- return (self._dec > other._dec) - (self._dec < other._dec)
- return -1
-
- def equals(self, other):
- if isinstance(other, BigDecimal):
- return self._dec == other._dec
- return False
-
- def hashCode(self):
- return hash(self._dec) & 0x7FFFFFFF
-
- def min(self, other):
- return BigDecimal(min(self._dec, other._dec if isinstance(other, BigDecimal) else _Decimal(str(other))))
-
- def max(self, other):
- return BigDecimal(max(self._dec, other._dec if isinstance(other, BigDecimal) else _Decimal(str(other))))
-
- def __str__(self):
- return str(self._dec)
-
- def __int__(self):
- return int(self._dec)
-
- def __float__(self):
- return float(self._dec)
-
- def __neg__(self):
- return self.negate()
-
- def __abs__(self):
- return self.abs()
-
- def __add__(self, other):
- return self.add(other)
-
- def __sub__(self, other):
- return self.subtract(other)
-
- def __mul__(self, other):
- return self.multiply(other)
-
- def __truediv__(self, other):
- return self.divide(other)
-
- def __mod__(self, other):
- return self.remainder(other)
-
- def __pow__(self, other):
- return self.pow(other)
-
-
-BigDecimal.ZERO = BigDecimal(0)
-BigDecimal.ONE = BigDecimal(1)
-BigDecimal.TEN = BigDecimal(10)
\ No newline at end of file
diff --git a/android_pyapi/java/net.py b/android_pyapi/java/net.py
deleted file mode 100644
index 1010666..0000000
--- a/android_pyapi/java/net.py
+++ /dev/null
@@ -1,1759 +0,0 @@
-"""
-Java net standard library APIs implemented in Python.
-java.net package - URL, Socket, HTTP connection, and networking classes.
-"""
-
-from .._core import Stub, AndroidOnlyError, HAS_REQUESTS, HAS_HTTPX
-from .io import IOException
-
-import os as _os
-import socket as _socket
-import struct as _struct
-import threading as _threading
-from urllib.parse import (
- urlparse as _urlparse,
- urlunparse as _urlunparse,
- quote as _quote,
- unquote as _unquote,
-)
-from datetime import datetime as _datetime
-from collections import OrderedDict as _OrderedDict
-
-__all__ = [
- "URL", "URLConnection", "HttpURLConnection",
- "InetAddress", "InetSocketAddress",
- "Socket", "ServerSocket", "DatagramSocket", "DatagramPacket",
- "Proxy", "ProxySelector", "Authenticator", "PasswordAuthentication",
- "NetworkInterface", "InterfaceAddress", "URI",
- "CookieHandler", "CookieManager", "HttpCookie",
- "URLDecoder", "URLEncoder",
- "SocketException", "ConnectException", "BindException",
- "NoRouteToHostException", "PortUnreachableException",
- "ProtocolException", "SocketTimeoutException",
- "MalformedURLException", "UnknownHostException", "UnknownServiceException",
-]
-
-
-# ============================================================
-# Exception classes
-# ============================================================
-
-class SocketException(IOException):
- pass
-
-class ConnectException(SocketException):
- pass
-
-class BindException(SocketException):
- pass
-
-class NoRouteToHostException(SocketException):
- pass
-
-class PortUnreachableException(SocketException):
- pass
-
-class ProtocolException(IOException):
- pass
-
-class SocketTimeoutException(IOException):
- pass
-
-class MalformedURLException(IOException):
- pass
-
-class UnknownHostException(IOException):
- pass
-
-class UnknownServiceException(IOException):
- pass
-
-
-# ============================================================
-# InetAddress
-# ============================================================
-
-class InetAddress(Stub):
- def __init__(self, host, addr):
- super().__init__()
- self._host = host
- self._addr = addr # bytes, 4 or 16
-
- @staticmethod
- def getByName(host):
- try:
- addr = _socket.getaddrinfo(host, None, family=_socket.AF_UNSPEC)
- if addr:
- raw = addr[0][4][0]
- return InetAddress(host, _socket.inet_pton(_socket.AF_INET, raw) if "." in raw else _socket.inet_pton(_socket.AF_INET6, raw))
- except Exception:
- raise UnknownHostException(host)
-
- @staticmethod
- def getAllByName(host):
- try:
- addrs = _socket.getaddrinfo(host, None, family=_socket.AF_UNSPEC)
- results = []
- seen = set()
- for a in addrs:
- raw = a[4][0]
- if raw not in seen:
- seen.add(raw)
- if "." in raw:
- results.append(InetAddress(host, _socket.inet_pton(_socket.AF_INET, raw)))
- else:
- results.append(InetAddress(host, _socket.inet_pton(_socket.AF_INET6, raw)))
- return results
- except Exception:
- raise UnknownHostException(host)
-
- @staticmethod
- def getLocalHost():
- hostname = _socket.gethostname()
- return InetAddress.getByName(hostname)
-
- @staticmethod
- def getLoopbackAddress():
- return InetAddress("localhost", b"\x7f\x00\x00\x01")
-
- @staticmethod
- def getByAddress(host, addr):
- return InetAddress(host, addr)
-
- def getHostName(self):
- return self._host
-
- def getHostAddress(self):
- if len(self._addr) == 4:
- return _socket.inet_ntoa(self._addr)
- return _socket.inet_ntop(_socket.AF_INET6, self._addr)
-
- def getCanonicalHostName(self):
- try:
- name, _, _ = _socket.gethostbyaddr(self.getHostAddress())
- return name
- except Exception:
- return self._host
-
- def isReachable(self, timeout=5000):
- try:
- s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- s.settimeout(timeout / 1000.0)
- result = s.connect_ex((self.getHostAddress(), 7))
- s.close()
- return result == 0
- except Exception:
- return False
-
- def isLoopbackAddress(self):
- if len(self._addr) == 4:
- return self._addr[0] == 127
- return self._addr == b"\x00" * 15 + b"\x01"
-
- def isLinkLocalAddress(self):
- if len(self._addr) == 4:
- return self._addr[0] == 169 and self._addr[1] == 254
- return (self._addr[0] & 0xFF) == 0xFE and (self._addr[1] & 0xC0) == 0x80
-
- def isSiteLocalAddress(self):
- if len(self._addr) == 4:
- b0 = self._addr[0]
- return b0 == 10 or (b0 == 172 and 16 <= self._addr[1] <= 31) or (b0 == 192 and self._addr[1] == 168)
- return False
-
- def isMCGlobal(self):
- if len(self._addr) == 4:
- return 224 <= self._addr[0] <= 239 and self._addr[0] != 224 and self._addr[0] != 239
- return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x0E and (self._addr[2] & 0x20) == 0
-
- def isMCLinkLocal(self):
- if len(self._addr) == 4:
- return self._addr[0] == 224 and self._addr[1] == 0 and self._addr[2] == 0
- return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x02
-
- def isMCNodeLocal(self):
- if len(self._addr) == 4:
- return self._addr[0] == 224 and self._addr[1] == 0 and self._addr[2] == 0 and self._addr[3] == 1
- return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x01
-
- def isMCOrgLocal(self):
- if len(self._addr) == 4:
- return self._addr[0] == 239 and 192 <= self._addr[1] <= 195
- return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x08
-
- def isMCSiteLocal(self):
- if len(self._addr) == 4:
- return self._addr[0] == 239 and 255 <= self._addr[1] <= 255
- return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x05
-
- def getAddress(self):
- return self._addr
-
- def toString(self):
- return f"{self._host}/{self.getHostAddress()}"
-
- def equals(self, other):
- if isinstance(other, InetAddress):
- return self._addr == other._addr
- return False
-
- def hashCode(self):
- return hash(bytes(self._addr)) & 0x7FFFFFFF
-
-
-# ============================================================
-# InetSocketAddress
-# ============================================================
-
-class InetSocketAddress(Stub):
- def __init__(self, *args):
- super().__init__()
- if len(args) == 2 and isinstance(args[0], int):
- self._addr = None
- self._port = args[0] if isinstance(args[0], int) else args[1]
- elif len(args) == 2:
- hostname, port = args
- self._addr = InetAddress.getByName(hostname) if isinstance(hostname, str) else hostname
- self._port = port
- elif len(args) == 1 and isinstance(args[0], int):
- self._addr = None
- self._port = args[0]
-
- def getAddress(self):
- return self._addr
-
- def getPort(self):
- return self._port
-
- def getHostName(self):
- return self._addr.getHostName() if self._addr else None
-
- def getHostString(self):
- return self.getHostName()
-
- def isUnresolved(self):
- return self._addr is None
-
- def toString(self):
- return f"{self.getHostName()}:{self._port}"
-
- def equals(self, other):
- if isinstance(other, InetSocketAddress):
- return self._port == other._port and self._addr == other._addr
- return False
-
- def hashCode(self):
- return hash((self._port, self._addr)) & 0x7FFFFFFF
-
-
-# ============================================================
-# URI
-# ============================================================
-
-class URI(Stub):
- def __init__(self, *args):
- super().__init__()
- if len(args) == 1:
- self._uri = args[0]
- parsed = _urlparse(self._uri)
- self._scheme = parsed.scheme
- self._host = parsed.hostname
- self._port = parsed.port
- self._path = parsed.path
- self._query = parsed.query
- self._fragment = parsed.fragment
- self._user_info = parsed.username
- self._authority = parsed.netloc
- elif len(args) == 5:
- self._scheme = args[0]
- self._authority = args[1] or ""
- self._path = args[2] or ""
- self._query = args[3] or ""
- self._fragment = args[4] or ""
- parsed = _urlparse(f"{self._scheme}://{self._authority}{self._path}")
- self._host = parsed.hostname
- self._port = parsed.port
- self._user_info = parsed.username
- self._uri = f"{self._scheme}://{self._authority}{self._path}"
- if self._query:
- self._uri += "?" + self._query
- if self._fragment:
- self._uri += "#" + self._fragment
- else:
- raise ValueError("URI constructor requires 1 or 5 arguments")
-
- def getScheme(self):
- return self._scheme
-
- def getHost(self):
- return self._host
-
- def getPort(self):
- return self._port if self._port else -1
-
- def getPath(self):
- return self._path
-
- def getQuery(self):
- return self._query
-
- def getFragment(self):
- return self._fragment
-
- def getAuthority(self):
- return self._authority
-
- def getRawAuthority(self):
- return self._authority
-
- def getRawFragment(self):
- return self._fragment
-
- def getRawPath(self):
- return self._path
-
- def getRawQuery(self):
- return self._query
-
- def getRawSchemeSpecificPart(self):
- return f"//{self._authority}{self._path}"
-
- def getRawUserInfo(self):
- return self._user_info or ""
-
- def getSchemeSpecificPart(self):
- return self.getRawSchemeSpecificPart()
-
- def getUserInfo(self):
- return self._user_info or ""
-
- def isAbsolute(self):
- return bool(self._scheme)
-
- def isOpaque(self):
- return not self._path and not self._authority and self._scheme
-
- def normalize(self):
- import posixpath
- normalized = posixpath.normpath(self._path)
- return URI(f"{self._scheme}://{self._authority}{normalized}")
-
- def resolve(self, uri_or_str):
- if isinstance(uri_or_str, URI):
- other = uri_or_str
- else:
- other = URI(uri_or_str)
- if other.isAbsolute():
- return other
- base_path = self._path or "/"
- if base_path.endswith("/"):
- new_path = base_path + other._path
- else:
- new_path = "/".join(base_path.rsplit("/", 1)[:-1] + [other._path]) if other._path else base_path
- return URI(f"{self._scheme}://{self._authority}{new_path}")
-
- def relativize(self, other):
- if self._path and other._path and other._path.startswith(self._path):
- rel = other._path[len(self._path):]
- if rel.startswith("/"):
- rel = rel[1:]
- return URI(rel)
- return other
-
- def toASCIIString(self):
- return _quote(self._uri, safe=":/?#[]@!$&'()*+,;=-._~")
-
- def toString(self):
- return self._uri
-
- def toURL(self):
- return URL(self._uri)
-
- def compareTo(self, other):
- return -1 if self._uri < other._uri else (1 if self._uri > other._uri else 0)
-
- def equals(self, other):
- if isinstance(other, URI):
- return self._uri == other._uri
- return False
-
- def hashCode(self):
- return hash(self._uri) & 0x7FFFFFFF
-
- def parseServerAuthority(self):
- return self
-
-
-# ============================================================
-# URL
-# ============================================================
-
-class URL(Stub):
- def __init__(self, *args):
- super().__init__()
- if len(args) == 1:
- spec = args[0]
- parsed = _urlparse(str(spec))
- self._protocol = parsed.scheme
- self._host = parsed.hostname or ""
- self._port = parsed.port
- self._path = parsed.path or ""
- self._file = parsed.path or ""
- if parsed.query:
- self._file += "?" + parsed.query
- self._query = parsed.query or ""
- self._ref = parsed.fragment or ""
- self._authority = parsed.netloc or ""
- self._user_info = parsed.username or ""
- self._url_str = str(spec)
- elif len(args) == 4:
- protocol, host, port, file = args
- self._protocol = protocol or ""
- self._host = host or ""
- self._port = port
- self._path = file or ""
- self._file = file or ""
- self._query = ""
- self._ref = ""
- self._authority = f"{host}:{port}" if port and port > 0 else host
- self._user_info = ""
- parts = [file or ""]
- self._url_str = f"{protocol}://{self._authority}{file}"
-
- def getProtocol(self):
- return self._protocol
-
- def getHost(self):
- return self._host
-
- def getPort(self):
- return self._port if self._port else -1
-
- def getDefaultPort(self):
- defaults = {
- "http": 80, "https": 443, "ftp": 21, "smtp": 25,
- "ssh": 22, "telnet": 23, "ldap": 389,
- }
- return defaults.get(self._protocol, -1)
-
- def getPath(self):
- return self._path
-
- def getFile(self):
- return self._file
-
- def getQuery(self):
- return self._query
-
- def getRef(self):
- return self._ref
-
- def getAuthority(self):
- return self._authority
-
- def getUserInfo(self):
- return self._user_info
-
- def getContent(self, classes=None):
- return self.openConnection().getContent(classes)
-
- def openConnection(self, proxy=None):
- return HttpURLConnection(self._url_str, proxy)
-
- def openStream(self):
- return self.openConnection().getInputStream()
-
- def sameFile(self, other):
- return (self._protocol == other._protocol and self._host == other._host
- and self._port == other._port and self._path == other._path)
-
- def toExternalForm(self):
- return self._url_str
-
- def toString(self):
- return self._url_str
-
- def toURI(self):
- return URI(self._url_str)
-
- def equals(self, other):
- if isinstance(other, URL):
- return self._url_str == other._url_str
- return False
-
- def hashCode(self):
- return hash(self._url_str) & 0x7FFFFFFF
-
- def openConnection(self, proxy=None):
- return HttpURLConnection(self._url_str, proxy)
-
- def __str__(self):
- return self._url_str
-
-
-# ============================================================
-# URLConnection
-# ============================================================
-
-class URLConnection(Stub):
- def __init__(self, url_str):
- super().__init__()
- self._url_str = url_str
- self._connected = False
- self._do_input = True
- self._do_output = False
- self._allow_user_interaction = False
- self._use_caches = True
- self._default_use_caches = True
- self._if_modified_since = 0
- self._read_timeout = 0
- self._connect_timeout = 0
- self._request_properties = _OrderedDict()
- self._response_code = None
- self._response_message = None
- self._response_headers = _OrderedDict()
- self._content = None
-
- def connect(self):
- if not self._connected:
- self._connected = True
-
- def getContent(self, classes=None):
- raise UnknownServiceException("getContent not implemented")
-
- def getContentEncoding(self):
- return self._response_headers.get("Content-Encoding")
-
- def getContentLength(self):
- val = self._response_headers.get("Content-Length")
- return int(val) if val else -1
-
- def getContentLengthLong(self):
- return self.getContentLength()
-
- def getContentType(self):
- return self._response_headers.get("Content-Type")
-
- def getDate(self):
- val = self._response_headers.get("Date")
- if val:
- try:
- return int(_datetime.strptime(val, "%a, %d %b %Y %H:%M:%S %Z").timestamp() * 1000)
- except Exception:
- pass
- return 0
-
- def getExpiration(self):
- val = self._response_headers.get("Expires")
- if val:
- try:
- return int(_datetime.strptime(val, "%a, %d %b %Y %H:%M:%S %Z").timestamp() * 1000)
- except Exception:
- pass
- return 0
-
- def getHeaderField(self, name):
- return self._response_headers.get(name)
-
- def getHeaderFieldDate(self, name, default):
- val = self._response_headers.get(name)
- if val:
- try:
- return int(_datetime.strptime(val, "%a, %d %b %Y %H:%M:%S %Z").timestamp() * 1000)
- except Exception:
- pass
- return default
-
- def getHeaderFieldInt(self, name, default):
- val = self._response_headers.get(name)
- return int(val) if val and val.isdigit() else default
-
- def getHeaderFieldKey(self, n):
- keys = list(self._response_headers.keys())
- return keys[n] if n < len(keys) else None
-
- def getHeaderFields(self):
- return self._response_headers
-
- def getInputStream(self):
- raise UnknownServiceException("getInputStream not implemented")
-
- def getOutputStream(self):
- raise UnknownServiceException("getOutputStream not implemented")
-
- def getPermission(self):
- return None
-
- def getReadTimeout(self):
- return self._read_timeout
-
- def setReadTimeout(self, timeout):
- self._read_timeout = timeout
-
- def getConnectTimeout(self):
- return self._connect_timeout
-
- def setConnectTimeout(self, timeout):
- self._connect_timeout = timeout
-
- def getRequestProperty(self, key):
- return self._request_properties.get(key)
-
- def setRequestProperty(self, key, value):
- self._request_properties[key] = value
-
- def addRequestProperty(self, key, value):
- if key in self._request_properties:
- existing = self._request_properties[key]
- if isinstance(existing, list):
- existing.append(value)
- else:
- self._request_properties[key] = [existing, value]
- else:
- self._request_properties[key] = value
-
- def getDefaultUseCaches(self):
- return self._default_use_caches
-
- def setDefaultUseCaches(self, use):
- self._default_use_caches = use
-
- def getUseCaches(self):
- return self._use_caches
-
- def setUseCaches(self, use):
- self._use_caches = use
-
- def setDoInput(self, do_input):
- self._do_input = do_input
-
- def getDoInput(self):
- return self._do_input
-
- def setDoOutput(self, do_output):
- self._do_output = do_output
-
- def getDoOutput(self):
- return self._do_output
-
- def setAllowUserInteraction(self, allow):
- self._allow_user_interaction = allow
-
- def getAllowUserInteraction(self):
- return self._allow_user_interaction
-
- def setIfModifiedSince(self, time):
- self._if_modified_since = time
-
- def getIfModifiedSince(self):
- return self._if_modified_since
-
-
-# ============================================================
-# HttpURLConnection
-# ============================================================
-
-class HttpURLConnection(URLConnection):
- HTTP_OK = 200
- HTTP_CREATED = 201
- HTTP_ACCEPTED = 202
- HTTP_MOVED_PERM = 301
- HTTP_MOVED_TEMP = 302
- HTTP_NOT_MODIFIED = 304
- HTTP_BAD_REQUEST = 400
- HTTP_UNAUTHORIZED = 401
- HTTP_FORBIDDEN = 403
- HTTP_NOT_FOUND = 404
- HTTP_INTERNAL_ERROR = 500
-
- def __init__(self, url_str, proxy=None):
- super().__init__(url_str)
- self._request_method = "GET"
- self._instance_follow_redirects = True
- self._chunked = False
- self._fixed_length = -1
- self._input_stream = None
- self._error_stream = None
- self._response_code = -1
- self._response_message = ""
-
- def setRequestMethod(self, method):
- method = method.upper()
- valid = ["GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"]
- if method not in valid:
- raise ProtocolException(f"Invalid HTTP method: {method}")
- self._request_method = method
-
- def getRequestMethod(self):
- return self._request_method
-
- def getResponseCode(self):
- if self._response_code == -1:
- self._do_request()
- return self._response_code
-
- def getResponseMessage(self):
- if self._response_code == -1:
- self._do_request()
- return self._response_message
-
- def getHeaderFields(self):
- if self._response_code == -1:
- self._do_request()
- return self._response_headers
-
- def setInstanceFollowRedirects(self, follow):
- self._instance_follow_redirects = follow
-
- def getInstanceFollowRedirects(self):
- return self._instance_follow_redirects
-
- def getErrorStream(self):
- if self._response_code == -1:
- self._do_request()
- if self._response_code >= 400:
- return self._error_stream
- return None
-
- def setChunkedStreamingMode(self, chunklen):
- self._chunked = True
- self._chunk_length = chunklen
-
- def setFixedLengthStreamingMode(self, content_length):
- self._fixed_length = content_length
-
- def setFixedLengthStreamingModeLong(self, content_length):
- self._fixed_length = content_length
-
- def disconnect(self):
- self._input_stream = None
- self._error_stream = None
- self._connected = False
-
- def usingProxy(self):
- return False
-
- def getInputStream(self):
- if self._response_code == -1:
- self._do_request()
- if self._input_stream is None:
- import io as _pyio_mod
- self._input_stream = _pyio_mod.BytesIO(self._content.encode("utf-8") if isinstance(self._content, str) else self._content)
- return self._input_stream
-
- def _do_request(self):
- if HAS_REQUESTS:
- self._do_requests()
- elif HAS_HTTPX:
- self._do_httpx()
- else:
- self._do_urllib()
-
- def _do_requests(self):
- import requests
- try:
- kwargs = {
- "headers": dict(self._request_properties),
- "timeout": self._read_timeout / 1000.0 if self._read_timeout else None,
- }
- if self._instance_follow_redirects:
- kwargs["allow_redirects"] = True
- else:
- kwargs["allow_redirects"] = False
- method = self._request_method.lower()
- if method == "get":
- r = requests.get(self._url_str, **kwargs)
- elif method == "post":
- body = self._request_properties.pop("__body", None)
- r = requests.post(self._url_str, data=body, **kwargs)
- elif method == "put":
- body = self._request_properties.pop("__body", None)
- r = requests.put(self._url_str, data=body, **kwargs)
- elif method == "delete":
- r = requests.delete(self._url_str, **kwargs)
- elif method == "head":
- r = requests.head(self._url_str, **kwargs)
- elif method == "options":
- r = requests.options(self._url_str, **kwargs)
- elif method == "patch":
- body = self._request_properties.pop("__body", None)
- r = requests.patch(self._url_str, data=body, **kwargs)
- else:
- r = requests.request(self._request_method, self._url_str, **kwargs)
- self._response_code = r.status_code
- self._response_message = r.reason
- self._response_headers = dict(r.headers)
- self._content = r.content
- except Exception as e:
- self._response_code = 0
- self._response_message = str(e)
-
- def _do_httpx(self):
- import httpx
- try:
- client = httpx.Client(follow_redirects=self._instance_follow_redirects)
- kwargs = {
- "headers": dict(self._request_properties) if self._request_properties else None,
- "timeout": self._read_timeout / 1000.0 if self._read_timeout else None,
- }
- method = self._request_method.lower()
- if method == "get":
- r = client.get(self._url_str, **kwargs)
- elif method == "post":
- body = self._request_properties.pop("__body", None)
- r = client.post(self._url_str, content=body, **kwargs)
- elif method == "put":
- body = self._request_properties.pop("__body", None)
- r = client.put(self._url_str, content=body, **kwargs)
- elif method == "delete":
- r = client.delete(self._url_str, **kwargs)
- else:
- r = client.request(self._request_method, self._url_str, **kwargs)
- self._response_code = r.status_code
- self._response_message = r.reason_phrase
- self._response_headers = dict(r.headers)
- self._content = r.content
- except Exception as e:
- self._response_code = 0
- self._response_message = str(e)
-
- def _do_urllib(self):
- from urllib.request import urlopen, Request
- from urllib.error import HTTPError
- try:
- req = Request(self._url_str, headers=dict(self._request_properties) if self._request_properties else {},
- method=self._request_method)
- resp = urlopen(req, timeout=self._read_timeout / 1000.0 if self._read_timeout else None)
- self._response_code = resp.status
- self._response_message = resp.reason
- self._response_headers = dict(resp.headers)
- self._content = resp.read()
- except HTTPError as e:
- self._response_code = e.code
- self._response_message = e.reason
- self._response_headers = dict(e.headers)
- self._content = e.read()
- except Exception as e:
- self._response_code = 0
- self._response_message = str(e)
- self._content = b""
-
-
-# ============================================================
-# Socket
-# ============================================================
-
-class Socket(Stub):
- def __init__(self, *args):
- super().__init__()
- self._socket = None
- self._connected = False
- self._bound = False
- self._closed = False
- self._input_shutdown = False
- self._output_shutdown = False
- self._input_stream = None
- self._output_stream = None
- self._timeout = 0
- self._keep_alive = False
- self._tcp_no_delay = False
- self._reuse_address = False
- self._send_buffer_size = 0
- self._receive_buffer_size = 0
- self._linger = -1
- self._traffic_class = 0
- if len(args) == 2:
- host, port = args
- self.connect(InetSocketAddress(host, port))
- elif len(args) == 1 and isinstance(args[0], InetAddress):
- addr, port = args[0], 0
- self.connect(InetSocketAddress(addr, port))
-
- def connect(self, endpoint, timeout=None):
- if isinstance(endpoint, InetSocketAddress):
- host = endpoint.getHostName()
- port = endpoint.getPort()
- else:
- host = str(endpoint)
- port = 80
- self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- if self._timeout > 0:
- self._socket.settimeout(self._timeout / 1000.0)
- try:
- self._socket.connect((host, port))
- self._connected = True
- except OSError as e:
- raise ConnectException(str(e))
-
- def bind(self, endpoint):
- if isinstance(endpoint, InetSocketAddress):
- host = endpoint.getHostName()
- port = endpoint.getPort()
- else:
- host = "0.0.0.0"
- port = 0
- self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- self._socket.bind((host or "0.0.0.0", port))
- self._bound = True
-
- def close(self):
- if not self._closed:
- self._closed = True
- if self._socket:
- self._socket.close()
-
- def getInputStream(self):
- if self._input_stream is None and self._socket:
- import io as _pyio_mod
- fd = self._socket.fileno()
- self._input_stream = _pyio_mod.FileIO(fd, closefd=False)
- return self._input_stream
-
- def getOutputStream(self):
- if self._output_stream is None and self._socket:
- import io as _pyio_mod
- fd = self._socket.fileno()
- self._output_stream = _pyio_mod.FileIO(fd, closefd=False, mode="ab")
- return self._output_stream
-
- def getInetAddress(self):
- if self._socket and self._connected:
- host, _ = self._socket.getpeername()
- return InetAddress.getByName(host)
- return None
-
- def getPort(self):
- if self._socket and self._connected:
- _, port = self._socket.getpeername()
- return port
- return 0
-
- def getLocalPort(self):
- if self._socket:
- _, port = self._socket.getsockname()
- return port
- return 0
-
- def getLocalAddress(self):
- if self._socket:
- host, _ = self._socket.getsockname()
- return InetAddress.getByName(host)
- return InetAddress.getLoopbackAddress()
-
- def getRemoteSocketAddress(self):
- if self._socket and self._connected:
- host, port = self._socket.getpeername()
- return InetSocketAddress(host, port)
- return None
-
- def getLocalSocketAddress(self):
- if self._socket:
- host, port = self._socket.getsockname()
- return InetSocketAddress(host, port)
- return None
-
- def getSoTimeout(self):
- return self._timeout
-
- def setSoTimeout(self, timeout):
- self._timeout = timeout
- if self._socket:
- self._socket.settimeout(timeout / 1000.0 if timeout > 0 else None)
-
- def getTcpNoDelay(self):
- return self._tcp_no_delay
-
- def setTcpNoDelay(self, on):
- self._tcp_no_delay = on
- if self._socket:
- self._socket.setsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 1 if on else 0)
-
- def getKeepAlive(self):
- return self._keep_alive
-
- def setKeepAlive(self, on):
- self._keep_alive = on
- if self._socket:
- self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_KEEPALIVE, 1 if on else 0)
-
- def getReuseAddress(self):
- return self._reuse_address
-
- def setReuseAddress(self, on):
- self._reuse_address = on
- if self._socket:
- self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1 if on else 0)
-
- def getSendBufferSize(self):
- return self._send_buffer_size
-
- def setSendBufferSize(self, size):
- self._send_buffer_size = size
- if self._socket:
- self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_SNDBUF, size)
-
- def getReceiveBufferSize(self):
- return self._receive_buffer_size
-
- def setReceiveBufferSize(self, size):
- self._receive_buffer_size = size
- if self._socket:
- self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_RCVBUF, size)
-
- def getSoLinger(self):
- return self._linger
-
- def setSoLinger(self, on, linger):
- if on:
- self._linger = linger
- if self._socket:
- self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_LINGER, _struct.pack("ii", 1, linger))
- else:
- self._linger = -1
-
- def getTrafficClass(self):
- return self._traffic_class
-
- def setTrafficClass(self, tc):
- self._traffic_class = tc
-
- def shutdownInput(self):
- if self._socket:
- self._socket.shutdown(_socket.SHUT_RD)
- self._input_shutdown = True
-
- def shutdownOutput(self):
- if self._socket:
- self._socket.shutdown(_socket.SHUT_WR)
- self._output_shutdown = True
-
- def isConnected(self):
- return self._connected
-
- def isBound(self):
- return self._bound
-
- def isClosed(self):
- return self._closed
-
- def isInputShutdown(self):
- return self._input_shutdown
-
- def isOutputShutdown(self):
- return self._output_shutdown
-
- def setPerformancePreferences(self, connection_time, latency, bandwidth):
- pass
-
-
-# ============================================================
-# ServerSocket
-# ============================================================
-
-class ServerSocket(Stub):
- def __init__(self, port=0, backlog=50, bindAddr=None):
- super().__init__()
- self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1)
- self._port = port
- self._backlog = backlog
- self._bind_addr = bindAddr
- self._closed = False
- self._timeout = 0
- if port > 0 or bindAddr:
- self.bind(InetSocketAddress(bindAddr or "0.0.0.0", port), backlog)
-
- def bind(self, endpoint, backlog=50):
- host = endpoint.getHostName() if isinstance(endpoint, InetSocketAddress) else str(endpoint)
- port = endpoint.getPort() if isinstance(endpoint, InetSocketAddress) else 0
- self._socket.bind((host or "0.0.0.0", port))
- self._socket.listen(backlog)
- self._port = self._socket.getsockname()[1]
-
- def accept(self):
- if self._closed:
- raise SocketException("Socket closed")
- if self._timeout > 0:
- self._socket.settimeout(self._timeout / 1000.0)
- try:
- client_sock, addr = self._socket.accept()
- sock = Socket()
- sock._socket = client_sock
- sock._connected = True
- return sock
- except _socket.timeout:
- raise SocketTimeoutException("Accept timed out")
-
- def close(self):
- if not self._closed:
- self._closed = True
- self._socket.close()
-
- def getInetAddress(self):
- host, _ = self._socket.getsockname()
- return InetAddress.getByName(host)
-
- def getLocalPort(self):
- return self._socket.getsockname()[1] if not self._closed else -1
-
- def getSoTimeout(self):
- return self._timeout
-
- def setSoTimeout(self, timeout):
- self._timeout = timeout
- self._socket.settimeout(timeout / 1000.0 if timeout > 0 else None)
-
- def getReceiveBufferSize(self):
- return self._socket.getsockopt(_socket.SOL_SOCKET, _socket.SO_RCVBUF)
-
- def setReceiveBufferSize(self, size):
- self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_RCVBUF, size)
-
- def getReuseAddress(self):
- return bool(self._socket.getsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR))
-
- def setReuseAddress(self, on):
- self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1 if on else 0)
-
-
-# ============================================================
-# DatagramSocket / DatagramPacket
-# ============================================================
-
-class DatagramPacket(Stub):
- def __init__(self, buf, length, address=None, port=None):
- super().__init__()
- if address is not None:
- self._buf = bytearray(buf)
- self._length = length
- self._address = address
- self._port = port
- else:
- self._buf = bytearray(buf)
- self._length = length
- self._address = None
- self._port = -1
-
- def getAddress(self):
- return self._address
-
- def getPort(self):
- return self._port
-
- def getData(self):
- return bytes(self._buf)
-
- def getLength(self):
- return self._length
-
- def setAddress(self, address):
- self._address = address
-
- def setPort(self, port):
- self._port = port
-
- def setData(self, buf, offset=None, length=None):
- if offset is not None and length is not None:
- self._buf = bytearray(buf[offset:offset+length])
- self._length = length
- else:
- self._buf = bytearray(buf)
- self._length = len(buf)
-
- def setLength(self, length):
- self._length = length
-
-
-class DatagramSocket(Stub):
- def __init__(self, port=None):
- super().__init__()
- self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM)
- self._bound = False
- self._closed = False
- if port is not None:
- self.bind(port)
-
- def bind(self, port):
- self._socket.bind(("0.0.0.0", port))
- self._bound = True
-
- def send(self, p):
- addr = p.getAddress()
- port = p.getPort()
- self._socket.sendto(p.getData()[:p.getLength()], (addr.getHostAddress(), port))
-
- def receive(self, p):
- data, addr = self._socket.recvfrom(p.getLength())
- p.setData(data)
- p.setAddress(InetAddress(addr[0], _socket.inet_pton(_socket.AF_INET, addr[0])))
- p.setPort(addr[1])
-
- def close(self):
- if not self._closed:
- self._closed = True
- self._socket.close()
-
- def getLocalPort(self):
- return self._socket.getsockname()[1] if not self._closed else -1
-
- def isBound(self):
- return self._bound
-
- def isClosed(self):
- return self._closed
-
- def setSoTimeout(self, timeout):
- self._socket.settimeout(timeout / 1000.0 if timeout > 0 else None)
-
- def getSoTimeout(self):
- return self._socket.gettimeout() * 1000 if self._socket.gettimeout() else 0
-
-
-# ============================================================
-# Proxy
-# ============================================================
-
-class Proxy(Stub):
- class Type:
- DIRECT = "DIRECT"
- HTTP = "HTTP"
- SOCKS = "SOCKS"
-
- NO_PROXY = None
-
- def __init__(self, typ, sa=None):
- super().__init__()
- self._type = typ
- self._address = sa
-
- def type(self):
- return self._type
-
- def address(self):
- return self._address
-
- def toString(self):
- return f"{self._type} proxy @ {self._address}"
-
-
-class ProxySelector(Stub):
- _default = None
-
- @staticmethod
- def getDefault():
- return ProxySelector._default
-
- @staticmethod
- def setDefault(sel):
- ProxySelector._default = sel
-
- def select(self, uri):
- return [Proxy.NO_PROXY]
-
- def connectFailed(self, uri, sa, ioe):
- pass
-
-
-# ============================================================
-# Authenticator / PasswordAuthentication
-# ============================================================
-
-class Authenticator(Stub):
- _default = None
-
- @staticmethod
- def getDefault():
- return Authenticator._default
-
- @staticmethod
- def setDefault(auth):
- Authenticator._default = auth
-
- def getPasswordAuthentication(self):
- return self._pwd_auth
-
- def requestPasswordAuthentication(self, addr, port, protocol, prompt, scheme):
- return self._pwd_auth
-
-
-class PasswordAuthentication(Stub):
- def __init__(self, user, password):
- super().__init__()
- self._user = user
- self._password = password
-
- def getUserName(self):
- return self._user
-
- def getPassword(self):
- return self._password
-
-
-# ============================================================
-# InterfaceAddress
-# ============================================================
-
-class InterfaceAddress(Stub):
- """java.net.InterfaceAddress — 接口地址信息 (地址/广播/前缀长度)"""
-
- def __init__(self, address=None, broadcast=None, prefix_length=0):
- super().__init__()
- self._address = address # InetAddress
- self._broadcast = broadcast # InetAddress or None
- self._prefix_length = prefix_length
-
- def getAddress(self):
- return self._address
-
- def getBroadcast(self):
- return self._broadcast
-
- def getNetworkPrefixLength(self):
- return self._prefix_length
-
- def equals(self, other):
- if isinstance(other, InterfaceAddress):
- return (self._address == other._address
- and self._prefix_length == other._prefix_length)
- return False
-
- def hashCode(self):
- return hash((repr(self._address), self._prefix_length)) & 0x7FFFFFFF
-
- def toString(self):
- addr = self._address.getHostAddress() if self._address else "0.0.0.0"
- return f"{addr}/{self._prefix_length}"
-
-
-# ============================================================
-# NetworkInterface
-# ============================================================
-
-class NetworkInterface(Stub):
- _cache = {}
- _initialized = False
-
- def __init__(self, name, display_name, addrs):
- super().__init__()
- self._name = name
- self._display_name = display_name
- self._addrs = addrs
- self._mac = None # bytes, hardware address
- self._mtu = 1500
- self._state = "unknown"
- self._flags = 0
- self._interface_addrs = [] # List[InterfaceAddress]
-
- @staticmethod
- def _read_sys_file(path):
- try:
- with open(path, "r") as f:
- return f.read().strip()
- except Exception:
- return None
-
- @staticmethod
- def getByName(name):
- if name is None:
- return None
- NetworkInterface._ensure_init()
- return NetworkInterface._cache.get(name)
-
- @staticmethod
- def getByInetAddress(addr):
- NetworkInterface._ensure_init()
- for ni in NetworkInterface._cache.values():
- for a in ni._addrs:
- if a.equals(addr):
- return ni
- return None
-
- @staticmethod
- def getNetworkInterfaces():
- NetworkInterface._ensure_init()
- return list(NetworkInterface._cache.values())
-
- @staticmethod
- def _ensure_init():
- if not NetworkInterface._initialized:
- NetworkInterface._initialized = True
- try:
- NetworkInterface._init_from_socket()
- except Exception:
- pass
-
- def getName(self):
- return self._name
-
- def getDisplayName(self):
- return self._display_name
-
- def getInetAddresses(self):
- return iter(self._addrs)
-
- def getInterfaceAddresses(self):
- return list(self._interface_addrs)
-
- def isUp(self):
- return self._state.lower() == "up" or (self._flags & 0x1) != 0
-
- def isLoopback(self):
- return (self._flags & 0x8) != 0 or self._name == "lo"
-
- def isPointToPoint(self):
- return (self._flags & 0x10) != 0
-
- def supportsMulticast(self):
- return (self._flags & 0x1000) != 0
-
- def getHardwareAddress(self):
- return self._mac
-
- def getMTU(self):
- return self._mtu
-
- def getSubInterfaces(self):
- return iter([])
-
- def getParent(self):
- return None
-
- def isVirtual(self):
- return False
-
- def toString(self):
- return f"{self._display_name} ({self._name})"
-
- @staticmethod
- def _init_from_socket():
- """从 /sys/class/net/ 和 socket/fcntl 枚举真实网络接口 (不依赖 netifaces)"""
- import os as _os
- net_dir = "/sys/class/net"
- if not _os.path.isdir(net_dir):
- # 非 Linux 环境: 尝试用 socket 获取本机地址
- try:
- hostname = _socket.gethostname()
- addr = InetAddress.getByName(hostname)
- ni = NetworkInterface(hostname, hostname, [addr])
- NetworkInterface._cache[hostname] = ni
- except Exception:
- pass
- return
-
- # 尝试用 fcntl.ioctl 获取 IPv4 地址/掩码/广播
- fcntl_available = True
- try:
- import fcntl as _fcntl
- except ImportError:
- fcntl_available = False
-
- for iface_name in _os.listdir(net_dir):
- addrs = []
- interface_addrs = []
- mac = None
- mtu = 1500
- state = "unknown"
- flags = 0
-
- # --- MAC 地址 ---
- mac_str = NetworkInterface._read_sys_file(f"{net_dir}/{iface_name}/address")
- if mac_str:
- try:
- mac = bytes(int(b, 16) for b in mac_str.split(":"))
- except Exception:
- mac = None
-
- # --- MTU ---
- mtu_str = NetworkInterface._read_sys_file(f"{net_dir}/{iface_name}/mtu")
- if mtu_str:
- try:
- mtu = int(mtu_str)
- except ValueError:
- pass
-
- # --- operstate ---
- state = NetworkInterface._read_sys_file(
- f"{net_dir}/{iface_name}/operstate") or "unknown"
-
- # --- flags (十六进制字符串, 如 0x1003) ---
- flags_str = NetworkInterface._read_sys_file(
- f"{net_dir}/{iface_name}/flags")
- if flags_str:
- try:
- flags = int(flags_str, 16)
- except ValueError:
- pass
-
- # --- IPv4 地址 (fcntl.ioctl) ---
- if fcntl_available:
- sock = None
- try:
- sock = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM)
- packed = _struct.pack('256s', iface_name.encode()[:15])
- # SIOCGIFADDR = 0x8915
- result = _fcntl.ioctl(sock.fileno(), 0x8915, packed)
- ip_raw = result[20:24]
- inet_addr = InetAddress(iface_name, bytes(ip_raw))
- addrs.append(inet_addr)
-
- # SIOCGIFNETMASK = 0x891b
- prefix = 24
- try:
- result = _fcntl.ioctl(sock.fileno(), 0x891b, packed)
- netmask_str = _socket.inet_ntoa(result[20:24])
- prefix = sum(bin(int(b)).count('1') for b in netmask_str.split('.'))
- except Exception:
- pass
-
- # SIOCGIFBRDADDR = 0x8919 (广播地址)
- broadcast_addr = None
- try:
- result = _fcntl.ioctl(sock.fileno(), 0x8919, packed)
- bcast_raw = result[20:24]
- broadcast_addr = InetAddress(iface_name, bytes(bcast_raw))
- except Exception:
- pass
-
- interface_addrs.append(InterfaceAddress(
- address=inet_addr,
- broadcast=broadcast_addr,
- prefix_length=prefix
- ))
- except OSError:
- pass # 接口没有 IPv4 地址
- finally:
- if sock is not None:
- try:
- sock.close()
- except Exception:
- pass
-
- # --- IPv6 地址 (/proc/net/if_inet6) ---
- try:
- with open("/proc/net/if_inet6", "r") as f:
- for line in f:
- parts = line.split()
- if len(parts) >= 6 and parts[5] == iface_name:
- hex_addr = parts[0]
- raw = bytes.fromhex(hex_addr)
- prefix6 = int(parts[2], 16) if parts[2] else 64
- inet6_addr = InetAddress(iface_name, raw)
- addrs.append(inet6_addr)
- interface_addrs.append(InterfaceAddress(
- address=inet6_addr,
- broadcast=None,
- prefix_length=prefix6
- ))
- except Exception:
- pass
-
- ni = NetworkInterface(iface_name, iface_name, addrs)
- ni._mac = mac
- ni._mtu = mtu
- ni._state = state
- ni._flags = flags
- ni._interface_addrs = interface_addrs
- NetworkInterface._cache[iface_name] = ni
-
-
-# 初始化缓存
-try:
- NetworkInterface._ensure_init()
-except Exception:
- pass
-
-
-# ============================================================
-# CookieHandler / CookieManager / HttpCookie
-# ============================================================
-
-class CookieHandler(Stub):
- _default = None
-
- @staticmethod
- def getDefault():
- return CookieHandler._default
-
- @staticmethod
- def setDefault(handler):
- CookieHandler._default = handler
-
- def get(self, uri, requestHeaders):
- raise NotImplementedError
-
- def put(self, uri, responseHeaders):
- raise NotImplementedError
-
-
-class HttpCookie(Stub):
- def __init__(self, name, value):
- super().__init__()
- self._name = name
- self._value = value
- self._comment = None
- self._comment_url = None
- self._discard = False
- self._domain = None
- self._max_age = -1
- self._path = None
- self._portlist = None
- self._secure = False
- self._version = 0
- self._http_only = False
- self._creation_time = _datetime.now()
-
- def getName(self):
- return self._name
-
- def getValue(self):
- return self._value
-
- def getComment(self):
- return self._comment
-
- def getCommentURL(self):
- return self._comment_url
-
- def getDiscard(self):
- return self._discard
-
- def getDomain(self):
- return self._domain
-
- def getMaxAge(self):
- return self._max_age
-
- def getPath(self):
- return self._path
-
- def getPortlist(self):
- return self._portlist
-
- def getSecure(self):
- return self._secure
-
- def getVersion(self):
- return self._version
-
- def getHttpOnly(self):
- return self._http_only
-
- def setComment(self, comment):
- self._comment = comment
-
- def setCommentURL(self, url):
- self._comment_url = url
-
- def setDiscard(self, discard):
- self._discard = discard
-
- def setDomain(self, domain):
- self._domain = domain
-
- def setMaxAge(self, max_age):
- self._max_age = max_age
-
- def setPath(self, path):
- self._path = path
-
- def setPortlist(self, portlist):
- self._portlist = portlist
-
- def setSecure(self, secure):
- self._secure = secure
-
- def setVersion(self, version):
- self._version = version
-
- def setHttpOnly(self, http_only):
- self._http_only = http_only
-
- def hasExpired(self):
- if self._max_age < 0:
- return False
- elapsed = (_datetime.now() - self._creation_time).total_seconds()
- return elapsed > self._max_age
-
- def equals(self, other):
- if isinstance(other, HttpCookie):
- return self._name == other._name
- return False
-
- def toString(self):
- return f"{self._name}={self._value}"
-
- def validate(self, name):
- if not name or name.strip() == "":
- raise ValueError("Cookie name cannot be empty")
-
- def __str__(self):
- return self.toString()
-
-
-class CookieManager(CookieHandler):
- def __init__(self):
- super().__init__()
- self._cookie_store = {}
-
- def get(self, uri, requestHeaders):
- cookies = []
- for domain, path, cookie in self._cookie_store.values():
- if not cookie.hasExpired():
- cookies.append(cookie.toString())
- return {"Cookie": "; ".join(cookies)} if cookies else {}
-
- def put(self, uri, responseHeaders):
- set_cookie = responseHeaders.get("Set-Cookie")
- if set_cookie:
- parts = set_cookie.split(";")
- name_val = parts[0].split("=", 1)
- if len(name_val) == 2:
- cookie = HttpCookie(name_val[0], name_val[1])
- for part in parts[1:]:
- part = part.strip()
- if "=" in part:
- k, v = part.split("=", 1)
- if k.lower() == "domain":
- cookie.setDomain(v)
- elif k.lower() == "path":
- cookie.setPath(v)
- elif k.lower() == "max-age":
- cookie.setMaxAge(int(v))
- elif k.lower() == "version":
- cookie.setVersion(int(v))
- else:
- if part.lower() == "secure":
- cookie.setSecure(True)
- elif part.lower() == "httponly":
- cookie.setHttpOnly(True)
- elif part.lower() == "discard":
- cookie.setDiscard(True)
- self._cookie_store[(cookie.getDomain(), cookie.getPath(), cookie.getName())] = (cookie.getDomain(), cookie.getPath(), cookie)
-
-
-# ============================================================
-# URLEncoder / URLDecoder
-# ============================================================
-
-class URLEncoder(Stub):
- @staticmethod
- def encode(s, charset="UTF-8"):
- return _quote(str(s), safe="")
-
- @staticmethod
- def encode(s):
- return _quote(str(s), safe="")
-
-
-class URLDecoder(Stub):
- @staticmethod
- def decode(s, charset="UTF-8"):
- return _unquote(str(s), encoding=charset)
-
- @staticmethod
- def decode(s):
- return _unquote(str(s))
-
-
-# Initialize NO_PROXY
-Proxy.NO_PROXY = Proxy(Proxy.Type.DIRECT, None)
\ No newline at end of file
diff --git a/android_pyapi/java/nio.py b/android_pyapi/java/nio.py
deleted file mode 100644
index 9418716..0000000
--- a/android_pyapi/java/nio.py
+++ /dev/null
@@ -1,622 +0,0 @@
-"""
-Java NIO standard library APIs implemented in Python.
-java.nio package - Buffer, ByteBuffer, CharBuffer, etc.
-"""
-
-from .._core import Stub
-from .lang import RuntimeException
-from .io import IOException
-import struct as _struct
-import sys as _sys
-
-IllegalStateException = type("IllegalStateException", (RuntimeException,), {})
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "Buffer", "ByteBuffer", "CharBuffer", "ShortBuffer",
- "IntBuffer", "LongBuffer", "FloatBuffer", "DoubleBuffer",
- "MappedByteBuffer", "ByteOrder",
- "BufferOverflowException", "BufferUnderflowException",
- "ReadOnlyBufferException", "InvalidMarkException",
-]
-
-
-# ============================================================
-# Exception classes
-# ============================================================
-
-class BufferOverflowException(RuntimeException):
- pass
-
-class BufferUnderflowException(RuntimeException):
- pass
-
-class ReadOnlyBufferException(RuntimeException):
- pass
-
-class InvalidMarkException(IllegalStateException):
- pass
-
-
-# ============================================================
-# ByteOrder
-# ============================================================
-
-class ByteOrder(Stub):
- BIG_ENDIAN = None
- LITTLE_ENDIAN = None
-
- def __init__(self, name):
- super().__init__()
- self._name = name
-
- @staticmethod
- def nativeOrder():
- if _sys.byteorder == "little":
- return ByteOrder.LITTLE_ENDIAN
- return ByteOrder.BIG_ENDIAN
-
- def toString(self):
- return self._name
-
-
-ByteOrder.BIG_ENDIAN = ByteOrder("BIG_ENDIAN")
-ByteOrder.LITTLE_ENDIAN = ByteOrder("LITTLE_ENDIAN")
-
-
-# ============================================================
-# Buffer
-# ============================================================
-
-class Buffer(Stub):
- def __init__(self, capacity, backing=None):
- super().__init__()
- self._capacity = capacity
- self._position = 0
- self._limit = capacity
- self._mark = -1
- self._backing = backing if backing is not None else bytearray(capacity)
- self._read_only = False
-
- def capacity(self):
- return self._capacity
-
- def position(self):
- return self._position
-
- def position(self, new_position):
- if new_position < 0 or new_position > self._limit:
- raise IllegalArgumentException("Invalid position")
- self._position = new_position
- return self
-
- def limit(self):
- return self._limit
-
- def limit(self, new_limit):
- if new_limit < 0 or new_limit > self._capacity:
- raise IllegalArgumentException("Invalid limit")
- self._limit = new_limit
- if self._position > self._limit:
- self._position = self._limit
- if self._mark > self._limit:
- self._mark = -1
- return self
-
- def mark(self):
- self._mark = self._position
- return self
-
- def reset(self):
- if self._mark < 0:
- raise InvalidMarkException()
- self._position = self._mark
- return self
-
- def clear(self):
- self._position = 0
- self._limit = self._capacity
- self._mark = -1
- return self
-
- def flip(self):
- self._limit = self._position
- self._position = 0
- self._mark = -1
- return self
-
- def rewind(self):
- self._position = 0
- self._mark = -1
- return self
-
- def remaining(self):
- return self._limit - self._position
-
- def hasRemaining(self):
- return self._position < self._limit
-
- def isReadOnly(self):
- return self._read_only
-
- def isDirect(self):
- return False
-
- def array(self):
- if self._read_only:
- raise ReadOnlyBufferException()
- return self._backing
-
- def arrayOffset(self):
- return 0
-
-
-# ============================================================
-# ByteBuffer
-# ============================================================
-
-class ByteBuffer(Buffer):
- def __init__(self, capacity, backing=None, order=None):
- super().__init__(capacity, backing)
- self._order = order or ByteOrder.BIG_ENDIAN
-
- @staticmethod
- def allocate(capacity):
- return ByteBuffer(capacity, bytearray(capacity))
-
- @staticmethod
- def allocateDirect(capacity):
- return ByteBuffer(capacity, bytearray(capacity))
-
- @staticmethod
- def wrap(array, offset=0, length=None):
- if length is None:
- length = len(array) - offset
- buf = ByteBuffer(length, bytearray(array))
- buf._position = offset
- buf._limit = offset + length
- return buf
-
- def put(self, b, index=None):
- if self._read_only:
- raise ReadOnlyBufferException()
- if index is None:
- if isinstance(b, int):
- if self._position >= self._limit:
- raise BufferOverflowException()
- self._backing[self._position] = b & 0xFF
- self._position += 1
- elif isinstance(b, ByteBuffer):
- n = b.remaining()
- if self.remaining() < n:
- raise BufferOverflowException()
- self._backing[self._position:self._position+n] = b._backing[b._position:b._limit]
- self._position += n
- b._position = b._limit
- elif isinstance(b, (bytes, bytearray)):
- if self.remaining() < len(b):
- raise BufferOverflowException()
- self._backing[self._position:self._position+len(b)] = b
- self._position += len(b)
- else:
- self._backing[index] = b & 0xFF
- return self
-
- def get(self, index=None):
- if index is None:
- if self._position >= self._limit:
- raise BufferUnderflowException()
- val = self._backing[self._position]
- self._position += 1
- return val & 0xFF
- return self._backing[index] & 0xFF
-
- def putInt(self, value, index=None):
- data = _struct.pack(">i" if self._order == ByteOrder.BIG_ENDIAN else "i" if self._order == ByteOrder.BIG_ENDIAN else "q" if self._order == ByteOrder.BIG_ENDIAN else "q" if self._order == ByteOrder.BIG_ENDIAN else "f" if self._order == ByteOrder.BIG_ENDIAN else "f" if self._order == ByteOrder.BIG_ENDIAN else "d" if self._order == ByteOrder.BIG_ENDIAN else "d" if self._order == ByteOrder.BIG_ENDIAN else "h" if self._order == ByteOrder.BIG_ENDIAN else "h" if self._order == ByteOrder.BIG_ENDIAN else " b) - (a < b)
- return -1
-
-
-# ============================================================
-# IntBuffer
-# ============================================================
-
-class IntBuffer(Buffer):
- def __init__(self, capacity, backing, offset=0, order=None):
- super().__init__(capacity, backing)
- self._int_order = order or ByteOrder.BIG_ENDIAN
- self._int_offset = offset
-
- def get(self, index=None):
- if index is not None:
- idx = self._int_offset + index * 4
- return _struct.unpack(">i" if self._int_order == ByteOrder.BIG_ENDIAN else "i" if self._int_order == ByteOrder.BIG_ENDIAN else "i" if self._int_order == ByteOrder.BIG_ENDIAN else "q" if self._long_order == ByteOrder.BIG_ENDIAN else "q" if self._long_order == ByteOrder.BIG_ENDIAN else "q" if self._long_order == ByteOrder.BIG_ENDIAN else "f" if self._float_order == ByteOrder.BIG_ENDIAN else "f" if self._float_order == ByteOrder.BIG_ENDIAN else "f" if self._float_order == ByteOrder.BIG_ENDIAN else "d" if self._double_order == ByteOrder.BIG_ENDIAN else "d" if self._double_order == ByteOrder.BIG_ENDIAN else "d" if self._double_order == ByteOrder.BIG_ENDIAN else "h" if self._short_order == ByteOrder.BIG_ENDIAN else "h" if self._short_order == ByteOrder.BIG_ENDIAN else "h" if self._short_order == ByteOrder.BIG_ENDIAN else "h" if self._char_order == ByteOrder.BIG_ENDIAN else "h" if self._char_order == ByteOrder.BIG_ENDIAN else "h" if self._char_order == ByteOrder.BIG_ENDIAN else " bool:
- return self._open
-
- def close(self):
- self._open = False
-
- def toString(self) -> str:
- return f"{self.__class__.__name__}@{hex(id(self))}[open={self._open}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class ReadableByteChannel(Channel):
- """A channel that can read bytes."""
- def read(self, dst) -> int:
- raise NotImplementedError
-
-
-class WritableByteChannel(Channel):
- """A channel that can write bytes."""
- def write(self, src) -> int:
- raise NotImplementedError
-
-
-class ByteChannel(ReadableByteChannel, WritableByteChannel):
- """A channel that can both read and write bytes."""
- pass
-
-
-class ScatteringByteChannel(ReadableByteChannel):
- """A channel that can read bytes into a sequence of buffers."""
- def read(self, dsts, offset=None, length=None) -> int:
- total = 0
- buffers = dsts[offset:offset + length] if offset is not None else dsts
- for buf in buffers:
- total += self.read(buf)
- return total
-
-
-class GatheringByteChannel(WritableByteChannel):
- """A channel that can write bytes from a sequence of buffers."""
- def write(self, srcs, offset=None, length=None) -> int:
- total = 0
- buffers = srcs[offset:offset + length] if offset is not None else srcs
- for buf in buffers:
- total += self.write(buf)
- return total
-
-
-class InterruptibleChannel(Channel):
- """A channel that can be asynchronously closed and interrupted."""
- pass
-
-
-# ============================================================
-# SelectionKey
-# ============================================================
-
-class SelectionKey(Stub):
- """
- java.nio.channels.SelectionKey
- A token representing the registration of a SelectableChannel with a Selector.
- """
- OP_ACCEPT: int = 1 << 4 # 16
- OP_CONNECT: int = 1 << 3 # 8
- OP_READ: int = 1 << 0 # 1
- OP_WRITE: int = 1 << 2 # 4
-
- def __init__(self, channel: "SelectableChannel", selector: "Selector",
- interest_ops: int = 0):
- super().__init__()
- self._channel = channel
- self._selector = selector
- self._interest_ops = interest_ops
- self._ready_ops = 0
- self._valid = True
- self._attachment = None
-
- def channel(self) -> "SelectableChannel":
- return self._channel
-
- def selector(self) -> "Selector":
- return self._selector
-
- def interestOps(self, ops: int = None):
- if ops is not None:
- self._interest_ops = ops
- return self
- return self._interest_ops
-
- def readyOps(self) -> int:
- return self._ready_ops
-
- def isValid(self) -> bool:
- return self._valid
-
- def isReadable(self) -> bool:
- return (self._ready_ops & SelectionKey.OP_READ) != 0
-
- def isWritable(self) -> bool:
- return (self._ready_ops & SelectionKey.OP_WRITE) != 0
-
- def isConnectable(self) -> bool:
- return (self._ready_ops & SelectionKey.OP_CONNECT) != 0
-
- def isAcceptable(self) -> bool:
- return (self._ready_ops & SelectionKey.OP_ACCEPT) != 0
-
- def cancel(self):
- self._valid = False
-
- def attach(self, ob: Any) -> Any:
- old = self._attachment
- self._attachment = ob
- return old
-
- def attachment(self) -> Any:
- return self._attachment
-
- def toString(self) -> str:
- return (f"SelectionKey@{hex(id(self))}[interest={self._interest_ops}, "
- f"ready={self._ready_ops}, valid={self._valid}]")
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(id(self)) & 0x7FFFFFFF
-
-
-# ============================================================
-# SelectableChannel
-# ============================================================
-
-class SelectableChannel(Channel):
- """
- java.nio.channels.SelectableChannel
- A channel that can be multiplexed via a Selector.
- """
-
- def __init__(self):
- super().__init__()
- self._blocking = True
- self._lock = _threading.Lock()
- self._keys = {}
-
- def register(self, sel: "Selector", ops: int, att: Any = None) -> SelectionKey:
- key = SelectionKey(self, sel, ops)
- if att is not None:
- key.attach(att)
- self._keys[sel] = key
- sel._register_key(key)
- return key
-
- def configureBlocking(self, block: bool) -> "SelectableChannel":
- self._blocking = block
- return self
-
- def isBlocking(self) -> bool:
- return self._blocking
-
- def blockingLock(self) -> Any:
- return self._lock
-
- def keyFor(self, sel: "Selector") -> Optional[SelectionKey]:
- return self._keys.get(sel)
-
- def provider(self):
- return None
-
- def validOps(self) -> int:
- return 0
-
-
-# ============================================================
-# Selector
-# ============================================================
-
-class Selector(Stub):
- """
- java.nio.channels.Selector
- A selector for selectable channels.
- """
-
- def __init__(self):
- super().__init__()
- self._open = True
- self._keys = {}
- self._selected_keys = set()
-
- def _register_key(self, key: SelectionKey):
- self._keys[key.channel()] = key
-
- @staticmethod
- def open() -> "Selector":
- return Selector()
-
- def isOpen(self) -> bool:
- return self._open
-
- def provider(self):
- return None
-
- def keys(self) -> Set[SelectionKey]:
- return set(self._keys.values())
-
- def selectedKeys(self) -> Set[SelectionKey]:
- return self._selected_keys
-
- def selectNow(self) -> int:
- """Non-blocking select. Returns number of ready channels."""
- return self._do_select(0)
-
- def select(self, timeout: int = 0) -> int:
- """Blocking select with optional timeout (ms)."""
- return self._do_select(timeout)
-
- def _do_select(self, timeout_ms: int) -> int:
- """Internal select implementation using Python select module."""
- read_fds = []
- write_fds = []
- for ch, key in self._keys.items():
- ops = key.interestOps()
- if hasattr(ch, '_socket') and ch._socket:
- fd = ch._socket
- if ops & SelectionKey.OP_READ:
- read_fds.append(fd)
- if ops & SelectionKey.OP_WRITE:
- write_fds.append(fd)
-
- timeout_s = timeout_ms / 1000.0 if timeout_ms > 0 else None
- ready_count = 0
-
- try:
- r_ready, w_ready, _ = _select.select(read_fds, write_fds, [], timeout_s if timeout_s else 0)
- except (ValueError, _socket.error):
- return 0
-
- self._selected_keys.clear()
- for fd in r_ready:
- for ch, key in self._keys.items():
- if hasattr(ch, '_socket') and ch._socket is fd:
- key._ready_ops |= SelectionKey.OP_READ
- self._selected_keys.add(key)
- ready_count += 1
- for fd in w_ready:
- for ch, key in self._keys.items():
- if hasattr(ch, '_socket') and ch._socket is fd:
- key._ready_ops |= SelectionKey.OP_WRITE
- self._selected_keys.add(key)
- ready_count += 1
-
- return ready_count
-
- def wakeup(self):
- """Wakes up a selector that is blocked on a select operation."""
- pass
-
- def close(self):
- self._open = False
- self._keys.clear()
- self._selected_keys.clear()
-
- def toString(self) -> str:
- return f"Selector@{hex(id(self))}[open={self._open}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# ServerSocketChannel
-# ============================================================
-
-class ServerSocketChannel(SelectableChannel):
- """
- java.nio.channels.ServerSocketChannel
- A selectable channel for stream-oriented listening sockets.
- """
-
- def __init__(self):
- super().__init__()
- self._socket = None
- self._server_socket = None
- self._local_address = None
-
- @staticmethod
- def open() -> "ServerSocketChannel":
- return ServerSocketChannel()
-
- def bind(self, local: Any, backlog: int = 50):
- """Binds the channel's socket to a local address."""
- if self._socket is None:
- self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1)
- if hasattr(local, 'getPort') and hasattr(local, 'getHostName'):
- addr = (local.getHostName(), local.getPort())
- elif isinstance(local, tuple):
- addr = local
- else:
- addr = ('0.0.0.0', 0)
- self._socket.bind(addr)
- self._socket.listen(backlog)
- self._local_address = self._socket.getsockname()
- return self
-
- def accept(self) -> Optional["SocketChannel"]:
- """Accepts a connection."""
- if self._socket is None:
- return None
- try:
- conn, addr = self._socket.accept()
- sc = SocketChannel()
- sc._socket = conn
- sc._connected = True
- sc._remote_address = addr
- return sc
- except (BlockingIOError, _socket.error):
- return None
-
- def socket(self):
- """Returns the underlying ServerSocket."""
- return self._server_socket
-
- def getLocalAddress(self):
- """Returns the local address of this channel."""
- return self._local_address
-
- def setOption(self, name, value):
- if self._socket:
- self._socket.setsockopt(_socket.SOL_SOCKET, name, value)
- return self
-
- def getOption(self, name):
- if self._socket:
- return self._socket.getsockopt(_socket.SOL_SOCKET, name)
- return None
-
- def supportsOption(self, name) -> bool:
- return True
-
- def validOps(self) -> int:
- return SelectionKey.OP_ACCEPT
-
- def close(self):
- super().close()
- if self._socket:
- self._socket.close()
-
- def toString(self) -> str:
- return f"ServerSocketChannel@{hex(id(self))}[local={self._local_address}]"
-
-
-# ============================================================
-# SocketChannel
-# ============================================================
-
-class SocketChannel(SelectableChannel):
- """
- java.nio.channels.SocketChannel
- A selectable channel for stream-oriented connecting sockets.
- """
-
- def __init__(self):
- super().__init__()
- self._socket = None
- self._connected = False
- self._connection_pending = False
- self._remote_address = None
- self._local_address = None
- self._input_shutdown = False
- self._output_shutdown = False
-
- @staticmethod
- def open() -> "SocketChannel":
- return SocketChannel()
-
- def connect(self, remote: Any) -> bool:
- """Connects this channel's socket to the remote address."""
- if self._socket is None:
- self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- if hasattr(remote, 'getHostName') and hasattr(remote, 'getPort'):
- addr = (remote.getHostName(), remote.getPort())
- elif isinstance(remote, tuple):
- addr = remote
- else:
- addr = (str(remote), 0)
- try:
- self._socket.connect(addr)
- self._connected = True
- self._remote_address = addr
- self._local_address = self._socket.getsockname()
- return True
- except _socket.error:
- self._connection_pending = True
- return False
-
- def finishConnect(self) -> bool:
- """Finishes the connection process."""
- self._connected = True
- self._connection_pending = False
- return True
-
- def isConnected(self) -> bool:
- return self._connected
-
- def isConnectionPending(self) -> bool:
- return self._connection_pending
-
- def read(self, dst) -> int:
- """Reads bytes from this channel into the given buffer."""
- if not self._connected or self._socket is None:
- return -1
- try:
- data = self._socket.recv(4096)
- if not data:
- return -1
- from ..nio import ByteBuffer
- if isinstance(dst, ByteBuffer):
- for b in data:
- dst.put(b)
- return len(data)
- except (_socket.error, BlockingIOError):
- return 0
-
- def write(self, src) -> int:
- """Writes bytes to this channel from the given buffer."""
- if not self._connected or self._socket is None:
- return 0
- from ..nio import ByteBuffer
- if isinstance(src, ByteBuffer):
- data = bytearray()
- for i in range(src.position(), src.limit()):
- data.append(src.get(i))
- try:
- return self._socket.send(bytes(data))
- except _socket.error:
- return 0
-
- def socket(self):
- return self._socket
-
- def getRemoteAddress(self):
- return self._remote_address
-
- def getLocalAddress(self):
- return self._local_address
-
- def shutdownInput(self):
- self._input_shutdown = True
- if self._socket:
- try:
- self._socket.shutdown(_socket.SHUT_RD)
- except _socket.error:
- pass
-
- def shutdownOutput(self):
- self._output_shutdown = True
- if self._socket:
- try:
- self._socket.shutdown(_socket.SHUT_WR)
- except _socket.error:
- pass
-
- def setOption(self, name, value):
- if self._socket:
- self._socket.setsockopt(_socket.SOL_SOCKET, name, value)
- return self
-
- def getOption(self, name):
- if self._socket:
- return self._socket.getsockopt(_socket.SOL_SOCKET, name)
- return None
-
- def supportsOption(self, name) -> bool:
- return True
-
- def validOps(self) -> int:
- return SelectionKey.OP_READ | SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT
-
- def close(self):
- super().close()
- self._connected = False
- if self._socket:
- self._socket.close()
-
- def toString(self) -> str:
- return f"SocketChannel@{hex(id(self))}[connected={self._connected}]"
-
-
-# ============================================================
-# DatagramChannel
-# ============================================================
-
-class DatagramChannel(SelectableChannel):
- """
- java.nio.channels.DatagramChannel
- A selectable channel for datagram-oriented sockets.
- """
-
- def __init__(self):
- super().__init__()
- self._socket = None
- self._connected = False
- self._remote_address = None
- self._local_address = None
-
- @staticmethod
- def open() -> "DatagramChannel":
- return DatagramChannel()
-
- def bind(self, local: Any):
- if self._socket is None:
- self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM)
- if hasattr(local, 'getPort'):
- addr = ('0.0.0.0', local.getPort())
- elif isinstance(local, tuple):
- addr = local
- else:
- addr = ('0.0.0.0', 0)
- self._socket.bind(addr)
- self._local_address = self._socket.getsockname()
- return self
-
- def connect(self, remote: Any):
- if self._socket is None:
- self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM)
- if hasattr(remote, 'getHostName') and hasattr(remote, 'getPort'):
- addr = (remote.getHostName(), remote.getPort())
- elif isinstance(remote, tuple):
- addr = remote
- else:
- addr = (str(remote), 0)
- self._socket.connect(addr)
- self._connected = True
- self._remote_address = addr
-
- def disconnect(self):
- self._connected = False
- self._remote_address = None
-
- def isConnected(self) -> bool:
- return self._connected
-
- def receive(self, dst) -> Any:
- """Receives a datagram."""
- if self._socket is None:
- return None
- try:
- data, addr = self._socket.recvfrom(65535)
- from ..nio import ByteBuffer
- if isinstance(dst, ByteBuffer):
- for b in data:
- dst.put(b)
- return addr
- except (_socket.error, BlockingIOError):
- return None
-
- def send(self, src, target) -> int:
- """Sends a datagram."""
- if self._socket is None:
- return 0
- from ..nio import ByteBuffer
- if isinstance(src, ByteBuffer):
- data = bytearray()
- for i in range(src.position(), src.limit()):
- data.append(src.get(i))
- if hasattr(target, 'getHostName') and hasattr(target, 'getPort'):
- addr = (target.getHostName(), target.getPort())
- else:
- addr = target
- try:
- return self._socket.sendto(bytes(data), addr)
- except _socket.error:
- return 0
- return 0
-
- def read(self, dst) -> int:
- """Reads a datagram (connected mode)."""
- return self.receive(dst)
-
- def write(self, src) -> int:
- """Writes a datagram (connected mode)."""
- return self.send(src, self._remote_address)
-
- def socket(self):
- return self._socket
-
- def getRemoteAddress(self):
- return self._remote_address
-
- def getLocalAddress(self):
- return self._local_address
-
- def setOption(self, name, value):
- if self._socket:
- self._socket.setsockopt(_socket.SOL_SOCKET, name, value)
- return self
-
- def getOption(self, name):
- if self._socket:
- return self._socket.getsockopt(_socket.SOL_SOCKET, name)
- return None
-
- def supportsOption(self, name) -> bool:
- return True
-
- def validOps(self) -> int:
- return SelectionKey.OP_READ | SelectionKey.OP_WRITE
-
- def close(self):
- super().close()
- if self._socket:
- self._socket.close()
-
- def toString(self) -> str:
- return f"DatagramChannel@{hex(id(self))}[connected={self._connected}]"
-
-
-# ============================================================
-# Pipe
-# ============================================================
-
-class Pipe(Stub):
- """
- java.nio.channels.Pipe
- A pair of channels that implements a unidirectional pipe.
- """
-
- class SourceChannel(SelectableChannel):
- """The readable end of the pipe."""
- def __init__(self, r_fd):
- super().__init__()
- self._r_fd = r_fd
-
- def read(self, dst) -> int:
- data = _os.read(self._r_fd, 4096)
- from ..nio import ByteBuffer
- if isinstance(dst, ByteBuffer):
- for b in data:
- dst.put(b)
- return len(data)
-
- def validOps(self) -> int:
- return SelectionKey.OP_READ
-
- def close(self):
- super().close()
- _os.close(self._r_fd)
-
- class SinkChannel(SelectableChannel):
- """The writable end of the pipe."""
- def __init__(self, w_fd):
- super().__init__()
- self._w_fd = w_fd
-
- def write(self, src) -> int:
- from ..nio import ByteBuffer
- if isinstance(src, ByteBuffer):
- data = bytearray()
- for i in range(src.position(), src.limit()):
- data.append(src.get(i))
- return _os.write(self._w_fd, bytes(data))
- return 0
-
- def validOps(self) -> int:
- return SelectionKey.OP_WRITE
-
- def close(self):
- super().close()
- _os.close(self._w_fd)
-
- @staticmethod
- def open() -> "Pipe":
- pipe = Pipe()
- r, w = _os.pipe()
- pipe._source = Pipe.SourceChannel(r)
- pipe._sink = Pipe.SinkChannel(w)
- return pipe
-
- def source(self) -> SourceChannel:
- return self._source
-
- def sink(self) -> SinkChannel:
- return self._sink
-
- def toString(self) -> str:
- return f"Pipe@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# FileChannel MapMode
-# ============================================================
-
-class FileChannelMapMode(Stub):
- """
- java.nio.channels.FileChannel.MapMode
- A file mapping mode.
- """
- READ_ONLY: "FileChannelMapMode" = None
- READ_WRITE: "FileChannelMapMode" = None
- PRIVATE: "FileChannelMapMode" = None
-
- def __init__(self, name: str):
- super().__init__()
- self._name = name
-
- def toString(self) -> str:
- return self._name
-
- def equals(self, other) -> bool:
- return isinstance(other, FileChannelMapMode) and self._name == other._name
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
-
-FileChannelMapMode.READ_ONLY = FileChannelMapMode("READ_ONLY")
-FileChannelMapMode.READ_WRITE = FileChannelMapMode("READ_WRITE")
-FileChannelMapMode.PRIVATE = FileChannelMapMode("PRIVATE")
-
-
-# ============================================================
-# FileChannel
-# ============================================================
-
-class FileChannel(Channel):
- """
- java.nio.channels.FileChannel
- A channel for reading, writing, mapping, and manipulating a file.
- """
- IMPL_OPEN_LOCKING: bool = True
-
- def __init__(self, file_path: str = None, mode: str = 'r'):
- super().__init__()
- self._file_path = file_path
- self._mode = mode
- self._fd = None
- self._position = 0
- if file_path:
- self._fd = _os.open(file_path, self._get_os_flags(mode))
-
- @staticmethod
- def open(path: Any, options=None, attrs=None) -> "FileChannel":
- """Opens a file channel."""
- return FileChannel(str(path))
-
- def _get_os_flags(self, mode: str) -> int:
- flags = 0
- if 'r' in mode and 'w' not in mode and '+' not in mode:
- flags = _os.O_RDONLY
- elif 'w' in mode or '+' in mode:
- flags = _os.O_RDWR | _os.O_CREAT
- return flags
-
- def read(self, dst) -> int:
- """Reads bytes from this channel into the given buffer."""
- if self._fd is None:
- return -1
- try:
- data = _os.read(self._fd, 4096)
- if not data:
- return -1
- from ..nio import ByteBuffer
- if isinstance(dst, ByteBuffer):
- for b in data:
- dst.put(b)
- self._position += len(data)
- return len(data)
- except OSError:
- return -1
-
- def read(self, dsts, offset: int = 0, length: int = 0) -> int:
- total = 0
- bufs = dsts[offset:offset + length] if length else dsts
- for buf in bufs:
- n = self.read(buf)
- if n < 0:
- break
- total += n
- return total
-
- def write(self, src) -> int:
- """Writes bytes to this channel from the given buffer."""
- if self._fd is None:
- return 0
- from ..nio import ByteBuffer
- if isinstance(src, ByteBuffer):
- data = bytearray()
- for i in range(src.position(), src.limit()):
- data.append(src.get(i))
- try:
- written = _os.write(self._fd, bytes(data))
- self._position += written
- return written
- except OSError:
- return 0
- return 0
-
- def write(self, srcs, offset: int = 0, length: int = 0) -> int:
- total = 0
- bufs = srcs[offset:offset + length] if length else srcs
- for buf in bufs:
- total += self.write(buf)
- return total
-
- def position(self) -> int:
- """Returns this channel's file position."""
- if self._fd is not None:
- self._position = _os.lseek(self._fd, 0, _os.SEEK_CUR)
- return self._position
-
- def position(self, new_position: int) -> "FileChannel":
- """Sets this channel's file position."""
- if self._fd is not None:
- _os.lseek(self._fd, new_position, _os.SEEK_SET)
- self._position = new_position
- return self
-
- def size(self) -> int:
- """Returns the current size of this channel's file."""
- if self._fd is not None:
- return _os.lseek(self._fd, 0, _os.SEEK_END)
- return 0
-
- def truncate(self, size: int) -> "FileChannel":
- """Truncates the file to the given size."""
- if self._fd is not None:
- _os.ftruncate(self._fd, size)
- return self
-
- def force(self, meta_data: bool):
- """Forces any updates to this channel's file to be written to storage."""
- if self._fd is not None:
- _os.fsync(self._fd)
-
- def transferTo(self, position: int, count: int, target: WritableByteChannel) -> int:
- """Transfers bytes from this channel to the given writable channel."""
- old_pos = self.position()
- self.position(position)
- from ..nio import ByteBuffer
- buf = ByteBuffer.allocate(count)
- n = self.read(buf)
- buf.flip()
- target.write(buf)
- self.position(old_pos)
- return n
-
- def transferFrom(self, src: ReadableByteChannel, position: int, count: int) -> int:
- """Transfers bytes from the given readable channel to this channel."""
- old_pos = self.position()
- self.position(position)
- from ..nio import ByteBuffer
- buf = ByteBuffer.allocate(count)
- n = src.read(buf)
- buf.flip()
- self.write(buf)
- self.position(old_pos)
- return n
-
- def map(self, mode: FileChannelMapMode, position: int, size: int):
- """Maps a region of this channel's file into memory (stub)."""
- return None
-
- def lock(self, position: int = 0, size: int = 0, shared: bool = False):
- """Locks a region of this channel's file (stub)."""
- return None
-
- def tryLock(self, position: int = 0, size: int = 0, shared: bool = False):
- """Attempts to lock a region of this channel's file (stub)."""
- return None
-
- def close(self):
- super().close()
- if self._fd is not None:
- _os.close(self._fd)
- self._fd = None
-
- def toString(self) -> str:
- return f"FileChannel@{hex(id(self))}[path={self._file_path}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# AsynchronousChannel stubs
-# ============================================================
-
-class CompletionHandler(Stub):
- """
- java.nio.channels.CompletionHandler
- A handler for consuming the result of an asynchronous I/O operation.
- """
- def completed(self, result, attachment):
- raise NotImplementedError
-
- def failed(self, exc: Exception, attachment):
- raise NotImplementedError
-
-
-class AsynchronousChannel(Channel):
- """An asynchronous channel for I/O operations."""
- pass
-
-
-class AsynchronousByteChannel(AsynchronousChannel):
- """An asynchronous channel that can read and write bytes."""
- pass
-
-
-class AsynchronousChannelGroup(Stub):
- """
- java.nio.channels.AsynchronousChannelGroup
- A grouping of asynchronous channels.
- """
- def __init__(self):
- super().__init__()
- self._channels = []
-
- def shutdown(self):
- pass
-
- def shutdownNow(self):
- pass
-
- def awaitTermination(self, timeout: int, unit) -> bool:
- return True
-
- def isShutdown(self) -> bool:
- return False
-
- def isTerminated(self) -> bool:
- return False
-
- def toString(self) -> str:
- return f"AsynchronousChannelGroup@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class AsynchronousServerSocketChannel(AsynchronousChannel):
- """An asynchronous channel for stream-oriented listening sockets."""
- @staticmethod
- def open(group: AsynchronousChannelGroup = None) -> "AsynchronousServerSocketChannel":
- return AsynchronousServerSocketChannel()
-
- def bind(self, local: Any) -> "AsynchronousServerSocketChannel":
- return self
-
- def accept(self, attachment=None, handler: CompletionHandler = None):
- pass
-
- def getLocalAddress(self):
- return None
-
- def setOption(self, name, value):
- return self
-
- def close(self):
- pass
-
- def toString(self) -> str:
- return f"AsynchronousServerSocketChannel@{hex(id(self))}"
-
-
-class AsynchronousSocketChannel(AsynchronousByteChannel):
- """An asynchronous channel for stream-oriented connecting sockets."""
- @staticmethod
- def open(group: AsynchronousChannelGroup = None) -> "AsynchronousSocketChannel":
- return AsynchronousSocketChannel()
-
- def connect(self, remote: Any, attachment=None, handler: CompletionHandler = None):
- pass
-
- def read(self, dst, attachment=None, handler: CompletionHandler = None):
- pass
-
- def write(self, src, attachment=None, handler: CompletionHandler = None):
- pass
-
- def getRemoteAddress(self):
- return None
-
- def getLocalAddress(self):
- return None
-
- def shutdownInput(self):
- pass
-
- def shutdownOutput(self):
- pass
-
- def close(self):
- pass
-
- def toString(self) -> str:
- return f"AsynchronousSocketChannel@{hex(id(self))}"
-
-
-class AsynchronousFileChannel(AsynchronousChannel):
- """An asynchronous channel for reading, writing, and manipulating a file."""
- @staticmethod
- def open(path: Any, options=None, executor=None, attrs=None) -> "AsynchronousFileChannel":
- return AsynchronousFileChannel()
-
- def read(self, dst, position: int, attachment=None, handler: CompletionHandler = None):
- pass
-
- def write(self, src, position: int, attachment=None, handler: CompletionHandler = None):
- pass
-
- def lock(self, position: int = 0, size: int = 0, shared: bool = False,
- attachment=None, handler: CompletionHandler = None):
- pass
-
- def tryLock(self, position: int = 0, size: int = 0, shared: bool = False):
- return None
-
- def size(self) -> int:
- return 0
-
- def truncate(self, size: int) -> "AsynchronousFileChannel":
- return self
-
- def force(self, meta_data: bool):
- pass
-
- def close(self):
- pass
-
- def isOpen(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"AsynchronousFileChannel@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/java/nio_charset.py b/android_pyapi/java/nio_charset.py
deleted file mode 100644
index 0acef20..0000000
--- a/android_pyapi/java/nio_charset.py
+++ /dev/null
@@ -1,573 +0,0 @@
-"""
-Java java.nio.charset APIs implemented in Python.
-java.nio.charset package - Charset, CharsetEncoder, CharsetDecoder, CoderResult, etc.
-Wraps Python codecs module.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-import codecs as _codecs
-import encodings as _encodings
-from typing import Set as _Set, List as _List
-
-__all__ = [
- "Charset", "CharsetEncoder", "CharsetDecoder", "CoderResult",
- "CodingErrorAction", "StandardCharsets",
-]
-
-
-# ============================================================
-# CodingErrorAction
-# ============================================================
-
-class CodingErrorAction(Stub):
- """
- java.nio.charset.CodingErrorAction
- Describes actions that a charset encoder or decoder may take on a coding error.
- """
- REPORT: "CodingErrorAction" = None
- IGNORE: "CodingErrorAction" = None
- REPLACE: "CodingErrorAction" = None
-
- def __init__(self, name: str):
- super().__init__()
- self._name = name
-
- def name(self) -> str:
- return self._name
-
- def toString(self) -> str:
- return self._name
-
- def equals(self, other) -> bool:
- if isinstance(other, CodingErrorAction):
- return self._name == other._name
- return False
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
-
-CodingErrorAction.REPORT = CodingErrorAction("REPORT")
-CodingErrorAction.IGNORE = CodingErrorAction("IGNORE")
-CodingErrorAction.REPLACE = CodingErrorAction("REPLACE")
-
-
-# ============================================================
-# CoderResult
-# ============================================================
-
-class CoderResult(Stub):
- """
- java.nio.charset.CoderResult
- Describes the result state of a coder (encoder or decoder).
- """
- UNDERFLOW: "CoderResult" = None
- OVERFLOW: "CoderResult" = None
-
- def __init__(self, _type: str, _length: int = 0):
- super().__init__()
- self._type = _type
- self._length = _length
-
- def isUnderflow(self) -> bool:
- """Returns True if the result is underflow (more input needed)."""
- return self._type == "UNDERFLOW"
-
- def isOverflow(self) -> bool:
- """Returns True if the result is overflow (output buffer too small)."""
- return self._type == "OVERFLOW"
-
- def isError(self) -> bool:
- """Returns True if the result is an error (malformed or unmappable)."""
- return self._type in ("MALFORMED", "UNMAPPABLE")
-
- def isMalformed(self) -> bool:
- """Returns True if the result is a malformed-input error."""
- return self._type == "MALFORMED"
-
- def isUnmappable(self) -> bool:
- """Returns True if the result is an unmappable-character error."""
- return self._type == "UNMAPPABLE"
-
- def length(self) -> int:
- """Returns the length of the erroneous input (for errors)."""
- return self._length
-
- @classmethod
- def malformedForLength(cls, length: int) -> "CoderResult":
- """Creates a malformed CoderResult for the given length."""
- return cls("MALFORMED", length)
-
- @classmethod
- def unmappableForLength(cls, length: int) -> "CoderResult":
- """Creates an unmappable CoderResult for the given length."""
- return cls("UNMAPPABLE", length)
-
- def toString(self) -> str:
- if self._type == "UNDERFLOW":
- return "UNDERFLOW"
- elif self._type == "OVERFLOW":
- return "OVERFLOW"
- return f"{self._type}[{self._length}]"
-
- def equals(self, other) -> bool:
- if not isinstance(other, CoderResult):
- return False
- return self._type == other._type and self._length == other._length
-
- def hashCode(self) -> int:
- return hash((self._type, self._length)) & 0x7FFFFFFF
-
-
-CoderResult.UNDERFLOW = CoderResult("UNDERFLOW")
-CoderResult.OVERFLOW = CoderResult("OVERFLOW")
-
-
-# ============================================================
-# Charset
-# ============================================================
-
-class Charset(Stub):
- """
- java.nio.charset.Charset
- A named mapping between sequences of 16-bit Unicode characters
- and sequences of bytes.
- """
-
- _cache: dict = {}
- _aliases: dict = {}
-
- # Standard charset constants
- US_ASCII: "Charset" = None
- ISO_8859_1: "Charset" = None
- UTF_8: "Charset" = None
- UTF_16: "Charset" = None
- UTF_16BE: "Charset" = None
- UTF_16LE: "Charset" = None
-
- def __init__(self, canonical_name: str, aliases: _List[str] = None):
- super().__init__()
- self._name = canonical_name
- self._aliases = aliases or []
- self._registered = True
-
- def name(self) -> str:
- """Returns the canonical name of this charset."""
- return self._name
-
- def displayName(self, locale=None) -> str:
- """Returns the display name of this charset."""
- return self._name
-
- def aliases(self) -> _Set[str]:
- """Returns a set containing this charset's aliases."""
- return set(self._aliases)
-
- def isRegistered(self) -> bool:
- """Returns True if this charset is registered in the IANA registry."""
- return self._registered
-
- def canEncode(self) -> bool:
- """Returns True if this charset supports encoding."""
- try:
- _codecs.lookup(self._name)
- return True
- except LookupError:
- return False
-
- def encode(self, text: str) -> "ByteBuffer":
- """
- Converts a string into bytes using this charset.
- Returns a ByteBuffer.
- """
- encoded = text.encode(self._name, errors="replace")
- from ..nio import ByteBuffer
- buf = ByteBuffer.allocate(len(encoded))
- buf.put(list(encoded))
- buf.flip()
- return buf
-
- def decode(self, buf: "ByteBuffer") -> "CharBuffer":
- """
- Converts bytes from a ByteBuffer into a CharBuffer.
- """
- arr = bytearray()
- for i in range(buf.position(), buf.limit()):
- arr.append(buf.get(i))
- decoded = arr.decode(self._name, errors="replace")
- from ..nio import CharBuffer
- cb = CharBuffer.allocate(len(decoded))
- cb.put(decoded)
- cb.flip()
- return cb
-
- def newDecoder(self) -> "CharsetDecoder":
- """Returns a new CharsetDecoder for this charset."""
- return CharsetDecoder(self)
-
- def newEncoder(self) -> "CharsetEncoder":
- """Returns a new CharsetEncoder for this charset."""
- return CharsetEncoder(self)
-
- def toString(self) -> str:
- return self._name
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
- def equals(self, other) -> bool:
- if not isinstance(other, Charset):
- return False
- return self._name == other._name
-
- def compareTo(self, other: "Charset") -> int:
- """Compares this charset to another by canonical name."""
- if not isinstance(other, Charset):
- return -1
- if self._name < other._name:
- return -1
- elif self._name > other._name:
- return 1
- return 0
-
- @classmethod
- def forName(cls, charset_name: str) -> "Charset":
- """Returns a Charset for the given charset name."""
- if charset_name in cls._cache:
- return cls._cache[charset_name]
-
- try:
- _codecs.lookup(charset_name)
- except LookupError:
- raise AndroidOnlyError(f"Charset not found: {charset_name}")
-
- # Resolve aliases
- canonical = charset_name.lower()
- alias_map = {
- "ascii": "US-ASCII", "us-ascii": "US-ASCII",
- "iso-8859-1": "ISO-8859-1", "latin1": "ISO-8859-1",
- "utf-8": "UTF-8", "utf8": "UTF-8",
- "utf-16": "UTF-16", "utf16": "UTF-16",
- "utf-16be": "UTF-16BE", "utf16be": "UTF-16BE",
- "utf-16le": "UTF-16LE", "utf16le": "UTF-16LE",
- }
- canonical_name = alias_map.get(canonical, charset_name.upper())
-
- charset = cls(canonical_name)
- cls._cache[charset_name] = charset
- return charset
-
- @classmethod
- def forNameUEE(cls, charset_name: str) -> "Charset":
- """Same as forName but wraps exception."""
- try:
- return cls.forName(charset_name)
- except Exception:
- return None
-
- @classmethod
- def isSupported(cls, charset_name: str) -> bool:
- """Returns True if the named charset is supported."""
- try:
- _codecs.lookup(charset_name)
- return True
- except LookupError:
- return False
-
- @classmethod
- def defaultCharset(cls) -> "Charset":
- """Returns the default charset of the JVM (platform native encoding)."""
- import locale
- enc = locale.getpreferredencoding()
- return cls.forName(enc)
-
- @classmethod
- def availableCharsets(cls) -> dict:
- """Returns a sorted map of available charset names to Charset objects."""
- result = {}
- for name in _codecs.available_encodings():
- try:
- result[name] = cls.forName(name)
- except Exception:
- pass
- return result
-
- @classmethod
- def requiredCharsets(cls) -> _Set[str]:
- """Returns the set of required charset names per Java spec."""
- return {
- "US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16",
- "UTF-16BE", "UTF-16LE",
- }
-
-
-# Initialize standard charset constants
-Charset.US_ASCII = Charset("US-ASCII", ["ASCII", "US-ASCII", "ascii", "cp367"])
-Charset.ISO_8859_1 = Charset("ISO-8859-1", ["ISO-8859-1", "latin1", "LATIN-1", "l1", "cp819"])
-Charset.UTF_8 = Charset("UTF-8", ["UTF-8", "utf8", "UTF8"])
-Charset.UTF_16 = Charset("UTF-16", ["UTF-16", "utf16", "UTF16", "UnicodeBig"])
-Charset.UTF_16BE = Charset("UTF-16BE", ["UTF-16BE", "utf16be", "UTF16BE", "ISO-10646-UCS-2"])
-Charset.UTF_16LE = Charset("UTF-16LE", ["UTF-16LE", "utf16le", "UTF16LE"])
-
-
-# ============================================================
-# CharsetEncoder
-# ============================================================
-
-class CharsetEncoder(Stub):
- """
- java.nio.charset.CharsetEncoder
- Converts character data to byte data using a Charset.
- """
-
- def __init__(self, charset: Charset, average_bytes_per_char: float = 1.0,
- max_bytes_per_char: float = 4.0, replacement: bytes = b'?'):
- super().__init__()
- self._charset = charset
- self._average_bytes_per_char = average_bytes_per_char
- self._max_bytes_per_char = max_bytes_per_char
- self._replacement = replacement
- self._malformed_input_action = CodingErrorAction.REPORT
- self._unmappable_action = CodingErrorAction.REPORT
-
- def charset(self) -> Charset:
- """Returns the charset that created this encoder."""
- return self._charset
-
- def replacement(self) -> bytes:
- """Returns the replacement value."""
- return self._replacement
-
- def replaceWith(self, new_replacement: bytes) -> "CharsetEncoder":
- """Sets a new replacement value."""
- self._replacement = new_replacement
- return self
-
- def encode(self, input_str: str) -> "ByteBuffer":
- """Encodes a string into bytes."""
- encoded = input_str.encode(self._charset.name(), errors="replace")
- from ..nio import ByteBuffer
- buf = ByteBuffer.allocate(len(encoded))
- buf.put(list(encoded))
- buf.flip()
- return buf
-
- def encode(self, input: "CharBuffer", output: "ByteBuffer", end_of_input: bool) -> CoderResult:
- """Encodes as much as possible from input to output."""
- in_str = ""
- for i in range(input.position(), input.limit()):
- in_str += chr(input.get(i))
- try:
- encoded = in_str.encode(self._charset.name())
- from ..nio import ByteBuffer
- out_arr = bytearray()
- for i in range(output.position(), output.limit()):
- if i < len(encoded):
- out_arr.append(encoded[i])
- return CoderResult.UNDERFLOW
- except UnicodeEncodeError:
- return CoderResult.unmappableForLength(1)
-
- def encodeLoop(self, input: "CharBuffer", output: "ByteBuffer") -> CoderResult:
- """The encoding loop (subclass hook)."""
- return self.encode(input, output, True)
-
- def implReplaceWith(self, new_replacement: bytes):
- """Hook for subclasses to react to replacement changes."""
- pass
-
- def implOnMalformedInput(self, new_action: CodingErrorAction):
- """Hook for subclasses to react to malformed input action changes."""
- pass
-
- def implOnUnmappableCharacter(self, new_action: CodingErrorAction):
- """Hook for subclasses to react to unmappable char action changes."""
- pass
-
- def implReset(self):
- """Hook for subclasses to reset internal state."""
- pass
-
- def averageBytesPerChar(self) -> float:
- return self._average_bytes_per_char
-
- def maxBytesPerChar(self) -> float:
- return self._max_bytes_per_char
-
- def isLegalReplacement(self, repl: bytes) -> bool:
- """Returns True if the replacement is a legal byte sequence."""
- return len(repl) > 0
-
- def malformedInputAction(self) -> CodingErrorAction:
- return self._malformed_input_action
-
- def unmappableCharacterAction(self) -> CodingErrorAction:
- return self._unmappable_action
-
- def onMalformedInput(self, action: CodingErrorAction) -> "CharsetEncoder":
- self._malformed_input_action = action
- return self
-
- def onUnmappableCharacter(self, action: CodingErrorAction) -> "CharsetEncoder":
- self._unmappable_action = action
- return self
-
- def reset(self) -> "CharsetEncoder":
- """Resets this encoder, clearing any internal state."""
- self.implReset()
- return self
-
- def toString(self) -> str:
- return f"CharsetEncoder@{hex(id(self))}[charset={self._charset.name()}]"
-
- def equals(self, other) -> bool:
- if not isinstance(other, CharsetEncoder):
- return False
- return self._charset == other._charset
-
- def hashCode(self) -> int:
- return hash(self._charset.name()) & 0x7FFFFFFF
-
-
-# ============================================================
-# CharsetDecoder
-# ============================================================
-
-class CharsetDecoder(Stub):
- """
- java.nio.charset.CharsetDecoder
- Converts byte data to character data using a Charset.
- """
-
- def __init__(self, charset: Charset, average_chars_per_byte: float = 1.0,
- max_chars_per_byte: float = 2.0, replacement: str = '\ufffd'):
- super().__init__()
- self._charset = charset
- self._average_chars_per_byte = average_chars_per_byte
- self._max_chars_per_byte = max_chars_per_byte
- self._replacement = replacement
- self._malformed_input_action = CodingErrorAction.REPORT
- self._unmappable_action = CodingErrorAction.REPORT
- self._auto_detect = False
- self._detected_charset = None
-
- def charset(self) -> Charset:
- """Returns the charset that created this decoder."""
- return self._charset
-
- def replacement(self) -> str:
- """Returns the replacement value."""
- return self._replacement
-
- def replaceWith(self, new_replacement: str) -> "CharsetDecoder":
- """Sets a new replacement value."""
- self._replacement = new_replacement
- return self
-
- def decode(self, buf: "ByteBuffer") -> "CharBuffer":
- """Decodes bytes from a ByteBuffer into a CharBuffer."""
- arr = bytearray()
- for i in range(buf.position(), buf.limit()):
- arr.append(buf.get(i))
- decoded = arr.decode(self._charset.name(), errors="replace")
- from ..nio import CharBuffer
- cb = CharBuffer.allocate(len(decoded))
- cb.put(decoded)
- cb.flip()
- return cb
-
- def decode(self, input: "ByteBuffer", output: "CharBuffer", end_of_input: bool) -> CoderResult:
- """Decodes as much as possible from input to output."""
- arr = bytearray()
- for i in range(input.position(), input.limit()):
- arr.append(input.get(i))
- try:
- decoded = arr.decode(self._charset.name())
- return CoderResult.UNDERFLOW
- except UnicodeDecodeError:
- return CoderResult.malformedForLength(1)
-
- def decodeLoop(self, input: "ByteBuffer", output: "CharBuffer") -> CoderResult:
- """The decoding loop (subclass hook)."""
- return self.decode(input, output, True)
-
- def implReplaceWith(self, new_replacement: str):
- """Hook for subclasses."""
- pass
-
- def implOnMalformedInput(self, new_action: CodingErrorAction):
- """Hook for subclasses."""
- pass
-
- def implOnUnmappableCharacter(self, new_action: CodingErrorAction):
- """Hook for subclasses."""
- pass
-
- def implReset(self):
- """Hook for subclasses."""
- pass
-
- def averageCharsPerByte(self) -> float:
- return self._average_chars_per_byte
-
- def maxCharsPerByte(self) -> float:
- return self._max_chars_per_byte
-
- def isCharsetDetected(self) -> bool:
- return self._detected_charset is not None
-
- def isAutoDetect(self) -> bool:
- return self._auto_detect
-
- def detectedCharset(self) -> Charset:
- if self._detected_charset is None:
- raise AndroidOnlyError("No charset detected")
- return self._detected_charset
-
- def malformedInputAction(self) -> CodingErrorAction:
- return self._malformed_input_action
-
- def unmappableCharacterAction(self) -> CodingErrorAction:
- return self._unmappable_action
-
- def onMalformedInput(self, action: CodingErrorAction) -> "CharsetDecoder":
- self._malformed_input_action = action
- return self
-
- def onUnmappableCharacter(self, action: CodingErrorAction) -> "CharsetDecoder":
- self._unmappable_action = action
- return self
-
- def reset(self) -> "CharsetDecoder":
- self.implReset()
- return self
-
- def toString(self) -> str:
- return f"CharsetDecoder@{hex(id(self))}[charset={self._charset.name()}]"
-
- def equals(self, other) -> bool:
- if not isinstance(other, CharsetDecoder):
- return False
- return self._charset == other._charset
-
- def hashCode(self) -> int:
- return hash(self._charset.name()) & 0x7FFFFFFF
-
-
-# ============================================================
-# StandardCharsets
-# ============================================================
-
-class StandardCharsets(Stub):
- """
- java.nio.charset.StandardCharsets
- Constant definitions for the standard charsets.
- """
- US_ASCII: Charset = Charset.US_ASCII
- ISO_8859_1: Charset = Charset.ISO_8859_1
- UTF_8: Charset = Charset.UTF_8
- UTF_16: Charset = Charset.UTF_16
- UTF_16BE: Charset = Charset.UTF_16BE
- UTF_16LE: Charset = Charset.UTF_16LE
\ No newline at end of file
diff --git a/android_pyapi/java/nio_file.py b/android_pyapi/java/nio_file.py
deleted file mode 100644
index 76a1131..0000000
--- a/android_pyapi/java/nio_file.py
+++ /dev/null
@@ -1,703 +0,0 @@
-"""
-Java NIO File standard library APIs implemented in Python.
-java.nio.file package - Path, Files, FileSystem, FileVisitor, etc.
-"""
-
-from .._core import Stub
-from .io import IOException
-from .lang import RuntimeException, Comparable
-import os as _os
-import shutil as _shutil
-import stat as _stat
-from pathlib import Path as _PathLibPath
-import tempfile as _tempfile
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "Path", "Paths", "Files", "FileSystem", "FileSystems",
- "FileStore", "FileVisitResult", "FileVisitor", "SimpleFileVisitor",
- "DirectoryStream", "DirectoryStreamFilter",
- "PathMatcher", "WatchService", "WatchKey", "WatchEvent", "Watchable",
- "CopyOption", "StandardCopyOption", "LinkOption", "OpenOption",
- "StandardOpenOption",
- "FileAlreadyExistsException", "DirectoryNotEmptyException",
- "NoSuchFileException", "FileSystemLoopException",
- "FileSystemNotFoundException", "ProviderMismatchException",
- "ProviderNotFoundException", "NotDirectoryException", "NotLinkException",
- "AtomicMoveNotSupportedException", "AccessDeniedException",
- "AccessMode",
-]
-
-
-# ============================================================
-# Exception classes
-# ============================================================
-
-class FileAlreadyExistsException(IOException):
- pass
-
-class DirectoryNotEmptyException(IOException):
- pass
-
-class NoSuchFileException(IOException):
- def __init__(self, file=None, other=None, reason=None):
- msg = str(file) if file else ""
- super().__init__(msg)
-
-class FileSystemLoopException(IOException):
- pass
-
-class FileSystemNotFoundException(IOException):
- pass
-
-class ProviderMismatchException(IllegalArgumentException):
- pass
-
-class ProviderNotFoundException(IllegalArgumentException):
- pass
-
-class NotDirectoryException(IOException):
- pass
-
-class NotLinkException(IOException):
- pass
-
-class AtomicMoveNotSupportedException(IOException):
- pass
-
-class AccessDeniedException(IOException):
- pass
-
-
-# ============================================================
-# Enums / Constants
-# ============================================================
-
-class FileVisitResult:
- CONTINUE = 0
- TERMINATE = 1
- SKIP_SUBTREE = 2
- SKIP_SIBLINGS = 3
-
-class StandardCopyOption:
- REPLACE_EXISTING = 0
- COPY_ATTRIBUTES = 1
- ATOMIC_MOVE = 2
-
-class StandardOpenOption:
- READ = 0
- WRITE = 1
- APPEND = 2
- TRUNCATE_EXISTING = 3
- CREATE = 4
- CREATE_NEW = 5
- DELETE_ON_CLOSE = 6
- SPARSE = 7
- SYNC = 8
- DSYNC = 9
-
-class LinkOption:
- NOFOLLOW_LINKS = 0
-
-class CopyOption(Stub):
- pass
-
-class OpenOption(Stub):
- pass
-
-class AccessMode:
- READ = 0
- WRITE = 1
- EXECUTE = 2
-
-
-# ============================================================
-# Path
-# ============================================================
-
-class Path(Comparable):
- def __init__(self, path_str, *more):
- super().__init__()
- if more:
- path_str = _os.path.join(path_str, *more)
- self._path = str(path_str)
- self._pypath = _PathLibPath(self._path)
-
- def getFileName(self):
- return Path(self._pypath.name)
-
- def getParent(self):
- parent = self._pypath.parent
- if parent == self._pypath:
- return None
- return Path(str(parent))
-
- def getRoot(self):
- root = self._pypath.anchor
- return Path(root) if root else None
-
- def toAbsolutePath(self):
- return Path(str(self._pypath.absolute()))
-
- def toRealPath(self):
- return Path(str(self._pypath.resolve()))
-
- def getName(self, index):
- parts = self._pypath.parts
- if self.getRoot():
- parts = parts[1:]
- if index < 0 or index >= len(parts):
- raise IllegalArgumentException("Invalid index")
- return Path(parts[index])
-
- def getNameCount(self):
- parts = self._pypath.parts
- if self.getRoot():
- parts = parts[1:]
- return len(parts)
-
- def subpath(self, beginIndex, endIndex):
- parts = self._pypath.parts
- if self.getRoot():
- parts = parts[1:]
- return Path(_os.path.join(*parts[beginIndex:endIndex]))
-
- def startsWith(self, other):
- if isinstance(other, Path):
- return str(self._pypath).startswith(str(other._pypath))
- return str(self._pypath).startswith(str(other))
-
- def endsWith(self, other):
- if isinstance(other, Path):
- return str(self._pypath).endswith(str(other._pypath))
- return str(self._pypath).endswith(str(other))
-
- def normalize(self):
- return Path(_os.path.normpath(self._path))
-
- def resolve(self, other):
- if isinstance(other, Path):
- other_path = str(other)
- else:
- other_path = str(other)
- if _os.path.isabs(other_path):
- return Path(other_path)
- return Path(_os.path.join(self._path, other_path))
-
- def resolveSibling(self, other):
- parent = self.getParent()
- if parent:
- return parent.resolve(other)
- return Path(other)
-
- def relativize(self, other):
- if isinstance(other, Path):
- other_str = str(other._pypath)
- else:
- other_str = str(other)
- try:
- rel = _os.path.relpath(other_str, self._path)
- return Path(rel)
- except ValueError:
- return other
-
- def compareTo(self, other):
- if isinstance(other, Path):
- return (self._path > other._path) - (self._path < other._path)
- return -1
-
- def toString(self):
- return self._path
-
- def toFile(self):
- from ..io import File
- return File(self._path)
-
- def isAbsolute(self):
- return _os.path.isabs(self._path)
-
- def getFileSystem(self):
- return FileSystems.getDefault()
-
- def iterator(self):
- parts = self._pypath.parts
- if self.getRoot():
- parts = parts[1:]
- return iter([Path(p) for p in parts])
-
- def register(self, watcher, events, *modifiers):
- raise AndroidOnlyError("WatchService nio")
-
- def __str__(self):
- return self._path
-
- def __eq__(self, other):
- if isinstance(other, Path):
- return self._path == other._path
- return NotImplemented
-
- def __hash__(self):
- return hash(self._path)
-
-
-# ============================================================
-# Paths
-# ============================================================
-
-class Paths(Stub):
- @staticmethod
- def get(first, *more):
- parts = [str(first)]
- parts.extend(str(m) for m in more)
- return Path(_os.path.join(*parts))
-
-
-# ============================================================
-# FileSystem
-# ============================================================
-
-class FileSystem(Stub):
- def __init__(self):
- super().__init__()
- self._separator = _os.sep
- self._open = True
-
- def getPath(self, first, *more):
- return Paths.get(first, *more)
-
- def getSeparator(self):
- return self._separator
-
- def getRootDirectories(self):
- if _os.name == "nt":
- import string
- return [Path(d + ":\\") for d in string.ascii_uppercase if _os.path.exists(d + ":\\")]
- return [Path("/")]
-
- def getUserPrincipalLookupService(self):
- raise AndroidOnlyError("UserPrincipalLookupService")
-
- def newWatchService(self):
- raise AndroidOnlyError("WatchService")
-
- def getFileStores(self):
- return [FileStore("/")]
-
- def supportedFileAttributeViews(self):
- return ["basic", "owner", "posix"]
-
- def close(self):
- self._open = False
-
- def isOpen(self):
- return self._open
-
- def isReadOnly(self):
- return False
-
-
-class FileSystems(Stub):
- _default = None
-
- @staticmethod
- def getDefault():
- if FileSystems._default is None:
- FileSystems._default = FileSystem()
- return FileSystems._default
-
-
-# ============================================================
-# FileStore
-# ============================================================
-
-class FileStore(Stub):
- def __init__(self, path):
- super().__init__()
- self._path = path
-
- def name(self):
- return _os.path.basename(self._path) or "/"
-
- def type(self):
- return "ext4"
-
- def isReadOnly(self):
- return False
-
- def getTotalSpace(self):
- try:
- st = _os.statvfs(self._path)
- return st.f_frsize * st.f_blocks
- except OSError:
- return 0
-
- def getUsableSpace(self):
- try:
- st = _os.statvfs(self._path)
- return st.f_frsize * st.f_bavail
- except OSError:
- return 0
-
- def getUnallocatedSpace(self):
- try:
- st = _os.statvfs(self._path)
- return st.f_frsize * st.f_bfree
- except OSError:
- return 0
-
- def toString(self):
- return f"{self.name()} ({self.type()})"
-
-
-# ============================================================
-# FileVisitor / SimpleFileVisitor
-# ============================================================
-
-class FileVisitor(Stub):
- def preVisitDirectory(self, dir, attrs):
- return FileVisitResult.CONTINUE
-
- def postVisitDirectory(self, dir, exc):
- return FileVisitResult.CONTINUE
-
- def visitFile(self, file, attrs):
- return FileVisitResult.CONTINUE
-
- def visitFileFailed(self, file, exc):
- return FileVisitResult.CONTINUE
-
-
-class SimpleFileVisitor(FileVisitor):
- pass
-
-
-# ============================================================
-# DirectoryStream / Filter
-# ============================================================
-
-class DirectoryStream(Stub):
- def __init__(self, path, filter=None):
- super().__init__()
- self._path = path
- self._filter = filter
-
- def __iter__(self):
- try:
- entries = _os.listdir(str(self._path))
- for entry in entries:
- p = Path(self._path, entry)
- if self._filter is None or self._filter.accept(p):
- yield p
- except OSError:
- raise IOException(f"Failed to list directory: {self._path}")
-
- def close(self):
- pass
-
-
-class DirectoryStreamFilter(Stub):
- def accept(self, entry):
- raise NotImplementedError
-
-
-# ============================================================
-# PathMatcher
-# ============================================================
-
-class PathMatcher(Stub):
- def __init__(self, pattern):
- super().__init__()
- self._pattern = pattern
-
- def matches(self, path):
- import fnmatch
- return fnmatch.fnmatch(str(path), self._pattern)
-
-
-# ============================================================
-# WatchService / WatchKey / WatchEvent / Watchable (stubs)
-# ============================================================
-
-class Watchable(Stub):
- def register(self, watcher, events, *modifiers):
- raise AndroidOnlyError("WatchService")
-
-class WatchService(Stub):
- def close(self):
- pass
- def poll(self):
- return None
- def take(self):
- raise AndroidOnlyError("WatchService.take")
- def poll(self, timeout, unit):
- return None
-
-class WatchKey(Stub):
- def isValid(self):
- return True
- def pollEvents(self):
- return []
- def reset(self):
- return True
- def cancel(self):
- pass
- def watchable(self):
- return None
-
-class WatchEvent(Stub):
- class Kind(Stub):
- def name(self):
- return ""
- def type(self):
- return None
-
- def kind(self):
- return None
- def count(self):
- return 0
- def context(self):
- return None
-
-
-# ============================================================
-# Files
-# ============================================================
-
-class Files(Stub):
- @staticmethod
- def copy(source, target, *options):
- src = str(source)
- dst = str(target)
- replace = any(isinstance(o, StandardCopyOption) and o == StandardCopyOption.REPLACE_EXISTING for o in options)
- try:
- if replace and _os.path.exists(dst):
- _os.remove(dst)
- if _os.path.isdir(src):
- _shutil.copytree(src, dst)
- else:
- _shutil.copy2(src, dst)
- except OSError as e:
- raise IOException(str(e))
-
- @staticmethod
- def move(source, target, *options):
- src = str(source)
- dst = str(target)
- replace = any(isinstance(o, StandardCopyOption) and o == StandardCopyOption.REPLACE_EXISTING for o in options)
- try:
- if replace and _os.path.exists(dst):
- _os.remove(dst)
- _shutil.move(src, dst)
- except OSError as e:
- raise IOException(str(e))
-
- @staticmethod
- def delete(path):
- try:
- p = str(path)
- if _os.path.isdir(p):
- _os.rmdir(p)
- else:
- _os.remove(p)
- except OSError as e:
- raise NoSuchFileException(str(path))
-
- @staticmethod
- def deleteIfExists(path):
- try:
- Files.delete(path)
- return True
- except NoSuchFileException:
- return False
-
- @staticmethod
- def createDirectories(path):
- _os.makedirs(str(path), exist_ok=True)
- return path
-
- @staticmethod
- def createDirectory(path, attrs=None):
- _os.makedirs(str(path), exist_ok=True)
- return path
-
- @staticmethod
- def createFile(path, attrs=None):
- p = str(path)
- if _os.path.exists(p):
- raise FileAlreadyExistsException(str(path))
- open(p, "a").close()
- return path
-
- @staticmethod
- def createTempFile(prefix, suffix, dir=None):
- f = _tempfile.NamedTemporaryFile(prefix=prefix, suffix=suffix,
- dir=str(dir) if dir else None, delete=False)
- p = f.name
- f.close()
- return Path(p)
-
- @staticmethod
- def createTempDirectory(prefix, attrs=None):
- d = _tempfile.mkdtemp(prefix=prefix)
- return Path(d)
-
- @staticmethod
- def exists(path, *options):
- return _os.path.exists(str(path))
-
- @staticmethod
- def notExists(path, *options):
- return not _os.path.exists(str(path))
-
- @staticmethod
- def isReadable(path):
- return _os.access(str(path), _os.R_OK)
-
- @staticmethod
- def isWritable(path):
- return _os.access(str(path), _os.W_OK)
-
- @staticmethod
- def isExecutable(path):
- return _os.access(str(path), _os.X_OK)
-
- @staticmethod
- def isDirectory(path, *options):
- return _os.path.isdir(str(path))
-
- @staticmethod
- def isRegularFile(path, *options):
- return _os.path.isfile(str(path))
-
- @staticmethod
- def isSymbolicLink(path):
- return _os.path.islink(str(path))
-
- @staticmethod
- def isHidden(path):
- return _os.path.basename(str(path)).startswith(".")
-
- @staticmethod
- def getLastModifiedTime(path, *options):
- return int(_os.path.getmtime(str(path)) * 1000)
-
- @staticmethod
- def setLastModifiedTime(path, time):
- _os.utime(str(path), (time / 1000, time / 1000))
-
- @staticmethod
- def getAttribute(path, attribute, *options):
- return None
-
- @staticmethod
- def setAttribute(path, attribute, value, *options):
- pass
-
- @staticmethod
- def getPosixFilePermissions(path, *options):
- return []
-
- @staticmethod
- def setPosixFilePermissions(path, perms, *options):
- pass
-
- @staticmethod
- def newInputStream(path, *options):
- from ..io import FileInputStream
- return FileInputStream(str(path))
-
- @staticmethod
- def newOutputStream(path, *options):
- from ..io import FileOutputStream
- append = any(isinstance(o, StandardOpenOption) and o == StandardOpenOption.APPEND for o in options)
- return FileOutputStream(str(path), append)
-
- @staticmethod
- def newBufferedReader(path, charset=None):
- from ..io import BufferedReader, InputStreamReader, FileInputStream
- inp = FileInputStream(str(path))
- reader = InputStreamReader(inp, charset or "utf-8")
- return BufferedReader(reader)
-
- @staticmethod
- def newBufferedWriter(path, charset=None, *options):
- from ..io import BufferedWriter, OutputStreamWriter, FileOutputStream
- append = any(isinstance(o, StandardOpenOption) and o == StandardOpenOption.APPEND for o in options)
- out = FileOutputStream(str(path), append)
- writer = OutputStreamWriter(out, charset or "utf-8")
- return BufferedWriter(writer)
-
- @staticmethod
- def readAllBytes(path):
- with open(str(path), "rb") as f:
- return f.read()
-
- @staticmethod
- def readAllLines(path, charset=None):
- with open(str(path), "r", encoding=charset or "utf-8") as f:
- return f.read().splitlines()
-
- @staticmethod
- def readString(path, charset=None):
- with open(str(path), "r", encoding=charset or "utf-8") as f:
- return f.read()
-
- @staticmethod
- def write(path, content, *options):
- mode = "wb" if isinstance(content, bytes) else "w"
- open_mode = mode
- if any(isinstance(o, StandardOpenOption) and o == StandardOpenOption.APPEND for o in options):
- open_mode = "ab" if mode == "wb" else "a"
- with open(str(path), open_mode) as f:
- f.write(content)
-
- @staticmethod
- def writeString(path, content, *options):
- open_mode = "w"
- if any(isinstance(o, StandardOpenOption) and o == StandardOpenOption.APPEND for o in options):
- open_mode = "a"
- with open(str(path), open_mode, encoding="utf-8") as f:
- f.write(content)
-
- @staticmethod
- def list(path):
- try:
- return [Path(_os.path.join(str(path), entry)) for entry in _os.listdir(str(path))]
- except OSError:
- raise IOException(f"Failed to list directory: {path}")
-
- @staticmethod
- def walk(path, maxDepth=None):
- for root, dirs, files in _os.walk(str(path)):
- yield Path(root)
-
- @staticmethod
- def find(start, maxDepth, matcher, *options):
- for root, dirs, files in _os.walk(str(start)):
- for f in files:
- p = Path(_os.path.join(root, f))
- if matcher.matches(p):
- yield p
-
- @staticmethod
- def lines(path, charset=None):
- with open(str(path), "r", encoding=charset or "utf-8") as f:
- for line in f:
- yield line.rstrip("\n")
-
- @staticmethod
- def getFileStore(path):
- return FileStore(str(path))
-
- @staticmethod
- def probeContentType(path):
- return "application/octet-stream"
-
- @staticmethod
- def getOwner(path, *options):
- raise AndroidOnlyError("getOwner")
-
- @staticmethod
- def setOwner(path, owner, *options):
- raise AndroidOnlyError("setOwner")
\ No newline at end of file
diff --git a/android_pyapi/java/rmi.py b/android_pyapi/java/rmi.py
deleted file mode 100644
index 78ea658..0000000
--- a/android_pyapi/java/rmi.py
+++ /dev/null
@@ -1,776 +0,0 @@
-"""
-Java java.rmi standard library APIs implemented in Python.
-java.rmi package - Remote, Registry, Activation, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-from .lang import RuntimeException, Exception as _JavaException
-import typing as _typing
-
-__all__ = [
- "Remote", "RemoteException", "RMISecurityManager", "RMISecurityException",
- "MarshalledObject", "Naming", "NamingException",
- "NotBoundException", "AlreadyBoundException",
- "ConnectException", "ConnectIOException", "ServerException",
- "ServerError", "ServerRuntimeException", "StubNotFoundException",
- "UnexpectedException", "UnmarshalException", "UnknownHostException",
- "NoSuchObjectException", "AccessException", "MarshalException",
- "ExportException", "SocketSecurityException",
- "Registry", "RegistryHandler",
- "ActivationException", "UnknownObjectException",
- "Activatable", "ActivationDesc", "ActivationGroup",
- "ActivationGroupDesc", "ActivationGroupID", "ActivationID",
- "ActivationMonitor", "ActivationSystem", "Activator",
- "RMIClassLoader", "RMISocketFactory", "RMIFailureHandler",
- "LogStream", "RemoteCall", "RemoteRef", "ServerRef", "Operation",
- "RemoteObject", "RemoteServer", "UnicastRemoteObject", "Unreferenced",
-]
-
-
-# ============================================================
-# Remote interface
-# ============================================================
-
-class Remote(Stub):
- """java.rmi.Remote"""
- pass
-
-
-# ============================================================
-# Exception hierarchy
-# ============================================================
-
-class RemoteException(_JavaException):
- """java.rmi.RemoteException"""
- def __init__(self, message=None, cause=None):
- msg = message or ""
- super().__init__(msg)
- self._detail = message
- self._cause = cause
-
- def getMessage(self):
- return self._detail or ""
-
- def getCause(self):
- return self._cause
-
-
-class NamingException(RemoteException):
- """java.rmi.NamingException"""
- pass
-
-
-class NotBoundException(RemoteException):
- """java.rmi.NotBoundException"""
- pass
-
-
-class AlreadyBoundException(RemoteException):
- """java.rmi.AlreadyBoundException"""
- pass
-
-
-class ConnectException(RemoteException):
- """java.rmi.ConnectException"""
- pass
-
-
-class ConnectIOException(RemoteException):
- """java.rmi.ConnectIOException"""
- pass
-
-
-class ServerException(RemoteException):
- """java.rmi.ServerException"""
- pass
-
-
-class ServerError(RemoteException):
- """java.rmi.ServerError"""
- pass
-
-
-class ServerRuntimeException(RemoteException):
- """java.rmi.ServerRuntimeException"""
- pass
-
-
-class StubNotFoundException(RemoteException):
- """java.rmi.StubNotFoundException"""
- pass
-
-
-class UnexpectedException(RemoteException):
- """java.rmi.UnexpectedException"""
- pass
-
-
-class UnmarshalException(RemoteException):
- """java.rmi.UnmarshalException"""
- pass
-
-
-class UnknownHostException(RemoteException):
- """java.rmi.UnknownHostException"""
- pass
-
-
-class NoSuchObjectException(RemoteException):
- """java.rmi.NoSuchObjectException"""
- pass
-
-
-class AccessException(RemoteException):
- """java.rmi.AccessException"""
- pass
-
-
-class MarshalException(RemoteException):
- """java.rmi.MarshalException"""
- pass
-
-
-class ExportException(RemoteException):
- """java.rmi.ExportException"""
- pass
-
-
-class SocketSecurityException(ExportException):
- """java.rmi.SocketSecurityException"""
- pass
-
-
-# java.lang.SecurityException (桌面模拟)
-class SecurityException(RuntimeException):
- def __init__(self, message=""):
- super().__init__(message)
-
-
-class RMISecurityException(SecurityException):
- """java.rmi.RMISecurityException"""
- pass
-
-
-# ============================================================
-# RMISecurityManager
-# ============================================================
-
-class RMISecurityManager(Stub):
- """java.rmi.RMISecurityManager"""
- def checkConnect(self, host, port):
- pass
-
- def checkAccept(self, host, port):
- pass
-
- def checkListen(self, port):
- pass
-
-
-# ============================================================
-# MarshalledObject
-# ============================================================
-
-class MarshalledObject(Stub):
- """java.rmi.MarshalledObject"""
- def __init__(self, obj):
- super().__init__()
- self._obj = obj
- import pickle
- self._bytes = pickle.dumps(obj)
-
- def get(self):
- import pickle
- try:
- return pickle.loads(self._bytes)
- except Exception:
- return self._obj
-
- def hashCode(self):
- return hash(self._bytes)
-
- def equals(self, obj):
- if not isinstance(obj, MarshalledObject):
- return False
- return self._bytes == obj._bytes
-
-
-# ============================================================
-# Naming
-# ============================================================
-
-class Naming(Stub):
- """java.rmi.Naming"""
- _registry = {}
-
- @staticmethod
- def lookup(name):
- if name in Naming._registry:
- return Naming._registry[name]
- raise NotBoundException(name)
-
- @staticmethod
- def bind(name, obj):
- if name in Naming._registry:
- raise AlreadyBoundException(name)
- Naming._registry[name] = obj
-
- @staticmethod
- def unbind(name):
- if name not in Naming._registry:
- raise NotBoundException(name)
- del Naming._registry[name]
-
- @staticmethod
- def rebind(name, obj):
- Naming._registry[name] = obj
-
- @staticmethod
- def list(name):
- return list(Naming._registry.keys())
-
-
-# ============================================================
-# Registry
-# ============================================================
-
-class Registry(Stub):
- """java.rmi.registry.Registry"""
- def lookup(self, name):
- raise NotBoundException(name)
-
- def bind(self, name, obj):
- raise AlreadyBoundException(name)
-
- def unbind(self, name):
- raise NotBoundException(name)
-
- def rebind(self, name, obj):
- pass
-
- def list(self):
- return []
-
- REGISTRY_PORT = 1099
-
-
-class RegistryHandler(Stub):
- """java.rmi.registry.RegistryHandler"""
- def registryStub(self, host, port):
- return Registry()
-
- def registryImpl(self, port):
- return Registry()
-
-
-# ============================================================
-# Activation Exceptions
-# ============================================================
-
-class ActivationException(RemoteException):
- """java.rmi.activation.ActivationException"""
- pass
-
-
-class UnknownObjectException(ActivationException):
- """java.rmi.activation.UnknownObjectException"""
- pass
-
-
-# ============================================================
-# ActivationID
-# ============================================================
-
-class ActivationID(Stub):
- """java.rmi.activation.ActivationID"""
- def __init__(self, activator=None):
- super().__init__()
- self._activator = activator
-
- def activate(self, force):
- if self._activator:
- return self._activator.activate(self, force)
- return None
-
- def hashCode(self):
- return hash(id(self))
-
- def equals(self, obj):
- return self is obj
-
-
-# ============================================================
-# ActivationDesc
-# ============================================================
-
-class ActivationDesc(Stub):
- """java.rmi.activation.ActivationDesc"""
- def __init__(self, class_name=None, location=None, marshalled_data=None,
- group_id=None, restart_mode=False):
- super().__init__()
- self._class_name = class_name
- self._location = location
- self._marshalled_data = marshalled_data
- self._group_id = group_id
- self._restart_mode = restart_mode
-
- def getClassName(self):
- return self._class_name
-
- def getLocation(self):
- return self._location
-
- def getData(self):
- return self._marshalled_data
-
- def getGroupID(self):
- return self._group_id
-
- def getRestartMode(self):
- return self._restart_mode
-
-
-# ============================================================
-# Activatable
-# ============================================================
-
-class Activatable(Remote):
- """java.rmi.activation.Activatable"""
- def __init__(self, activation_desc, port, obj_id=None, server_port=0,
- csf=None, ssf=None):
- super().__init__()
- self._activation_desc = activation_desc
- self._port = port
- self._group_id = ActivationGroupID()
- self._id = ActivationID()
-
- @staticmethod
- def register(desc):
- return ActivationID()
-
- @staticmethod
- def inactive(id_):
- return True
-
- @staticmethod
- def unregister(id_):
- pass
-
- @staticmethod
- def exportObject(obj, desc, port):
- return Remote()
-
- def getID(self):
- return self._id
-
-
-# ============================================================
-# ActivationGroup / ActivationGroupDesc / ActivationGroupID
-# ============================================================
-
-class ActivationGroupID(Stub):
- """java.rmi.activation.ActivationGroupID"""
- def __init__(self, activation_system=None):
- super().__init__()
- self._activation_system = activation_system
-
- def getSystem(self):
- return self._activation_system
-
- def hashCode(self):
- return hash(id(self))
-
-
-class ActivationGroupDesc(Stub):
- """java.rmi.activation.ActivationGroupDesc"""
- class CommandEnvironment(Stub):
- def __init__(self, cmd=None, props=None):
- super().__init__()
- self._command = cmd
- self._properties = props or []
-
- def getCommandPath(self):
- return self._command
-
- def getCommandProperties(self):
- return self._properties
-
- def __init__(self, props=None, env=None, class_name=None,
- location=None, info=None):
- super().__init__()
- self._props = props or {}
- self._env = env or ActivationGroupDesc.CommandEnvironment()
- self._class_name = class_name
- self._location = location
- self._info = info
-
- def getPropertyOverrides(self):
- return self._props
-
- def getCommandEnvironment(self):
- return self._env
-
- def getClassName(self):
- return self._class_name
-
- def getLocation(self):
- return self._location
-
- def getData(self):
- return self._info
-
-
-class ActivationGroup(Activatable):
- """java.rmi.activation.ActivationGroup"""
- def __init__(self, group_id, desc, incarnation):
- super().__init__(None, 0)
- self._group_id = group_id
- self._desc = desc
- self._incarnation = incarnation
-
- @staticmethod
- def createGroup(id_, desc, incarnation):
- return ActivationGroup(id_, desc, incarnation)
-
- @staticmethod
- def currentGroupID():
- return ActivationGroupID()
-
- @staticmethod
- def setGroup(group):
- pass
-
- @staticmethod
- def activeGroup(id_, group, incarnation):
- return True
-
- @staticmethod
- def inactiveGroup(group_id):
- pass
-
- def newInstance(self, desc):
- return None
-
- def activeObject(self, id_, obj):
- pass
-
- def inactiveObject(self, id_):
- pass
-
-
-# ============================================================
-# ActivationMonitor / ActivationSystem / Activator
-# ============================================================
-
-class ActivationMonitor(Stub):
- """java.rmi.activation.ActivationMonitor"""
- def inactiveObject(self, id_):
- pass
-
- def activeObject(self, id_, obj):
- pass
-
- def inactiveGroup(self, group_id, incarnation):
- pass
-
-
-class ActivationSystem(Stub):
- """java.rmi.activation.ActivationSystem"""
- def registerActivationDesc(self, desc):
- return ActivationID()
-
- def unregisterActivationDesc(self, id_):
- pass
-
- def shutdown(self):
- pass
-
- def setActivationMonitor(self, monitor):
- pass
-
- def getActivationMonitor(self):
- return ActivationMonitor()
-
- def activeGroup(self, id_, group, incarnation):
- return ActivationMonitor()
-
- def registerGroup(self, desc):
- return ActivationGroupID()
-
- def unregisterGroup(self, group_id):
- pass
-
- SYSTEM_PORT = 1098
-
-
-class Activator(Stub):
- """java.rmi.activation.Activator"""
- def activate(self, id_, force):
- return MarshalledObject(None)
-
-
-# ============================================================
-# RMIClassLoader
-# ============================================================
-
-class RMIClassLoader(Stub):
- """java.rmi.server.RMIClassLoader"""
- @staticmethod
- def loadClass(codebase, name, default_loader=None):
- import importlib
- try:
- return importlib.import_module(name)
- except ImportError:
- return None
-
- @staticmethod
- def getClassAnnotation(cls):
- return ""
-
- @staticmethod
- def getClassLoader(codebase):
- return None
-
- @staticmethod
- def getDefaultProviderInstance():
- return None
-
- @staticmethod
- def loadProxyClass(codebase, interfaces, default_loader):
- return None
-
-
-# ============================================================
-# RMISocketFactory / RMIFailureHandler
-# ============================================================
-
-class RMISocketFactory(Stub):
- """java.rmi.server.RMISocketFactory"""
- _factory = None
- _handler = None
-
- @staticmethod
- def getDefaultSocketFactory():
- if RMISocketFactory._factory is None:
- RMISocketFactory._factory = RMISocketFactory()
- return RMISocketFactory._factory
-
- @staticmethod
- def setSocketFactory(factory):
- RMISocketFactory._factory = factory
-
- @staticmethod
- def getFailureHandler():
- return RMISocketFactory._handler
-
- @staticmethod
- def setFailureHandler(handler):
- RMISocketFactory._handler = handler
-
- def createSocket(self, host, port):
- import socket
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.connect((host, port))
- return s
-
- def getDefaultPort(self):
- return 0
-
-
-class RMIFailureHandler(Stub):
- """java.rmi.server.RMIFailureHandler"""
- def failure(self, ex):
- return False
-
-
-# ============================================================
-# LogStream
-# ============================================================
-
-class LogStream(Stub):
- """java.rmi.server.LogStream"""
- def __init__(self, name):
- super().__init__()
- self._name = name
- self._stream = None
-
- @staticmethod
- def log(name):
- return LogStream(name)
-
- @staticmethod
- def getDefaultStream():
- return None
-
- @staticmethod
- def setDefaultStream(stream):
- pass
-
- def getOutputStream(self):
- return self._stream
-
- def setOutputStream(self, stream):
- self._stream = stream
-
- def toString(self):
- return self._name
-
- SILENT = 0
- BRIEF = 10
- VERBOSE = 20
-
-
-# ============================================================
-# RemoteCall / RemoteRef / ServerRef / Operation
-# ============================================================
-
-class RemoteCall(Stub):
- """java.rmi.server.RemoteCall"""
- def getInputStream(self):
- return None
-
- def getOutputStream(self):
- return None
-
- def getResultStream(self, success):
- return None
-
- def executeCall(self):
- pass
-
- def done(self):
- pass
-
- def releaseInputStream(self):
- pass
-
- def releaseOutputStream(self):
- pass
-
-
-class RemoteRef(Stub):
- """java.rmi.server.RemoteRef"""
- def invoke(self, call):
- return None
-
- def remoteEquals(self, obj):
- return False
-
- def remoteHashCode(self):
- return 0
-
- def remoteToString(self):
- return ""
-
- def getRefClass(self, out):
- return ""
-
- def newCall(self, obj, operations, opnum, hash_):
- return RemoteCall()
-
- def invoke(self, call):
- pass
-
- def done(self, call):
- pass
-
- packagePrefix = "sun.rmi.server"
-
-
-class ServerRef(RemoteRef):
- """java.rmi.server.ServerRef"""
- def exportObject(self, obj, data):
- return RemoteStub()
-
- def getClientHost(self):
- return "localhost"
-
-
-class RemoteStub(Stub):
- """java.rmi.server.RemoteStub"""
- def __init__(self, ref=None):
- super().__init__()
- self._ref = ref
-
-
-class Operation(Stub):
- """java.rmi.server.Operation"""
- def __init__(self, name):
- super().__init__()
- self._name = name
-
- def getOperation(self):
- return self._name
-
- def toString(self):
- return self._name
-
-
-# ============================================================
-# RemoteObject / RemoteServer / UnicastRemoteObject
-# ============================================================
-
-class RemoteObject(Stub):
- """java.rmi.server.RemoteObject"""
- def __init__(self, ref=None):
- super().__init__()
- self._ref = ref
-
- def getRef(self):
- return self._ref
-
- def toString(self):
- return "RemoteObject"
-
- def hashCode(self):
- return super().hashCode()
-
- def equals(self, obj):
- return super().equals(obj)
-
-
-class RemoteServer(RemoteObject):
- """java.rmi.server.RemoteServer"""
- def __init__(self, ref=None):
- super().__init__(ref)
-
- @staticmethod
- def getClientHost():
- return "localhost"
-
- @staticmethod
- def setLog(output_stream):
- pass
-
- @staticmethod
- def getLog():
- return None
-
-
-class UnicastRemoteObject(RemoteServer):
- """java.rmi.server.UnicastRemoteObject"""
- def __init__(self, port=0, csf=None, ssf=None):
- super().__init__()
- self._port = port
- self._csf = csf
- self._ssf = ssf
- self._exported = False
-
- @staticmethod
- def exportObject(obj, port=0, csf=None, ssf=None):
- return RemoteStub()
-
- @staticmethod
- def unexportObject(obj, force):
- return True
-
- def clone(self):
- return UnicastRemoteObject(self._port)
-
-
-class Unreferenced(Stub):
- """java.rmi.server.Unreferenced"""
- def unreferenced(self):
- pass
\ No newline at end of file
diff --git a/android_pyapi/java/security.py b/android_pyapi/java/security.py
deleted file mode 100644
index 2a7e131..0000000
--- a/android_pyapi/java/security.py
+++ /dev/null
@@ -1,1145 +0,0 @@
-"""
-Java security standard library APIs implemented in Python.
-java.security package - MessageDigest, SecureRandom, KeyStore, Signature, etc.
-"""
-
-from .._core import Stub, AndroidOnlyError
-from .lang import RuntimeException
-import hashlib as _hashlib
-import os as _os
-
-GeneralSecurityException = type("GeneralSecurityException", (RuntimeException,), {})
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-DigestException = type("DigestException", (GeneralSecurityException,), {})
-InvalidAlgorithmParameterException = type("InvalidAlgorithmParameterException", (GeneralSecurityException,), {})
-InvalidKeyException = type("InvalidKeyException", (GeneralSecurityException,), {})
-InvalidKeySpecException = type("InvalidKeySpecException", (GeneralSecurityException,), {})
-InvalidParameterException = type("InvalidParameterException", (IllegalArgumentException,), {})
-KeyException = type("KeyException", (GeneralSecurityException,), {})
-KeyManagementException = type("KeyManagementException", (KeyException,), {})
-KeyStoreException = type("KeyStoreException", (GeneralSecurityException,), {})
-NoSuchAlgorithmException = type("NoSuchAlgorithmException", (GeneralSecurityException,), {})
-NoSuchProviderException = type("NoSuchProviderException", (GeneralSecurityException,), {})
-ProviderException = type("ProviderException", (RuntimeException,), {})
-SignatureException = type("SignatureException", (GeneralSecurityException,), {})
-
-__all__ = [
- "MessageDigest", "MessageDigestSpi",
- "SecureRandom", "SecureRandomSpi",
- "KeyStore", "KeyStoreSpi",
- "Key", "PrivateKey", "PublicKey", "KeyPair", "KeyPairGenerator",
- "KeyPairGeneratorSpi", "KeyFactory", "KeyFactorySpi",
- "KeySpec", "SecretKeySpec",
- "RSAPublicKeySpec", "RSAPrivateKeySpec",
- "PKCS8EncodedKeySpec", "X509EncodedKeySpec",
- "AlgorithmParameters", "AlgorithmParameterGenerator",
- "AlgorithmParameterGeneratorSpi", "AlgorithmParametersSpi",
- "Provider", "Security",
- "DigestInputStream", "DigestOutputStream",
- "Signature", "SignatureSpi",
- "CodeSigner", "CodeSource", "Policy", "Permission",
- "AllPermission", "BasicPermission", "PermissionCollection",
- "Principal",
- "CertPath", "CertPathBuilder", "CertPathBuilderSpi",
- "CertPathValidator", "CertPathValidatorSpi",
- "CertificateFactory", "CertificateFactorySpi",
- "CertStore", "CertStoreSpi",
- "CRL", "X509CRL", "X509Certificate", "X509Extension",
- "Guard", "GuardedObject", "Identity", "IdentityScope", "Signer",
- "Timestamp", "UnresolvedPermission",
- "GeneralSecurityException", "DigestException",
- "InvalidAlgorithmParameterException", "InvalidKeyException",
- "InvalidKeySpecException", "InvalidParameterException",
- "KeyException", "KeyManagementException", "KeyStoreException",
- "NoSuchAlgorithmException", "NoSuchProviderException",
- "ProviderException", "SignatureException",
-]
-
-
-# ============================================================
-# Key interfaces
-# ============================================================
-
-class Key(Stub):
- def getAlgorithm(self):
- return ""
-
- def getFormat(self):
- return ""
-
- def getEncoded(self):
- return b""
-
-
-class PrivateKey(Key):
- pass
-
-
-class PublicKey(Key):
- pass
-
-
-# ============================================================
-# KeySpec / SecretKeySpec / RSA specs / EncodedKeySpecs
-# ============================================================
-
-class KeySpec(Stub):
- pass
-
-
-class SecretKeySpec(KeySpec, Key):
- def __init__(self, key_bytes, algorithm):
- super().__init__()
- self._key = key_bytes
- self._algorithm = algorithm
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getFormat(self):
- return "RAW"
-
- def getEncoded(self):
- return self._key
-
- def hashCode(self):
- return hash(self._key) ^ hash(self._algorithm)
-
-
-class RSAPublicKeySpec(KeySpec):
- def __init__(self, modulus, public_exponent):
- super().__init__()
- self._modulus = modulus
- self._public_exponent = public_exponent
-
- def getModulus(self):
- return self._modulus
-
- def getPublicExponent(self):
- return self._public_exponent
-
-
-class RSAPrivateKeySpec(KeySpec):
- def __init__(self, modulus, private_exponent):
- super().__init__()
- self._modulus = modulus
- self._private_exponent = private_exponent
-
- def getModulus(self):
- return self._modulus
-
- def getPrivateExponent(self):
- return self._private_exponent
-
-
-class PKCS8EncodedKeySpec(KeySpec):
- def __init__(self, encoded_key):
- super().__init__()
- self._encoded_key = encoded_key
-
- def getEncoded(self):
- return self._encoded_key
-
- def getFormat(self):
- return "PKCS#8"
-
-
-class X509EncodedKeySpec(KeySpec):
- def __init__(self, encoded_key):
- super().__init__()
- self._encoded_key = encoded_key
-
- def getEncoded(self):
- return self._encoded_key
-
- def getFormat(self):
- return "X.509"
-
-
-# ============================================================
-# KeyPair
-# ============================================================
-
-class KeyPair(Stub):
- def __init__(self, public_key, private_key):
- super().__init__()
- self._public = public_key
- self._private = private_key
-
- def getPublic(self):
- return self._public
-
- def getPrivate(self):
- return self._private
-
-
-# ============================================================
-# KeyPairGenerator
-# ============================================================
-
-class KeyPairGenerator(Stub):
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
- self._keysize = 2048
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return KeyPairGenerator(algorithm)
-
- def initialize(self, keysize_or_spec, random=None):
- if isinstance(keysize_or_spec, int):
- self._keysize = keysize_or_spec
-
- def generateKeyPair(self):
- return KeyPair(PublicKey(), PrivateKey())
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getProvider(self):
- return Provider("SUN", 1.0, "Default provider")
-
-
-# ============================================================
-# KeyFactory
-# ============================================================
-
-class KeyFactory(Stub):
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return KeyFactory(algorithm)
-
- def generatePublic(self, key_spec):
- return PublicKey()
-
- def generatePrivate(self, key_spec):
- return PrivateKey()
-
- def getKeySpec(self, key, key_spec_cls):
- if key_spec_cls == X509EncodedKeySpec:
- return X509EncodedKeySpec(key.getEncoded())
- raise InvalidKeySpecException("Unsupported key spec")
-
- def translateKey(self, key):
- return key
-
- def getAlgorithm(self):
- return self._algorithm
-
-
-# ============================================================
-# KeyFactorySpi / KeyPairGeneratorSpi (stubs)
-# ============================================================
-
-class KeyFactorySpi(Stub):
- pass
-
-class KeyPairGeneratorSpi(Stub):
- pass
-
-
-# ============================================================
-# MessageDigest
-# ============================================================
-
-class MessageDigest(Stub):
- _MD_MAP = {
- "MD5": "md5",
- "SHA-1": "sha1",
- "SHA": "sha1",
- "SHA-224": "sha224",
- "SHA-256": "sha256",
- "SHA-384": "sha384",
- "SHA-512": "sha512",
- }
-
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
- algo_lower = algorithm.replace("-", "").lower()
- if algo_lower in ("md5", "sha1", "sha224", "sha256", "sha384", "sha512"):
- self._impl = _hashlib.new(algo_lower)
- else:
- self._impl = _hashlib.new("sha256")
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- if algorithm not in MessageDigest._MD_MAP:
- raise NoSuchAlgorithmException(f"{algorithm} not available")
- return MessageDigest(algorithm)
-
- def update(self, data, offset=0, length=-1):
- if length < 0:
- self._impl.update(data)
- else:
- self._impl.update(data[offset:offset+length])
-
- def digest(self, data=None):
- if data is not None:
- self._impl.update(data)
- return self._impl.digest()
-
- def toString(self):
- return f"MessageDigest: {self._algorithm}"
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getProvider(self):
- return Provider("SUN", 1.0, "Default provider")
-
- def getDigestLength(self):
- return self._impl.digest_size
-
- @staticmethod
- def isEqual(digest_a, digest_b):
- return digest_a == digest_b
-
- def clone(self):
- md = MessageDigest(self._algorithm)
- md._impl = self._impl.copy()
- return md
-
- def reset(self):
- self._impl = _hashlib.new(self._algorithm.replace("-", "").lower())
-
-
-class MessageDigestSpi(Stub):
- pass
-
-
-# ============================================================
-# SecureRandom
-# ============================================================
-
-class SecureRandom(Stub):
- def __init__(self, seed=None):
- super().__init__()
- import random as _random
- self._random = _random.Random()
- if seed is not None:
- self._random.seed(seed)
-
- def nextBytes(self, bytes_arr):
- data = _os.urandom(len(bytes_arr))
- for i in range(len(bytes_arr)):
- bytes_arr[i] = data[i]
-
- def nextInt(self, bound=None):
- if bound is None:
- return int.from_bytes(_os.urandom(4), "big")
- return int.from_bytes(_os.urandom(4), "big") % bound
-
- def nextLong(self):
- return int.from_bytes(_os.urandom(8), "big")
-
- def nextBoolean(self):
- return int.from_bytes(_os.urandom(1), "big") % 2 == 0
-
- def nextFloat(self):
- return int.from_bytes(_os.urandom(4), "big") / 4294967296.0
-
- def nextDouble(self):
- return int.from_bytes(_os.urandom(8), "big") / 18446744073709551616.0
-
- def nextGaussian(self):
- import random as _random
- return _random.gauss(0, 1)
-
- def generateSeed(self, num_bytes):
- return _os.urandom(num_bytes)
-
- def getAlgorithm(self):
- return "SHA1PRNG"
-
- def getProvider(self):
- return Provider("SUN", 1.0, "Default provider")
-
- def setSeed(self, seed):
- self._random.seed(seed)
-
- def getSeed(self, num_bytes):
- return _os.urandom(num_bytes)
-
-
-class SecureRandomSpi(Stub):
- pass
-
-
-# ============================================================
-# Provider / Security
-# ============================================================
-
-class Provider(Stub):
- def __init__(self, name, version, info):
- super().__init__()
- self._name = name
- self._version = version
- self._info = info
- self._properties = {}
-
- def getName(self):
- return self._name
-
- def getVersion(self):
- return self._version
-
- def getInfo(self):
- return self._info
-
- def getProperty(self, key):
- return self._properties.get(key)
-
- def setProperty(self, key, value):
- self._properties[key] = value
-
- def toString(self):
- return f"{self._name} v{self._version}"
-
-
-class Security(Stub):
- _providers = [Provider("SUN", 1.0, "SUN provider")]
-
- @staticmethod
- def getProvider(name):
- for p in Security._providers:
- if p.getName() == name:
- return p
- return None
-
- @staticmethod
- def getProviders():
- return Security._providers
-
- @staticmethod
- def addProvider(provider):
- Security._providers.append(provider)
- return len(Security._providers) - 1
-
- @staticmethod
- def removeProvider(name):
- for i, p in enumerate(Security._providers):
- if p.getName() == name:
- Security._providers.pop(i)
- return
-
- @staticmethod
- def getAlgorithms(service_name):
- if service_name == "MessageDigest":
- return list(MessageDigest._MD_MAP.keys())
- return []
-
-
-# ============================================================
-# DigestInputStream / DigestOutputStream
-# ============================================================
-
-class DigestInputStream(Stub):
- def __init__(self, stream, digest):
- super().__init__()
- self._stream = stream
- self._digest = digest
-
- def getMessageDigest(self):
- return self._digest
-
- def setMessageDigest(self, digest):
- self._digest = digest
-
- def read(self, b=None, off=0, length=0):
- if b is None:
- data = self._stream.read()
- else:
- data = self._stream.read(length)
- if data:
- self._digest.update(data)
- return data
-
- def toString(self):
- return f"DigestInputStream: {self._digest}"
-
-
-class DigestOutputStream(Stub):
- def __init__(self, stream, digest):
- super().__init__()
- self._stream = stream
- self._digest = digest
-
- def getMessageDigest(self):
- return self._digest
-
- def setMessageDigest(self, digest):
- self._digest = digest
-
- def write(self, b, off=0, length=0):
- if isinstance(b, (bytes, bytearray)):
- data = b if length == 0 else b[off:off+length]
- else:
- data = bytes([b])
- self._digest.update(data)
- self._stream.write(data)
-
- def toString(self):
- return f"DigestOutputStream: {self._digest}"
-
-
-# ============================================================
-# Signature
-# ============================================================
-
-class Signature(Stub):
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
- self._state = "UNINITIALIZED"
- self._impl = _hashlib.new("sha256")
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return Signature(algorithm)
-
- def initSign(self, private_key, random=None):
- self._state = "SIGN"
-
- def initVerify(self, public_key):
- self._state = "VERIFY"
-
- def update(self, data, off=0, length=-1):
- if length < 0:
- self._impl.update(data)
- else:
- self._impl.update(data[off:off+length])
-
- def sign(self):
- self._state = "UNINITIALIZED"
- return self._impl.digest()
-
- def verify(self, signature):
- self._state = "UNINITIALIZED"
- return self._impl.digest() == signature
-
- def setParameter(self, param, value=None):
- pass
-
- def getParameters(self):
- return None
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getProvider(self):
- return Provider("SUN", 1.0, "SUN provider")
-
-
-class SignatureSpi(Stub):
- pass
-
-
-# ============================================================
-# KeyStore
-# ============================================================
-
-class KeyStore(Stub):
- class PasswordProtection(Stub):
- def __init__(self, password):
- super().__init__()
- self._password = password
-
- def getPassword(self):
- return self._password
-
- class Entry(Stub):
- pass
-
- class PrivateKeyEntry(Entry):
- def __init__(self, private_key, cert_chain):
- super().__init__()
- self._private_key = private_key
- self._cert_chain = cert_chain
-
- def getPrivateKey(self):
- return self._private_key
-
- def getCertificateChain(self):
- return self._cert_chain
-
- class SecretKeyEntry(Entry):
- def __init__(self, secret_key):
- super().__init__()
- self._secret_key = secret_key
-
- def getSecretKey(self):
- return self._secret_key
-
- class TrustedCertificateEntry(Entry):
- def __init__(self, cert):
- super().__init__()
- self._cert = cert
-
- def getTrustedCertificate(self):
- return self._cert
-
- def __init__(self, type_name="JKS"):
- super().__init__()
- self._type = type_name
- self._entries = {}
- self._loaded = False
-
- @staticmethod
- def getInstance(type_name, provider=None):
- return KeyStore(type_name)
-
- def load(self, stream=None, password=None):
- self._loaded = True
-
- def store(self, stream, password):
- pass
-
- def setKeyEntry(self, alias, key, password, chain):
- self._entries[alias] = (key, chain)
-
- def setCertificateEntry(self, alias, cert):
- self._entries[alias] = cert
-
- def getKey(self, alias, password):
- entry = self._entries.get(alias)
- if isinstance(entry, tuple):
- return entry[0]
- return None
-
- def getCertificate(self, alias):
- entry = self._entries.get(alias)
- if isinstance(entry, tuple):
- return entry[1][0] if entry[1] else None
- return entry
-
- def getCertificateChain(self, alias):
- entry = self._entries.get(alias)
- if isinstance(entry, tuple):
- return entry[1]
- return None
-
- def getCertificateAliases(self, cert):
- return []
-
- def aliases(self):
- return list(self._entries.keys())
-
- def containsAlias(self, alias):
- return alias in self._entries
-
- def deleteEntry(self, alias):
- if alias in self._entries:
- del self._entries[alias]
-
- def size(self):
- return len(self._entries)
-
- def isCertificateEntry(self, alias):
- return alias in self._entries and not isinstance(self._entries[alias], tuple)
-
- def isKeyEntry(self, alias):
- return alias in self._entries and isinstance(self._entries[alias], tuple)
-
- def getType(self):
- return self._type
-
- def getProvider(self):
- return Provider("SUN", 1.0, "SUN provider")
-
- def getCreationDate(self, alias):
- from datetime import datetime
- return datetime.now()
-
-
-class KeyStoreSpi(Stub):
- pass
-
-
-# ============================================================
-# X509Certificate
-# ============================================================
-
-class X509Certificate(Stub):
- def __init__(self):
- super().__init__()
- self._encoded = b""
-
- def getSubjectX500Principal(self):
- return Principal()
-
- def getIssuerX500Principal(self):
- return Principal()
-
- def getSerialNumber(self):
- return 0
-
- def getNotBefore(self):
- from datetime import datetime
- return datetime.now()
-
- def getNotAfter(self):
- from datetime import datetime
- return datetime.now()
-
- def getSigAlgName(self):
- return "SHA256withRSA"
-
- def getSigAlgOID(self):
- return "1.2.840.113549.1.1.11"
-
- def getVersion(self):
- return 3
-
- def getPublicKey(self):
- return PublicKey()
-
- def getEncoded(self):
- return self._encoded
-
- def verify(self, key):
- return True
-
- def checkValidity(self, date=None):
- return True
-
- def toString(self):
- return "X509Certificate"
-
-
-# ============================================================
-# AlgorithmParameters / AlgorithmParameterGenerator (stubs)
-# ============================================================
-
-class AlgorithmParameters(Stub):
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return AlgorithmParameters(algorithm)
-
- def init(self, params, format=None):
- pass
-
- def getEncoded(self, format=None):
- return b""
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getProvider(self):
- return Provider("SUN", 1.0, "SUN provider")
-
- def toString(self):
- return f"{self._algorithm} parameters"
-
-
-class AlgorithmParametersSpi(Stub):
- pass
-
-
-class AlgorithmParameterGenerator(Stub):
- @staticmethod
- def getInstance(algorithm, provider=None):
- return AlgorithmParameterGenerator()
-
- def init(self, size_or_genparam, random=None):
- pass
-
- def generateParameters(self):
- return AlgorithmParameters("DSA")
-
-
-class AlgorithmParameterGeneratorSpi(Stub):
- pass
-
-
-# ============================================================
-# Permission / AllPermission / BasicPermission (stubs)
-# ============================================================
-
-class Permission(Stub):
- def __init__(self, name):
- super().__init__()
- self._name = name
-
- def getName(self):
- return self._name
-
- def getActions(self):
- return ""
-
- def implies(self, permission):
- return True
-
- def equals(self, obj):
- return isinstance(obj, Permission) and self._name == obj._name
-
- def hashCode(self):
- return hash(self._name)
-
- def toString(self):
- return f"({self.__class__.__name__} {self._name})"
-
-
-class AllPermission(Permission):
- def __init__(self):
- super().__init__("")
-
-
-class BasicPermission(Permission):
- def __init__(self, name, actions=None):
- super().__init__(name)
-
-
-class PermissionCollection(Stub):
- def __init__(self):
- super().__init__()
- self._permissions = []
-
- def add(self, permission):
- self._permissions.append(permission)
-
- def implies(self, permission):
- return True
-
- def elements(self):
- return iter(self._permissions)
-
- def toString(self):
- return str(self._permissions)
-
-
-class UnresolvedPermission(Permission):
- def __init__(self, type_name, name, actions, certs):
- super().__init__(name)
- self._unresolved_type = type_name
- self._unresolved_actions = actions
- self._certs = certs
-
- def getUnresolvedType(self):
- return self._unresolved_type
-
- def getUnresolvedActions(self):
- return self._unresolved_actions
-
- def getUnresolvedCerts(self):
- return self._certs
-
-
-# ============================================================
-# Principal / CodeSource / Policy (stubs)
-# ============================================================
-
-class Principal(Stub):
- def __init__(self, name=""):
- super().__init__()
- self._name = name
-
- def getName(self):
- return self._name
-
- def toString(self):
- return self._name
-
- def equals(self, other):
- return isinstance(other, Principal) and self._name == other._name
-
- def hashCode(self):
- return hash(self._name)
-
-
-class CodeSource(Stub):
- def __init__(self, location, certs):
- super().__init__()
- self._location = location
-
- def getLocation(self):
- return self._location
-
- def getCertificates(self):
- return []
-
- def implies(self, codesource):
- return True
-
-
-class Policy(Stub):
- _policy = None
-
- @staticmethod
- def getPolicy():
- if Policy._policy is None:
- Policy._policy = Policy()
- return Policy._policy
-
- @staticmethod
- def setPolicy(policy):
- Policy._policy = policy
-
- def getPermissions(self, codesource):
- return PermissionCollection()
-
- def implies(self, cs, perm):
- return True
-
- def refresh(self):
- pass
-
-
-# ============================================================
-# CertPath / CertPathBuilder / CertPathValidator (stubs)
-# ============================================================
-
-class CertPath(Stub):
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
- self._certs = []
-
- def getCertificates(self):
- return self._certs
-
- def getType(self):
- return self._algorithm
-
- def getEncoded(self):
- return b""
-
- def toString(self):
- return f"CertPath: {self._algorithm}"
-
-
-class CertPathBuilder(Stub):
- @staticmethod
- def getInstance(algorithm, provider=None):
- return CertPathBuilder()
-
- def build(self, params):
- return CertPath("X.509")
-
-
-class CertPathBuilderSpi(Stub):
- pass
-
-
-class CertPathValidator(Stub):
- @staticmethod
- def getInstance(algorithm, provider=None):
- return CertPathValidator()
-
- def validate(self, cert_path, params):
- return None
-
-
-class CertPathValidatorSpi(Stub):
- pass
-
-
-class CertificateFactory(Stub):
- @staticmethod
- def getInstance(algorithm, provider=None):
- return CertificateFactory()
-
- def generateCertificate(self, in_stream):
- return X509Certificate()
-
- def generateCertPath(self, in_stream):
- return CertPath("X.509")
-
- def getCertPathEncodings(self):
- return ["PKCS7"]
-
-
-class CertificateFactorySpi(Stub):
- pass
-
-
-class CertStore(Stub):
- @staticmethod
- def getInstance(type_name, params, provider=None):
- return CertStore()
-
- def getCertificates(self, selector):
- return []
-
- def getCRLs(self, selector):
- return []
-
-
-class CertStoreSpi(Stub):
- pass
-
-
-# ============================================================
-# CRL / X509CRL (stubs)
-# ============================================================
-
-class CRL(Stub):
- def __init__(self):
- super().__init__()
-
- def isRevoked(self, cert):
- return False
-
- def toString(self):
- return "CRL"
-
-
-class X509CRL(CRL):
- def __init__(self):
- super().__init__()
-
- def getEncoded(self):
- return b""
-
- def verify(self, key):
- return True
-
- def getIssuerX500Principal(self):
- return Principal()
-
- def toString(self):
- return "X509CRL"
-
-
-class X509Extension(Stub):
- pass
-
-
-# ============================================================
-# Guard / GuardedObject (stubs)
-# ============================================================
-
-class Guard(Stub):
- def checkGuard(self, object):
- pass
-
-
-class GuardedObject(Stub):
- def __init__(self, object, guard):
- super().__init__()
- self._object = object
-
- def getObject(self):
- return self._object
-
-
-# ============================================================
-# Identity / IdentityScope / Signer (stubs)
-# ============================================================
-
-class Identity(Stub):
- def __init__(self, name, scope=None):
- super().__init__()
- self._name = name
-
- def getName(self):
- return self._name
-
- def getPublicKey(self):
- return PublicKey()
-
- def setPublicKey(self, key):
- pass
-
- def toString(self):
- return self._name
-
- def getScope(self):
- return None
-
-
-class IdentityScope(Identity):
- def __init__(self, name):
- super().__init__(name)
-
- def getIdentity(self, name):
- return None
-
- def addIdentity(self, identity):
- pass
-
- def removeIdentity(self, identity):
- pass
-
- def identities(self):
- return []
-
- @staticmethod
- def getSystemScope():
- return None
-
- def size(self):
- return 0
-
- def toString(self):
- return self._name
-
-
-class Signer(Identity):
- def __init__(self, name):
- super().__init__(name)
-
- def getPrivateKey(self):
- return PrivateKey()
-
- def setKeyPair(self, pair):
- pass
-
- def toString(self):
- return self._name
-
-
-# ============================================================
-# CodeSigner / Timestamp (stubs)
-# ============================================================
-
-class Timestamp(Stub):
- def __init__(self, timestamp, signer_cert_path):
- super().__init__()
- self._timestamp = timestamp
-
- def getTimestamp(self):
- return self._timestamp
-
- def getSignerCertPath(self):
- return CertPath("X.509")
-
- def equals(self, other):
- return isinstance(other, Timestamp)
-
- def hashCode(self):
- return 0
-
- def toString(self):
- return "Timestamp"
-
-
-class CodeSigner(Stub):
- def __init__(self, signer_cert_path, timestamp):
- super().__init__()
- self._signer_cert_path = signer_cert_path
- self._timestamp = timestamp
-
- def getSignerCertPath(self):
- return self._signer_cert_path
-
- def getTimestamp(self):
- return self._timestamp
-
- def equals(self, other):
- return isinstance(other, CodeSigner)
-
- def hashCode(self):
- return 0
-
- def toString(self):
- return "CodeSigner"
\ No newline at end of file
diff --git a/android_pyapi/java/security_cert.py b/android_pyapi/java/security_cert.py
deleted file mode 100644
index b2d436e..0000000
--- a/android_pyapi/java/security_cert.py
+++ /dev/null
@@ -1,907 +0,0 @@
-"""
-Java security.cert standard library APIs implemented in Python.
-java.security.cert package - Certificate, CertPath, CRL, PKIX, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-from .security import GeneralSecurityException, CertificateFactory as _OldCF
-from .lang import RuntimeException, String
-import datetime as _datetime
-import typing as _typing
-
-__all__ = [
- "Certificate", "CertificateFactory", "X509Certificate",
- "X509CRL", "X509CRLEntry", "CertPath", "CertPathBuilder",
- "CertPathValidator", "CertStore", "CertificateNotYetValidException",
- "CertificateExpiredException", "CertificateEncodingException",
- "CertificateParsingException", "CertPathValidatorException",
- "CertPathBuilderException", "CRL", "CRLException",
- "PolicyQualifierInfo", "TrustAnchor", "Extension", "X509Extension",
- "CollectionCertStoreParameters", "LDAPCertStoreParameters",
- "CertStoreParameters", "PKIXParameters", "PKIXBuilderParameters",
- "PKIXCertPathBuilderResult", "PKIXCertPathValidatorResult",
- "CertPathBuilderResult", "CertPathValidatorResult", "CertPathParameters",
- "CRL_REASON_UNSPECIFIED", "CRL_REASON_KEY_COMPROMISE",
- "CRL_REASON_CA_COMPROMISE", "CRL_REASON_AFFILIATION_CHANGED",
- "CRL_REASON_SUPERSEDED", "CRL_REASON_CESSATION_OF_OPERATION",
- "CRL_REASON_CERTIFICATE_HOLD", "CRL_REASON_REMOVE_FROM_CRL",
- "CRL_REASON_PRIVILEGE_WITHDRAWN", "CRL_REASON_AA_COMPROMISE",
-]
-
-# ============================================================
-# CRL Reason Constants
-# ============================================================
-
-CRL_REASON_UNSPECIFIED = 0
-CRL_REASON_KEY_COMPROMISE = 1
-CRL_REASON_CA_COMPROMISE = 2
-CRL_REASON_AFFILIATION_CHANGED = 3
-CRL_REASON_SUPERSEDED = 4
-CRL_REASON_CESSATION_OF_OPERATION = 5
-CRL_REASON_CERTIFICATE_HOLD = 6
-CRL_REASON_REMOVE_FROM_CRL = 8
-CRL_REASON_PRIVILEGE_WITHDRAWN = 9
-CRL_REASON_AA_COMPROMISE = 10
-
-# ============================================================
-# CertPathParameters
-# ============================================================
-
-class CertPathParameters(Stub):
- """java.security.cert.CertPathParameters"""
- def clone(self):
- return self.__class__()
-
-
-class CertPathBuilderResult(Stub):
- """java.security.cert.CertPathBuilderResult"""
- def getCertPath(self):
- return CertPath("")
-
- def clone(self):
- return self.__class__()
-
-
-class CertPathValidatorResult(Stub):
- """java.security.cert.CertPathValidatorResult"""
- def clone(self):
- return self.__class__()
-
-
-# ============================================================
-# CertStoreParameters
-# ============================================================
-
-class CertStoreParameters(Stub):
- """java.security.cert.CertStoreParameters"""
- def clone(self):
- return self.__class__()
-
-
-class CollectionCertStoreParameters(CertStoreParameters):
- """java.security.cert.CollectionCertStoreParameters"""
- def __init__(self, collection=None):
- super().__init__()
- if collection is None:
- self._collection = []
- else:
- self._collection = list(collection)
-
- def getCollection(self):
- return self._collection
-
- def clone(self):
- return CollectionCertStoreParameters(self._collection)
-
- def toString(self):
- return f"CollectionCertStoreParameters: [collection: {len(self._collection)}]"
-
-
-class LDAPCertStoreParameters(CertStoreParameters):
- """java.security.cert.LDAPCertStoreParameters"""
- def __init__(self, server_name="localhost", port=389):
- super().__init__()
- self._server_name = server_name
- self._port = port
-
- def getServerName(self):
- return self._server_name
-
- def getPort(self):
- return self._port
-
- def clone(self):
- return LDAPCertStoreParameters(self._server_name, self._port)
-
- def toString(self):
- return f"LDAPCertStoreParameters: [serverName: {self._server_name}, port: {self._port}]"
-
-
-# ============================================================
-# Exception Classes
-# ============================================================
-
-class CertificateException(GeneralSecurityException):
- """java.security.cert.CertificateException"""
- pass
-
-class CertificateEncodingException(CertificateException):
- """java.security.cert.CertificateEncodingException"""
- pass
-
-class CertificateParsingException(CertificateException):
- """java.security.cert.CertificateParsingException"""
- pass
-
-class CertificateNotYetValidException(CertificateException):
- """java.security.cert.CertificateNotYetValidException"""
- pass
-
-class CertificateExpiredException(CertificateException):
- """java.security.cert.CertificateExpiredException"""
- pass
-
-class CRLException(GeneralSecurityException):
- """java.security.cert.CRLException"""
- pass
-
-class CertPathBuilderException(GeneralSecurityException):
- """java.security.cert.CertPathBuilderException"""
- def __init__(self, message=None, cause=None):
- super().__init__()
- self._detail = message or ""
- self._cause = cause
-
- def getMessage(self):
- return self._detail
-
- def getCause(self):
- return self._cause
-
-class CertPathValidatorException(GeneralSecurityException):
- """java.security.cert.CertPathValidatorException"""
- class Reason(Stub):
- pass
-
- def __init__(self, message=None, cause=None, cert_path=None, index=-1):
- super().__init__()
- self._detail = message or ""
- self._cause = cause
- self._cert_path = cert_path
- self._index = index
-
- def getMessage(self):
- return self._detail
-
- def getCause(self):
- return self._cause
-
- def getCertPath(self):
- return self._cert_path
-
- def getIndex(self):
- return self._index
-
-
-# ============================================================
-# Certificate
-# ============================================================
-
-class Certificate(Stub):
- """java.security.cert.Certificate"""
- def __init__(self, type_name=""):
- super().__init__()
- self._type = type_name
-
- def getType(self):
- return self._type
-
- def getEncoded(self):
- raise CertificateEncodingException("Certificate not encoded")
-
- def verify(self, key):
- raise NotImplementedError
-
- def toString(self):
- return f"Certificate type={self._type}"
-
- def getPublicKey(self):
- from .security import PublicKey
- return PublicKey()
-
- def equals(self, other):
- if not isinstance(other, Certificate):
- return False
- return self._type == other._type
-
- def hashCode(self):
- return hash(self._type)
-
-
-class X509Certificate(Certificate):
- """java.security.cert.X509Certificate"""
- def __init__(self):
- super().__init__("X.509")
- self._encoded = b""
- self._subject = ""
- self._issuer = ""
- self._serial = 0
- self._not_before = _datetime.datetime.now()
- self._not_after = _datetime.datetime.now() + _datetime.timedelta(days=365)
- self._sig_alg = "SHA256withRSA"
- self._sig_alg_oid = "1.2.840.113549.1.1.11"
- self._version = 3
- self._public_key = None
- self._extensions = {}
-
- def getEncoded(self):
- if not self._encoded:
- raise CertificateEncodingException("X509Cert not encoded")
- return self._encoded
-
- def verify(self, key):
- return True
-
- def getPublicKey(self):
- if self._public_key is None:
- from .security import PublicKey
- self._public_key = PublicKey()
- return self._public_key
-
- def getSubjectX500Principal(self):
- from .security import Principal
- return Principal(self._subject)
-
- def getIssuerX500Principal(self):
- from .security import Principal
- return Principal(self._issuer)
-
- def getSerialNumber(self):
- return self._serial
-
- def getNotBefore(self):
- return self._not_before
-
- def getNotAfter(self):
- return self._not_after
-
- def getSigAlgName(self):
- return self._sig_alg
-
- def getSigAlgOID(self):
- return self._sig_alg_oid
-
- def getVersion(self):
- return self._version
-
- def checkValidity(self, date=None):
- if date is None:
- date = _datetime.datetime.now()
- if date < self._not_before:
- raise CertificateNotYetValidException(
- f"Certificate not valid until {self._not_before}"
- )
- if date > self._not_after:
- raise CertificateExpiredException(
- f"Certificate expired at {self._not_after}"
- )
-
- def getExtendedKeyUsage(self):
- return None
-
- def getBasicConstraints(self):
- return -1
-
- def getSubjectAlternativeNames(self):
- return None
-
- def getIssuerAlternativeNames(self):
- return None
-
- def getKeyUsage(self):
- return None
-
- def hasUnsupportedCriticalExtension(self):
- return False
-
- def getCriticalExtensionOIDs(self):
- return list(self._extensions.keys())
-
- def getNonCriticalExtensionOIDs(self):
- return []
-
- def getExtensionValue(self, oid):
- return self._extensions.get(oid)
-
- def toString(self):
- return f"X509Certificate [subject={self._subject}, issuer={self._issuer}]"
-
- def setEncoded(self, encoded):
- self._encoded = bytes(encoded)
-
- def setSubject(self, subject):
- self._subject = subject
-
- def setIssuer(self, issuer):
- self._issuer = issuer
-
- def setSerialNumber(self, serial):
- self._serial = serial
-
- def setNotBefore(self, dt):
- self._not_before = dt
-
- def setNotAfter(self, dt):
- self._not_after = dt
-
-
-# ============================================================
-# CRL / X509CRL / X509CRLEntry
-# ============================================================
-
-class CRL(Stub):
- """java.security.cert.CRL"""
- def __init__(self, type_name=""):
- super().__init__()
- self._type = type_name
-
- def getType(self):
- return self._type
-
- def isRevoked(self, cert):
- return False
-
- def toString(self):
- return f"CRL type={self._type}"
-
-
-class X509CRLEntry(Stub):
- """java.security.cert.X509CRLEntry"""
- def __init__(self):
- super().__init__()
- self._serial_number = 0
- self._revocation_date = _datetime.datetime.now()
- self._extensions = {}
-
- def getSerialNumber(self):
- return self._serial_number
-
- def getRevocationDate(self):
- return self._revocation_date
-
- def hasExtensions(self):
- return len(self._extensions) > 0
-
- def toString(self):
- return f"X509CRLEntry serial={self._serial_number}"
-
- def getCertificateIssuer(self):
- return None
-
- def getEncoded(self):
- return b""
-
- def getCriticalExtensionOIDs(self):
- return list(self._extensions.keys())
-
- def getNonCriticalExtensionOIDs(self):
- return []
-
- def getExtensionValue(self, oid):
- return self._extensions.get(oid)
-
-
-class X509CRL(CRL):
- """java.security.cert.X509CRL"""
- def __init__(self):
- super().__init__("X.509")
- self._encoded = b""
- self._issuer = ""
- self._this_update = _datetime.datetime.now()
- self._next_update = _datetime.datetime.now() + _datetime.timedelta(days=7)
- self._sig_alg = "SHA256withRSA"
- self._version = 2
- self._entries = []
-
- def getEncoded(self):
- return self._encoded
-
- def verify(self, key):
- return True
-
- def getIssuerX500Principal(self):
- from .security import Principal
- return Principal(self._issuer)
-
- def getThisUpdate(self):
- return self._this_update
-
- def getNextUpdate(self):
- return self._next_update
-
- def getSigAlgName(self):
- return self._sig_alg
-
- def getSigAlgOID(self):
- return "1.2.840.113549.1.1.11"
-
- def getVersion(self):
- return self._version
-
- def isRevoked(self, cert):
- for entry in self._entries:
- if hasattr(cert, 'getSerialNumber'):
- if entry.getSerialNumber() == cert.getSerialNumber():
- return True
- return False
-
- def getRevokedCertificate(self, cert):
- for entry in self._entries:
- if hasattr(cert, 'getSerialNumber'):
- if entry.getSerialNumber() == cert.getSerialNumber():
- return entry
- return None
-
- def getRevokedCertificates(self):
- return self._entries if self._entries else None
-
- def getCriticalExtensionOIDs(self):
- return []
-
- def getNonCriticalExtensionOIDs(self):
- return []
-
- def getExtensionValue(self, oid):
- return None
-
- def hasUnsupportedCriticalExtension(self):
- return False
-
- def toString(self):
- return f"X509CRL issuer={self._issuer}"
-
- def addEntry(self, entry):
- self._entries.append(entry)
-
- def setIssuer(self, issuer):
- self._issuer = issuer
-
-
-# ============================================================
-# CertPath
-# ============================================================
-
-class CertPath(Stub):
- """java.security.cert.CertPath"""
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
- self._certs = []
- self._encoded = b""
-
- def getType(self):
- return self._algorithm
-
- def getCertificates(self):
- return self._certs
-
- def getEncoded(self, encoding=None):
- return self._encoded
-
- def getEncodings(self):
- return ["PKCS7"]
-
- def toString(self):
- return f"CertPath: {self._algorithm} [{len(self._certs)} cert(s)]"
-
- def equals(self, other):
- if not isinstance(other, CertPath):
- return False
- return self._algorithm == other._algorithm and self._certs == other._certs
-
- def hashCode(self):
- return hash(self._algorithm) ^ hash(tuple(self._certs))
-
-
-# ============================================================
-# CertificateFactory
-# ============================================================
-
-class CertificateFactory(Stub):
- """java.security.cert.CertificateFactory"""
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return CertificateFactory(algorithm)
-
- def generateCertificate(self, in_stream):
- cert = X509Certificate()
- if hasattr(in_stream, 'read'):
- data = in_stream.read()
- cert.setEncoded(data if isinstance(data, bytes) else data.encode())
- return cert
-
- def generateCertPath(self, in_stream, encoding=None):
- return CertPath("X.509")
-
- def generateCRL(self, in_stream):
- return X509CRL()
-
- def getCertPathEncodings(self):
- return ["PKCS7"]
-
- def getProvider(self):
- from .security import Provider
- return Provider("SUN", 1.0, "Default provider")
-
- def getType(self):
- return self._algorithm
-
-
-# ============================================================
-# CertPathBuilder / CertPathValidator / CertStore
-# ============================================================
-
-class CertPathBuilder(Stub):
- """java.security.cert.CertPathBuilder"""
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return CertPathBuilder(algorithm)
-
- def build(self, params):
- if not isinstance(params, CertPathParameters):
- raise CertPathBuilderException("Invalid params")
- return PKIXCertPathBuilderResult(CertPath("X.509"))
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getProvider(self):
- from .security import Provider
- return Provider("SUN", 1.0, "Default provider")
-
-
-class CertPathValidator(Stub):
- """java.security.cert.CertPathValidator"""
- def __init__(self, algorithm):
- super().__init__()
- self._algorithm = algorithm
-
- @staticmethod
- def getInstance(algorithm, provider=None):
- return CertPathValidator(algorithm)
-
- def validate(self, cert_path, params):
- if not isinstance(cert_path, CertPath):
- raise CertPathValidatorException("Invalid cert path")
- return PKIXCertPathValidatorResult()
-
- def getAlgorithm(self):
- return self._algorithm
-
- def getProvider(self):
- from .security import Provider
- return Provider("SUN", 1.0, "Default provider")
-
-
-class CertStore(Stub):
- """java.security.cert.CertStore"""
- def __init__(self, type_name, params):
- super().__init__()
- self._type = type_name
- self._params = params
-
- @staticmethod
- def getInstance(type_name, params, provider=None):
- return CertStore(type_name, params)
-
- def getCertificates(self, selector):
- return []
-
- def getCRLs(self, selector):
- return []
-
- def getType(self):
- return self._type
-
- def getCertStoreParameters(self):
- return self._params
-
-
-# ============================================================
-# PolicyQualifierInfo
-# ============================================================
-
-class PolicyQualifierInfo(Stub):
- """java.security.cert.PolicyQualifierInfo"""
- def __init__(self, encoded):
- super().__init__()
- self._encoded = encoded
-
- def getEncoded(self):
- return self._encoded
-
- def getPolicyQualifierId(self):
- return "1.3.6.1.5.5.7.2.1"
-
- def getPolicyQualifier(self):
- return self._encoded
-
- def toString(self):
- return f"PolicyQualifierInfo [id={self.getPolicyQualifierId()}]"
-
-
-# ============================================================
-# TrustAnchor
-# ============================================================
-
-class TrustAnchor(Stub):
- """java.security.cert.TrustAnchor"""
- def __init__(self, ca_cert, ca_name=None, ca_public_key=None, name_constraints=None):
- super().__init__()
- self._ca_cert = ca_cert
- self._ca_name = ca_name
- self._ca_public_key = ca_public_key
- self._name_constraints = name_constraints
-
- def getTrustedCert(self):
- return self._ca_cert
-
- def getCAName(self):
- return self._ca_name
-
- def getCAPublicKey(self):
- return self._ca_public_key
-
- def getNameConstraints(self):
- return self._name_constraints
-
- def toString(self):
- return f"TrustAnchor [CA={self._ca_name}]"
-
-
-# ============================================================
-# Extension / X509Extension
-# ============================================================
-
-class Extension(Stub):
- """java.security.cert.Extension"""
- def __init__(self, oid="", critical=False, value=b""):
- super().__init__()
- self._oid = oid
- self._critical = critical
- self._value = value
-
- def getId(self):
- return self._oid
-
- def isCritical(self):
- return self._critical
-
- def getValue(self):
- return self._value
-
- def getEncoded(self):
- return self._value
-
- def toString(self):
- return f"Extension oid={self._oid} critical={self._critical}"
-
-
-class X509Extension(Stub):
- """java.security.cert.X509Extension"""
- def hasUnsupportedCriticalExtension(self):
- return False
-
- def getCriticalExtensionOIDs(self):
- return []
-
- def getNonCriticalExtensionOIDs(self):
- return []
-
- def getExtensionValue(self, oid):
- return None
-
-
-# ============================================================
-# PKIXParameters / PKIXBuilderParameters
-# ============================================================
-
-class PKIXParameters(CertPathParameters):
- """java.security.cert.PKIXParameters"""
- def __init__(self, trust_anchors=None):
- super().__init__()
- if trust_anchors is not None:
- if isinstance(trust_anchors, set):
- self._trust_anchors = trust_anchors
- else:
- self._trust_anchors = set(trust_anchors)
- else:
- self._trust_anchors = set()
- self._date = None
- self._cert_stores = []
- self._revocation_enabled = True
- self._explicit_policy_required = False
- self._policy_mapping_inhibited = False
- self._any_policy_inhibited = False
- self._policy_qualifiers_rejected = True
- self._sig_provider = None
- self._target_cert_constraints = None
- self._initial_policies = None
- self._cert_path_checkers = []
- self._stores = []
-
- def getTrustAnchors(self):
- return self._trust_anchors
-
- def setTrustAnchors(self, trust_anchors):
- if isinstance(trust_anchors, set):
- self._trust_anchors = trust_anchors
- else:
- self._trust_anchors = set(trust_anchors)
-
- def getDate(self):
- return self._date
-
- def setDate(self, date):
- self._date = date
-
- def addCertStore(self, store):
- self._cert_stores.append(store)
-
- def getCertStores(self):
- return self._cert_stores
-
- def setCertStores(self, stores):
- self._cert_stores = list(stores)
-
- def isRevocationEnabled(self):
- return self._revocation_enabled
-
- def setRevocationEnabled(self, enabled):
- self._revocation_enabled = enabled
-
- def isExplicitPolicyRequired(self):
- return self._explicit_policy_required
-
- def setExplicitPolicyRequired(self, required):
- self._explicit_policy_required = required
-
- def isPolicyMappingInhibited(self):
- return self._policy_mapping_inhibited
-
- def setPolicyMappingInhibited(self, inhibited):
- self._policy_mapping_inhibited = inhibited
-
- def isAnyPolicyInhibited(self):
- return self._any_policy_inhibited
-
- def setAnyPolicyInhibited(self, inhibited):
- self._any_policy_inhibited = inhibited
-
- def getPolicyQualifiersRejected(self):
- return self._policy_qualifiers_rejected
-
- def setPolicyQualifiersRejected(self, rejected):
- self._policy_qualifiers_rejected = rejected
-
- def getSigProvider(self):
- return self._sig_provider
-
- def setSigProvider(self, provider):
- self._sig_provider = provider
-
- def getTargetCertConstraints(self):
- return self._target_cert_constraints
-
- def setTargetCertConstraints(self, constraints):
- self._target_cert_constraints = constraints
-
- def getInitialPolicies(self):
- return self._initial_policies
-
- def setInitialPolicies(self, policies):
- self._initial_policies = policies
-
- def addCertPathChecker(self, checker):
- self._cert_path_checkers.append(checker)
-
- def getCertPathCheckers(self):
- return self._cert_path_checkers
-
- def setCertPathCheckers(self, checkers):
- self._cert_path_checkers = list(checkers)
-
- def clone(self):
- return PKIXParameters(self._trust_anchors)
-
- def toString(self):
- return f"PKIXParameters [trust_anchors={len(self._trust_anchors)}]"
-
-
-class PKIXBuilderParameters(PKIXParameters):
- """java.security.cert.PKIXBuilderParameters"""
- def __init__(self, trust_anchors, target_constraints=None):
- super().__init__(trust_anchors)
- self._max_path_length = 5
- if target_constraints is not None:
- self.setTargetCertConstraints(target_constraints)
-
- def getMaxPathLength(self):
- return self._max_path_length
-
- def setMaxPathLength(self, length):
- if length < -1:
- raise IllegalArgumentException("max path length must be >= -1")
- self._max_path_length = length
-
- def toString(self):
- return f"PKIXBuilderParameters [max_path={self._max_path_length}]"
-
-
-# ============================================================
-# PKIXCertPathBuilderResult / PKIXCertPathValidatorResult
-# ============================================================
-
-class PKIXCertPathBuilderResult(CertPathBuilderResult):
- """java.security.cert.PKIXCertPathBuilderResult"""
- def __init__(self, cert_path=None, trust_anchor=None, policy_tree=None, subject_public_key=None):
- super().__init__()
- self._cert_path = cert_path
- self._trust_anchor = trust_anchor
- self._policy_tree = policy_tree
- self._subject_public_key = subject_public_key
-
- def getCertPath(self):
- return self._cert_path
-
- def getTrustAnchor(self):
- return self._trust_anchor
-
- def getPolicyTree(self):
- return self._policy_tree
-
- def getPublicKey(self):
- return self._subject_public_key
-
- def toString(self):
- return f"PKIXCertPathBuilderResult [path={self._cert_path}]"
-
-
-class PKIXCertPathValidatorResult(CertPathValidatorResult):
- """java.security.cert.PKIXCertPathValidatorResult"""
- def __init__(self, trust_anchor=None, policy_tree=None, subject_public_key=None):
- super().__init__()
- self._trust_anchor = trust_anchor
- self._policy_tree = policy_tree
- self._subject_public_key = subject_public_key
-
- def getTrustAnchor(self):
- return self._trust_anchor
-
- def getPolicyTree(self):
- return self._policy_tree
-
- def getPublicKey(self):
- return self._subject_public_key
-
- def toString(self):
- return "PKIXCertPathValidatorResult"
-
-
-# ============================================================
-# IllegalArgumentException (local)
-# ============================================================
-
-class IllegalArgumentException(RuntimeException):
- """java.lang.IllegalArgumentException"""
- pass
\ No newline at end of file
diff --git a/android_pyapi/java/security_spec.py b/android_pyapi/java/security_spec.py
deleted file mode 100644
index 26963e3..0000000
--- a/android_pyapi/java/security_spec.py
+++ /dev/null
@@ -1,697 +0,0 @@
-"""
-Java security.spec standard library APIs implemented in Python.
-java.security.spec package - KeySpec, AlgorithmParameterSpec, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-from .security import GeneralSecurityException, InvalidKeySpecException, InvalidParameterException
-from .lang import RuntimeException
-import math as _py_math
-
-__all__ = [
- "KeySpec", "EncodedKeySpec", "PKCS8EncodedKeySpec", "X509EncodedKeySpec",
- "DSAPrivateKeySpec", "DSAPublicKeySpec",
- "RSAPrivateKeySpec", "RSAPublicKeySpec", "RSAPrivateCrtKeySpec",
- "RSAOtherPrimeInfo",
- "ECPrivateKeySpec", "ECPublicKeySpec",
- "ECField", "ECFieldF2m", "ECFieldFp", "EllipticCurve",
- "ECGenParameterSpec", "ECParameterSpec", "ECPoint",
- "AlgorithmParameterSpec",
- "IvParameterSpec", "OAEPParameterSpec", "PSSParameterSpec",
- "MGF1ParameterSpec", "PBEParameterSpec",
- "RC2ParameterSpec", "RC5ParameterSpec",
- "DHParameterSpec", "DHGenParameterSpec",
- "DHPrivateKeySpec", "DHPublicKeySpec",
- "DSAGenParameterSpec",
-]
-
-
-# ============================================================
-# KeySpec
-# ============================================================
-
-class KeySpec(Stub):
- """java.security.spec.KeySpec"""
- pass
-
-
-class EncodedKeySpec(KeySpec):
- """java.security.spec.EncodedKeySpec"""
- def __init__(self, encoded_key):
- super().__init__()
- self._encoded_key = bytes(encoded_key)
-
- def getEncoded(self):
- return self._encoded_key
-
- def getFormat(self):
- raise NotImplementedError
-
-
-class PKCS8EncodedKeySpec(EncodedKeySpec):
- """java.security.spec.PKCS8EncodedKeySpec"""
- def __init__(self, encoded_key):
- super().__init__(encoded_key)
-
- def getFormat(self):
- return "PKCS#8"
-
-
-class X509EncodedKeySpec(EncodedKeySpec):
- """java.security.spec.X509EncodedKeySpec"""
- def __init__(self, encoded_key):
- super().__init__(encoded_key)
-
- def getFormat(self):
- return "X.509"
-
-
-# ============================================================
-# DSA KeySpecs
-# ============================================================
-
-class DSAPrivateKeySpec(KeySpec):
- """java.security.spec.DSAPrivateKeySpec"""
- def __init__(self, x, p, q, g):
- super().__init__()
- self._x = x
- self._p = p
- self._q = q
- self._g = g
-
- def getX(self):
- return self._x
-
- def getP(self):
- return self._p
-
- def getQ(self):
- return self._q
-
- def getG(self):
- return self._g
-
-
-class DSAPublicKeySpec(KeySpec):
- """java.security.spec.DSAPublicKeySpec"""
- def __init__(self, y, p, q, g):
- super().__init__()
- self._y = y
- self._p = p
- self._q = q
- self._g = g
-
- def getY(self):
- return self._y
-
- def getP(self):
- return self._p
-
- def getQ(self):
- return self._q
-
- def getG(self):
- return self._g
-
-
-# ============================================================
-# RSA KeySpecs
-# ============================================================
-
-class RSAPrivateKeySpec(KeySpec):
- """java.security.spec.RSAPrivateKeySpec"""
- def __init__(self, modulus, private_exponent):
- super().__init__()
- self._modulus = modulus
- self._private_exponent = private_exponent
-
- def getModulus(self):
- return self._modulus
-
- def getPrivateExponent(self):
- return self._private_exponent
-
-
-class RSAPublicKeySpec(KeySpec):
- """java.security.spec.RSAPublicKeySpec"""
- def __init__(self, modulus, public_exponent):
- super().__init__()
- self._modulus = modulus
- self._public_exponent = public_exponent
-
- def getModulus(self):
- return self._modulus
-
- def getPublicExponent(self):
- return self._public_exponent
-
-
-class RSAPrivateCrtKeySpec(RSAPrivateKeySpec):
- """java.security.spec.RSAPrivateCrtKeySpec"""
- def __init__(self, modulus, public_exponent, private_exponent,
- prime_p, prime_q, prime_exponent_p, prime_exponent_q,
- crt_coefficient):
- super().__init__(modulus, private_exponent)
- self._public_exponent = public_exponent
- self._prime_p = prime_p
- self._prime_q = prime_q
- self._prime_exponent_p = prime_exponent_p
- self._prime_exponent_q = prime_exponent_q
- self._crt_coefficient = crt_coefficient
-
- def getPublicExponent(self):
- return self._public_exponent
-
- def getPrimeP(self):
- return self._prime_p
-
- def getPrimeQ(self):
- return self._prime_q
-
- def getPrimeExponentP(self):
- return self._prime_exponent_p
-
- def getPrimeExponentQ(self):
- return self._prime_exponent_q
-
- def getCrtCoefficient(self):
- return self._crt_coefficient
-
-
-class RSAOtherPrimeInfo(Stub):
- """java.security.spec.RSAOtherPrimeInfo"""
- def __init__(self, prime, exponent, coefficient):
- super().__init__()
- self._prime = prime
- self._exponent = exponent
- self._coefficient = coefficient
-
- def getPrime(self):
- return self._prime
-
- def getExponent(self):
- return self._exponent
-
- def getCrtCoefficient(self):
- return self._coefficient
-
-
-# ============================================================
-# EC KeySpecs
-# ============================================================
-
-class ECPoint(Stub):
- """java.security.spec.ECPoint"""
- def __init__(self, affine_x, affine_y):
- super().__init__()
- self._affine_x = affine_x
- self._affine_y = affine_y
-
- def getAffineX(self):
- return self._affine_x
-
- def getAffineY(self):
- return self._affine_y
-
- def equals(self, other):
- if not isinstance(other, ECPoint):
- return False
- return self._affine_x == other._affine_x and self._affine_y == other._affine_y
-
- def hashCode(self):
- return hash((self._affine_x, self._affine_y))
-
- def toString(self):
- return f"ECPoint(x={self._affine_x}, y={self._affine_y})"
-
- POINT_INFINITY = None
-
-
-class ECField(Stub):
- """java.security.spec.ECField"""
- def getFieldSize(self):
- raise NotImplementedError
-
-
-class ECFieldFp(ECField):
- """java.security.spec.ECFieldFp"""
- def __init__(self, prime):
- super().__init__()
- self._prime = prime
-
- def getP(self):
- return self._prime
-
- def getFieldSize(self):
- return self._prime.bit_length()
-
- def equals(self, other):
- if not isinstance(other, ECFieldFp):
- return False
- return self._prime == other._prime
-
- def hashCode(self):
- return hash(self._prime)
-
-
-class ECFieldF2m(ECField):
- """java.security.spec.ECFieldF2m"""
- def __init__(self, m, ks=None, rp=None):
- super().__init__()
- self._m = m
- if ks is not None and rp is None:
- if isinstance(ks, int):
- self._ks = [ks]
- self._rp = None
- else:
- self._ks = list(ks)
- self._rp = None
- elif rp is not None:
- self._ks = None
- self._rp = rp
- else:
- self._ks = None
- self._rp = None
-
- def getM(self):
- return self._m
-
- def getKs(self):
- return self._ks
-
- def getFieldSize(self):
- return self._m
-
- def getReductionPolynomial(self):
- return self._rp
-
- def equals(self, other):
- if not isinstance(other, ECFieldF2m):
- return False
- return self._m == other._m and self._ks == other._ks and self._rp == other._rp
-
- def hashCode(self):
- return hash(self._m)
-
-
-class EllipticCurve(Stub):
- """java.security.spec.EllipticCurve"""
- def __init__(self, field, a, b, seed=None):
- super().__init__()
- self._field = field
- self._a = a
- self._b = b
- self._seed = seed
-
- def getField(self):
- return self._field
-
- def getA(self):
- return self._a
-
- def getB(self):
- return self._b
-
- def getSeed(self):
- return self._seed
-
- def equals(self, other):
- if not isinstance(other, EllipticCurve):
- return False
- return (self._field == other._field and self._a == other._a
- and self._b == other._b)
-
- def hashCode(self):
- return hash((self._field, self._a, self._b))
-
-
-class ECParameterSpec(Stub):
- """java.security.spec.ECParameterSpec"""
- def __init__(self, curve, generator, order, cofactor):
- super().__init__()
- self._curve = curve
- self._generator = generator
- self._order = order
- self._cofactor = cofactor
-
- def getCurve(self):
- return self._curve
-
- def getGenerator(self):
- return self._generator
-
- def getOrder(self):
- return self._order
-
- def getCofactor(self):
- return self._cofactor
-
- def toString(self):
- return f"ECParameterSpec [order={self._order}]"
-
-
-class ECGenParameterSpec(Stub):
- """java.security.spec.ECGenParameterSpec"""
- def __init__(self, name):
- super().__init__()
- self._name = name
-
- def getName(self):
- return self._name
-
- def toString(self):
- return f"ECGenParameterSpec [name={self._name}]"
-
-
-class ECPrivateKeySpec(KeySpec):
- """java.security.spec.ECPrivateKeySpec"""
- def __init__(self, s, params):
- super().__init__()
- self._s = s
- self._params = params
-
- def getS(self):
- return self._s
-
- def getParams(self):
- return self._params
-
-
-class ECPublicKeySpec(KeySpec):
- """java.security.spec.ECPublicKeySpec"""
- def __init__(self, w, params):
- super().__init__()
- self._w = w
- self._params = params
-
- def getW(self):
- return self._w
-
- def getParams(self):
- return self._params
-
-
-# ============================================================
-# AlgorithmParameterSpec
-# ============================================================
-
-class AlgorithmParameterSpec(Stub):
- """java.security.spec.AlgorithmParameterSpec"""
- pass
-
-
-class IvParameterSpec(AlgorithmParameterSpec):
- """javax.crypto.spec.IvParameterSpec"""
- def __init__(self, iv, offset=0, length=None):
- super().__init__()
- if length is None:
- self._iv = bytes(iv[offset:])
- else:
- self._iv = bytes(iv[offset:offset + length])
-
- def getIV(self):
- return self._iv
-
-
-class OAEPParameterSpec(AlgorithmParameterSpec):
- """javax.crypto.spec.OAEPParameterSpec"""
- def __init__(self, md_name="SHA-256", mgf_name="MGF1", mgf_spec=None, p_src=None):
- super().__init__()
- self._md_name = md_name
- self._mgf_name = mgf_name
- self._mgf_spec = mgf_spec or MGF1ParameterSpec.SHA256
- self._p_src = p_src
-
- def getDigestAlgorithm(self):
- return self._md_name
-
- def getMGFAlgorithm(self):
- return self._mgf_name
-
- def getMGFParameters(self):
- return self._mgf_spec
-
- def getPSource(self):
- return self._p_src
-
- DEFAULT = None
-
-
-class PSSParameterSpec(AlgorithmParameterSpec):
- """java.security.spec.PSSParameterSpec"""
- def __init__(self, md_name="SHA-256", mgf_name="MGF1", mgf_spec=None,
- salt_len=None, trailer_field=1):
- super().__init__()
- if isinstance(md_name, int):
- # Legacy constructor: PSSParameterSpec(int saltLen)
- self._salt_len = md_name
- self._md_name = "SHA-1"
- self._mgf_name = "MGF1"
- self._mgf_spec = MGF1ParameterSpec.SHA1
- self._trailer_field = 1
- else:
- self._md_name = md_name
- self._mgf_name = mgf_name
- self._mgf_spec = mgf_spec or MGF1ParameterSpec.SHA256
- self._salt_len = salt_len if salt_len is not None else 32
- self._trailer_field = trailer_field
-
- def getDigestAlgorithm(self):
- return self._md_name
-
- def getMGFAlgorithm(self):
- return self._mgf_name
-
- def getMGFParameters(self):
- return self._mgf_spec
-
- def getSaltLength(self):
- return self._salt_len
-
- def getTrailerField(self):
- return self._trailer_field
-
- DEFAULT = None
- TRAILER_FIELD_BC = 1
-
-
-class MGF1ParameterSpec(AlgorithmParameterSpec):
- """java.security.spec.MGF1ParameterSpec"""
- def __init__(self, md_name):
- super().__init__()
- self._md_name = md_name
-
- def getDigestAlgorithm(self):
- return self._md_name
-
- def toString(self):
- return f"MGF1ParameterSpec [{self._md_name}]"
-
- SHA1 = None
- SHA224 = None
- SHA256 = None
- SHA384 = None
- SHA512 = None
-
-
-class PBEParameterSpec(AlgorithmParameterSpec):
- """javax.crypto.spec.PBEParameterSpec"""
- def __init__(self, salt, iteration_count):
- super().__init__()
- self._salt = bytes(salt)
- self._iteration_count = iteration_count
-
- def getSalt(self):
- return self._salt
-
- def getIterationCount(self):
- return self._iteration_count
-
-
-class RC2ParameterSpec(AlgorithmParameterSpec):
- """javax.crypto.spec.RC2ParameterSpec"""
- def __init__(self, effective_key_bits, iv=None, offset=0):
- super().__init__()
- self._effective_key_bits = effective_key_bits
- if iv is not None:
- self._iv = bytes(iv[offset:offset + 8]) if offset + 8 <= len(iv) else bytes(iv[offset:])
- else:
- self._iv = None
-
- def getEffectiveKeyBits(self):
- return self._effective_key_bits
-
- def getIV(self):
- return self._iv
-
- def equals(self, other):
- if not isinstance(other, RC2ParameterSpec):
- return False
- return (self._effective_key_bits == other._effective_key_bits
- and self._iv == other._iv)
-
- def hashCode(self):
- return hash(self._effective_key_bits) ^ hash(self._iv)
-
-
-class RC5ParameterSpec(AlgorithmParameterSpec):
- """javax.crypto.spec.RC5ParameterSpec"""
- def __init__(self, version, rounds, word_size, iv=None, offset=0):
- super().__init__()
- self._version = version
- self._rounds = rounds
- self._word_size = word_size
- if iv is not None:
- self._iv = bytes(iv[offset:offset + 8]) if offset + 8 <= len(iv) else bytes(iv[offset:])
- else:
- self._iv = None
-
- def getVersion(self):
- return self._version
-
- def getRounds(self):
- return self._rounds
-
- def getWordSize(self):
- return self._word_size
-
- def getIV(self):
- return self._iv
-
- def equals(self, other):
- if not isinstance(other, RC5ParameterSpec):
- return False
- return (self._version == other._version and self._rounds == other._rounds
- and self._word_size == other._word_size and self._iv == other._iv)
-
- def hashCode(self):
- return hash((self._version, self._rounds, self._word_size, bytes(self._iv) if self._iv else b""))
-
-
-# ============================================================
-# DH (Diffie-Hellman) Specs
-# ============================================================
-
-class DHParameterSpec(AlgorithmParameterSpec):
- """javax.crypto.spec.DHParameterSpec"""
- def __init__(self, p, g, l=0):
- super().__init__()
- self._p = p
- self._g = g
- self._l = l
-
- def getP(self):
- return self._p
-
- def getG(self):
- return self._g
-
- def getL(self):
- return self._l
-
-
-class DHGenParameterSpec(AlgorithmParameterSpec):
- """javax.crypto.spec.DHGenParameterSpec"""
- def __init__(self, prime_size, exponent_size):
- super().__init__()
- self._prime_size = prime_size
- self._exponent_size = exponent_size
-
- def getPrimeSize(self):
- return self._prime_size
-
- def getExponentSize(self):
- return self._exponent_size
-
-
-class DHPrivateKeySpec(KeySpec):
- """javax.crypto.spec.DHPrivateKeySpec"""
- def __init__(self, x, p, g):
- super().__init__()
- self._x = x
- self._p = p
- self._g = g
-
- def getX(self):
- return self._x
-
- def getP(self):
- return self._p
-
- def getG(self):
- return self._g
-
-
-class DHPublicKeySpec(KeySpec):
- """javax.crypto.spec.DHPublicKeySpec"""
- def __init__(self, y, p, g):
- super().__init__()
- self._y = y
- self._p = p
- self._g = g
-
- def getY(self):
- return self._y
-
- def getP(self):
- return self._p
-
- def getG(self):
- return self._g
-
-
-# ============================================================
-# DSAGenParameterSpec
-# ============================================================
-
-class DSAGenParameterSpec(AlgorithmParameterSpec):
- """java.security.spec.DSAGenParameterSpec"""
- def __init__(self, prime_pl, subprime_ql, seed_len):
- super().__init__()
- self._prime_pl = prime_pl
- self._subprime_ql = subprime_ql
- self._seed_len = seed_len
-
- def getPrimePL(self):
- return self._prime_pl
-
- def getSubprimeQL(self):
- return self._subprime_ql
-
- def getSeedLen(self):
- return self._seed_len
-
-
-# ============================================================
-# Initialize MGF1ParameterSpec constants
-# ============================================================
-
-MGF1ParameterSpec.SHA1 = MGF1ParameterSpec("SHA-1")
-MGF1ParameterSpec.SHA224 = MGF1ParameterSpec("SHA-224")
-MGF1ParameterSpec.SHA256 = MGF1ParameterSpec("SHA-256")
-MGF1ParameterSpec.SHA384 = MGF1ParameterSpec("SHA-384")
-MGF1ParameterSpec.SHA512 = MGF1ParameterSpec("SHA-512")
-
-# ============================================================
-# Initialize OAEPParameterSpec DEFAULT
-# ============================================================
-
-OAEPParameterSpec.DEFAULT = OAEPParameterSpec(
- "SHA-1", "MGF1", MGF1ParameterSpec.SHA1, None
-)
-
-# ============================================================
-# Initialize PSSParameterSpec DEFAULT
-# ============================================================
-
-PSSParameterSpec.DEFAULT = PSSParameterSpec(
- "SHA-1", "MGF1", MGF1ParameterSpec.SHA1, 20, 1
-)
-
-# ============================================================
-# ECPoint.POINT_INFINITY
-# ============================================================
-
-ECPoint.POINT_INFINITY = ECPoint(None, None)
\ No newline at end of file
diff --git a/android_pyapi/java/sql.py b/android_pyapi/java/sql.py
deleted file mode 100644
index 323160c..0000000
--- a/android_pyapi/java/sql.py
+++ /dev/null
@@ -1,2242 +0,0 @@
-"""
-Java SQL standard library APIs implemented in Python.
-java.sql package - Connection, Statement, ResultSet, Types, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-from .lang import RuntimeException, Exception as _JavaException
-import datetime as _datetime
-import typing as _typing
-
-__all__ = [
- "Connection", "Statement", "PreparedStatement", "CallableStatement",
- "ResultSet", "ResultSetMetaData", "DatabaseMetaData",
- "Driver", "DriverManager", "DriverPropertyInfo",
- "SQLException", "SQLWarning", "SQLData", "SQLInput", "SQLOutput",
- "BatchUpdateException", "DataTruncation",
- "Date", "Time", "Timestamp", "Savepoint",
- "Blob", "Clob", "NClob", "Ref", "RowId", "Struct", "SQLXML", "Array",
- "Types", "JDBCType", "Wrapper",
- "FETCH_FORWARD", "FETCH_REVERSE", "FETCH_UNKNOWN",
- "TYPE_FORWARD_ONLY", "TYPE_SCROLL_INSENSITIVE", "TYPE_SCROLL_SENSITIVE",
- "HOLD_CURSORS_OVER_COMMIT", "CLOSE_CURSORS_AT_COMMIT",
- "CLOSE_ALL_RESULTS", "KEEP_CURRENT_RESULT",
- "NO_GENERATED_KEYS", "RETURN_GENERATED_KEYS",
- "CLOSE_CURRENT_RESULT",
-]
-
-# ============================================================
-# Constants
-# ============================================================
-
-FETCH_FORWARD = 1000
-FETCH_REVERSE = 1001
-FETCH_UNKNOWN = 1002
-
-TYPE_FORWARD_ONLY = 1003
-TYPE_SCROLL_INSENSITIVE = 1004
-TYPE_SCROLL_SENSITIVE = 1005
-
-HOLD_CURSORS_OVER_COMMIT = 1
-CLOSE_CURSORS_AT_COMMIT = 2
-
-CLOSE_ALL_RESULTS = 1
-KEEP_CURRENT_RESULT = 2
-CLOSE_CURRENT_RESULT = 3
-
-NO_GENERATED_KEYS = 1
-RETURN_GENERATED_KEYS = 2
-
-
-# ============================================================
-# SQLException hierarchy
-# ============================================================
-
-class SQLException(_JavaException):
- """java.sql.SQLException"""
- def __init__(self, reason=None, sql_state=None, vendor_code=0, cause=None):
- msg = reason or ""
- super().__init__(msg)
- self._reason = reason
- self._sql_state = sql_state
- self._vendor_code = vendor_code
- self._cause = cause
- self._next_exception = None
-
- def getMessage(self):
- return self._reason or ""
-
- def getSQLState(self):
- return self._sql_state
-
- def getErrorCode(self):
- return self._vendor_code
-
- def getNextException(self):
- return self._next_exception
-
- def setNextException(self, ex):
- self._next_exception = ex
-
- def getCause(self):
- return self._cause
-
-
-class SQLWarning(SQLException):
- """java.sql.SQLWarning"""
- def __init__(self, reason=None, sql_state=None, vendor_code=0):
- super().__init__(reason, sql_state, vendor_code)
- self._next_warning = None
-
- def getNextWarning(self):
- return self._next_warning
-
- def setNextWarning(self, warning):
- self._next_warning = warning
-
-
-class BatchUpdateException(SQLException):
- """java.sql.BatchUpdateException"""
- def __init__(self, reason=None, sql_state=None, vendor_code=0,
- update_counts=None, cause=None):
- super().__init__(reason, sql_state, vendor_code, cause)
- self._update_counts = update_counts or []
-
- def getUpdateCounts(self):
- return self._update_counts
-
- def getLargeUpdateCounts(self):
- return [int(c) for c in self._update_counts]
-
-
-class DataTruncation(SQLWarning):
- """java.sql.DataTruncation"""
- def __init__(self, index, parameter, read, data_size, transfer_size):
- super().__init__("Data truncation")
- self._index = index
- self._parameter = parameter
- self._read = read
- self._data_size = data_size
- self._transfer_size = transfer_size
-
- def getIndex(self):
- return self._index
-
- def getParameter(self):
- return self._parameter
-
- def getRead(self):
- return self._read
-
- def getDataSize(self):
- return self._data_size
-
- def getTransferSize(self):
- return self._transfer_size
-
-
-# ============================================================
-# Wrapper
-# ============================================================
-
-class Wrapper(Stub):
- """java.sql.Wrapper"""
- def unwrap(self, iface):
- if iface is None:
- raise SQLException("iface is null")
- return self
-
- def isWrapperFor(self, iface):
- return iface is not None and isinstance(self, iface)
-
-
-# ============================================================
-# Types Constants
-# ============================================================
-
-class Types:
- """java.sql.Types"""
- ARRAY = 2003
- BIGINT = -5
- BINARY = -2
- BIT = -7
- BLOB = 2004
- BOOLEAN = 16
- CHAR = 1
- CLOB = 2005
- DATALINK = 70
- DATE = 91
- DECIMAL = 3
- DISTINCT = 2001
- DOUBLE = 8
- FLOAT = 6
- INTEGER = 4
- JAVA_OBJECT = 2000
- LONGNVARCHAR = -16
- LONGVARBINARY = -4
- LONGVARCHAR = -1
- NCHAR = -15
- NCLOB = 2011
- NULL = 0
- NUMERIC = 2
- NVARCHAR = -9
- OTHER = 1111
- REAL = 7
- REF = 2006
- REF_CURSOR = 2012
- ROWID = -8
- SMALLINT = 5
- SQLXML = 2009
- STRUCT = 2002
- TIME = 92
- TIMESTAMP = 93
- TINYINT = -6
- VARBINARY = -3
- VARCHAR = 12
-
-
-class JDBCType(Stub):
- """java.sql.JDBCType"""
- _type_map = {}
-
- def __init__(self, vendor_type_number):
- super().__init__()
- self._vendor_type_number = vendor_type_number
-
- def getVendorTypeNumber(self):
- return self._vendor_type_number
-
- def getName(self):
- for name, val in vars(Types).items():
- if isinstance(val, int) and val == self._vendor_type_number:
- return name
- return "UNKNOWN"
-
- @staticmethod
- def valueOf(name):
- val = getattr(Types, name, None)
- if val is None:
- raise IllegalArgumentException(f"No JDBC type: {name}")
- return JDBCType(val)
-
- @staticmethod
- def values():
- return [JDBCType(v) for v in set(
- v for v in vars(Types).values() if isinstance(v, int)
- )]
-
-
-# ============================================================
-# Date / Time / Timestamp
-# ============================================================
-
-class Date(_datetime.date):
- """java.sql.Date"""
- def __init__(self, *args):
- if len(args) == 1:
- ms = args[0]
- dt = _datetime.datetime.fromtimestamp(ms / 1000.0)
- super().__init__(dt.year, dt.month, dt.day)
- elif len(args) == 3:
- super().__init__(args[0], args[1], args[2])
- else:
- super().__init__()
-
- def getTime(self):
- dt = _datetime.datetime.combine(self, _datetime.time.min)
- return int(dt.timestamp() * 1000)
-
- def setTime(self, ms):
- dt = _datetime.datetime.fromtimestamp(ms / 1000.0)
- super().__init__(dt.year, dt.month, dt.day)
-
- def toString(self):
- return self.strftime("%Y-%m-%d")
-
- @staticmethod
- def valueOf(s):
- parts = s.split("-")
- return Date(int(parts[0]), int(parts[1]), int(parts[2]))
-
-
-class Time(_datetime.time):
- """java.sql.Time"""
- def __init__(self, *args):
- if len(args) == 1:
- ms = args[0]
- dt = _datetime.datetime.fromtimestamp(ms / 1000.0)
- super().__init__(dt.hour, dt.minute, dt.second)
- elif len(args) == 3:
- super().__init__(args[0], args[1], args[2])
- else:
- super().__init__()
-
- def getTime(self):
- dt = _datetime.datetime.combine(_datetime.date.today(), self)
- return int(dt.timestamp() * 1000)
-
- def setTime(self, ms):
- dt = _datetime.datetime.fromtimestamp(ms / 1000.0)
- super().__init__(dt.hour, dt.minute, dt.second)
-
- def toString(self):
- return self.strftime("%H:%M:%S")
-
- @staticmethod
- def valueOf(s):
- parts = s.split(":")
- return Time(int(parts[0]), int(parts[1]), int(parts[2]))
-
-
-class Timestamp(_datetime.datetime):
- """java.sql.Timestamp"""
- def __init__(self, *args):
- if len(args) == 1:
- ms = args[0]
- dt = _datetime.datetime.fromtimestamp(ms / 1000.0)
- super().__init__(dt.year, dt.month, dt.day, dt.hour,
- dt.minute, dt.second, dt.microsecond)
- self._nanos = (ms % 1000) * 1000000
- else:
- super().__init__(*args)
- self._nanos = 0
-
- def getTime(self):
- return int(self.timestamp() * 1000)
-
- def setTime(self, ms):
- dt = _datetime.datetime.fromtimestamp(ms / 1000.0)
- super().__init__(dt.year, dt.month, dt.day, dt.hour,
- dt.minute, dt.second, dt.microsecond)
- self._nanos = (ms % 1000) * 1000000
-
- def getNanos(self):
- return self._nanos
-
- def setNanos(self, n):
- self._nanos = n
-
- def toString(self):
- return self.strftime("%Y-%m-%d %H:%M:%S")
-
- @staticmethod
- def valueOf(s):
- parts = s.split(" ")
- date_part = parts[0].split("-")
- time_part = parts[1].split(":")
- return Timestamp(int(date_part[0]), int(date_part[1]), int(date_part[2]),
- int(time_part[0]), int(time_part[1]), int(time_part[2]))
-
-
-# ============================================================
-# Savepoint
-# ============================================================
-
-class Savepoint(Stub):
- """java.sql.Savepoint"""
- def __init__(self, name=None):
- super().__init__()
- self._savepoint_id = id(self)
- self._savepoint_name = name
-
- def getSavepointId(self):
- if self._savepoint_name is not None:
- raise SQLException("Named savepoint")
- return self._savepoint_id
-
- def getSavepointName(self):
- if self._savepoint_name is None:
- raise SQLException("Unnamed savepoint")
- return self._savepoint_name
-
-
-# ============================================================
-# Blob / Clob / NClob / Ref / RowId / Struct / SQLXML / Array
-# ============================================================
-
-class Blob(Stub):
- """java.sql.Blob"""
- def __init__(self, data=b""):
- super().__init__()
- self._data = bytearray(data)
- self._length = len(data)
-
- def length(self):
- return self._length
-
- def getBytes(self, pos, length):
- start = pos - 1
- return bytes(self._data[start:start + length])
-
- def setBytes(self, pos, bytes_data, offset=0, length=None):
- start = pos - 1
- if length is None:
- length = len(bytes_data) - offset
- self._data[start:start + length] = bytearray(bytes_data[offset:offset + length])
- return length
-
- def position(self, pattern, start):
- return -1
-
- def truncate(self, length):
- self._data = self._data[:length]
- self._length = length
-
- def free(self):
- self._data = bytearray()
- self._length = 0
-
- def getBinaryStream(self, pos=None, length=None):
- import io
- return io.BytesIO(bytes(self._data))
-
-
-class Clob(Stub):
- """java.sql.Clob"""
- def __init__(self, data=""):
- super().__init__()
- self._data = data
- self._length = len(data)
-
- def length(self):
- return self._length
-
- def getSubString(self, pos, length):
- start = pos - 1
- return self._data[start:start + length]
-
- def setString(self, pos, val, offset=0, length=None):
- start = pos - 1
- if length is None:
- length = len(val) - offset
- self._data = self._data[:start] + val[offset:offset + length] + self._data[start + length:]
- return length
-
- def position(self, search_str, start):
- return self._data.find(search_str, start - 1)
-
- def truncate(self, length):
- self._data = self._data[:length]
- self._length = length
-
- def free(self):
- self._data = ""
- self._length = 0
-
- def getAsciiStream(self):
- import io
- return io.BytesIO(self._data.encode())
-
- def getCharacterStream(self, pos=None, length=None):
- import io
- if pos is not None and length is not None:
- return io.StringIO(self._data[pos - 1:pos - 1 + length])
- return io.StringIO(self._data)
-
- def setAsciiStream(self, pos, stream, length=None):
- data = stream.read() if length is None else stream.read(length)
- if isinstance(data, bytes):
- data = data.decode()
- self._data = self._data[:pos - 1] + data + self._data[pos - 1 + len(data):]
-
-
-class NClob(Clob):
- """java.sql.NClob"""
- pass
-
-
-class Ref(Stub):
- """java.sql.Ref"""
- def __init__(self, base_type_name=None, obj=None):
- super().__init__()
- self._base_type_name = base_type_name
- self._object = obj
-
- def getBaseTypeName(self):
- return self._base_type_name
-
- def getObject(self, type_map=None):
- return self._object
-
- def setObject(self, obj):
- self._object = obj
-
-
-class RowId(Stub):
- """java.sql.RowId"""
- def __init__(self, data=b""):
- super().__init__()
- self._data = bytes(data)
-
- def getBytes(self):
- return self._data
-
- def toString(self):
- return self._data.hex()
-
- def equals(self, other):
- if not isinstance(other, RowId):
- return False
- return self._data == other._data
-
- def hashCode(self):
- return hash(self._data)
-
-
-class Struct(Stub):
- """java.sql.Struct"""
- def __init__(self, sql_type_name, attributes):
- super().__init__()
- self._sql_type_name = sql_type_name
- self._attributes = list(attributes)
-
- def getSQLTypeName(self):
- return self._sql_type_name
-
- def getAttributes(self, type_map=None):
- return self._attributes
-
-
-class SQLXML(Stub):
- """java.sql.SQLXML"""
- def __init__(self, xml_string=""):
- super().__init__()
- self._xml = xml_string
-
- def getString(self):
- return self._xml
-
- def setString(self, value):
- self._xml = value
-
- def free(self):
- self._xml = ""
-
- def getBinaryStream(self):
- import io
- return io.BytesIO(self._xml.encode())
-
- def setBinaryStream(self):
- import io
- buf = io.BytesIO()
- return buf
-
- def getCharacterStream(self):
- import io
- return io.StringIO(self._xml)
-
- def setCharacterStream(self):
- import io
- buf = io.StringIO()
- return buf
-
- def getSource(self, source_class=None):
- return None
-
- def getResult(self, result_class=None):
- return None
-
-
-class Array(Stub):
- """java.sql.Array"""
- def __init__(self, type_name=None, elements=None):
- super().__init__()
- self._type_name = type_name
- self._elements = list(elements) if elements else []
-
- def getBaseTypeName(self):
- return self._type_name or "VARCHAR"
-
- def getBaseType(self):
- return Types.VARCHAR
-
- def getArray(self, index=None, count=None):
- if index is None:
- return self._elements
- start = index - 1
- if count is None:
- return self._elements[start:]
- return self._elements[start:start + count]
-
- def getResultSet(self, index=None, count=None):
- raise SQLException("Not implemented")
-
-
-# ============================================================
-# SQLData / SQLInput / SQLOutput
-# ============================================================
-
-class SQLData(Stub):
- """java.sql.SQLData"""
- def getSQLTypeName(self):
- raise SQLException("Not implemented")
-
- def readSQL(self, stream, type_name):
- pass
-
- def writeSQL(self, stream):
- pass
-
-
-class SQLInput(Stub):
- """java.sql.SQLInput"""
- def __init__(self, data=None):
- super().__init__()
- self._data = list(data) if data else []
- self._pos = 0
-
- def readString(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- return str(val) if val is not None else None
-
- def readBoolean(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- return bool(val)
-
- def readByte(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- return int(val) if val is not None else 0
-
- def readShort(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- return int(val) if val is not None else 0
-
- def readInt(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- return int(val) if val is not None else 0
-
- def readLong(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- return int(val) if val is not None else 0
-
- def readFloat(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- return float(val) if val is not None else 0.0
-
- def readDouble(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- return float(val) if val is not None else 0.0
-
- def readBigDecimal(self):
- return self.readDouble()
-
- def readBytes(self):
- return b""
-
- def readDate(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- if isinstance(val, Date):
- return val
- return Date()
-
- def readTime(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- if isinstance(val, Time):
- return val
- return Time()
-
- def readTimestamp(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- if isinstance(val, Timestamp):
- return val
- return Timestamp()
-
- def readCharacterStream(self):
- import io
- return io.StringIO("")
-
- def readBinaryStream(self):
- import io
- return io.BytesIO(b"")
-
- def readObject(self):
- val = self._data[self._pos] if self._pos < len(self._data) else None
- self._pos += 1
- return val
-
- def readRef(self):
- return Ref()
-
- def readBlob(self):
- return Blob()
-
- def readClob(self):
- return Clob()
-
- def readArray(self):
- return Array()
-
- def readURL(self):
- return None
-
- def readNClob(self):
- return NClob()
-
- def readNString(self):
- return self.readString()
-
- def readSQLXML(self):
- return SQLXML()
-
- def readRowId(self):
- return RowId()
-
- def wasNull(self):
- return False
-
-
-class SQLOutput(Stub):
- """java.sql.SQLOutput"""
- def __init__(self):
- super().__init__()
- self._data = []
-
- def writeString(self, x):
- self._data.append(x)
-
- def writeBoolean(self, x):
- self._data.append(x)
-
- def writeByte(self, x):
- self._data.append(x)
-
- def writeShort(self, x):
- self._data.append(x)
-
- def writeInt(self, x):
- self._data.append(x)
-
- def writeLong(self, x):
- self._data.append(x)
-
- def writeFloat(self, x):
- self._data.append(x)
-
- def writeDouble(self, x):
- self._data.append(x)
-
- def writeBigDecimal(self, x):
- self._data.append(x)
-
- def writeBytes(self, x):
- self._data.append(x)
-
- def writeDate(self, x):
- self._data.append(x)
-
- def writeTime(self, x):
- self._data.append(x)
-
- def writeTimestamp(self, x):
- self._data.append(x)
-
- def writeCharacterStream(self, x):
- self._data.append(x.read() if hasattr(x, 'read') else x)
-
- def writeBinaryStream(self, x):
- self._data.append(x.read() if hasattr(x, 'read') else x)
-
- def writeObject(self, x):
- self._data.append(x)
-
- def writeRef(self, x):
- self._data.append(x)
-
- def writeBlob(self, x):
- self._data.append(x)
-
- def writeClob(self, x):
- self._data.append(x)
-
- def writeStruct(self, x):
- self._data.append(x)
-
- def writeArray(self, x):
- self._data.append(x)
-
- def writeURL(self, x):
- self._data.append(x)
-
- def writeNClob(self, x):
- self._data.append(x)
-
- def writeNString(self, x):
- self._data.append(x)
-
- def writeSQLXML(self, x):
- self._data.append(x)
-
- def writeRowId(self, x):
- self._data.append(x)
-
-
-# ============================================================
-# Driver / DriverManager / DriverPropertyInfo
-# ============================================================
-
-class Driver(Stub):
- """java.sql.Driver"""
- def connect(self, url, info):
- raise SQLException("No suitable driver")
-
- def acceptsURL(self, url):
- return False
-
- def getPropertyInfo(self, url, info):
- return []
-
- def getMajorVersion(self):
- return 1
-
- def getMinorVersion(self):
- return 0
-
- def jdbcCompliant(self):
- return False
-
- def getParentLogger(self):
- return None
-
-
-class DriverPropertyInfo(Stub):
- """java.sql.DriverPropertyInfo"""
- def __init__(self, name, value=None):
- super().__init__()
- self.name = name
- self.description = None
- self.required = False
- self.value = value
- self.choices = None
-
-
-class DriverManager(Stub):
- """java.sql.DriverManager"""
- _registered_drivers = []
- _log_stream = None
- _log_writer = None
- _login_timeout = 0
-
- @staticmethod
- def getConnection(url, user=None, password=None):
- for driver in DriverManager._registered_drivers:
- if driver.acceptsURL(url):
- props = {}
- if user is not None:
- props["user"] = user
- if password is not None:
- props["password"] = password
- return driver.connect(url, props)
- raise SQLException(f"No suitable driver found for {url}")
-
- @staticmethod
- def registerDriver(driver):
- DriverManager._registered_drivers.append(driver)
-
- @staticmethod
- def deregisterDriver(driver):
- if driver in DriverManager._registered_drivers:
- DriverManager._registered_drivers.remove(driver)
-
- @staticmethod
- def getDrivers():
- return DriverManager._registered_drivers
-
- @staticmethod
- def getLoginTimeout():
- return DriverManager._login_timeout
-
- @staticmethod
- def setLoginTimeout(seconds):
- DriverManager._login_timeout = seconds
-
- @staticmethod
- def getLogWriter():
- return DriverManager._log_writer
-
- @staticmethod
- def setLogWriter(writer):
- DriverManager._log_writer = writer
-
- @staticmethod
- def println(message):
- if DriverManager._log_writer is not None:
- DriverManager._log_writer.write(str(message) + "\n")
-
-
-# ============================================================
-# Connection
-# ============================================================
-
-class Connection(Stub):
- """java.sql.Connection"""
- def createStatement(self):
- return Statement()
-
- def prepareStatement(self, sql):
- return PreparedStatement(sql)
-
- def prepareCall(self, sql):
- return CallableStatement(sql)
-
- def nativeSQL(self, sql):
- return sql
-
- def setAutoCommit(self, auto_commit):
- pass
-
- def getAutoCommit(self):
- return True
-
- def commit(self):
- pass
-
- def rollback(self, savepoint=None):
- pass
-
- def close(self):
- pass
-
- def isClosed(self):
- return False
-
- def getMetaData(self):
- return DatabaseMetaData()
-
- def setReadOnly(self, read_only):
- pass
-
- def isReadOnly(self):
- return False
-
- def setCatalog(self, catalog):
- pass
-
- def getCatalog(self):
- return ""
-
- def setTransactionIsolation(self, level):
- pass
-
- def getTransactionIsolation(self):
- return Connection.TRANSACTION_READ_COMMITTED
-
- def getWarnings(self):
- return None
-
- def clearWarnings(self):
- pass
-
- def setSavepoint(self, name=None):
- return Savepoint(name)
-
- def releaseSavepoint(self, savepoint):
- pass
-
- def createStatement(self, result_set_type, result_set_concurrency):
- return Statement()
-
- def prepareStatement(self, sql, *args):
- return PreparedStatement(sql)
-
- def prepareCall(self, sql, result_set_type, result_set_concurrency):
- return CallableStatement(sql)
-
- def setTypeMap(self, type_map):
- pass
-
- def getTypeMap(self):
- return {}
-
- def setHoldability(self, holdability):
- pass
-
- def getHoldability(self):
- return HOLD_CURSORS_OVER_COMMIT
-
- def setSchema(self, schema):
- pass
-
- def getSchema(self):
- return ""
-
- def abort(self, executor):
- pass
-
- def getNetworkTimeout(self):
- return 0
-
- def setNetworkTimeout(self, executor, milliseconds):
- pass
-
- def createArrayOf(self, type_name, elements):
- return Array(type_name, elements)
-
- def createBlob(self):
- return Blob()
-
- def createClob(self):
- return Clob()
-
- def createNClob(self):
- return NClob()
-
- def createSQLXML(self):
- return SQLXML()
-
- def createStruct(self, type_name, attributes):
- return Struct(type_name, attributes)
-
- def isValid(self, timeout):
- return not self.isClosed()
-
- # Transaction isolation constants
- TRANSACTION_NONE = 0
- TRANSACTION_READ_COMMITTED = 2
- TRANSACTION_READ_UNCOMMITTED = 1
- TRANSACTION_REPEATABLE_READ = 4
- TRANSACTION_SERIALIZABLE = 8
-
-
-# ============================================================
-# Statement
-# ============================================================
-
-class Statement(Stub):
- """java.sql.Statement"""
- def __init__(self):
- super().__init__()
- self._max_rows = 0
- self._query_timeout = 0
- self._fetch_direction = FETCH_FORWARD
- self._fetch_size = 0
- self._max_field_size = 0
- self._poolable = True
- self._close_on_completion = False
- self._result_set_type = TYPE_FORWARD_ONLY
- self._result_set_concurrency = 0
- self._result_set_holdability = HOLD_CURSORS_OVER_COMMIT
- self._generated_keys = None
- self._update_count = -1
- self._result_set = None
- self._more_results = False
- self._closed = False
- self._warnings = None
- self._poolable = True
-
- def executeQuery(self, sql):
- return ResultSet()
-
- def executeUpdate(self, sql):
- return 0
-
- def close(self):
- self._closed = True
-
- def getMaxFieldSize(self):
- return self._max_field_size
-
- def setMaxFieldSize(self, max_size):
- self._max_field_size = max_size
-
- def getMaxRows(self):
- return self._max_rows
-
- def setMaxRows(self, max_rows):
- self._max_rows = max_rows
-
- def setEscapeProcessing(self, enable):
- pass
-
- def getQueryTimeout(self):
- return self._query_timeout
-
- def setQueryTimeout(self, seconds):
- self._query_timeout = seconds
-
- def cancel(self):
- pass
-
- def getWarnings(self):
- return self._warnings
-
- def clearWarnings(self):
- self._warnings = None
-
- def setCursorName(self, name):
- pass
-
- def execute(self, sql):
- return False
-
- def getResultSet(self):
- return self._result_set
-
- def getUpdateCount(self):
- return self._update_count
-
- def getMoreResults(self, current=None):
- return False
-
- def setFetchDirection(self, direction):
- self._fetch_direction = direction
-
- def getFetchDirection(self):
- return self._fetch_direction
-
- def setFetchSize(self, rows):
- self._fetch_size = rows
-
- def getFetchSize(self):
- return self._fetch_size
-
- def getResultSetConcurrency(self):
- return self._result_set_concurrency
-
- def getResultSetType(self):
- return self._result_set_type
-
- def addBatch(self, sql):
- pass
-
- def clearBatch(self):
- pass
-
- def executeBatch(self):
- return []
-
- def getConnection(self):
- return Connection()
-
- def getMoreResults(self, current):
- return False
-
- def getGeneratedKeys(self):
- return self._generated_keys or ResultSet()
-
- def getResultSetHoldability(self):
- return self._result_set_holdability
-
- def isClosed(self):
- return self._closed
-
- def setPoolable(self, poolable):
- self._poolable = poolable
-
- def isPoolable(self):
- return self._poolable
-
- def closeOnCompletion(self):
- self._close_on_completion = True
-
- def isCloseOnCompletion(self):
- return self._close_on_completion
-
- def executeLargeUpdate(self, sql):
- return 0
-
- def getLargeUpdateCount(self):
- return self._update_count
-
- def getLargeMaxRows(self):
- return self._max_rows
-
- def setLargeMaxRows(self, max_rows):
- self._max_rows = max_rows
-
- def executeLargeBatch(self):
- return []
-
- def unwrap(self, iface):
- return self
-
- def isWrapperFor(self, iface):
- return isinstance(self, iface)
-
- SUCCESS_NO_INFO = -2
- EXECUTE_FAILED = -3
- RETURN_GENERATED_KEYS = 1
- NO_GENERATED_KEYS = 2
- CLOSE_ALL_RESULTS = 3
- KEEP_CURRENT_RESULT = 2
- CLOSE_CURRENT_RESULT = 1
- NO_GENERATED_KEYS = 2
- RETURN_GENERATED_KEYS = 1
-
-
-# ============================================================
-# PreparedStatement
-# ============================================================
-
-class PreparedStatement(Statement):
- """java.sql.PreparedStatement"""
- def __init__(self, sql=""):
- super().__init__()
- self._sql = sql
- self._parameters = []
-
- def setNull(self, parameter_index, sql_type, type_name=None):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = None
-
- def setBoolean(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setByte(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setShort(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setInt(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setLong(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setFloat(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setDouble(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setBigDecimal(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setString(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setBytes(self, parameter_index, x):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = bytes(x) if x else None
-
- def setDate(self, parameter_index, x, calendar=None):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setTime(self, parameter_index, x, calendar=None):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setTimestamp(self, parameter_index, x, calendar=None):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setAsciiStream(self, parameter_index, stream, length=None):
- self._ensure_params(parameter_index)
- data = stream.read() if hasattr(stream, 'read') else stream
- if isinstance(data, bytes):
- data = data.decode()
- self._parameters[parameter_index - 1] = data
-
- def setBinaryStream(self, parameter_index, stream, length=None):
- self._ensure_params(parameter_index)
- data = stream.read() if hasattr(stream, 'read') else stream
- self._parameters[parameter_index - 1] = data
-
- def setObject(self, parameter_index, x, target_sql_type=None, scale_or_length=None):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = x
-
- def setCharacterStream(self, parameter_index, reader, length=None):
- self._ensure_params(parameter_index)
- data = reader.read() if hasattr(reader, 'read') else reader
- self._parameters[parameter_index - 1] = data
-
- def setBlob(self, parameter_index, blob):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = blob
-
- def setClob(self, parameter_index, clob):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = clob
-
- def setArray(self, parameter_index, array):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = array
-
- def setRef(self, parameter_index, ref):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = ref
-
- def setNString(self, parameter_index, value):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = value
-
- def setNClob(self, parameter_index, nclob):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = nclob
-
- def setNCharacterStream(self, parameter_index, reader, length=None):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = reader
-
- def setRowId(self, parameter_index, row_id):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = row_id
-
- def setSQLXML(self, parameter_index, xml):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = xml
-
- def setURL(self, parameter_index, url):
- self._ensure_params(parameter_index)
- self._parameters[parameter_index - 1] = url
-
- def clearParameters(self):
- self._parameters = []
-
- def executeQuery(self):
- return ResultSet()
-
- def executeUpdate(self):
- return 0
-
- def execute(self):
- return False
-
- def addBatch(self):
- pass
-
- def getParameterMetaData(self):
- return ResultSetMetaData()
-
- def getMetaData(self):
- return ResultSetMetaData()
-
- def _ensure_params(self, idx):
- while len(self._parameters) < idx:
- self._parameters.append(None)
-
-
-# ============================================================
-# CallableStatement
-# ============================================================
-
-class CallableStatement(PreparedStatement):
- """java.sql.CallableStatement"""
- def __init__(self, sql=""):
- super().__init__(sql)
- self._output_params = {}
-
- def registerOutParameter(self, parameter_index, sql_type, scale_or_type_name=None):
- pass
-
- def wasNull(self):
- return False
-
- def getString(self, parameter_index):
- return self._output_params.get(parameter_index)
-
- def getBoolean(self, parameter_index):
- return bool(self._output_params.get(parameter_index))
-
- def getByte(self, parameter_index):
- return self._output_params.get(parameter_index, 0)
-
- def getShort(self, parameter_index):
- return self._output_params.get(parameter_index, 0)
-
- def getInt(self, parameter_index):
- return self._output_params.get(parameter_index, 0)
-
- def getLong(self, parameter_index):
- return self._output_params.get(parameter_index, 0)
-
- def getFloat(self, parameter_index):
- return float(self._output_params.get(parameter_index, 0.0))
-
- def getDouble(self, parameter_index):
- return float(self._output_params.get(parameter_index, 0.0))
-
- def getBigDecimal(self, parameter_index):
- return self._output_params.get(parameter_index)
-
- def getBytes(self, parameter_index):
- return b""
-
- def getDate(self, parameter_index):
- return Date()
-
- def getTime(self, parameter_index):
- return Time()
-
- def getTimestamp(self, parameter_index):
- return Timestamp()
-
- def getObject(self, parameter_index, type_map=None):
- return self._output_params.get(parameter_index)
-
- def getRef(self, parameter_index):
- return Ref()
-
- def getBlob(self, parameter_index):
- return Blob()
-
- def getClob(self, parameter_index):
- return Clob()
-
- def getArray(self, parameter_index):
- return Array()
-
- def getURL(self, parameter_index):
- return None
-
- def getNClob(self, parameter_index):
- return NClob()
-
- def getNString(self, parameter_index):
- return self.getString(parameter_index)
-
- def getNCharacterStream(self, parameter_index):
- import io
- return io.StringIO("")
-
- def getRowId(self, parameter_index):
- return RowId()
-
- def getSQLXML(self, parameter_index):
- return SQLXML()
-
-
-# ============================================================
-# ResultSet
-# ============================================================
-
-class ResultSet(Stub):
- """java.sql.ResultSet"""
- def __init__(self):
- super().__init__()
- self._rows = []
- self._row_index = -1
- self._closed = False
- self._warnings = None
- self._fetch_direction = FETCH_FORWARD
- self._fetch_size = 0
- self._type = TYPE_FORWARD_ONLY
- self._concurrency = 0
- self._holdability = HOLD_CURSORS_OVER_COMMIT
- self._meta_data = ResultSetMetaData()
-
- def next(self):
- if self._row_index + 1 < len(self._rows):
- self._row_index += 1
- return True
- return False
-
- def close(self):
- self._closed = True
-
- def wasNull(self):
- return False
-
- def getString(self, column_index_or_label):
- return str(self._get_value(column_index_or_label) or "")
-
- def getBoolean(self, column_index_or_label):
- return bool(self._get_value(column_index_or_label))
-
- def getByte(self, column_index_or_label):
- return int(self._get_value(column_index_or_label) or 0)
-
- def getShort(self, column_index_or_label):
- return int(self._get_value(column_index_or_label) or 0)
-
- def getInt(self, column_index_or_label):
- return int(self._get_value(column_index_or_label) or 0)
-
- def getLong(self, column_index_or_label):
- return int(self._get_value(column_index_or_label) or 0)
-
- def getFloat(self, column_index_or_label):
- return float(self._get_value(column_index_or_label) or 0.0)
-
- def getDouble(self, column_index_or_label):
- return float(self._get_value(column_index_or_label) or 0.0)
-
- def getBytes(self, column_index_or_label):
- val = self._get_value(column_index_or_label)
- if isinstance(val, bytes):
- return val
- if isinstance(val, str):
- return val.encode()
- return b""
-
- def getDate(self, column_index_or_label):
- val = self._get_value(column_index_or_label)
- if isinstance(val, Date):
- return val
- return Date()
-
- def getTime(self, column_index_or_label):
- val = self._get_value(column_index_or_label)
- if isinstance(val, Time):
- return val
- return Time()
-
- def getTimestamp(self, column_index_or_label):
- val = self._get_value(column_index_or_label)
- if isinstance(val, Timestamp):
- return val
- return Timestamp()
-
- def getObject(self, column_index_or_label, type_map=None):
- return self._get_value(column_index_or_label)
-
- def findColumn(self, column_label):
- return 1
-
- def getMetaData(self):
- return self._meta_data
-
- def getWarnings(self):
- return self._warnings
-
- def clearWarnings(self):
- self._warnings = None
-
- def setFetchDirection(self, direction):
- self._fetch_direction = direction
-
- def getFetchDirection(self):
- return self._fetch_direction
-
- def setFetchSize(self, rows):
- self._fetch_size = rows
-
- def getFetchSize(self):
- return self._fetch_size
-
- def getType(self):
- return self._type
-
- def getConcurrency(self):
- return self._concurrency
-
- def rowUpdated(self):
- return False
-
- def rowInserted(self):
- return False
-
- def rowDeleted(self):
- return False
-
- def updateNull(self, column_index_or_label):
- pass
-
- def updateBoolean(self, column_index_or_label, x):
- pass
-
- def updateByte(self, column_index_or_label, x):
- pass
-
- def updateShort(self, column_index_or_label, x):
- pass
-
- def updateInt(self, column_index_or_label, x):
- pass
-
- def updateLong(self, column_index_or_label, x):
- pass
-
- def updateFloat(self, column_index_or_label, x):
- pass
-
- def updateDouble(self, column_index_or_label, x):
- pass
-
- def updateString(self, column_index_or_label, x):
- pass
-
- def updateBytes(self, column_index_or_label, x):
- pass
-
- def updateDate(self, column_index_or_label, x):
- pass
-
- def updateTime(self, column_index_or_label, x):
- pass
-
- def updateTimestamp(self, column_index_or_label, x):
- pass
-
- def updateRow(self):
- pass
-
- def insertRow(self):
- pass
-
- def deleteRow(self):
- pass
-
- def refreshRow(self):
- pass
-
- def cancelRowUpdates(self):
- pass
-
- def moveToInsertRow(self):
- pass
-
- def moveToCurrentRow(self):
- pass
-
- def isClosed(self):
- return self._closed
-
- def getHoldability(self):
- return self._holdability
-
- def getStatement(self):
- return None
-
- def getArray(self, column_index_or_label):
- return Array()
-
- def getBlob(self, column_index_or_label):
- return Blob()
-
- def getClob(self, column_index_or_label):
- return Clob()
-
- def getRef(self, column_index_or_label):
- return Ref()
-
- def getURL(self, column_index_or_label):
- return None
-
- def getNClob(self, column_index_or_label):
- return NClob()
-
- def getNString(self, column_index_or_label):
- return self.getString(column_index_or_label)
-
- def getNCharacterStream(self, column_index_or_label):
- import io
- return io.StringIO("")
-
- def getRowId(self, column_index_or_label):
- return RowId()
-
- def getSQLXML(self, column_index_or_label):
- return SQLXML()
-
- def getBinaryStream(self, column_index_or_label):
- import io
- return io.BytesIO(b"")
-
- def getCharacterStream(self, column_index_or_label):
- import io
- return io.StringIO("")
-
- def getAsciiStream(self, column_index_or_label):
- import io
- return io.BytesIO(b"")
-
- def updateObject(self, column_index_or_label, x, scale_or_target=None):
- pass
-
- def beforeFirst(self):
- self._row_index = -1
-
- def afterLast(self):
- self._row_index = len(self._rows)
-
- def first(self):
- if self._rows:
- self._row_index = 0
- return True
- return False
-
- def last(self):
- if self._rows:
- self._row_index = len(self._rows) - 1
- return True
- return False
-
- def absolute(self, row):
- if row == 0:
- self._row_index = -1
- return False
- idx = row - 1 if row > 0 else len(self._rows) + row
- if 0 <= idx < len(self._rows):
- self._row_index = idx
- return True
- return False
-
- def relative(self, rows):
- new_idx = self._row_index + rows
- if 0 <= new_idx < len(self._rows):
- self._row_index = new_idx
- return True
- return False
-
- def previous(self):
- if self._row_index > 0:
- self._row_index -= 1
- return True
- return False
-
- def isBeforeFirst(self):
- return self._row_index < 0 and len(self._rows) > 0
-
- def isAfterLast(self):
- return self._row_index >= len(self._rows) and len(self._rows) > 0
-
- def isFirst(self):
- return self._row_index == 0
-
- def isLast(self):
- return self._row_index == len(self._rows) - 1
-
- def getRow(self):
- return self._row_index + 1 if 0 <= self._row_index < len(self._rows) else 0
-
- def _get_value(self, col):
- if 0 <= self._row_index < len(self._rows):
- row = self._rows[self._row_index]
- if isinstance(col, int) and col - 1 < len(row):
- return row[col - 1]
- return None
-
- # Constants
- FETCH_FORWARD = 1000
- FETCH_REVERSE = 1001
- FETCH_UNKNOWN = 1002
- TYPE_FORWARD_ONLY = 1003
- TYPE_SCROLL_INSENSITIVE = 1004
- TYPE_SCROLL_SENSITIVE = 1005
- CONCUR_READ_ONLY = 1007
- CONCUR_UPDATABLE = 1008
- HOLD_CURSORS_OVER_COMMIT = 1
- CLOSE_CURSORS_AT_COMMIT = 2
-
-
-# ============================================================
-# ResultSetMetaData
-# ============================================================
-
-class ResultSetMetaData(Stub):
- """java.sql.ResultSetMetaData"""
- def __init__(self):
- super().__init__()
- self._column_count = 0
- self._column_names = []
- self._column_types = []
-
- def getColumnCount(self):
- return self._column_count
-
- def isAutoIncrement(self, column):
- return False
-
- def isCaseSensitive(self, column):
- return True
-
- def isSearchable(self, column):
- return True
-
- def isCurrency(self, column):
- return False
-
- def isNullable(self, column):
- return ResultSetMetaData.columnNullable
-
- def isSigned(self, column):
- return True
-
- def getColumnDisplaySize(self, column):
- return 255
-
- def getColumnLabel(self, column):
- return self.getColumnName(column)
-
- def getColumnName(self, column):
- if column - 1 < len(self._column_names):
- return self._column_names[column - 1]
- return f"COLUMN_{column}"
-
- def getSchemaName(self, column):
- return ""
-
- def getPrecision(self, column):
- return 0
-
- def getScale(self, column):
- return 0
-
- def getTableName(self, column):
- return ""
-
- def getCatalogName(self, column):
- return ""
-
- def getColumnType(self, column):
- if column - 1 < len(self._column_types):
- return self._column_types[column - 1]
- return Types.VARCHAR
-
- def getColumnTypeName(self, column):
- return "VARCHAR"
-
- def isReadOnly(self, column):
- return False
-
- def isWritable(self, column):
- return True
-
- def isDefinitelyWritable(self, column):
- return True
-
- def getColumnClassName(self, column):
- return "java.lang.String"
-
- columnNoNulls = 0
- columnNullable = 1
- columnNullableUnknown = 2
-
-
-# ============================================================
-# DatabaseMetaData
-# ============================================================
-
-class DatabaseMetaData(Stub):
- """java.sql.DatabaseMetaData"""
- def getDatabaseProductName(self):
- return "Android-pyApi SQL"
-
- def getDatabaseProductVersion(self):
- return "1.0"
-
- def getDriverName(self):
- return "Android-pyApi JDBC Driver"
-
- def getDriverVersion(self):
- return "1.0"
-
- def getDriverMajorVersion(self):
- return 1
-
- def getDriverMinorVersion(self):
- return 0
-
- def getURL(self):
- return ""
-
- def getUserName(self):
- return ""
-
- def isReadOnly(self):
- return False
-
- def nullsAreSortedHigh(self):
- return True
-
- def nullsAreSortedLow(self):
- return False
-
- def nullsAreSortedAtStart(self):
- return False
-
- def nullsAreSortedAtEnd(self):
- return False
-
- def getDatabaseMajorVersion(self):
- return 1
-
- def getDatabaseMinorVersion(self):
- return 0
-
- def getJDBCMajorVersion(self):
- return 4
-
- def getJDBCMinorVersion(self):
- return 2
-
- def getDefaultTransactionIsolation(self):
- return Connection.TRANSACTION_READ_COMMITTED
-
- def supportsTransactions(self):
- return True
-
- def supportsTransactionIsolationLevel(self, level):
- return True
-
- def supportsResultSetType(self, type_):
- return True
-
- def supportsResultSetConcurrency(self, type_, concurrency):
- return True
-
- def getTables(self, catalog, schema_pattern, table_name_pattern, types):
- return ResultSet()
-
- def getColumns(self, catalog, schema_pattern, table_name_pattern, column_name_pattern):
- return ResultSet()
-
- def getPrimaryKeys(self, catalog, schema, table):
- return ResultSet()
-
- def getImportedKeys(self, catalog, schema, table):
- return ResultSet()
-
- def getExportedKeys(self, catalog, schema, table):
- return ResultSet()
-
- def getSchemas(self):
- return ResultSet()
-
- def getCatalogs(self):
- return ResultSet()
-
- def getTableTypes(self):
- return ResultSet()
-
- def getTypeInfo(self):
- return ResultSet()
-
- def getIndexInfo(self, catalog, schema, table, unique, approximate):
- return ResultSet()
-
- def getProcedures(self, catalog, schema_pattern, procedure_name_pattern):
- return ResultSet()
-
- def getProcedureColumns(self, catalog, schema_pattern, procedure_name_pattern, column_name_pattern):
- return ResultSet()
-
- def supportsSavepoints(self):
- return True
-
- def supportsBatchUpdates(self):
- return True
-
- def supportsStoredProcedures(self):
- return True
-
- def allProceduresAreCallable(self):
- return True
-
- def allTablesAreSelectable(self):
- return True
-
- def dataDefinitionCausesTransactionCommit(self):
- return False
-
- def dataDefinitionIgnoredInTransactions(self):
- return False
-
- def doesMaxRowSizeIncludeBlobs(self):
- return False
-
- def getMaxBinaryLiteralLength(self):
- return 0
-
- def getMaxCharLiteralLength(self):
- return 0
-
- def getMaxColumnNameLength(self):
- return 128
-
- def getMaxColumnsInGroupBy(self):
- return 0
-
- def getMaxColumnsInIndex(self):
- return 0
-
- def getMaxColumnsInOrderBy(self):
- return 0
-
- def getMaxColumnsInSelect(self):
- return 0
-
- def getMaxColumnsInTable(self):
- return 0
-
- def getMaxConnections(self):
- return 0
-
- def getMaxCursorNameLength(self):
- return 0
-
- def getMaxIndexLength(self):
- return 0
-
- def getMaxSchemaNameLength(self):
- return 0
-
- def getMaxProcedureNameLength(self):
- return 0
-
- def getMaxRowSize(self):
- return 0
-
- def getMaxStatementLength(self):
- return 0
-
- def getMaxStatements(self):
- return 0
-
- def getMaxTableNameLength(self):
- return 0
-
- def getMaxTablesInSelect(self):
- return 0
-
- def getMaxUserNameLength(self):
- return 0
-
- def getNumericFunctions(self):
- return ""
-
- def getSQLKeywords(self):
- return ""
-
- def getStringFunctions(self):
- return ""
-
- def getSystemFunctions(self):
- return ""
-
- def getTimeDateFunctions(self):
- return ""
-
- def getSearchStringEscape(self):
- return "\\"
-
- def getExtraNameCharacters(self):
- return ""
-
- def getSchemaTerm(self):
- return "schema"
-
- def getCatalogTerm(self):
- return "catalog"
-
- def getProcedureTerm(self):
- return "procedure"
-
- def getCatalogSeparator(self):
- return "."
-
- def isCatalogAtStart(self):
- return True
-
- def autoCommitFailureClosesAllResultSets(self):
- return False
-
- def generatedKeyAlwaysReturned(self):
- return True
-
- def getSQLStateType(self):
- return DatabaseMetaData.sqlStateSQL
-
- def locatorsUpdateCopy(self):
- return False
-
- def supportsDifferentTableCorrelationNames(self):
- return True
-
- def supportsANSI92EntryLevelSQL(self):
- return True
-
- def supportsANSI92IntermediateSQL(self):
- return True
-
- def supportsANSI92FullSQL(self):
- return False
-
- def supportsIntegrityEnhancementFacility(self):
- return False
-
- def supportsOuterJoins(self):
- return True
-
- def supportsFullOuterJoins(self):
- return True
-
- def supportsLimitedOuterJoins(self):
- return True
-
- def supportsSchemasInDataManipulation(self):
- return True
-
- def supportsSchemasInProcedureCalls(self):
- return True
-
- def supportsSchemasInTableDefinitions(self):
- return True
-
- def supportsSchemasInIndexDefinitions(self):
- return True
-
- def supportsSchemasInPrivilegeDefinitions(self):
- return True
-
- def supportsCatalogsInDataManipulation(self):
- return True
-
- def supportsCatalogsInProcedureCalls(self):
- return True
-
- def supportsCatalogsInTableDefinitions(self):
- return True
-
- def supportsCatalogsInIndexDefinitions(self):
- return True
-
- def supportsCatalogsInPrivilegeDefinitions(self):
- return True
-
- def supportsPositionedDelete(self):
- return False
-
- def supportsPositionedUpdate(self):
- return False
-
- def supportsSelectForUpdate(self):
- return True
-
- def supportsSubqueriesInComparisons(self):
- return True
-
- def supportsSubqueriesInExists(self):
- return True
-
- def supportsSubqueriesInIns(self):
- return True
-
- def supportsSubqueriesInQuantifieds(self):
- return True
-
- def supportsCorrelatedSubqueries(self):
- return True
-
- def supportsUnion(self):
- return True
-
- def supportsUnionAll(self):
- return True
-
- def supportsOpenCursorsAcrossCommit(self):
- return True
-
- def supportsOpenCursorsAcrossRollback(self):
- return True
-
- def supportsOpenStatementsAcrossCommit(self):
- return True
-
- def supportsOpenStatementsAcrossRollback(self):
- return True
-
- def supportsMixedCaseIdentifiers(self):
- return True
-
- def storesMixedCaseIdentifiers(self):
- return True
-
- def supportsMixedCaseQuotedIdentifiers(self):
- return True
-
- def storesMixedCaseQuotedIdentifiers(self):
- return True
-
- def supportsAlterTableWithAddColumn(self):
- return True
-
- def supportsAlterTableWithDropColumn(self):
- return True
-
- def supportsColumnAliasing(self):
- return True
-
- def supportsConvert(self):
- return True
-
- def supportsTableCorrelationNames(self):
- return True
-
- def getConnection(self):
- return Connection()
-
- # Constants
- attributeNoNulls = 0
- attributeNullable = 1
- attributeNullableUnknown = 2
- bestRowTemporary = 0
- bestRowTransaction = 1
- bestRowSession = 2
- bestRowUnknown = 0
- bestRowNotPseudo = 1
- bestRowPseudo = 2
- columnNoNulls = 0
- columnNullable = 1
- columnNullableUnknown = 2
- functionColumnIn = 1
- functionColumnInOut = 2
- functionColumnOut = 3
- functionColumnReturn = 4
- functionColumnResult = 5
- functionNoNulls = 0
- functionNullable = 1
- functionNullableUnknown = 2
- functionResultUnknown = 0
- functionNoTable = 1
- functionReturnsTable = 2
- importedKeyCascade = 0
- importedKeyRestrict = 1
- importedKeySetNull = 2
- importedKeyNoAction = 3
- importedKeySetDefault = 4
- importedKeyInitiallyDeferred = 5
- importedKeyInitiallyImmediate = 6
- importedKeyNotDeferrable = 7
- procedureColumnIn = 1
- procedureColumnInOut = 2
- procedureColumnOut = 4
- procedureColumnReturn = 5
- procedureColumnResult = 3
- procedureNoNulls = 0
- procedureNullable = 1
- procedureNullableUnknown = 2
- procedureResultUnknown = 0
- sqlStateSQL = 2
- sqlStateXOpen = 1
- tableIndexStatistic = 0
- tableIndexClustered = 1
- tableIndexHashed = 2
- tableIndexOther = 3
- versionColumnUnknown = 0
- versionColumnNotPseudo = 1
- versionColumnPseudo = 2
-
-
-# ============================================================
-# IllegalArgumentException
-# ============================================================
-
-class IllegalArgumentException(RuntimeException):
- """java.lang.IllegalArgumentException"""
- pass
\ No newline at end of file
diff --git a/android_pyapi/java/text.py b/android_pyapi/java/text.py
deleted file mode 100644
index 3e36ffa..0000000
--- a/android_pyapi/java/text.py
+++ /dev/null
@@ -1,1041 +0,0 @@
-"""
-Java text standard library APIs implemented in Python.
-java.text package - DateFormat, SimpleDateFormat, DecimalFormat, NumberFormat, etc.
-"""
-
-from .._core import Stub
-from .lang import RuntimeException
-import datetime as _datetime
-import time as _time
-import re as _re
-import math as _py_math
-import locale as _locale
-from decimal import Decimal as _Decimal
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "SimpleDateFormat", "DateFormat", "DateFormatSymbols",
- "DecimalFormat", "DecimalFormatSymbols", "NumberFormat",
- "ChoiceFormat", "MessageFormat", "FieldPosition", "ParsePosition",
- "ParseException", "Normalizer",
- "StringCharacterIterator", "CharacterIterator",
- "BreakIterator", "Collator", "CollationKey", "RuleBasedCollator",
- "Annotation", "AttributedCharacterIterator", "AttributedString",
- "Bidi", "Format",
-]
-
-
-# ============================================================
-# ParseException
-# ============================================================
-
-class ParseException(Exception):
- def __init__(self, s, error_offset):
- super().__init__(s)
- self._error_offset = error_offset
-
- def getErrorOffset(self):
- return self._error_offset
-
-
-# ============================================================
-# ParsePosition
-# ============================================================
-
-class ParsePosition(Stub):
- def __init__(self, index):
- super().__init__()
- self._index = index
- self._error_index = -1
-
- def getIndex(self):
- return self._index
-
- def setIndex(self, index):
- self._index = index
-
- def getErrorIndex(self):
- return self._error_index
-
- def setErrorIndex(self, ei):
- self._error_index = ei
-
-
-# ============================================================
-# FieldPosition
-# ============================================================
-
-class FieldPosition(Stub):
- def __init__(self, field):
- super().__init__()
- self._field = field
- self._begin = 0
- self._end = 0
-
- def getField(self):
- return self._field
-
- def getBeginIndex(self):
- return self._begin
-
- def getEndIndex(self):
- return self._end
-
- def setBeginIndex(self, bi):
- self._begin = bi
-
- def setEndIndex(self, ei):
- self._end = ei
-
-
-# ============================================================
-# Format (base)
-# ============================================================
-
-class Format(Stub):
- def format(self, obj, to_append_to=None, pos=None):
- raise NotImplementedError
-
- def parseObject(self, source, pos=None):
- raise NotImplementedError
-
-
-# ============================================================
-# DateFormat
-# ============================================================
-
-class DateFormat(Format):
- SHORT = 3
- MEDIUM = 2
- LONG = 1
- FULL = 0
- DEFAULT = 2
-
- def __init__(self):
- super().__init__()
- self._calendar = None
- self._number_format = None
- self._lenient = False
- self._timezone = None
-
- @staticmethod
- def getDateInstance(style=2, locale=None):
- return SimpleDateFormat("yyyy-MM-dd")
-
- @staticmethod
- def getTimeInstance(style=2, locale=None):
- return SimpleDateFormat("HH:mm:ss")
-
- @staticmethod
- def getDateTimeInstance(date_style=2, time_style=2, locale=None):
- return SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
-
- @staticmethod
- def getInstance():
- return SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
-
- def format(self, date, to_append_to=None, pos=None):
- raise NotImplementedError
-
- def parse(self, source, pos=None):
- raise NotImplementedError
-
- def setLenient(self, lenient):
- self._lenient = lenient
-
- def isLenient(self):
- return self._lenient
-
- def getCalendar(self):
- return self._calendar
-
- def setCalendar(self, cal):
- self._calendar = cal
-
- def getNumberFormat(self):
- return self._number_format
-
- def setNumberFormat(self, nf):
- self._number_format = nf
-
- def getTimeZone(self):
- return self._timezone
-
- def setTimeZone(self, tz):
- self._timezone = tz
-
-
-# ============================================================
-# DateFormatSymbols
-# ============================================================
-
-class DateFormatSymbols(Stub):
- def __init__(self, locale=None):
- super().__init__()
- self._months = [
- "January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December",
- ]
- self._short_months = [
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
- ]
- self._weekdays = [
- "", "Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday",
- ]
- self._short_weekdays = [
- "", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
- ]
- self._ampm = ["AM", "PM"]
- self._eras = ["BC", "AD"]
- self._zone_strings = []
- self._local_pattern_chars = "GyMdkHmsSEDFwWahKzZ"
-
- def getMonths(self):
- return self._months
-
- def setMonths(self, months):
- self._months = months
-
- def getShortMonths(self):
- return self._short_months
-
- def setShortMonths(self, months):
- self._short_months = months
-
- def getWeekdays(self):
- return self._weekdays
-
- def setWeekdays(self, wd):
- self._weekdays = wd
-
- def getShortWeekdays(self):
- return self._short_weekdays
-
- def setShortWeekdays(self, wd):
- self._short_weekdays = wd
-
- def getAmPmStrings(self):
- return self._ampm
-
- def setAmPmStrings(self, ap):
- self._ampm = ap
-
- def getZoneStrings(self):
- return self._zone_strings
-
- def setZoneStrings(self, zs):
- self._zone_strings = zs
-
- def getLocalPatternChars(self):
- return self._local_pattern_chars
-
- def setLocalPatternChars(self, chars):
- self._local_pattern_chars = chars
-
- def getEras(self):
- return self._eras
-
- def setEras(self, eras):
- self._eras = eras
-
-
-# ============================================================
-# SimpleDateFormat
-# ============================================================
-
-_JAVA_TO_PYTHON_FORMAT = {
- "yyyy": "%Y", "yy": "%y",
- "MM": "%m",
- "dd": "%d",
- "HH": "%H",
- "mm": "%M",
- "ss": "%S",
- "SSS": "%f",
- "a": "%p",
- "EEE": "%a", "EEEE": "%A",
- "D": "%j",
- "zzz": "%Z", "z": "%Z",
- "Z": "%z",
-}
-
-class SimpleDateFormat(DateFormat):
- def __init__(self, pattern, locale=None):
- super().__init__()
- self._pattern = pattern
- self._locale = locale
- self._dfs = DateFormatSymbols(locale)
- self._lenient = False
-
- def applyPattern(self, pattern):
- self._pattern = pattern
-
- def toPattern(self):
- return self._pattern
-
- def toLocalizedPattern(self):
- return self._pattern
-
- def applyLocalizedPattern(self, pattern):
- self._pattern = pattern
-
- def _java_to_py(self, pattern):
- py_pattern = pattern
- sorted_keys = sorted(_JAVA_TO_PYTHON_FORMAT.keys(), key=lambda x: -len(x))
- for java_fmt in sorted_keys:
- py_fmt = _JAVA_TO_PYTHON_FORMAT[java_fmt]
- py_pattern = py_pattern.replace(java_fmt, py_fmt)
- py_pattern = py_pattern.replace("'", "")
- return py_pattern
-
- def _to_datetime(self, date):
- if isinstance(date, _datetime.datetime):
- return date
- if isinstance(date, _datetime.date):
- return _datetime.datetime.combine(date, _datetime.time())
- try:
- ts = date.getTime() / 1000.0
- return _datetime.datetime.fromtimestamp(ts)
- except AttributeError:
- return _datetime.datetime.now()
-
- def format(self, date, to_append_to=None, pos=None):
- py_pattern = self._java_to_py(self._pattern)
- dt = self._to_datetime(date)
- result = dt.strftime(py_pattern)
- if to_append_to is not None:
- sb = str(to_append_to)
- idx = len(sb)
- to_append_to.append(result)
- if pos is not None:
- pos.setBeginIndex(idx)
- pos.setEndIndex(idx + len(result))
- return to_append_to
- return result
-
- def parse(self, source, pos=None):
- py_pattern = self._java_to_py(self._pattern)
- try:
- dt = _datetime.datetime.strptime(source, py_pattern)
- if pos is not None:
- pos.setIndex(len(source))
- return dt
- except ValueError:
- if pos is not None:
- pos.setErrorIndex(0)
- raise ParseException(f"Unparseable date: {source}", 0)
-
- def setLenient(self, lenient):
- self._lenient = lenient
-
- def isLenient(self):
- return self._lenient
-
- def setTimeZone(self, tz):
- self._timezone = tz
-
- def getTimeZone(self):
- return self._timezone
-
- def setCalendar(self, cal):
- self._calendar = cal
-
- def getCalendar(self):
- return self._calendar
-
- def setNumberFormat(self, nf):
- self._number_format = nf
-
- def getNumberFormat(self):
- return self._number_format
-
- def getDateFormatSymbols(self):
- return self._dfs
-
- def setDateFormatSymbols(self, dfs):
- self._dfs = dfs
-
-
-# ============================================================
-# DecimalFormatSymbols
-# ============================================================
-
-class DecimalFormatSymbols(Stub):
- def __init__(self, locale=None):
- super().__init__()
- self._decimal_sep = "."
- self._grouping_sep = ","
- self._pattern_sep = ";"
- self._minus_sign = "-"
- self._infinity = "\u221e"
- self._nan = "NaN"
- self._percent = "%"
- self._per_mill = "\u2030"
- self._zero_digit = "0"
- self._digit = "#"
- self._exponential_sep = "E"
- self._monetary_decimal_sep = "."
- self._intl_currency_symbol = "USD"
- self._currency = "USD"
-
- def getDecimalSeparator(self): return self._decimal_sep
- def setDecimalSeparator(self, c): self._decimal_sep = c
- def getGroupingSeparator(self): return self._grouping_sep
- def setGroupingSeparator(self, c): self._grouping_sep = c
- def getPatternSeparator(self): return self._pattern_sep
- def setPatternSeparator(self, c): self._pattern_sep = c
- def getMinusSign(self): return self._minus_sign
- def setMinusSign(self, c): self._minus_sign = c
- def getInfinity(self): return self._infinity
- def setInfinity(self, s): self._infinity = s
- def getNaN(self): return self._nan
- def setNaN(self, s): self._nan = s
- def getPercent(self): return self._percent
- def setPercent(self, c): self._percent = c
- def getPerMill(self): return self._per_mill
- def setPerMill(self, c): self._per_mill = c
- def getZeroDigit(self): return self._zero_digit
- def setZeroDigit(self, c): self._zero_digit = c
- def getDigit(self): return self._digit
- def setDigit(self, c): self._digit = c
- def getExponentialSeparator(self): return self._exponential_sep
- def setExponentialSeparator(self, s): self._exponential_sep = s
- def getMonetaryDecimalSeparator(self): return self._monetary_decimal_sep
- def setMonetaryDecimalSeparator(self, c): self._monetary_decimal_sep = c
- def getInternationalCurrencySymbol(self): return self._intl_currency_symbol
- def setInternationalCurrencySymbol(self, s): self._intl_currency_symbol = s
- def getCurrency(self): return self._currency
- def setCurrency(self, c): self._currency = c
-
-
-# ============================================================
-# DecimalFormat
-# ============================================================
-
-class NumberFormat(Format):
- def __init__(self):
- super().__init__()
- self._grouping_used = True
- self._max_int_digits = 2000000000
- self._min_int_digits = 1
- self._max_frac_digits = 3
- self._min_frac_digits = 0
- self._parse_integer_only = False
- self._rounding_mode = 4
-
- @staticmethod
- def getInstance(locale=None):
- return DecimalFormat("#,##0.###")
-
- @staticmethod
- def getNumberInstance(locale=None):
- return DecimalFormat("#,##0.###")
-
- @staticmethod
- def getCurrencyInstance(locale=None):
- return DecimalFormat("#,##0.00")
-
- @staticmethod
- def getPercentInstance(locale=None):
- return DecimalFormat("#,##0%")
-
- @staticmethod
- def getIntegerInstance(locale=None):
- nf = DecimalFormat("#,##0")
- nf.setMaximumFractionDigits(0)
- return nf
-
- @staticmethod
- def getCompactNumberInstance(locale=None, style=None):
- return DecimalFormat("#,##0")
-
- def format(self, number, to_append_to=None, pos=None):
- raise NotImplementedError
-
- def parse(self, source, pos=None):
- raise NotImplementedError
-
- def isGroupingUsed(self): return self._grouping_used
- def setGroupingUsed(self, v): self._grouping_used = v
- def getMaximumIntegerDigits(self): return self._max_int_digits
- def setMaximumIntegerDigits(self, v): self._max_int_digits = v
- def getMinimumIntegerDigits(self): return self._min_int_digits
- def setMinimumIntegerDigits(self, v): self._min_int_digits = v
- def getMaximumFractionDigits(self): return self._max_frac_digits
- def setMaximumFractionDigits(self, v): self._max_frac_digits = v
- def getMinimumFractionDigits(self): return self._min_frac_digits
- def setMinimumFractionDigits(self, v): self._min_frac_digits = v
- def setParseIntegerOnly(self, v): self._parse_integer_only = v
- def isParseIntegerOnly(self): return self._parse_integer_only
- def setRoundingMode(self, v): self._rounding_mode = v
- def getRoundingMode(self): return self._rounding_mode
- def getCurrency(self): return "USD"
- def setCurrency(self, c): pass
-
- @staticmethod
- def getAvailableLocales():
- return list(_locale.locale_alias.keys())
-
-
-# ============================================================
-# ChoiceFormat
-# ============================================================
-
-class ChoiceFormat(NumberFormat):
- def __init__(self, formats=None, limits=None):
- super().__init__()
- self._formats = formats if formats is not None else []
- self._limits = limits if limits is not None else []
-
- def format(self, number, to_append_to=None, pos=None):
- val = float(number)
- idx = 0
- for i, lim in enumerate(self._limits):
- if val >= lim:
- idx = i
- result = str(self._formats[idx]) if idx < len(self._formats) else ""
- if to_append_to is not None:
- sb = str(to_append_to)
- idx2 = len(sb)
- to_append_to.append(result)
- if pos is not None:
- pos.setBeginIndex(idx2)
- pos.setEndIndex(idx2 + len(result))
- return to_append_to
- return result
-
- def parse(self, source, pos=None):
- raise NotImplementedError
-
- @staticmethod
- def nextDouble(d, upwards=True):
- if upwards:
- return d + _py_math.ulp(d)
- return d - _py_math.ulp(d)
-
- @staticmethod
- def previousDouble(d):
- return ChoiceFormat.nextDouble(d, False)
-
- def getLimits(self):
- return self._limits
-
- def getFormats(self):
- return self._formats
-
-
-# ============================================================
-# MessageFormat
-# ============================================================
-# NumberFormat
-# ============================================================
-
-# ============================================================
-# DecimalFormat
-# ============================================================
-
-class DecimalFormat(NumberFormat):
- def __init__(self, pattern=None, symbols=None):
- super().__init__()
- self._pattern = pattern or "#,##0.###"
- self._symbols = symbols or DecimalFormatSymbols()
- self._decimal_sep_always = False
- self._grouping_size = 3
- self._grouping_used = True
- self._max_int_digits = 2000000000
- self._min_int_digits = 1
- self._max_frac_digits = 2000000000
- self._min_frac_digits = 0
- self._neg_prefix = "-"
- self._neg_suffix = ""
- self._pos_prefix = ""
- self._pos_suffix = ""
- self._multiplier = 1
- self._rounding_mode = 4
- self._parse_bigdecimal = False
-
- def applyPattern(self, pattern):
- self._pattern = pattern
-
- def toPattern(self):
- return self._pattern
-
- def toLocalizedPattern(self):
- return self._pattern
-
- def applyLocalizedPattern(self, pattern):
- self._pattern = pattern
-
- def format(self, number, to_append_to=None, pos=None):
- if isinstance(number, (int, float)):
- val = number * self._multiplier
- elif isinstance(number, _Decimal):
- val = float(str(number)) * self._multiplier
- else:
- val = float(str(number)) * self._multiplier
- if self._grouping_used and self._grouping_size > 0:
- result = f"{val:,.{self._max_frac_digits}f}"
- else:
- fmt = "{{:.{}f}}".format(self._max_frac_digits)
- result = fmt.format(val)
- prefix = self._pos_prefix if val >= 0 else self._neg_prefix
- suffix = self._pos_suffix if val >= 0 else self._neg_suffix
- result = prefix + result + suffix
- if to_append_to is not None:
- sb = str(to_append_to)
- idx = len(sb)
- to_append_to.append(result)
- if pos is not None:
- pos.setBeginIndex(idx)
- pos.setEndIndex(idx + len(result))
- return to_append_to
- return result
-
- def parse(self, source, pos=None):
- text = source.strip()
- try:
- val = float(text)
- if pos is not None:
- pos.setIndex(len(source))
- if self._parse_bigdecimal:
- return _Decimal(str(val))
- return val
- except ValueError:
- if pos is not None:
- pos.setErrorIndex(0)
- raise Exception(f"Unparseable: {source}")
-
- def setDecimalSeparatorAlwaysShown(self, v): self._decimal_sep_always = v
- def getDecimalSeparatorAlwaysShown(self): return self._decimal_sep_always
- def setGroupingSize(self, v): self._grouping_size = v
- def getGroupingSize(self): return self._grouping_size
- def setGroupingUsed(self, v): self._grouping_used = v
- def isGroupingUsed(self): return self._grouping_used
- def setMaximumIntegerDigits(self, v): self._max_int_digits = v
- def getMaximumIntegerDigits(self): return self._max_int_digits
- def setMinimumIntegerDigits(self, v): self._min_int_digits = v
- def getMinimumIntegerDigits(self): return self._min_int_digits
- def setMaximumFractionDigits(self, v): self._max_frac_digits = v
- def getMaximumFractionDigits(self): return self._max_frac_digits
- def setMinimumFractionDigits(self, v): self._min_frac_digits = v
- def getMinimumFractionDigits(self): return self._min_frac_digits
- def setNegativePrefix(self, v): self._neg_prefix = v
- def getNegativePrefix(self): return self._neg_prefix
- def setNegativeSuffix(self, v): self._neg_suffix = v
- def getNegativeSuffix(self): return self._neg_suffix
- def setPositivePrefix(self, v): self._pos_prefix = v
- def getPositivePrefix(self): return self._pos_prefix
- def setPositiveSuffix(self, v): self._pos_suffix = v
- def getPositiveSuffix(self): return self._pos_suffix
- def setDecimalFormatSymbols(self, v): self._symbols = v
- def getDecimalFormatSymbols(self): return self._symbols
- def setParseBigDecimal(self, v): self._parse_bigdecimal = v
- def isParseBigDecimal(self): return self._parse_bigdecimal
- def setMultiplier(self, v): self._multiplier = v
- def getMultiplier(self): return self._multiplier
- def setRoundingMode(self, v): self._rounding_mode = v
- def getRoundingMode(self): return self._rounding_mode
-
-
-# ============================================================
-# MessageFormat
-# ============================================================
-
-_MSG_PATTERN_RE = _re.compile(r"\{(\d+)(?:,(\w+)(?:,(.+))?)?\}")
-
-class MessageFormat(Format):
- def __init__(self, pattern, locale=None):
- super().__init__()
- self._pattern = pattern
- self._locale = locale
- self._formats = {}
-
- def applyPattern(self, pattern):
- self._pattern = pattern
-
- def toPattern(self):
- return self._pattern
-
- def _format_impl(self, objects):
- def replacer(m):
- idx = int(m.group(1))
- if idx < len(objects):
- return str(objects[idx])
- return m.group(0)
- return _MSG_PATTERN_RE.sub(replacer, self._pattern)
-
- def format(self, objects, to_append_to=None, pos=None):
- result = self._format_impl(objects)
- if to_append_to is not None:
- sb = str(to_append_to)
- idx = len(sb)
- to_append_to.append(result)
- if pos is not None:
- pos.setBeginIndex(idx)
- pos.setEndIndex(idx + len(result))
- return to_append_to
- return result
-
- @staticmethod
- def format_static(pattern, *args):
- mf = MessageFormat(pattern)
- return mf.format(args)
-
- def parse(self, source, pos=None):
- parts = _MSG_PATTERN_RE.split(self._pattern)
- result = []
- idx = 0
- for i, part in enumerate(parts):
- if i % 2 == 0:
- if not source[idx:].startswith(part):
- if pos is not None:
- pos.setErrorIndex(idx)
- return result
- idx += len(part)
- else:
- arg_idx = int(part)
- remaining = source[idx:]
- next_part = parts[i + 1] if i + 1 < len(parts) else ""
- end = remaining.find(next_part) if next_part else len(remaining)
- if end < 0:
- end = len(remaining)
- result.append(remaining[:end])
- idx += end
- if pos is not None:
- pos.setIndex(idx)
- return result
-
- def setLocale(self, locale):
- self._locale = locale
-
- def getLocale(self):
- return self._locale
-
- def setFormats(self, formats):
- self._formats = formats
-
- def getFormats(self):
- return self._formats
-
- def setFormat(self, idx, fmt):
- self._formats[idx] = fmt
-
- def getFormat(self, idx):
- return self._formats.get(idx)
-
-
-# ============================================================
-# CharacterIterator
-# ============================================================
-
-class CharacterIterator(Stub):
- DONE = chr(0xFFFF)
-
- def first(self):
- raise NotImplementedError
-
- def last(self):
- raise NotImplementedError
-
- def current(self):
- raise NotImplementedError
-
- def next(self):
- raise NotImplementedError
-
- def previous(self):
- raise NotImplementedError
-
- def setIndex(self, position):
- raise NotImplementedError
-
- def getBeginIndex(self):
- raise NotImplementedError
-
- def getEndIndex(self):
- raise NotImplementedError
-
- def getIndex(self):
- raise NotImplementedError
-
- def clone(self):
- raise NotImplementedError
-
-
-# ============================================================
-# StringCharacterIterator
-# ============================================================
-
-class StringCharacterIterator(CharacterIterator):
- def __init__(self, text):
- super().__init__()
- self._text = text
- self._begin = 0
- self._end = len(text)
- self._pos = 0
-
- def first(self):
- self._pos = self._begin
- return self.current()
-
- def last(self):
- self._pos = self._end - 1 if self._end > self._begin else self._begin
- return self.current()
-
- def current(self):
- if self._pos >= self._begin and self._pos < self._end:
- return self._text[self._pos]
- return CharacterIterator.DONE
-
- def next(self):
- self._pos += 1
- if self._pos >= self._end:
- self._pos = self._end
- return CharacterIterator.DONE
- return self._text[self._pos]
-
- def previous(self):
- self._pos -= 1
- if self._pos < self._begin:
- self._pos = self._begin
- return CharacterIterator.DONE
- return self._text[self._pos]
-
- def setIndex(self, pos):
- self._pos = max(self._begin, min(pos, self._end))
- return self.current()
-
- def getBeginIndex(self):
- return self._begin
-
- def getEndIndex(self):
- return self._end
-
- def getIndex(self):
- return self._pos
-
- def clone(self):
- return StringCharacterIterator(self._text)
-
-
-# ============================================================
-# BreakIterator
-# ============================================================
-
-class BreakIterator(Stub):
- DONE = -1
-
- @staticmethod
- def getWordInstance(locale=None):
- return BreakIterator()
-
- @staticmethod
- def getLineInstance(locale=None):
- return BreakIterator()
-
- @staticmethod
- def getCharacterInstance(locale=None):
- return BreakIterator()
-
- @staticmethod
- def getSentenceInstance(locale=None):
- return BreakIterator()
-
- def setText(self, text):
- self._text = text
-
- def first(self):
- return 0
-
- def last(self):
- return len(self._text) if hasattr(self, "_text") else 0
-
- def next(self, n=1):
- return BreakIterator.DONE
-
- def previous(self):
- return BreakIterator.DONE
-
- def current(self):
- return 0
-
- def following(self, offset):
- return BreakIterator.DONE
-
- def preceding(self, offset):
- return BreakIterator.DONE
-
- def isBoundary(self, offset):
- return True
-
-
-# ============================================================
-# Collator / CollationKey / RuleBasedCollator
-# ============================================================
-
-class CollationKey(Stub):
- def __init__(self, source, key):
- super().__init__()
- self._source = source
- self._key = key
-
- def compareTo(self, other):
- if isinstance(other, CollationKey):
- return (self._key > other._key) - (self._key < other._key)
- return -1
-
- def getSourceString(self):
- return self._source
-
- def toByteArray(self):
- return self._key.encode("utf-8")
-
-
-class Collator(Stub):
- PRIMARY = 0
- SECONDARY = 1
- TERTIARY = 2
- IDENTICAL = 3
- NO_DECOMPOSITION = 0
- CANONICAL_DECOMPOSITION = 1
- FULL_DECOMPOSITION = 2
-
- @staticmethod
- def getInstance(locale=None):
- return RuleBasedCollator()
-
- def compare(self, source, target):
- return (source > target) - (source < target)
-
- def getCollationKey(self, source):
- return CollationKey(source, source)
-
- def setStrength(self, strength):
- self._strength = strength
-
- def getStrength(self):
- return getattr(self, "_strength", Collator.TERTIARY)
-
- def setDecomposition(self, decomposition):
- self._decomposition = decomposition
-
- def getDecomposition(self):
- return getattr(self, "_decomposition", Collator.NO_DECOMPOSITION)
-
-
-class RuleBasedCollator(Collator):
- def __init__(self, rules=None):
- super().__init__()
- self._rules = rules or ""
-
-
-# ============================================================
-# Normalizer
-# ============================================================
-
-class Normalizer(Stub):
- class Form(Stub):
- NFC = "NFC"
- NFD = "NFD"
- NFKC = "NFKC"
- NFKD = "NFKD"
-
- @staticmethod
- def normalize(src, form):
- import unicodedata
- form_map = {
- Normalizer.Form.NFC: "NFC",
- Normalizer.Form.NFD: "NFD",
- Normalizer.Form.NFKC: "NFKC",
- Normalizer.Form.NFKD: "NFKD",
- }
- return unicodedata.normalize(form_map.get(form, "NFC"), src)
-
- @staticmethod
- def isNormalized(src, form):
- return Normalizer.normalize(src, form) == src
-
-
-# ============================================================
-# Annotation / AttributedCharacterIterator / AttributedString
-# ============================================================
-
-class Annotation(Stub):
- def __init__(self, value):
- super().__init__()
- self._value = value
-
- def getValue(self):
- return self._value
-
- def toString(self):
- return str(self._value)
-
-
-class AttributedCharacterIterator(CharacterIterator):
- pass
-
-
-class AttributedString(Stub):
- def __init__(self, text, attributes=None):
- super().__init__()
- self._text = text
-
- def getIterator(self):
- return StringCharacterIterator(self._text)
-
-
-# ============================================================
-# Bidi
-# ============================================================
-
-class Bidi(Stub):
- DIRECTION_LEFT_TO_RIGHT = 0
- DIRECTION_RIGHT_TO_LEFT = 1
- DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2
- DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1
-
- def __init__(self, text, flags=0):
- super().__init__()
- self._text = text
- self._base_level = 0 if flags >= 0 else 1
-
- def isLeftToRight(self):
- return self._base_level == 0
-
- def isRightToLeft(self):
- return self._base_level == 1
-
- def getLength(self):
- return len(self._text)
-
- def getLevelAt(self, offset):
- return self._base_level
-
- def getRunCount(self):
- return 1
-
- def getRunLevel(self, run):
- return self._base_level
-
- def getRunLimit(self, run):
- return len(self._text)
-
- def getRunStart(self, run):
- return 0
-
- def requiresBidi(self, text):
- for ch in text:
- if ord(ch) > 0x590:
- return True
- return False
-
- @staticmethod
- def reorderVisually(levels, objects, index, count):
- pass
-
- @staticmethod
- def baseIsLeftToRight():
- return True
\ No newline at end of file
diff --git a/android_pyapi/java/time.py b/android_pyapi/java/time.py
deleted file mode 100644
index c68f1cc..0000000
--- a/android_pyapi/java/time.py
+++ /dev/null
@@ -1,1619 +0,0 @@
-"""
-Java time standard library APIs implemented in Python.
-java.time package - LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, etc.
-"""
-
-from .._core import Stub
-from .lang import RuntimeException, Comparable
-import datetime as _dt
-import re as _re
-import math as _py_math
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-__all__ = [
- "LocalDate", "LocalTime", "LocalDateTime",
- "ZonedDateTime", "OffsetDateTime", "OffsetTime",
- "Instant", "Duration", "Period",
- "ZoneId", "ZoneOffset", "ZoneRules",
- "DayOfWeek", "Month", "Year", "YearMonth", "MonthDay",
- "Clock",
- "DateTimeFormatter", "DateTimeFormatterBuilder",
- "TemporalAdjusters",
- "Temporal", "TemporalAccessor", "TemporalUnit",
- "ChronoUnit", "ChronoField",
-]
-
-
-# ============================================================
-# TemporalAccessor / Temporal / TemporalUnit (base interfaces)
-# ============================================================
-
-class TemporalAccessor(Stub):
- def get(self, field):
- raise NotImplementedError
-
- def getLong(self, field):
- raise NotImplementedError
-
- def isSupported(self, field):
- raise NotImplementedError
-
- def range(self, field):
- raise NotImplementedError
-
-
-class Temporal(TemporalAccessor):
- def plus(self, amount, unit=None):
- raise NotImplementedError
-
- def minus(self, amount, unit=None):
- raise NotImplementedError
-
- def with_(self, field, new_value):
- raise NotImplementedError
-
- def until(self, end_exclusive, unit):
- raise NotImplementedError
-
-
-class TemporalUnit(Stub):
- def getDuration(self):
- raise NotImplementedError
-
- def isDurationEstimated(self):
- raise NotImplementedError
-
- def isDateBased(self):
- raise NotImplementedError
-
- def isTimeBased(self):
- raise NotImplementedError
-
- def between(self, temporal1, temporal2):
- raise NotImplementedError
-
-
-# ============================================================
-# ChronoField
-# ============================================================
-
-class ChronoField(Stub):
- NANO_OF_SECOND = "NanoOfSecond"
- NANO_OF_DAY = "NanoOfDay"
- MICRO_OF_SECOND = "MicroOfSecond"
- MICRO_OF_DAY = "MicroOfDay"
- MILLI_OF_SECOND = "MilliOfSecond"
- MILLI_OF_DAY = "MilliOfDay"
- SECOND_OF_MINUTE = "SecondOfMinute"
- SECOND_OF_DAY = "SecondOfDay"
- MINUTE_OF_HOUR = "MinuteOfHour"
- MINUTE_OF_DAY = "MinuteOfDay"
- HOUR_OF_AMPM = "HourOfAmPm"
- CLOCK_HOUR_OF_AMPM = "ClockHourOfAmPm"
- HOUR_OF_DAY = "HourOfDay"
- CLOCK_HOUR_OF_DAY = "ClockHourOfDay"
- AMPM_OF_DAY = "AmPmOfDay"
- DAY_OF_WEEK = "DayOfWeek"
- ALIGNED_DAY_OF_WEEK_IN_MONTH = "AlignedDayOfWeekInMonth"
- ALIGNED_DAY_OF_WEEK_IN_YEAR = "AlignedDayOfWeekInYear"
- DAY_OF_MONTH = "DayOfMonth"
- DAY_OF_YEAR = "DayOfYear"
- EPOCH_DAY = "EpochDay"
- ALIGNED_WEEK_OF_MONTH = "AlignedWeekOfMonth"
- ALIGNED_WEEK_OF_YEAR = "AlignedWeekOfYear"
- MONTH_OF_YEAR = "MonthOfYear"
- PROLEPTIC_MONTH = "ProlepticMonth"
- YEAR_OF_ERA = "YearOfEra"
- YEAR = "Year"
- ERA = "Era"
- INSTANT_SECONDS = "InstantSeconds"
- OFFSET_SECONDS = "OffsetSeconds"
-
- def __init__(self, name):
- super().__init__()
- self._name = name
-
- def toString(self):
- return self._name
-
- def getDisplayName(self, locale=None):
- return self._name
-
-
-# ============================================================
-# ChronoUnit
-# ============================================================
-
-class ChronoUnit(Stub):
- NANOS = None
- MICROS = None
- MILLIS = None
- SECONDS = None
- MINUTES = None
- HOURS = None
- HALF_DAYS = None
- DAYS = None
- WEEKS = None
- MONTHS = None
- YEARS = None
- DECADES = None
- CENTURIES = None
- MILLENNIA = None
- ERAS = None
- FOREVER = None
-
- def __init__(self, name, duration, estimated=False):
- self._name = name
- self._duration = duration
- self._estimated = estimated
-
- def toString(self):
- return self._name
-
- def getDuration(self):
- return self._duration
-
- def isDurationEstimated(self):
- return self._estimated
-
- def isDateBased(self):
- return self in (ChronoUnit.WEEKS, ChronoUnit.MONTHS, ChronoUnit.YEARS,
- ChronoUnit.DECADES, ChronoUnit.CENTURIES,
- ChronoUnit.MILLENNIA, ChronoUnit.ERAS)
-
- def isTimeBased(self):
- return self in (ChronoUnit.NANOS, ChronoUnit.MICROS, ChronoUnit.MILLIS,
- ChronoUnit.SECONDS, ChronoUnit.MINUTES, ChronoUnit.HOURS,
- ChronoUnit.HALF_DAYS)
-
- def between(self, temporal1, temporal2):
- return temporal1.until(temporal2, self)
-
- @staticmethod
- def from_(temporal):
- if isinstance(temporal, ChronoUnit):
- return temporal
- raise Exception(f"Cannot convert to ChronoUnit: {temporal}")
-
-
-# ChronoUnit 常量在 Duration 定义之后初始化(见下方)
-
-
-# ============================================================
-# DayOfWeek
-# ============================================================
-
-class DayOfWeek(Stub):
- MONDAY = None
- TUESDAY = None
- WEDNESDAY = None
- THURSDAY = None
- FRIDAY = None
- SATURDAY = None
- SUNDAY = None
-
- def __init__(self, value, name):
- self._value = value
- self._name = name
-
- def getValue(self):
- return self._value
-
- def getDisplayName(self, style, locale=None):
- return self._name
-
- def plus(self, days):
- idx = ((self._value - 1 + days) % 7) + 1
- return DayOfWeek._from_value(idx)
-
- def minus(self, days):
- return self.plus(-days)
-
- @staticmethod
- def _from_value(v):
- mapping = {1: DayOfWeek.MONDAY, 2: DayOfWeek.TUESDAY, 3: DayOfWeek.WEDNESDAY,
- 4: DayOfWeek.THURSDAY, 5: DayOfWeek.FRIDAY, 6: DayOfWeek.SATURDAY,
- 7: DayOfWeek.SUNDAY}
- return mapping.get(v)
-
- def toString(self):
- return self._name
-
- def compareTo(self, other):
- if isinstance(other, DayOfWeek):
- return self._value - other._value
- return -1
-
-
-DayOfWeek.MONDAY = DayOfWeek(1, "MONDAY")
-DayOfWeek.TUESDAY = DayOfWeek(2, "TUESDAY")
-DayOfWeek.WEDNESDAY = DayOfWeek(3, "WEDNESDAY")
-DayOfWeek.THURSDAY = DayOfWeek(4, "THURSDAY")
-DayOfWeek.FRIDAY = DayOfWeek(5, "FRIDAY")
-DayOfWeek.SATURDAY = DayOfWeek(6, "SATURDAY")
-DayOfWeek.SUNDAY = DayOfWeek(7, "SUNDAY")
-
-
-# ============================================================
-# Month
-# ============================================================
-
-class Month(Stub):
- JANUARY = None
- FEBRUARY = None
- MARCH = None
- APRIL = None
- MAY = None
- JUNE = None
- JULY = None
- AUGUST = None
- SEPTEMBER = None
- OCTOBER = None
- NOVEMBER = None
- DECEMBER = None
-
- def __init__(self, value, name):
- self._value = value
- self._name = name
-
- def getValue(self):
- return self._value
-
- def getDisplayName(self, style, locale=None):
- return self._name
-
- def plus(self, months):
- idx = ((self._value - 1 + months) % 12) + 1
- return Month._from_value(idx)
-
- def minus(self, months):
- return self.plus(-months)
-
- def length(self, leap_year=False):
- if self._value == 2:
- return 29 if leap_year else 28
- if self._value in (4, 6, 9, 11):
- return 30
- return 31
-
- def minLength(self):
- return 29 if self._value == 2 else (30 if self._value in (4, 6, 9, 11) else 31)
-
- def maxLength(self):
- return 29 if self._value == 2 else (30 if self._value in (4, 6, 9, 11) else 31)
-
- def firstDayOfYear(self, leap_year=False):
- days = 0
- for m in range(1, self._value):
- days += Month._from_value(m).length(leap_year)
- return days + 1
-
- def firstMonthOfQuarter(self):
- q = (self._value - 1) // 3
- return Month._from_value(q * 3 + 1)
-
- @staticmethod
- def _from_value(v):
- values = [None, Month.JANUARY, Month.FEBRUARY, Month.MARCH, Month.APRIL,
- Month.MAY, Month.JUNE, Month.JULY, Month.AUGUST,
- Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER, Month.DECEMBER]
- return values[v] if 0 < v <= 12 else None
-
- def toString(self):
- return self._name
-
- def compareTo(self, other):
- if isinstance(other, Month):
- return self._value - other._value
- return -1
-
-
-Month.JANUARY = Month(1, "JANUARY")
-Month.FEBRUARY = Month(2, "FEBRUARY")
-Month.MARCH = Month(3, "MARCH")
-Month.APRIL = Month(4, "APRIL")
-Month.MAY = Month(5, "MAY")
-Month.JUNE = Month(6, "JUNE")
-Month.JULY = Month(7, "JULY")
-Month.AUGUST = Month(8, "AUGUST")
-Month.SEPTEMBER = Month(9, "SEPTEMBER")
-Month.OCTOBER = Month(10, "OCTOBER")
-Month.NOVEMBER = Month(11, "NOVEMBER")
-Month.DECEMBER = Month(12, "DECEMBER")
-
-
-# ============================================================
-# ZoneId / ZoneOffset / ZoneRules
-# ============================================================
-
-class ZoneId(Stub):
- SHORT_IDS = {
- "ACT": "Australia/Darwin",
- "AET": "Australia/Sydney",
- "AGT": "America/Argentina/Buenos_Aires",
- "ART": "Africa/Cairo",
- "AST": "America/Anchorage",
- "BET": "America/Sao_Paulo",
- "BST": "Asia/Dhaka",
- "CAT": "Africa/Harare",
- "CNT": "America/St_Johns",
- "CST": "America/Chicago",
- "CTT": "Asia/Shanghai",
- "EAT": "Africa/Addis_Ababa",
- "ECT": "Europe/Paris",
- "EST": "America/New_York",
- "HST": "Pacific/Honolulu",
- "IET": "America/Indianapolis",
- "IST": "Asia/Kolkata",
- "JST": "Asia/Tokyo",
- "MIT": "Pacific/Apia",
- "MST": "America/Denver",
- "NET": "Asia/Yerevan",
- "NST": "Pacific/Auckland",
- "PLT": "Asia/Karachi",
- "PNT": "America/Phoenix",
- "PRT": "America/Puerto_Rico",
- "PST": "America/Los_Angeles",
- "SST": "Pacific/Guadalcanal",
- "VST": "Asia/Ho_Chi_Minh",
- }
-
- _cache = {}
-
- def __init__(self, zone_id):
- super().__init__()
- self._id = zone_id
-
- @staticmethod
- def systemDefault():
- import time as _t
- idx = 1 if _t.daylight else 0
- tz_name = _t.tzname[idx] if idx < len(_t.tzname) and _t.tzname[idx] else _t.tzname[0]
- return ZoneId.of(tz_name) if tz_name else ZoneId("UTC")
-
- @staticmethod
- def of(zone_id):
- if zone_id in ZoneId.SHORT_IDS:
- zone_id = ZoneId.SHORT_IDS[zone_id]
- if zone_id not in ZoneId._cache:
- ZoneId._cache[zone_id] = ZoneId(zone_id)
- return ZoneId._cache[zone_id]
-
- @staticmethod
- def getAvailableZoneIds():
- import time as _t
- return set(_t.tzname)
-
- def getDisplayName(self, style, locale=None):
- return self._id
-
- def getRules(self):
- return ZoneRules()
-
- def toString(self):
- return self._id
-
- def equals(self, other):
- if isinstance(other, ZoneId):
- return self._id == other._id
- return False
-
- def hashCode(self):
- return hash(self._id)
-
-
-class ZoneOffset(ZoneId):
- MAX = None
- MIN = None
- UTC = None
-
- _cache = {}
-
- def __init__(self, total_seconds):
- hours = total_seconds // 3600
- mins = (abs(total_seconds) % 3600) // 60
- sign = "+" if total_seconds >= 0 else "-"
- if mins == 0:
- zone_id = f"{sign}{abs(hours):02d}:00"
- else:
- zone_id = f"{sign}{abs(hours):02d}:{mins:02d}"
- super().__init__(zone_id)
- self._total_seconds = total_seconds
-
- @staticmethod
- def of(offset_id):
- if offset_id in ZoneOffset._cache:
- return ZoneOffset._cache[offset_id]
- if offset_id == "Z" or offset_id == "UTC" or offset_id == "GMT":
- z = ZoneOffset(0)
- ZoneOffset._cache[offset_id] = z
- return z
- sign = 1 if offset_id[0] == "+" else -1
- parts = offset_id[1:].split(":")
- h = int(parts[0])
- m = int(parts[1]) if len(parts) > 1 else 0
- total = sign * (h * 3600 + m * 60)
- z = ZoneOffset(total)
- ZoneOffset._cache[offset_id] = z
- return z
-
- @staticmethod
- def ofHours(hours):
- return ZoneOffset(hours * 3600)
-
- @staticmethod
- def ofHoursMinutes(hours, minutes):
- sign = 1 if hours >= 0 else -1
- return ZoneOffset(sign * (abs(hours) * 3600 + minutes * 60))
-
- @staticmethod
- def ofTotalSeconds(total_seconds):
- if total_seconds in ZoneOffset._cache:
- return ZoneOffset._cache[total_seconds]
- z = ZoneOffset(total_seconds)
- ZoneOffset._cache[total_seconds] = z
- return z
-
- def getTotalSeconds(self):
- return self._total_seconds
-
- def toString(self):
- if self._total_seconds == 0:
- return "Z"
- return super().toString()
-
- def equals(self, other):
- if isinstance(other, ZoneOffset):
- return self._total_seconds == other._total_seconds
- return False
-
- def hashCode(self):
- return self._total_seconds
-
-
-ZoneOffset.MAX = ZoneOffset(18 * 3600)
-ZoneOffset.MIN = ZoneOffset(-18 * 3600)
-ZoneOffset.UTC = ZoneOffset(0)
-
-
-class ZoneRules(Stub):
- def isFixedOffset(self):
- return True
-
- def getOffset(self, instant):
- return ZoneOffset.UTC
-
- def getDaylightSavings(self, instant):
- return Duration.ZERO
-
- def isDaylightSavings(self, instant):
- return False
-
- def isValidOffset(self, local_date_time, offset):
- return True
-
- def nextTransition(self, instant):
- return None
-
- def previousTransition(self, instant):
- return None
-
- def getTransitions(self):
- return []
-
- def getTransitionRules(self):
- return []
-
-
-# ============================================================
-# Instant
-# ============================================================
-
-class Instant(Temporal, Comparable):
- EPOCH = None
-
- def __init__(self, epoch_second, nano=0):
- super().__init__()
- self._epoch_second = int(epoch_second)
- self._nano = int(nano)
-
- @staticmethod
- def now():
- import time as _t
- t = _t.time()
- sec = int(t)
- nano = int((t - sec) * 1_000_000_000)
- return Instant(sec, nano)
-
- @staticmethod
- def ofEpochMilli(epoch_milli):
- return Instant(epoch_milli // 1000, (epoch_milli % 1000) * 1_000_000)
-
- @staticmethod
- def ofEpochSecond(epoch_second, nano_adjustment=0):
- return Instant(epoch_second + nano_adjustment // 1_000_000_000,
- nano_adjustment % 1_000_000_000)
-
- def getEpochSecond(self):
- return self._epoch_second
-
- def getNano(self):
- return self._nano
-
- def toEpochMilli(self):
- return self._epoch_second * 1000 + self._nano // 1_000_000
-
- def plus(self, seconds, nano=0):
- return Instant(self._epoch_second + seconds, self._nano + nano)
-
- def minus(self, seconds, nano=0):
- return self.plus(-seconds, -nano)
-
- def isBefore(self, other):
- if isinstance(other, Instant):
- return (self._epoch_second, self._nano) < (other._epoch_second, other._nano)
- return False
-
- def isAfter(self, other):
- if isinstance(other, Instant):
- return (self._epoch_second, self._nano) > (other._epoch_second, other._nano)
- return False
-
- def compareTo(self, other):
- if isinstance(other, Instant):
- diff = self._epoch_second - other._epoch_second
- if diff != 0:
- return -1 if diff < 0 else 1
- diff = self._nano - other._nano
- return -1 if diff < 0 else (1 if diff > 0 else 0)
- return -1
-
- def equals(self, other):
- if isinstance(other, Instant):
- return self._epoch_second == other._epoch_second and self._nano == other._nano
- return False
-
- def hashCode(self):
- return hash((self._epoch_second, self._nano))
-
- def toString(self):
- return f"Instant({self._epoch_second},{self._nano})"
-
-
-Instant.EPOCH = Instant(0, 0)
-
-
-# ============================================================
-# Duration
-# ============================================================
-
-class Duration(Temporal, Comparable):
- ZERO = None
-
- def __init__(self, seconds, nanos=0):
- super().__init__()
- self._seconds = int(seconds)
- self._nanos = int(nanos)
-
- @staticmethod
- def ofDays(days):
- return Duration(days * 86400)
-
- @staticmethod
- def ofHours(hours):
- return Duration(hours * 3600)
-
- @staticmethod
- def ofMinutes(minutes):
- return Duration(minutes * 60)
-
- @staticmethod
- def ofSeconds(seconds):
- return Duration(seconds)
-
- @staticmethod
- def ofMillis(millis):
- return Duration(millis // 1000, (millis % 1000) * 1_000_000)
-
- @staticmethod
- def ofNanos(nanos):
- return Duration(nanos // 1_000_000_000, nanos % 1_000_000_000)
-
- @staticmethod
- def between(start, end):
- if isinstance(start, Instant) and isinstance(end, Instant):
- return Duration(end.getEpochSecond() - start.getEpochSecond(),
- end.getNano() - start.getNano())
- return Duration.ZERO
-
- def getSeconds(self):
- return self._seconds
-
- def getNano(self):
- return self._nanos
-
- def toDays(self):
- return self._seconds // 86400
-
- def toHours(self):
- return self._seconds // 3600
-
- def toMinutes(self):
- return self._seconds // 60
-
- def toSeconds(self):
- return self._seconds
-
- def toMillis(self):
- return self._seconds * 1000 + self._nanos // 1_000_000
-
- def toNanos(self):
- return self._seconds * 1_000_000_000 + self._nanos
-
- def plus(self, duration):
- if isinstance(duration, Duration):
- return Duration(self._seconds + duration._seconds,
- self._nanos + duration._nanos)
- return self
-
- def minus(self, duration):
- if isinstance(duration, Duration):
- return Duration(self._seconds - duration._seconds,
- self._nanos - duration._nanos)
- return self
-
- def isNegative(self):
- return self._seconds < 0 or (self._seconds == 0 and self._nanos < 0)
-
- def isZero(self):
- return self._seconds == 0 and self._nanos == 0
-
- def compareTo(self, other):
- if isinstance(other, Duration):
- diff = self._seconds - other._seconds
- if diff != 0:
- return -1 if diff < 0 else 1
- diff = self._nanos - other._nanos
- return -1 if diff < 0 else (1 if diff > 0 else 0)
- return -1
-
- def equals(self, other):
- if isinstance(other, Duration):
- return self._seconds == other._seconds and self._nanos == other._nanos
- return False
-
- def toString(self):
- return f"PT{self._seconds}S"
-
- def hashCode(self):
- return hash((self._seconds, self._nanos))
-
-
-Duration.ZERO = Duration(0, 0)
-
-
-# === 延迟初始化 ChronoUnit 常量(必须在 Duration 定义之后) ===
-ChronoUnit.NANOS = ChronoUnit("Nanos", Duration.ofNanos(1))
-ChronoUnit.MICROS = ChronoUnit("Micros", Duration.ofNanos(1000))
-ChronoUnit.MILLIS = ChronoUnit("Millis", Duration.ofNanos(1_000_000))
-ChronoUnit.SECONDS = ChronoUnit("Seconds", Duration.ofSeconds(1))
-ChronoUnit.MINUTES = ChronoUnit("Minutes", Duration.ofMinutes(1))
-ChronoUnit.HOURS = ChronoUnit("Hours", Duration.ofHours(1))
-ChronoUnit.HALF_DAYS = ChronoUnit("HalfDays", Duration.ofHours(12))
-ChronoUnit.DAYS = ChronoUnit("Days", Duration.ofDays(1))
-ChronoUnit.WEEKS = ChronoUnit("Weeks", Duration.ofDays(7))
-ChronoUnit.MONTHS = ChronoUnit("Months", Duration.ofDays(30), estimated=True)
-ChronoUnit.YEARS = ChronoUnit("Years", Duration.ofDays(365), estimated=True)
-ChronoUnit.DECADES = ChronoUnit("Decades", Duration.ofDays(365 * 10), estimated=True)
-ChronoUnit.CENTURIES = ChronoUnit("Centuries", Duration.ofDays(365 * 100), estimated=True)
-ChronoUnit.MILLENNIA = ChronoUnit("Millennia", Duration.ofDays(365 * 1000), estimated=True)
-ChronoUnit.ERAS = ChronoUnit("Eras", Duration.ofDays(365 * 1_000_000_000), estimated=True)
-ChronoUnit.FOREVER = ChronoUnit("Forever", Duration.ofSeconds(1_000_000_000 * 86400 * 365), estimated=True)
-
-
-# ============================================================
-# Period
-# ============================================================
-
-class Period(Stub):
- ZERO = None
-
- def __init__(self, years, months, days):
- super().__init__()
- self._years = years
- self._months = months
- self._days = days
-
- @staticmethod
- def ofDays(days):
- return Period(0, 0, days)
-
- @staticmethod
- def ofWeeks(weeks):
- return Period(0, 0, weeks * 7)
-
- @staticmethod
- def ofMonths(months):
- return Period(0, months, 0)
-
- @staticmethod
- def ofYears(years):
- return Period(years, 0, 0)
-
- @staticmethod
- def between(start, end):
- if isinstance(start, LocalDate) and isinstance(end, LocalDate):
- return Period(end._year - start._year,
- end._month - start._month,
- end._day - start._day)
- return Period.ZERO
-
- def getYears(self):
- return self._years
-
- def getMonths(self):
- return self._months
-
- def getDays(self):
- return self._days
-
- def plus(self, period):
- if isinstance(period, Period):
- return Period(self._years + period._years,
- self._months + period._months,
- self._days + period._days)
- return self
-
- def minus(self, period):
- if isinstance(period, Period):
- return Period(self._years - period._years,
- self._months - period._months,
- self._days - period._days)
- return self
-
- def isZero(self):
- return self._years == 0 and self._months == 0 and self._days == 0
-
- def isNegative(self):
- return self._years < 0 or self._months < 0 or self._days < 0
-
- def equals(self, other):
- if isinstance(other, Period):
- return (self._years == other._years and
- self._months == other._months and
- self._days == other._days)
- return False
-
- def toString(self):
- return f"P{self._years}Y{self._months}M{self._days}D"
-
- def hashCode(self):
- return hash((self._years, self._months, self._days))
-
-
-Period.ZERO = Period(0, 0, 0)
-
-
-# ============================================================
-# LocalDate
-# ============================================================
-
-class LocalDate(Temporal, Comparable):
- MIN = None
- MAX = None
-
- def __init__(self, year, month, day):
- super().__init__()
- self._year = year
- self._month = month
- self._day = day
-
- @staticmethod
- def now(zone=None):
- today = _dt.date.today()
- return LocalDate(today.year, today.month, today.day)
-
- @staticmethod
- def of(year, month, dayOfMonth):
- if isinstance(month, Month):
- month = month.getValue()
- return LocalDate(year, month, dayOfMonth)
-
- @staticmethod
- def parse(text, formatter=None):
- if formatter is None:
- parts = text.split("-")
- return LocalDate(int(parts[0]), int(parts[1]), int(parts[2]))
- return formatter.parse(text, LocalDate)
-
- def getYear(self):
- return self._year
-
- def getMonth(self):
- return Month._from_value(self._month)
-
- def getMonthValue(self):
- return self._month
-
- def getDayOfMonth(self):
- return self._day
-
- def getDayOfWeek(self):
- import time as _t
- import datetime as _dt2
- d = _dt2.date(self._year, self._month, self._day)
- return DayOfWeek._from_value(d.isoweekday())
-
- def getDayOfYear(self):
- d = _dt.date(self._year, self._month, self._day)
- return d.timetuple().tm_yday
-
- def getEra(self):
- return "CE" if self._year > 0 else "BCE"
-
- def isLeapYear(self):
- return _dt.date(self._year, 3, 1) - _dt.date(self._year, 2, 28) == _dt.timedelta(days=1)
-
- def lengthOfMonth(self):
- m = self._month
- if m == 2:
- return 29 if self.isLeapYear() else 28
- if m in (4, 6, 9, 11):
- return 30
- return 31
-
- def lengthOfYear(self):
- return 366 if self.isLeapYear() else 365
-
- def toEpochDay(self):
- d = _dt.date(self._year, self._month, self._day)
- return d.toordinal()
-
- def plusDays(self, days):
- d = _dt.date(self._year, self._month, self._day) + _dt.timedelta(days=days)
- return LocalDate(d.year, d.month, d.day)
-
- def plusWeeks(self, weeks):
- return self.plusDays(weeks * 7)
-
- def plusMonths(self, months):
- total = self._year * 12 + (self._month - 1) + months
- y = total // 12
- m = (total % 12) + 1
- d = min(self._day, 29 if m == 2 and _dt.date(y, 3, 1) - _dt.date(y, 2, 28) == _dt.timedelta(days=1) else
- 30 if m in (4, 6, 9, 11) else 31)
- return LocalDate(y, m, d)
-
- def plusYears(self, years):
- return self.plusMonths(years * 12)
-
- def minusDays(self, days):
- return self.plusDays(-days)
-
- def minusWeeks(self, weeks):
- return self.plusDays(-weeks * 7)
-
- def minusMonths(self, months):
- return self.plusMonths(-months)
-
- def minusYears(self, years):
- return self.plusYears(-years)
-
- def isBefore(self, other):
- if isinstance(other, LocalDate):
- return (self._year, self._month, self._day) < (other._year, other._month, other._day)
- return False
-
- def isAfter(self, other):
- if isinstance(other, LocalDate):
- return (self._year, self._month, self._day) > (other._year, other._month, other._day)
- return False
-
- def isEqual(self, other):
- if isinstance(other, LocalDate):
- return (self._year, self._month, self._day) == (other._year, other._month, other._day)
- return False
-
- def withDayOfMonth(self, day):
- return LocalDate(self._year, self._month, day)
-
- def withMonth(self, month):
- if isinstance(month, Month):
- month = month.getValue()
- return LocalDate(self._year, month, self._day)
-
- def withYear(self, year):
- return LocalDate(year, self._month, self._day)
-
- def atTime(self, hour, minute=0, second=0, nano=0):
- return LocalDateTime(self, LocalTime(hour, minute, second, nano))
-
- def atStartOfDay(self, zone=None):
- return LocalDateTime(self, LocalTime.MIDNIGHT)
-
- def format(self, formatter):
- return formatter.format(self)
-
- def compareTo(self, other):
- if isinstance(other, LocalDate):
- v = self._year - other._year
- if v != 0:
- return -1 if v < 0 else 1
- v = self._month - other._month
- if v != 0:
- return -1 if v < 0 else 1
- v = self._day - other._day
- return -1 if v < 0 else (1 if v > 0 else 0)
- return -1
-
- def equals(self, other):
- if isinstance(other, LocalDate):
- return (self._year, self._month, self._day) == (other._year, other._month, other._day)
- return False
-
- def toString(self):
- return f"{self._year:04d}-{self._month:02d}-{self._day:02d}"
-
- def hashCode(self):
- return hash((self._year, self._month, self._day))
-
-
-LocalDate.MIN = LocalDate(-999999999, 1, 1)
-LocalDate.MAX = LocalDate(999999999, 12, 31)
-
-
-# ============================================================
-# LocalTime
-# ============================================================
-
-class LocalTime(Temporal, Comparable):
- MIDNIGHT = None
- NOON = None
- MIN = None
- MAX = None
-
- def __init__(self, hour, minute=0, second=0, nano=0):
- super().__init__()
- self._hour = hour
- self._minute = minute
- self._second = second
- self._nano = nano
-
- @staticmethod
- def now(zone=None):
- t = _dt.datetime.now().time()
- return LocalTime(t.hour, t.minute, t.second, t.microsecond * 1000)
-
- @staticmethod
- def of(hour, minute=0, second=0, nano=0):
- return LocalTime(hour, minute, second, nano)
-
- @staticmethod
- def parse(text, formatter=None):
- parts = text.split(":")
- h = int(parts[0])
- m = int(parts[1])
- s = int(parts[2]) if len(parts) > 2 else 0
- return LocalTime(h, m, s)
-
- def getHour(self):
- return self._hour
-
- def getMinute(self):
- return self._minute
-
- def getSecond(self):
- return self._second
-
- def getNano(self):
- return self._nano
-
- def toSecondOfDay(self):
- return self._hour * 3600 + self._minute * 60 + self._second
-
- def toNanoOfDay(self):
- return self.toSecondOfDay() * 1_000_000_000 + self._nano
-
- def plusHours(self, h):
- total = self._hour + h
- return LocalTime(total % 24, self._minute, self._second, self._nano)
-
- def plusMinutes(self, m):
- total = self.toSecondOfDay() + m * 60
- total %= 86400
- h = total // 3600
- total %= 3600
- mi = total // 60
- s = total % 60
- return LocalTime(h, mi, s, self._nano)
-
- def plusSeconds(self, s):
- total = self.toSecondOfDay() + s
- total %= 86400
- h = total // 3600
- total %= 3600
- mi = total // 60
- sec = total % 60
- return LocalTime(h, mi, sec, self._nano)
-
- def plusNanos(self, n):
- return LocalTime(self._hour, self._minute, self._second, self._nano + n)
-
- def minusHours(self, h):
- return self.plusHours(-h)
-
- def minusMinutes(self, m):
- return self.plusMinutes(-m)
-
- def minusSeconds(self, s):
- return self.plusSeconds(-s)
-
- def withHour(self, h):
- return LocalTime(h, self._minute, self._second, self._nano)
-
- def withMinute(self, m):
- return LocalTime(self._hour, m, self._second, self._nano)
-
- def withSecond(self, s):
- return LocalTime(self._hour, self._minute, s, self._nano)
-
- def withNano(self, n):
- return LocalTime(self._hour, self._minute, self._second, n)
-
- def atDate(self, date):
- return LocalDateTime(date, self)
-
- def isBefore(self, other):
- if isinstance(other, LocalTime):
- return self.toNanoOfDay() < other.toNanoOfDay()
- return False
-
- def isAfter(self, other):
- if isinstance(other, LocalTime):
- return self.toNanoOfDay() > other.toNanoOfDay()
- return False
-
- def format(self, formatter):
- return formatter.format(self)
-
- def compareTo(self, other):
- if isinstance(other, LocalTime):
- diff = self.toNanoOfDay() - other.toNanoOfDay()
- return -1 if diff < 0 else (1 if diff > 0 else 0)
- return -1
-
- def equals(self, other):
- if isinstance(other, LocalTime):
- return (self._hour, self._minute, self._second, self._nano) == \
- (other._hour, other._minute, other._second, other._nano)
- return False
-
- def toString(self):
- return f"{self._hour:02d}:{self._minute:02d}:{self._second:02d}"
-
- def hashCode(self):
- return hash((self._hour, self._minute, self._second, self._nano))
-
-
-LocalTime.MIDNIGHT = LocalTime(0, 0, 0, 0)
-LocalTime.NOON = LocalTime(12, 0, 0, 0)
-LocalTime.MIN = LocalTime(0, 0, 0, 0)
-LocalTime.MAX = LocalTime(23, 59, 59, 999999999)
-
-
-# ============================================================
-# LocalDateTime
-# ============================================================
-
-class LocalDateTime(Temporal, Comparable):
- MIN = None
- MAX = None
-
- def __init__(self, date, time):
- super().__init__()
- self._date = date
- self._time = time
-
- @staticmethod
- def now(zone=None):
- now = _dt.datetime.now()
- date = LocalDate(now.year, now.month, now.day)
- time = LocalTime(now.hour, now.minute, now.second, now.microsecond * 1000)
- return LocalDateTime(date, time)
-
- @staticmethod
- def of(date_or_year, month=None, dayOfMonth=None, hour=None, minute=0, second=0, nano=0):
- if isinstance(date_or_year, LocalDate):
- return LocalDateTime(date_or_year, LocalTime(month or 0, dayOfMonth or 0, hour or 0))
- return LocalDateTime(LocalDate(date_or_year, month, dayOfMonth),
- LocalTime(hour, minute, second, nano))
-
- @staticmethod
- def parse(text, formatter=None):
- parts = text.split("T")
- date = LocalDate.parse(parts[0])
- time = LocalTime.parse(parts[1]) if len(parts) > 1 else LocalTime.MIDNIGHT
- return LocalDateTime(date, time)
-
- def toLocalDate(self):
- return self._date
-
- def toLocalTime(self):
- return self._time
-
- def getYear(self):
- return self._date.getYear()
-
- def getMonth(self):
- return self._date.getMonth()
-
- def getMonthValue(self):
- return self._date.getMonthValue()
-
- def getDayOfMonth(self):
- return self._date.getDayOfMonth()
-
- def getDayOfWeek(self):
- return self._date.getDayOfWeek()
-
- def getDayOfYear(self):
- return self._date.getDayOfYear()
-
- def getHour(self):
- return self._time.getHour()
-
- def getMinute(self):
- return self._time.getMinute()
-
- def getSecond(self):
- return self._time.getSecond()
-
- def getNano(self):
- return self._time.getNano()
-
- def plusDays(self, d):
- return LocalDateTime(self._date.plusDays(d), self._time)
-
- def plusHours(self, h):
- return LocalDateTime(self._date, self._time.plusHours(h))
-
- def plusMinutes(self, m):
- return LocalDateTime(self._date, self._time.plusMinutes(m))
-
- def plusSeconds(self, s):
- return LocalDateTime(self._date, self._time.plusSeconds(s))
-
- def minusDays(self, d):
- return self.plusDays(-d)
-
- def minusHours(self, h):
- return self.plusHours(-h)
-
- def minusMinutes(self, m):
- return self.plusMinutes(-m)
-
- def minusSeconds(self, s):
- return self.plusSeconds(-s)
-
- def withYear(self, y):
- return LocalDateTime(self._date.withYear(y), self._time)
-
- def withMonth(self, m):
- return LocalDateTime(self._date.withMonth(m), self._time)
-
- def withDayOfMonth(self, d):
- return LocalDateTime(self._date.withDayOfMonth(d), self._time)
-
- def atZone(self, zone):
- return ZonedDateTime(self, zone)
-
- def isBefore(self, other):
- if isinstance(other, LocalDateTime):
- if not self._date.isEqual(other._date):
- return self._date.isBefore(other._date)
- return self._time.isBefore(other._time)
- return False
-
- def isAfter(self, other):
- if isinstance(other, LocalDateTime):
- if not self._date.isEqual(other._date):
- return self._date.isAfter(other._date)
- return self._time.isAfter(other._time)
- return False
-
- def format(self, formatter):
- return formatter.format(self)
-
- def compareTo(self, other):
- if isinstance(other, LocalDateTime):
- c = self._date.compareTo(other._date)
- return c if c != 0 else self._time.compareTo(other._time)
- return -1
-
- def equals(self, other):
- if isinstance(other, LocalDateTime):
- return self._date.equals(other._date) and self._time.equals(other._time)
- return False
-
- def toString(self):
- return f"{self._date}T{self._time}"
-
- def hashCode(self):
- return hash((self._date, self._time))
-
-
-LocalDateTime.MIN = LocalDateTime(LocalDate.MIN, LocalTime.MIN)
-LocalDateTime.MAX = LocalDateTime(LocalDate.MAX, LocalTime.MAX)
-
-
-# ============================================================
-# ZonedDateTime
-# ============================================================
-
-class ZonedDateTime(Temporal, Comparable):
- def __init__(self, date_time, zone):
- super().__init__()
- self._date_time = date_time
- self._zone = zone
-
- @staticmethod
- def now(zone=None):
- ldt = LocalDateTime.now()
- z = zone or ZoneId.systemDefault()
- return ZonedDateTime(ldt, z)
-
- @staticmethod
- def of(date, time=None, zone=None, offset=None):
- if isinstance(date, LocalDateTime):
- return ZonedDateTime(date, time or ZoneId.systemDefault())
- return ZonedDateTime(LocalDateTime.of(date, time), zone)
-
- @staticmethod
- def parse(text, formatter=None):
- return ZonedDateTime(LocalDateTime.now(), ZoneId.systemDefault())
-
- def getZone(self):
- return self._zone
-
- def getOffset(self):
- return ZoneOffset.UTC
-
- def withZoneSameInstant(self, zone):
- return ZonedDateTime(self._date_time, zone)
-
- def withZoneSameLocal(self, zone):
- return ZonedDateTime(self._date_time, zone)
-
- def toLocalDate(self):
- return self._date_time.toLocalDate()
-
- def toLocalTime(self):
- return self._date_time.toLocalTime()
-
- def toLocalDateTime(self):
- return self._date_time
-
- def toInstant(self):
- return Instant.now()
-
- def plusDays(self, d):
- return ZonedDateTime(self._date_time.plusDays(d), self._zone)
-
- def plusHours(self, h):
- return ZonedDateTime(self._date_time.plusHours(h), self._zone)
-
- def minusDays(self, d):
- return self.plusDays(-d)
-
- def minusHours(self, h):
- return self.plusHours(-h)
-
- def format(self, formatter):
- return formatter.format(self)
-
- def compareTo(self, other):
- if isinstance(other, ZonedDateTime):
- return self._date_time.compareTo(other._date_time)
- return -1
-
- def equals(self, other):
- if isinstance(other, ZonedDateTime):
- return self._date_time.equals(other._date_time) and str(self._zone) == str(other._zone)
- return False
-
- def toString(self):
- return f"{self._date_time}[{self._zone}]"
-
- def hashCode(self):
- return hash((self._date_time, str(self._zone)))
-
-
-# ============================================================
-# OffsetDateTime / OffsetTime (stubs)
-# ============================================================
-
-class OffsetDateTime(Temporal):
- def __init__(self, date_time, offset):
- super().__init__()
- self._date_time = date_time
- self._offset = offset
-
- @staticmethod
- def now():
- return OffsetDateTime(LocalDateTime.now(), ZoneOffset.UTC)
-
- def toLocalDate(self):
- return self._date_time.toLocalDate()
-
- def toLocalTime(self):
- return self._date_time.toLocalTime()
-
- def toString(self):
- return f"{self._date_time}{self._offset}"
-
-
-class OffsetTime(Stub):
- def __init__(self, time, offset):
- super().__init__()
- self._time = time
- self._offset = offset
-
- @staticmethod
- def now():
- return OffsetTime(LocalTime.now(), ZoneOffset.UTC)
-
- def toString(self):
- return f"{self._time}{self._offset}"
-
-
-# ============================================================
-# Year / YearMonth / MonthDay
-# ============================================================
-
-class Year(Temporal, Comparable):
- def __init__(self, year):
- super().__init__()
- self._year = year
-
- @staticmethod
- def now():
- return Year(_dt.date.today().year)
-
- @staticmethod
- def of(year):
- return Year(year)
-
- def getValue(self):
- return self._year
-
- def isLeap(self):
- return _dt.date(self._year, 3, 1) - _dt.date(self._year, 2, 28) == _dt.timedelta(days=1)
-
- def length(self):
- return 366 if self.isLeap() else 365
-
- def atMonth(self, month):
- if isinstance(month, Month):
- month = month.getValue()
- return YearMonth(self._year, month)
-
- def compareTo(self, other):
- if isinstance(other, Year):
- return -1 if self._year < other._year else (1 if self._year > other._year else 0)
- return -1
-
- def toString(self):
- return str(self._year)
-
-
-class YearMonth(Temporal, Comparable):
- def __init__(self, year, month):
- super().__init__()
- self._year = year
- self._month = month
-
- @staticmethod
- def now():
- d = _dt.date.today()
- return YearMonth(d.year, d.month)
-
- @staticmethod
- def of(year, month):
- return YearMonth(year, month)
-
- def getYear(self):
- return self._year
-
- def getMonth(self):
- return self._month
-
- def getMonthValue(self):
- return self._month if isinstance(self._month, int) else self._month.getValue()
-
- def lengthOfMonth(self):
- m = self.getMonthValue()
- if m == 2:
- return 29 if _dt.date(self._year, 3, 1) - _dt.date(self._year, 2, 28) == _dt.timedelta(days=1) else 28
- return 30 if m in (4, 6, 9, 11) else 31
-
- def lengthOfYear(self):
- return 366 if _dt.date(self._year, 3, 1) - _dt.date(self._year, 2, 28) == _dt.timedelta(days=1) else 365
-
- def atDay(self, day):
- return LocalDate(self._year, self.getMonthValue(), day)
-
- def compareTo(self, other):
- if isinstance(other, YearMonth):
- diff = self._year - other._year
- if diff != 0:
- return -1 if diff < 0 else 1
- diff = self.getMonthValue() - other.getMonthValue()
- return -1 if diff < 0 else (1 if diff > 0 else 0)
- return -1
-
- def toString(self):
- return f"{self._year}-{self.getMonthValue():02d}"
-
-
-class MonthDay(Stub):
- def __init__(self, month, day):
- super().__init__()
- self._month = month
- self._day = day
-
- @staticmethod
- def now():
- d = _dt.date.today()
- return MonthDay(d.month, d.day)
-
- @staticmethod
- def of(month, day):
- return MonthDay(month, day)
-
- def getMonth(self):
- return self._month
-
- def getMonthValue(self):
- return self._month if isinstance(self._month, int) else self._month.getValue()
-
- def getDayOfMonth(self):
- return self._day
-
- def atYear(self, year):
- return LocalDate.of(year, self.getMonthValue(), self._day)
-
- def toString(self):
- return f"--{self.getMonthValue():02d}-{self._day:02d}"
-
-
-# ============================================================
-# Clock
-# ============================================================
-
-class Clock(Stub):
- @staticmethod
- def systemUTC():
- return Clock()
-
- @staticmethod
- def systemDefaultZone():
- return Clock()
-
- @staticmethod
- def system(zone):
- return Clock()
-
- def millis(self):
- import time as _t
- return int(_t.time() * 1000)
-
- def instant(self):
- return Instant.now()
-
- def getZone(self):
- return ZoneId.systemDefault()
-
-
-# ============================================================
-# DateTimeFormatter
-# ============================================================
-
-class DateTimeFormatter(Stub):
- ISO_LOCAL_DATE = None
- ISO_LOCAL_TIME = None
- ISO_LOCAL_DATE_TIME = None
- ISO_INSTANT = None
- ISO_ZONED_DATE_TIME = None
- ISO_OFFSET_DATE_TIME = None
-
- def __init__(self, pattern):
- super().__init__()
- self._pattern = pattern
-
- @staticmethod
- def ofPattern(pattern):
- return DateTimeFormatter(pattern)
-
- def format(self, temporal):
- if isinstance(temporal, LocalDate):
- return temporal.toString()
- if isinstance(temporal, LocalTime):
- return temporal.toString()
- if isinstance(temporal, LocalDateTime):
- return temporal.toString()
- if isinstance(temporal, ZonedDateTime):
- return temporal.toString()
- if isinstance(temporal, Instant):
- return temporal.toString()
- return str(temporal)
-
- def parse(self, text, query=None):
- if query is LocalDate or query is None:
- return LocalDate.parse(text)
- if query is LocalTime:
- return LocalTime.parse(text)
- if query is LocalDateTime:
- return LocalDateTime.parse(text)
- return text
-
-
-DateTimeFormatter.ISO_LOCAL_DATE = DateTimeFormatter("yyyy-MM-dd")
-DateTimeFormatter.ISO_LOCAL_TIME = DateTimeFormatter("HH:mm:ss")
-DateTimeFormatter.ISO_LOCAL_DATE_TIME = DateTimeFormatter("yyyy-MM-ddTHH:mm:ss")
-DateTimeFormatter.ISO_INSTANT = DateTimeFormatter("yyyy-MM-ddTHH:mm:ssZ")
-DateTimeFormatter.ISO_ZONED_DATE_TIME = DateTimeFormatter("yyyy-MM-ddTHH:mm:ssZ")
-DateTimeFormatter.ISO_OFFSET_DATE_TIME = DateTimeFormatter("yyyy-MM-ddTHH:mm:ssZ")
-
-
-# ============================================================
-# DateTimeFormatterBuilder (stub)
-# ============================================================
-
-class DateTimeFormatterBuilder(Stub):
- def __init__(self):
- super().__init__()
- self._pattern_parts = []
-
- def appendValue(self, field, width=1):
- return self
-
- def appendLiteral(self, literal):
- return self
-
- def appendPattern(self, pattern):
- self._pattern_parts.append(pattern)
- return self
-
- def toFormatter(self):
- return DateTimeFormatter("".join(self._pattern_parts))
-
-
-# ============================================================
-# TemporalAdjusters (stub)
-# ============================================================
-
-class TemporalAdjusters(Stub):
- @staticmethod
- def firstDayOfMonth():
- return lambda d: d.withDayOfMonth(1)
-
- @staticmethod
- def lastDayOfMonth():
- return lambda d: d.withDayOfMonth(d.lengthOfMonth())
-
- @staticmethod
- def firstDayOfYear():
- return lambda d: d.withDayOfMonth(1).withMonth(1)
-
- @staticmethod
- def lastDayOfYear():
- return lambda d: d.withDayOfMonth(31).withMonth(12)
-
- @staticmethod
- def firstInMonth(day_of_week):
- return lambda d: d
-
- @staticmethod
- def next(day_of_week):
- return lambda d: d.plusDays(1)
\ No newline at end of file
diff --git a/android_pyapi/java/util.py b/android_pyapi/java/util.py
deleted file mode 100644
index dd61244..0000000
--- a/android_pyapi/java/util.py
+++ /dev/null
@@ -1,4096 +0,0 @@
-"""
-Java java.util standard library APIs implemented in Python.
-Android-pyApi: desktop Python translation of Android Java APIs.
-"""
-
-from .._core import Stub
-from .lang import RuntimeException
-import heapq as _heapq
-import bisect as _bisect
-import datetime as _datetime
-import uuid as _uuid
-import random as _py_random
-import math as _py_math
-import copy as _copy
-import re as _re
-import io as _io
-import threading as _threading
-import time as _time
-from typing import Any, Dict, List, Callable, Tuple, Iterable as _IterableType
-import typing as _typing
-from collections.abc import Iterable as _IterableABC
-
-__all__ = [
- "ArrayList", "LinkedList", "HashMap", "LinkedHashMap", "TreeMap",
- "HashSet", "TreeSet", "LinkedHashSet",
- "Collections", "Arrays", "Date", "Calendar", "GregorianCalendar",
- "UUID", "StringTokenizer", "Optional", "Random",
- "Properties", "EnumSet", "EnumMap",
- "Iterator", "ListIterator", "Enumeration",
- "Objects", "Locale", "BitSet", "PriorityQueue",
- "Vector", "Stack",
- "ConcurrentModificationException", "NoSuchElementException",
- "EmptyStackException", "TooManyListenersException",
- "MissingResourceException", "IllegalFormatException",
- "DuplicateFormatFlagsException", "FormatFlagsConversionMismatchException",
- "FormatterClosedException",
-]
-
-# ============================================================
-# Exceptions
-# ============================================================
-
-# Define exception classes in correct dependency order.
-# IllegalArgumentException comes before IllegalFormatException.
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-
-ConcurrentModificationException = type(
- "ConcurrentModificationException", (RuntimeException,), {}
-)
-NoSuchElementException = type("NoSuchElementException", (RuntimeException,), {})
-EmptyStackException = type("EmptyStackException", (RuntimeException,), {})
-TooManyListenersException = type("TooManyListenersException", (Exception,), {})
-MissingResourceException = type("MissingResourceException", (RuntimeException,), {})
-IllegalFormatException = type("IllegalFormatException", (IllegalArgumentException,), {})
-DuplicateFormatFlagsException = type(
- "DuplicateFormatFlagsException", (IllegalFormatException,), {}
-)
-FormatFlagsConversionMismatchException = type(
- "FormatFlagsConversionMismatchException", (IllegalFormatException,), {}
-)
-
-# We need IllegalStateException for FormatterClosedException
-from .lang import RuntimeException as _RuntimeException
-IllegalStateException = type("IllegalStateException", (_RuntimeException,), {})
-
-FormatterClosedException = type("FormatterClosedException", (IllegalStateException,), {})
-UnsupportedOperationException = type("UnsupportedOperationException", (RuntimeException,), {})
-
-# ============================================================
-# Iterator / ListIterator / Enumeration
-# ============================================================
-
-class Iterator(Stub):
- """java.util.Iterator"""
- def __init__(self, data):
- super().__init__()
- self._data = list(data)
- self._index = 0
- self._mod_count = 0
-
- def hasNext(self) -> bool:
- return self._index < len(self._data)
-
- def next(self):
- if not self.hasNext():
- raise NoSuchElementException()
- val = self._data[self._index]
- self._index += 1
- return val
-
- def remove(self):
- raise UnsupportedOperationException("remove")
-
- def forEachRemaining(self, action):
- while self.hasNext():
- action(self.next())
-
-
-class ListIterator(Iterator):
- """java.util.ListIterator"""
- def __init__(self, data):
- super().__init__(data)
-
- def hasPrevious(self) -> bool:
- return self._index > 0
-
- def previous(self):
- if not self.hasPrevious():
- raise NoSuchElementException()
- self._index -= 1
- return self._data[self._index]
-
- def nextIndex(self) -> int:
- return self._index
-
- def previousIndex(self) -> int:
- return self._index - 1
-
- def set(self, obj):
- self._data[self._index - 1] = obj
-
- def add(self, obj):
- self._data.insert(self._index, obj)
- self._index += 1
-
-
-class Enumeration(Stub):
- """java.util.Enumeration"""
- def __init__(self, data):
- super().__init__()
- self._it = iter(data)
-
- def hasMoreElements(self) -> bool:
- try:
- self._next = next(self._it)
- return True
- except StopIteration:
- return False
-
- def nextElement(self):
- if hasattr(self, '_next'):
- val = self._next
- del self._next
- return val
- return next(self._it)
-
- def asIterator(self) -> Iterator:
- return Iterator(self._it)
-
-
-# ============================================================
-# Stream / Spliterator helpers (lightweight, stdlib-backed)
-# ============================================================
-
-class _Spliterator(Stub):
- """Lightweight java.util.Spliterator backed by a Python sequence."""
- ORDERED = 0x00000010
- DISTINCT = 0x00000001
- SORTED = 0x00000004
- SIZED = 0x00000040
- NONNULL = 0x00000100
- IMMUTABLE = 0x00000400
- CONCURRENT = 0x00001000
- SUBSIZED = 0x00004000
-
- def __init__(self, data, characteristics: int = 0):
- super().__init__()
- self._data = list(data)
- self._index = 0
- self._characteristics = (characteristics
- | _Spliterator.SIZED
- | _Spliterator.SUBSIZED)
-
- def tryAdvance(self, action) -> bool:
- if self._index < len(self._data):
- action(self._data[self._index])
- self._index += 1
- return True
- return False
-
- def forEachRemaining(self, action) -> None:
- while self._index < len(self._data):
- action(self._data[self._index])
- self._index += 1
-
- def trySplit(self):
- mid = (self._index + len(self._data)) // 2
- if self._index >= mid:
- return None
- split = _Spliterator(self._data[self._index:mid],
- self._characteristics)
- self._index = mid
- return split
-
- def estimateSize(self) -> int:
- return len(self._data) - self._index
-
- def getExactSizeIfKnown(self) -> int:
- return self.estimateSize()
-
- def characteristics(self) -> int:
- return self._characteristics
-
- def hasCharacteristics(self, characteristics: int) -> bool:
- return (self._characteristics & characteristics) == characteristics
-
- def iterator(self) -> Iterator:
- return Iterator(self._data[self._index:])
-
-
-class _Stream(Stub):
- """Lightweight java.util.stream.Stream wrapper over a Python list."""
- def __init__(self, data):
- super().__init__()
- self._data = list(data)
- self._parallel = False
-
- def iterator(self) -> Iterator:
- return Iterator(self._data)
-
- def spliterator(self) -> _Spliterator:
- return _Spliterator(self._data)
-
- def isParallel(self) -> bool:
- return self._parallel
-
- def parallel(self) -> '_Stream':
- self._parallel = True
- return self
-
- def sequential(self) -> '_Stream':
- self._parallel = False
- return self
-
- def unordered(self) -> '_Stream':
- return self
-
- def filter(self, predicate) -> '_Stream':
- return _Stream([x for x in self._data if predicate(x)])
-
- def map(self, mapper) -> '_Stream':
- return _Stream([mapper(x) for x in self._data])
-
- def mapToInt(self, mapper) -> '_Stream':
- return _Stream([mapper(x) for x in self._data])
-
- def mapToLong(self, mapper) -> '_Stream':
- return _Stream([mapper(x) for x in self._data])
-
- def mapToDouble(self, mapper) -> '_Stream':
- return _Stream([mapper(x) for x in self._data])
-
- def flatMap(self, mapper) -> '_Stream':
- result = []
- for x in self._data:
- part = mapper(x)
- if isinstance(part, (list, tuple)):
- result.extend(part)
- else:
- result.extend(list(part))
- return _Stream(result)
-
- def peek(self, action) -> '_Stream':
- for x in self._data:
- action(x)
- return self
-
- def distinct(self) -> '_Stream':
- seen = []
- seen_keys = set()
- for x in self._data:
- key = x if isinstance(x, (int, str, tuple, frozenset)) else id(x)
- if key not in seen_keys:
- seen_keys.add(key)
- seen.append(x)
- return _Stream(seen)
-
- def sorted(self, key=None, reverse: bool = False) -> '_Stream':
- return _Stream(sorted(self._data, key=key, reverse=reverse))
-
- def limit(self, maxSize: int) -> '_Stream':
- return _Stream(self._data[:maxSize])
-
- def skip(self, n: int) -> '_Stream':
- return _Stream(self._data[n:])
-
- def forEach(self, action) -> None:
- for x in self._data:
- action(x)
-
- def forEachOrdered(self, action) -> None:
- for x in self._data:
- action(x)
-
- def toArray(self, generator=None):
- if generator is None:
- return list(self._data)
- return list(self._data)
-
- def reduce(self, *args):
- if len(args) == 1:
- accumulator = args[0]
- it = iter(self._data)
- try:
- acc = next(it)
- except StopIteration:
- return Optional.empty()
- for x in it:
- acc = accumulator(acc, x)
- return Optional.of(acc)
- elif len(args) == 2:
- identity, accumulator = args
- acc = identity
- for x in self._data:
- acc = accumulator(acc, x)
- return acc
- else:
- identity, accumulator, combiner = args
- acc = identity
- for x in self._data:
- acc = accumulator(acc, x)
- return acc
-
- def collect(self, *args):
- if not args:
- return list(self._data)
- if len(args) == 1:
- collector = args[0]
- supplier = getattr(collector, 'supplier', None)
- accumulator = getattr(collector, 'accumulator', None)
- finisher = getattr(collector, 'finisher', None)
- if supplier is not None and accumulator is not None:
- container = supplier() if callable(supplier) else supplier
- for x in self._data:
- if callable(accumulator):
- accumulator(container, x)
- if finisher is not None and callable(finisher):
- return finisher(container)
- return container
- if callable(collector):
- return collector(list(self._data))
- return list(self._data)
- supplier, accumulator, combiner = args[0], args[1], args[2]
- container = supplier() if callable(supplier) else supplier
- for x in self._data:
- if callable(accumulator):
- accumulator(container, x)
- return container
-
- def count(self) -> int:
- return len(self._data)
-
- def findFirst(self):
- return Optional.of(self._data[0]) if self._data else Optional.empty()
-
- def findAny(self):
- return self.findFirst()
-
- def anyMatch(self, predicate) -> bool:
- return any(predicate(x) for x in self._data)
-
- def allMatch(self, predicate) -> bool:
- return all(predicate(x) for x in self._data)
-
- def noneMatch(self, predicate) -> bool:
- return not any(predicate(x) for x in self._data)
-
- def min(self, key=None):
- if not self._data:
- return Optional.empty()
- return Optional.of(min(self._data, key=key) if key else min(self._data))
-
- def max(self, key=None):
- if not self._data:
- return Optional.empty()
- return Optional.of(max(self._data, key=key) if key else max(self._data))
-
- def onClose(self, close_handler) -> '_Stream':
- return self
-
- def close(self) -> None:
- pass
-
-
-# ============================================================
-# ArrayList
-# ============================================================
-
-class ArrayList(Stub):
- """java.util.ArrayList — backed by Python list"""
- def __init__(self, initial_capacity: Any = None):
- super().__init__()
- if initial_capacity is None:
- self._data = []
- elif isinstance(initial_capacity, int):
- self._data = []
- elif isinstance(initial_capacity, _IterableABC):
- self._data = list(initial_capacity)
- else:
- self._data = []
-
- def add(self, obj) -> bool:
- self._data.append(obj)
- return True
-
- def addAt(self, index: int, obj) -> None:
- self._data.insert(index, obj)
-
- def addAll(self, c) -> bool:
- if isinstance(c, ArrayList):
- self._data.extend(c._data)
- else:
- self._data.extend(c)
- return True
-
- def addAllAt(self, index: int, c) -> bool:
- if isinstance(c, ArrayList):
- self._data[index:index] = c._data
- else:
- self._data[index:index] = list(c)
- return True
-
- def clear(self) -> None:
- self._data.clear()
-
- def clone(self) -> 'ArrayList':
- return ArrayList(self._data)
-
- def contains(self, obj) -> bool:
- return obj in self._data
-
- def containsAll(self, c) -> bool:
- if isinstance(c, ArrayList):
- return all(x in self._data for x in c._data)
- return all(x in self._data for x in c)
-
- def ensureCapacity(self, min_capacity: int) -> None:
- pass # Python list handles resizing automatically
-
- def get(self, index: int):
- return self._data[index]
-
- def indexOf(self, obj) -> int:
- try:
- return self._data.index(obj)
- except ValueError:
- return -1
-
- def isEmpty(self) -> bool:
- return len(self._data) == 0
-
- def iterator(self) -> Iterator:
- return Iterator(self._data)
-
- def listIterator(self) -> ListIterator:
- return ListIterator(self._data)
-
- def lastIndexOf(self, obj) -> int:
- try:
- return len(self._data) - 1 - self._data[::-1].index(obj)
- except ValueError:
- return -1
-
- def remove(self, obj) -> bool:
- if obj in self._data:
- self._data.remove(obj)
- return True
- return False
-
- def removeAt(self, index: int):
- return self._data.pop(index)
-
- def removeAll(self, c) -> bool:
- if isinstance(c, ArrayList):
- items = c._data
- else:
- items = list(c)
- old_len = len(self._data)
- self._data = [x for x in self._data if x not in items]
- return len(self._data) != old_len
-
- def retainAll(self, c) -> bool:
- if isinstance(c, ArrayList):
- items = set(c._data)
- else:
- items = set(c)
- old_len = len(self._data)
- self._data = [x for x in self._data if x in items]
- return len(self._data) != old_len
-
- def set(self, index: int, obj):
- old = self._data[index]
- self._data[index] = obj
- return old
-
- def size(self) -> int:
- return len(self._data)
-
- def sort(self, key=None, reverse: bool = False) -> None:
- self._data.sort(key=key, reverse=reverse)
-
- def subList(self, from_index: int, to_index: int) -> 'ArrayList':
- return ArrayList(self._data[from_index:to_index])
-
- def toArray(self, a=None):
- if a is None:
- return list(self._data)
- if len(a) < len(self._data):
- return list(self._data)
- for i, v in enumerate(self._data):
- a[i] = v
- if len(self._data) < len(a):
- a[len(self._data)] = None
- return a
-
- def trimToSize(self) -> None:
- pass
-
- def forEach(self, action) -> None:
- for item in self._data:
- action(item)
-
- def removeIf(self, predicate) -> bool:
- old_len = len(self._data)
- self._data = [x for x in self._data if not predicate(x)]
- return len(self._data) != old_len
-
- def replaceAll(self, operator) -> None:
- self._data = [operator(x) for x in self._data]
-
- def spliterator(self) -> _Spliterator:
- return _Spliterator(self._data, _Spliterator.ORDERED)
-
- def stream(self) -> _Stream:
- return _Stream(self._data)
-
- def equals(self, other) -> bool:
- if isinstance(other, ArrayList):
- return self._data == other._data
- return False
-
- def hashCode(self) -> int:
- h = 1
- for v in self._data:
- h = (31 * h + hash(v)) & 0x7FFFFFFF
- return h
-
- def toString(self) -> str:
- items = ", ".join(str(x) for x in self._data)
- return f"[{items}]"
-
- def __len__(self):
- return len(self._data)
-
- def __getitem__(self, idx):
- return self._data[idx]
-
- def __setitem__(self, idx, val):
- self._data[idx] = val
-
- def __delitem__(self, idx):
- del self._data[idx]
-
- def __iter__(self):
- return iter(self._data)
-
- def __repr__(self):
- return self.toString()
-
- def __contains__(self, obj):
- return obj in self._data
-
- def __add__(self, other):
- if isinstance(other, ArrayList):
- result = ArrayList(self._data)
- result._data.extend(other._data)
- return result
- return NotImplemented
-
- def __eq__(self, other):
- return self.equals(other)
-
-
-# ============================================================
-# LinkedList
-# ============================================================
-
-class LinkedList(Stub):
- """java.util.LinkedList — backed by Python list"""
- def __init__(self, c=None):
- super().__init__()
- if c is None:
- self._data = []
- elif isinstance(c, _IterableABC):
- self._data = list(c)
- else:
- self._data = []
-
- def add(self, obj) -> bool:
- self._data.append(obj)
- return True
-
- def addFirst(self, obj) -> None:
- self._data.insert(0, obj)
-
- def addLast(self, obj) -> None:
- self._data.append(obj)
-
- def addAt(self, index: int, obj) -> None:
- self._data.insert(index, obj)
-
- def addAll(self, c) -> bool:
- if isinstance(c, LinkedList):
- self._data.extend(c._data)
- else:
- self._data.extend(c)
- return True
-
- def clear(self) -> None:
- self._data.clear()
-
- def clone(self) -> 'LinkedList':
- return LinkedList(self._data)
-
- def contains(self, obj) -> bool:
- return obj in self._data
-
- def descendingIterator(self) -> Iterator:
- return Iterator(reversed(self._data))
-
- def element(self):
- if not self._data:
- raise NoSuchElementException()
- return self._data[0]
-
- def get(self, index: int):
- return self._data[index]
-
- def getFirst(self):
- if not self._data:
- raise NoSuchElementException()
- return self._data[0]
-
- def getLast(self):
- if not self._data:
- raise NoSuchElementException()
- return self._data[-1]
-
- def indexOf(self, obj) -> int:
- try:
- return self._data.index(obj)
- except ValueError:
- return -1
-
- def isEmpty(self) -> bool:
- return len(self._data) == 0
-
- def iterator(self) -> Iterator:
- return Iterator(self._data)
-
- def lastIndexOf(self, obj) -> int:
- try:
- return len(self._data) - 1 - self._data[::-1].index(obj)
- except ValueError:
- return -1
-
- def listIterator(self, index: int = 0) -> ListIterator:
- li = ListIterator(self._data)
- li._index = index
- return li
-
- def offer(self, obj) -> bool:
- self._data.append(obj)
- return True
-
- def offerFirst(self, obj) -> bool:
- self._data.insert(0, obj)
- return True
-
- def offerLast(self, obj) -> bool:
- self._data.append(obj)
- return True
-
- def peek(self):
- return self._data[0] if self._data else None
-
- def peekFirst(self):
- return self._data[0] if self._data else None
-
- def peekLast(self):
- return self._data[-1] if self._data else None
-
- def poll(self):
- return self._data.pop(0) if self._data else None
-
- def pollFirst(self):
- return self._data.pop(0) if self._data else None
-
- def pollLast(self):
- return self._data.pop() if self._data else None
-
- def pop(self):
- if not self._data:
- raise NoSuchElementException()
- return self._data.pop()
-
- def push(self, obj) -> None:
- self._data.insert(0, obj)
-
- def remove(self, obj) -> bool:
- if obj in self._data:
- self._data.remove(obj)
- return True
- return False
-
- def removeAt(self, index: int):
- return self._data.pop(index)
-
- def removeFirst(self):
- if not self._data:
- raise NoSuchElementException()
- return self._data.pop(0)
-
- def removeFirstOccurrence(self, obj) -> bool:
- try:
- idx = self._data.index(obj)
- self._data.pop(idx)
- return True
- except ValueError:
- return False
-
- def removeLast(self):
- if not self._data:
- raise NoSuchElementException()
- return self._data.pop()
-
- def removeLastOccurrence(self, obj) -> bool:
- try:
- idx = len(self._data) - 1 - self._data[::-1].index(obj)
- self._data.pop(idx)
- return True
- except ValueError:
- return False
-
- def set(self, index: int, obj):
- old = self._data[index]
- self._data[index] = obj
- return old
-
- def size(self) -> int:
- return len(self._data)
-
- def toArray(self, a=None):
- if a is None:
- return list(self._data)
- if len(a) < len(self._data):
- return list(self._data)
- for i, v in enumerate(self._data):
- a[i] = v
- if len(self._data) < len(a):
- a[len(self._data)] = None
- return a
-
- def forEach(self, action) -> None:
- for item in self._data:
- action(item)
-
- def equals(self, other) -> bool:
- if isinstance(other, LinkedList):
- return self._data == other._data
- return False
-
- def hashCode(self) -> int:
- h = 1
- for v in self._data:
- h = (31 * h + hash(v)) & 0x7FFFFFFF
- return h
-
- def toString(self) -> str:
- items = ", ".join(str(x) for x in self._data)
- return f"[{items}]"
-
- def __len__(self):
- return len(self._data)
-
- def __getitem__(self, idx):
- return self._data[idx]
-
- def __iter__(self):
- return iter(self._data)
-
- def __repr__(self):
- return self.toString()
-
- def __eq__(self, other):
- return self.equals(other)
-
-
-# ============================================================
-# HashMap
-# ============================================================
-
-class HashMap(Stub):
- """java.util.HashMap — backed by Python dict"""
- def __init__(self, initial_capacity: Any = None, load_factor: float = 0.75):
- super().__init__()
- self._data: Dict = {}
- if initial_capacity is not None and not isinstance(initial_capacity, (int, float)):
- if isinstance(initial_capacity, HashMap):
- self._data.update(initial_capacity._data)
- elif isinstance(initial_capacity, dict):
- self._data.update(initial_capacity)
- elif isinstance(initial_capacity, _IterableABC):
- for item in initial_capacity:
- if hasattr(item, 'getKey') and hasattr(item, 'getValue'):
- k, v = item.getKey(), item.getValue()
- elif isinstance(item, tuple) and len(item) >= 2:
- k, v = item[0], item[1]
- else:
- continue
- self._data[k] = v
-
- def clear(self) -> None:
- self._data.clear()
-
- def clone(self) -> 'HashMap':
- return HashMap(self._data)
-
- def compute(self, key, remapping_function):
- old = self._data.get(key)
- new_val = remapping_function(key, old)
- if new_val is not None:
- self._data[key] = new_val
- return new_val
- self._data.pop(key, None)
- return None
-
- def computeIfAbsent(self, key, mapping_function):
- if key not in self._data:
- new_val = mapping_function(key)
- if new_val is not None:
- self._data[key] = new_val
- return new_val
- return self._data.get(key)
-
- def computeIfPresent(self, key, remapping_function):
- if key in self._data:
- new_val = remapping_function(key, self._data[key])
- if new_val is not None:
- self._data[key] = new_val
- return new_val
- self._data.pop(key, None)
- return None
-
- def containsKey(self, key) -> bool:
- return key in self._data
-
- def containsValue(self, value) -> bool:
- return value in self._data.values()
-
- def entrySet(self) -> set:
- return self._data.items()
-
- def forEach(self, action) -> None:
- for k, v in self._data.items():
- action(k, v)
-
- def get(self, key):
- return self._data.get(key)
-
- def getOrDefault(self, key, default):
- return self._data.get(key, default)
-
- def isEmpty(self) -> bool:
- return len(self._data) == 0
-
- def keySet(self) -> set:
- return set(self._data.keys())
-
- def merge(self, key, value, remapping_function):
- old = self._data.get(key)
- if old is None:
- self._data[key] = value
- return value
- new_val = remapping_function(old, value)
- if new_val is not None:
- self._data[key] = new_val
- return new_val
- self._data.pop(key, None)
- return None
-
- def put(self, key, value):
- old = self._data.get(key)
- self._data[key] = value
- return old
-
- def putAll(self, m) -> None:
- if isinstance(m, HashMap):
- self._data.update(m._data)
- else:
- self._data.update(m)
-
- def putIfAbsent(self, key, value):
- if key not in self._data:
- self._data[key] = value
- return None
- return self._data[key]
-
- def remove(self, key, value=None):
- if value is not None:
- # remove(key, value) — 返回 boolean
- if key in self._data and self._data[key] == value:
- del self._data[key]
- return True
- return False
- else:
- # remove(key) — 返回被删除的 value(与 Java 语义一致)
- if key in self._data:
- old = self._data[key]
- del self._data[key]
- return old
- return None
-
- def replace(self, key, old_value=None, new_value=None):
- if old_value is None and new_value is None:
- return None
- if new_value is None:
- # replace(key, value) form
- if key in self._data:
- old = self._data[key]
- self._data[key] = old_value # old_value is actually new value here
- return old
- return None
- # replace(key, oldValue, newValue) form
- if key in self._data and self._data[key] == old_value:
- self._data[key] = new_value
- return True
- return False
-
- def replaceAll(self, function) -> None:
- for k in list(self._data.keys()):
- self._data[k] = function(k, self._data[k])
-
- def size(self) -> int:
- return len(self._data)
-
- def values(self):
- return list(self._data.values())
-
- def equals(self, other) -> bool:
- if isinstance(other, HashMap):
- return self._data == other._data
- return False
-
- def hashCode(self) -> int:
- h = 0
- for k, v in self._data.items():
- h = (h + (hash(k) ^ hash(v))) & 0x7FFFFFFF
- return h
-
- def toString(self) -> str:
- items = ", ".join(f"{k}={v}" for k, v in self._data.items())
- return f"{{{items}}}"
-
- def __len__(self):
- return len(self._data)
-
- def __getitem__(self, key):
- return self._data[key]
-
- def __setitem__(self, key, value):
- self._data[key] = value
-
- def __delitem__(self, key):
- del self._data[key]
-
- def __iter__(self):
- return iter(self._data)
-
- def __contains__(self, key):
- return key in self._data
-
- def __repr__(self):
- return self.toString()
-
- def __eq__(self, other):
- return self.equals(other)
-
-
-# ============================================================
-# LinkedHashMap
-# ============================================================
-
-class LinkedHashMap(HashMap):
- """java.util.LinkedHashMap — backed by dict (preserves order in Python 3.7+)"""
- def __init__(self, initial_capacity: Any = None, load_factor: float = 0.75,
- access_order: bool = False):
- super().__init__(initial_capacity, load_factor)
- self._access_order = access_order
-
- def get(self, key):
- val = self._data.get(key)
- if val is not None and self._access_order:
- # Move to end (most recently accessed) by delete/reinsert
- del self._data[key]
- self._data[key] = val
- return val
-
- def getOrDefault(self, key, default):
- val = self._data.get(key, default)
- if key in self._data and self._access_order:
- del self._data[key]
- self._data[key] = val
- return val
-
- def put(self, key, value):
- old = self._data.get(key)
- if key in self._data:
- del self._data[key]
- self._data[key] = value
- return old
-
- def removeEldestEntry(self, eldest) -> bool:
- return False
-
- def eldest(self):
- if not self._data:
- return None
- key = next(iter(self._data))
- return (key, self._data[key])
-
- def clone(self) -> 'LinkedHashMap':
- result = LinkedHashMap(self._data, 0.75, self._access_order)
- return result
-
-
-# ============================================================
-# TreeMap
-# ============================================================
-
-class TreeMap(Stub):
- """java.util.TreeMap — sorted map using Python's sorted()"""
- def __init__(self, comparator=None, m=None):
- super().__init__()
- self._data: Dict = {}
- self._comparator = comparator
- if m is not None:
- if isinstance(m, TreeMap):
- self._data.update(m._data)
- elif isinstance(m, dict):
- self._data.update(m)
- elif isinstance(m, _IterableABC):
- for item in m:
- if isinstance(item, tuple) and len(item) >= 2:
- self._data[item[0]] = item[1]
-
- def _sorted_keys(self):
- key_fn = self._comparator if self._comparator else None
- return sorted(self._data.keys(), key=key_fn)
-
- def _get_entry_by_key(self, key):
- if key in self._data:
- return (key, self._data[key])
- return None
-
- def clear(self) -> None:
- self._data.clear()
-
- def clone(self) -> 'TreeMap':
- return TreeMap(self._comparator, self._data)
-
- def comparator(self):
- return self._comparator
-
- def containsKey(self, key) -> bool:
- return key in self._data
-
- def containsValue(self, value) -> bool:
- return value in self._data.values()
-
- def ceilingKey(self, key):
- keys = self._sorted_keys()
- for k in keys:
- if (self._comparator(k, key) >= 0 if self._comparator else k >= key):
- return k
- return None
-
- def ceilingEntry(self, key):
- k = self.ceilingKey(key)
- return (k, self._data[k]) if k is not None else None
-
- def floorKey(self, key):
- keys = self._sorted_keys()
- for k in reversed(keys):
- if (self._comparator(k, key) <= 0 if self._comparator else k <= key):
- return k
- return None
-
- def floorEntry(self, key):
- k = self.floorKey(key)
- return (k, self._data[k]) if k is not None else None
-
- def higherKey(self, key):
- keys = self._sorted_keys()
- for k in keys:
- if (self._comparator(k, key) > 0 if self._comparator else k > key):
- return k
- return None
-
- def higherEntry(self, key):
- k = self.higherKey(key)
- return (k, self._data[k]) if k is not None else None
-
- def lowerKey(self, key):
- keys = self._sorted_keys()
- for k in reversed(keys):
- if (self._comparator(k, key) < 0 if self._comparator else k < key):
- return k
- return None
-
- def lowerEntry(self, key):
- k = self.lowerKey(key)
- return (k, self._data[k]) if k is not None else None
-
- def firstKey(self):
- if not self._data:
- raise NoSuchElementException()
- return self._sorted_keys()[0]
-
- def firstEntry(self):
- k = self.firstKey()
- return (k, self._data[k])
-
- def lastKey(self):
- if not self._data:
- raise NoSuchElementException()
- return self._sorted_keys()[-1]
-
- def lastEntry(self):
- k = self.lastKey()
- return (k, self._data[k])
-
- def pollFirstEntry(self):
- if not self._data:
- return None
- k = self.firstKey()
- v = self._data.pop(k)
- return (k, v)
-
- def pollLastEntry(self):
- if not self._data:
- return None
- k = self.lastKey()
- v = self._data.pop(k)
- return (k, v)
-
- def entrySet(self):
- return [(k, self._data[k]) for k in self._sorted_keys()]
-
- def forEach(self, action) -> None:
- for k in self._sorted_keys():
- action(k, self._data[k])
-
- def get(self, key):
- return self._data.get(key)
-
- def getOrDefault(self, key, default):
- return self._data.get(key, default)
-
- def headMap(self, to_key, inclusive: bool = False) -> 'TreeMap':
- result = TreeMap(self._comparator)
- for k in self._sorted_keys():
- cmp = self._comparator(k, to_key) if self._comparator else (k < to_key)
- if cmp or (inclusive and (self._comparator(k, to_key) == 0 if self._comparator else k == to_key)):
- result._data[k] = self._data[k]
- elif not inclusive and (self._comparator(k, to_key) < 0 if self._comparator else k < to_key):
- result._data[k] = self._data[k]
- else:
- break
- return result
-
- def tailMap(self, from_key, inclusive: bool = True) -> 'TreeMap':
- result = TreeMap(self._comparator)
- started = False
- for k in self._sorted_keys():
- cmp = self._comparator(k, from_key) if self._comparator else (k >= from_key)
- if cmp or (inclusive and (self._comparator(k, from_key) == 0 if self._comparator else k == from_key)):
- started = True
- if started:
- result._data[k] = self._data[k]
- return result
-
- def subMap(self, from_key, to_key, from_inclusive: bool = True, to_inclusive: bool = False) -> 'TreeMap':
- result = TreeMap(self._comparator)
- for k in self._sorted_keys():
- cmp_from = self._comparator(k, from_key) if self._comparator else (k >= from_key if from_inclusive else k > from_key)
- cmp_to = self._comparator(k, to_key) if self._comparator else (k <= to_key if to_inclusive else k < to_key)
- if cmp_from and cmp_to:
- result._data[k] = self._data[k]
- return result
-
- def isEmpty(self) -> bool:
- return len(self._data) == 0
-
- def keySet(self):
- return self._sorted_keys()
-
- def put(self, key, value):
- old = self._data.get(key)
- self._data[key] = value
- return old
-
- def putAll(self, m) -> None:
- if isinstance(m, TreeMap):
- self._data.update(m._data)
- else:
- self._data.update(m)
-
- def putIfAbsent(self, key, value):
- if key not in self._data:
- self._data[key] = value
- return None
- return self._data[key]
-
- def remove(self, key):
- return self._data.pop(key, None)
-
- def replace(self, key, old_value=None, new_value=None):
- if new_value is None:
- if key in self._data:
- old = self._data[key]
- self._data[key] = old_value
- return old
- return None
- if key in self._data and self._data[key] == old_value:
- self._data[key] = new_value
- return True
- return False
-
- def replaceAll(self, function) -> None:
- for k in list(self._data.keys()):
- self._data[k] = function(k, self._data[k])
-
- def compute(self, key, remapping_function):
- old = self._data.get(key)
- new_val = remapping_function(key, old)
- if new_val is not None:
- self._data[key] = new_val
- return new_val
- self._data.pop(key, None)
- return None
-
- def computeIfAbsent(self, key, mapping_function):
- if key not in self._data:
- new_val = mapping_function(key)
- if new_val is not None:
- self._data[key] = new_val
- return new_val
- return self._data.get(key)
-
- def computeIfPresent(self, key, remapping_function):
- if key in self._data:
- new_val = remapping_function(key, self._data[key])
- if new_val is not None:
- self._data[key] = new_val
- return new_val
- self._data.pop(key, None)
- return None
-
- def merge(self, key, value, remapping_function):
- old = self._data.get(key)
- if old is None:
- self._data[key] = value
- return value
- new_val = remapping_function(old, value)
- if new_val is not None:
- self._data[key] = new_val
- return new_val
- self._data.pop(key, None)
- return None
-
- def size(self) -> int:
- return len(self._data)
-
- def values(self):
- return [self._data[k] for k in self._sorted_keys()]
-
- def navigableKeySet(self):
- return self._sorted_keys()
-
- def descendingKeySet(self):
- return list(reversed(self._sorted_keys()))
-
- def descendingMap(self) -> 'TreeMap':
- result = TreeMap(self._comparator)
- for k in reversed(self._sorted_keys()):
- result._data[k] = self._data[k]
- return result
-
- def equals(self, other) -> bool:
- if isinstance(other, TreeMap):
- return self._data == other._data
- return False
-
- def hashCode(self) -> int:
- h = 0
- for k, v in self._data.items():
- h = (h + (hash(k) ^ hash(v))) & 0x7FFFFFFF
- return h
-
- def toString(self) -> str:
- items = ", ".join(f"{k}={v}" for k in self._data.items())
- return f"{{{items}}}"
-
- def __len__(self):
- return len(self._data)
-
- def __getitem__(self, key):
- return self._data[key]
-
- def __setitem__(self, key, value):
- self._data[key] = value
-
- def __delitem__(self, key):
- del self._data[key]
-
- def __iter__(self):
- return iter(self._sorted_keys())
-
- def __repr__(self):
- return self.toString()
-
- def __eq__(self, other):
- return self.equals(other)
-
-
-# ============================================================
-# HashSet
-# ============================================================
-
-class HashSet(Stub):
- """java.util.HashSet — backed by Python set"""
- def __init__(self, c=None):
- super().__init__()
- if c is None:
- self._data: set = set()
- elif isinstance(c, _IterableABC):
- self._data = set(c)
- else:
- self._data = set()
-
- def add(self, obj) -> bool:
- if obj in self._data:
- return False
- self._data.add(obj)
- return True
-
- def addAll(self, c) -> bool:
- old_size = len(self._data)
- if isinstance(c, HashSet):
- self._data.update(c._data)
- elif isinstance(c, set):
- self._data.update(c)
- else:
- self._data.update(c)
- return len(self._data) != old_size
-
- def clear(self) -> None:
- self._data.clear()
-
- def clone(self) -> 'HashSet':
- return HashSet(self._data)
-
- def contains(self, obj) -> bool:
- return obj in self._data
-
- def containsAll(self, c) -> bool:
- if isinstance(c, HashSet):
- return all(x in self._data for x in c._data)
- return all(x in self._data for x in c)
-
- def isEmpty(self) -> bool:
- return len(self._data) == 0
-
- def iterator(self) -> Iterator:
- return Iterator(list(self._data))
-
- def remove(self, obj) -> bool:
- if obj in self._data:
- self._data.remove(obj)
- return True
- return False
-
- def removeAll(self, c) -> bool:
- old_size = len(self._data)
- if isinstance(c, HashSet):
- self._data.difference_update(c._data)
- else:
- self._data.difference_update(c)
- return len(self._data) != old_size
-
- def retainAll(self, c) -> bool:
- old_size = len(self._data)
- if isinstance(c, HashSet):
- self._data.intersection_update(c._data)
- else:
- self._data.intersection_update(c)
- return len(self._data) != old_size
-
- def size(self) -> int:
- return len(self._data)
-
- def toArray(self, a=None):
- items = list(self._data)
- if a is None:
- return items
- if len(a) < len(items):
- return items
- for i, v in enumerate(items):
- a[i] = v
- if len(items) < len(a):
- a[len(items)] = None
- return a
-
- def forEach(self, action) -> None:
- for item in list(self._data):
- action(item)
-
- def removeIf(self, predicate) -> bool:
- old_size = len(self._data)
- to_remove = [x for x in self._data if predicate(x)]
- for x in to_remove:
- self._data.discard(x)
- return len(self._data) != old_size
-
- def spliterator(self) -> _Spliterator:
- return _Spliterator(self._data, _Spliterator.DISTINCT)
-
- def stream(self) -> _Stream:
- return _Stream(self._data)
-
- def equals(self, other) -> bool:
- if isinstance(other, HashSet):
- return self._data == other._data
- return False
-
- def hashCode(self) -> int:
- h = 0
- for v in self._data:
- h = (h + hash(v)) & 0x7FFFFFFF
- return h
-
- def toString(self) -> str:
- items = ", ".join(str(x) for x in self._data)
- return f"[{items}]"
-
- def __len__(self):
- return len(self._data)
-
- def __iter__(self):
- return iter(self._data)
-
- def __contains__(self, obj):
- return obj in self._data
-
- def __repr__(self):
- return self.toString()
-
- def __eq__(self, other):
- return self.equals(other)
-
-
-# ============================================================
-# LinkedHashSet
-# ============================================================
-
-class LinkedHashSet(HashSet):
- """java.util.LinkedHashSet — ordered set (preserves insertion order)"""
- def __init__(self, c=None):
- # dict keys preserve insertion order in Python 3.7+
- self._order: Dict[Any, None] = {}
- if c is not None:
- if isinstance(c, _IterableABC):
- for item in c:
- self._order[item] = None
- self._data = set(self._order.keys())
-
- def add(self, obj) -> bool:
- if obj in self._order:
- return False
- self._order[obj] = None
- self._data.add(obj)
- return True
-
- def remove(self, obj) -> bool:
- if obj in self._order:
- del self._order[obj]
- self._data.discard(obj)
- return True
- return False
-
- def clear(self) -> None:
- self._order.clear()
- self._data.clear()
-
- def iterator(self) -> Iterator:
- return Iterator(list(self._order.keys()))
-
- def toArray(self, a=None):
- items = list(self._order.keys())
- if a is None:
- return items
- if len(a) < len(items):
- return items
- for i, v in enumerate(items):
- a[i] = v
- if len(items) < len(a):
- a[len(items)] = None
- return a
-
- def forEach(self, action) -> None:
- for item in list(self._order.keys()):
- action(item)
-
- def __iter__(self):
- return iter(self._order.keys())
-
-
-# ============================================================
-# TreeSet
-# ============================================================
-
-class TreeSet(Stub):
- """java.util.TreeSet — sorted set"""
- def __init__(self, comparator=None, c=None):
- super().__init__()
- self._data: set = set()
- self._comparator = comparator
- if c is not None:
- if isinstance(c, _IterableABC):
- self._data = set(c)
-
- def _sorted(self):
- key_fn = self._comparator if self._comparator else None
- return sorted(self._data, key=key_fn)
-
- def add(self, obj) -> bool:
- if obj in self._data:
- return False
- self._data.add(obj)
- return True
-
- def addAll(self, c) -> bool:
- old_size = len(self._data)
- if isinstance(c, TreeSet):
- self._data.update(c._data)
- else:
- self._data.update(c)
- return len(self._data) != old_size
-
- def ceiling(self, obj):
- sorted_items = self._sorted()
- for item in sorted_items:
- if (self._comparator(item, obj) >= 0 if self._comparator else item >= obj):
- return item
- return None
-
- def floor(self, obj):
- sorted_items = self._sorted()
- for item in reversed(sorted_items):
- if (self._comparator(item, obj) <= 0 if self._comparator else item <= obj):
- return item
- return None
-
- def higher(self, obj):
- sorted_items = self._sorted()
- for item in sorted_items:
- if (self._comparator(item, obj) > 0 if self._comparator else item > obj):
- return item
- return None
-
- def lower(self, obj):
- sorted_items = self._sorted()
- for item in reversed(sorted_items):
- if (self._comparator(item, obj) < 0 if self._comparator else item < obj):
- return item
- return None
-
- def clear(self) -> None:
- self._data.clear()
-
- def clone(self) -> 'TreeSet':
- return TreeSet(self._comparator, self._data)
-
- def comparator(self):
- return self._comparator
-
- def contains(self, obj) -> bool:
- return obj in self._data
-
- def containsAll(self, c) -> bool:
- if isinstance(c, TreeSet):
- return all(x in self._data for x in c._data)
- return all(x in self._data for x in c)
-
- def first(self):
- if not self._data:
- raise NoSuchElementException()
- return self._sorted()[0]
-
- def last(self):
- if not self._data:
- raise NoSuchElementException()
- return self._sorted()[-1]
-
- def pollFirst(self):
- if not self._data:
- return None
- val = self._sorted()[0]
- self._data.discard(val)
- return val
-
- def pollLast(self):
- if not self._data:
- return None
- val = self._sorted()[-1]
- self._data.discard(val)
- return val
-
- def headSet(self, to_element, inclusive: bool = False) -> 'TreeSet':
- result = TreeSet(self._comparator)
- for item in self._data:
- cmp = self._comparator(item, to_element) if self._comparator else (item < to_element)
- if cmp or (inclusive and item == to_element):
- result._data.add(item)
- return result
-
- def tailSet(self, from_element, inclusive: bool = True) -> 'TreeSet':
- result = TreeSet(self._comparator)
- for item in self._data:
- cmp = self._comparator(item, from_element) if self._comparator else (item > from_element)
- if cmp or (inclusive and item == from_element):
- result._data.add(item)
- return result
-
- def subSet(self, from_element, to_element,
- from_inclusive: bool = True, to_inclusive: bool = False) -> 'TreeSet':
- result = TreeSet(self._comparator)
- for item in self._data:
- cmp_from = self._comparator(item, from_element) if self._comparator else (
- item >= from_element if from_inclusive else item > from_element)
- cmp_to = self._comparator(item, to_element) if self._comparator else (
- item <= to_element if to_inclusive else item < to_element)
- if cmp_from and cmp_to:
- result._data.add(item)
- return result
-
- def descendingIterator(self) -> Iterator:
- return Iterator(reversed(self._sorted()))
-
- def descendingSet(self) -> 'TreeSet':
- result = TreeSet(self._comparator)
- result._data = set(self._data)
- return result
-
- def isEmpty(self) -> bool:
- return len(self._data) == 0
-
- def iterator(self) -> Iterator:
- return Iterator(self._sorted())
-
- def remove(self, obj) -> bool:
- if obj in self._data:
- self._data.discard(obj)
- return True
- return False
-
- def removeAll(self, c) -> bool:
- old_size = len(self._data)
- if isinstance(c, TreeSet):
- self._data.difference_update(c._data)
- else:
- self._data.difference_update(c)
- return len(self._data) != old_size
-
- def retainAll(self, c) -> bool:
- old_size = len(self._data)
- if isinstance(c, TreeSet):
- self._data.intersection_update(c._data)
- else:
- self._data.intersection_update(c)
- return len(self._data) != old_size
-
- def size(self) -> int:
- return len(self._data)
-
- def toArray(self, a=None):
- items = self._sorted()
- if a is None:
- return items
- if len(a) < len(items):
- return items
- for i, v in enumerate(items):
- a[i] = v
- if len(items) < len(a):
- a[len(items)] = None
- return a
-
- def forEach(self, action) -> None:
- for item in self._sorted():
- action(item)
-
- def equals(self, other) -> bool:
- if isinstance(other, TreeSet):
- return self._data == other._data
- return False
-
- def hashCode(self) -> int:
- h = 0
- for v in self._data:
- h = (h + hash(v)) & 0x7FFFFFFF
- return h
-
- def toString(self) -> str:
- items = ", ".join(str(x) for x in self._sorted())
- return f"[{items}]"
-
- def __len__(self):
- return len(self._data)
-
- def __iter__(self):
- return iter(self._sorted())
-
- def __contains__(self, obj):
- return obj in self._data
-
- def __repr__(self):
- return self.toString()
-
- def __eq__(self, other):
- return self.equals(other)
-
-
-# ============================================================
-# Collections
-# ============================================================
-
-class Collections:
- """java.util.Collections — static utility methods"""
- EMPTY_LIST = []
- EMPTY_SET = set()
- EMPTY_MAP = {}
-
- @staticmethod
- def sort(data, key=None, reverse: bool = False) -> None:
- if key is not None:
- if isinstance(data, ArrayList):
- data._data.sort(key=key, reverse=reverse)
- elif isinstance(data, Vector):
- data._data.sort(key=key, reverse=reverse)
- else:
- data.sort(key=key, reverse=reverse)
- else:
- data.sort(reverse=reverse)
-
- @staticmethod
- def reverse(data) -> None:
- if isinstance(data, ArrayList):
- data._data.reverse()
- elif isinstance(data, Vector):
- data._data.reverse()
- else:
- data.reverse()
-
- @staticmethod
- def shuffle(data, rnd: _typing.Optional['Random'] = None) -> None:
- if isinstance(data, ArrayList):
- lst = data._data
- elif isinstance(data, Vector):
- lst = data._data
- else:
- lst = data
- if rnd:
- _py_random.shuffle(lst)
- else:
- _py_random.shuffle(lst)
-
- @staticmethod
- def swap(data, i: int, j: int) -> None:
- if isinstance(data, ArrayList):
- data._data[i], data._data[j] = data._data[j], data._data[i]
- elif isinstance(data, Vector):
- data._data[i], data._data[j] = data._data[j], data._data[i]
- else:
- data[i], data[j] = data[j], data[i]
-
- @staticmethod
- def fill(data, obj) -> None:
- if isinstance(data, ArrayList):
- for i in range(len(data._data)):
- data._data[i] = obj
- elif isinstance(data, Vector):
- for i in range(len(data._data)):
- data._data[i] = obj
- else:
- for i in range(len(data)):
- data[i] = obj
-
- @staticmethod
- def copy(dest, src) -> None:
- if isinstance(dest, ArrayList) and isinstance(src, ArrayList):
- dest._data[:len(src._data)] = src._data[:]
- elif isinstance(dest, Vector) and isinstance(src, Vector):
- dest._data[:len(src._data)] = src._data[:]
- else:
- dest[:len(src)] = src[:]
-
- @staticmethod
- def min(coll, comp=None):
- if comp:
- return min(coll, key=comp)
- return min(coll)
-
- @staticmethod
- def max(coll, comp=None):
- if comp:
- return max(coll, key=comp)
- return max(coll)
-
- @staticmethod
- def rotate(data, distance: int) -> None:
- if isinstance(data, ArrayList):
- lst = data._data
- elif isinstance(data, Vector):
- lst = data._data
- else:
- lst = data
- n = len(lst)
- if n == 0:
- return
- d = distance % n
- lst[:] = lst[-d:] + lst[:-d]
-
- @staticmethod
- def indexOfSubList(source, target) -> int:
- if isinstance(source, ArrayList):
- src = source._data
- else:
- src = list(source)
- if isinstance(target, ArrayList):
- tgt = target._data
- else:
- tgt = list(target)
- for i in range(len(src) - len(tgt) + 1):
- if src[i:i + len(tgt)] == tgt:
- return i
- return -1
-
- @staticmethod
- def lastIndexOfSubList(source, target) -> int:
- if isinstance(source, ArrayList):
- src = source._data
- else:
- src = list(source)
- if isinstance(target, ArrayList):
- tgt = target._data
- else:
- tgt = list(target)
- for i in range(len(src) - len(tgt), -1, -1):
- if src[i:i + len(tgt)] == tgt:
- return i
- return -1
-
- @staticmethod
- def replaceAll(data, old_val, new_val) -> bool:
- if isinstance(data, ArrayList):
- lst = data._data
- elif isinstance(data, Vector):
- lst = data._data
- else:
- lst = data
- found = False
- for i, v in enumerate(lst):
- if v == old_val:
- lst[i] = new_val
- found = True
- return found
-
- @staticmethod
- def binarySearch(data, key):
- if isinstance(data, ArrayList):
- lst = data._data
- else:
- lst = list(data)
- idx = _bisect.bisect_left(lst, key)
- if idx < len(lst) and lst[idx] == key:
- return idx
- return -1
-
- @staticmethod
- def disjoint(c1, c2) -> bool:
- set1 = set(c1)
- set2 = set(c2)
- return set1.isdisjoint(set2)
-
- @staticmethod
- def frequency(c, obj) -> int:
- count = 0
- for item in c:
- if item == obj:
- count += 1
- return count
-
- @staticmethod
- def nCopies(n: int, obj) -> list:
- return [obj] * n
-
- @staticmethod
- def singleton(obj) -> set:
- return {obj}
-
- @staticmethod
- def singletonList(obj) -> list:
- return [obj]
-
- @staticmethod
- def singletonMap(key, value) -> dict:
- return {key: value}
-
- @staticmethod
- def unmodifiableList(data) -> list:
- if isinstance(data, ArrayList):
- return tuple(data._data)
- return tuple(data)
-
- @staticmethod
- def unmodifiableSet(data) -> frozenset:
- if isinstance(data, HashSet):
- return frozenset(data._data)
- return frozenset(data)
-
- @staticmethod
- def unmodifiableMap(data) -> dict:
- if isinstance(data, HashMap):
- return dict(data._data)
- return dict(data)
-
- @staticmethod
- def synchronizedList(data):
- lock = _threading.Lock()
-
- class _SyncList:
- def __init__(self, lst):
- self._lock = lock
- self._lst = lst
-
- def __getattr__(self, name):
- with self._lock:
- return getattr(self._lst, name)
-
- def add(self, obj):
- with self._lock:
- return self._lst.add(obj)
-
- def get(self, idx):
- with self._lock:
- return self._lst[idx]
-
- def set(self, idx, val):
- with self._lock:
- old = self._lst[idx]
- self._lst[idx] = val
- return old
-
- def remove(self, obj):
- with self._lock:
- return self._lst.remove(obj)
-
- def size(self):
- with self._lock:
- return len(self._lst)
-
- def __len__(self):
- with self._lock:
- return len(self._lst)
-
- def __getitem__(self, idx):
- with self._lock:
- return self._lst[idx]
-
- def __setitem__(self, idx, val):
- with self._lock:
- self._lst[idx] = val
-
- def __iter__(self):
- with self._lock:
- return iter(list(self._lst))
-
- return _SyncList(data)
-
- @staticmethod
- def synchronizedSet(data):
- lock = _threading.Lock()
-
- class _SyncSet:
- def __init__(self, s):
- self._lock = lock
- self._s = s
-
- def add(self, obj):
- with self._lock:
- return self._s.add(obj)
-
- def remove(self, obj):
- with self._lock:
- return self._s.remove(obj)
-
- def __contains__(self, obj):
- with self._lock:
- return obj in self._s
-
- def __iter__(self):
- with self._lock:
- return iter(list(self._s))
-
- def __len__(self):
- with self._lock:
- return len(self._s)
-
- return _SyncSet(data)
-
- @staticmethod
- def synchronizedMap(data):
- lock = _threading.Lock()
-
- class _SyncMap:
- def __init__(self, m):
- self._lock = lock
- self._m = m
-
- def put(self, k, v):
- with self._lock:
- return self._m.put(k, v)
-
- def get(self, k):
- with self._lock:
- return self._m.get(k)
-
- def remove(self, k):
- with self._lock:
- return self._m.remove(k)
-
- def __getitem__(self, k):
- with self._lock:
- return self._m[k]
-
- def __setitem__(self, k, v):
- with self._lock:
- self._m[k] = v
-
- def __contains__(self, k):
- with self._lock:
- return k in self._m
-
- def __len__(self):
- with self._lock:
- return len(self._m)
-
- def keys(self):
- with self._lock:
- return list(self._m.keys())
-
- return _SyncMap(data)
-
- @staticmethod
- def enumaration(c) -> Enumeration:
- return Enumeration(c)
-
- @staticmethod
- def list(enum: Enumeration) -> ArrayList:
- items = []
- while enum.hasMoreElements():
- items.append(enum.nextElement())
- return ArrayList(items)
-
- @staticmethod
- def newSetFromMap(m) -> HashSet:
- class _SetFromMap(HashSet):
- def __init__(self, backing_map):
- super().__init__()
- self._backing = backing_map
-
- def add(self, obj):
- return self._backing.put(obj, True) is None
-
- def iterator(self):
- return Iterator(self._backing.keySet())
-
- def size(self):
- return self._backing.size()
-
- def remove(self, obj):
- return self._backing.remove(obj) is not None
-
- def contains(self, obj):
- return self._backing.containsKey(obj)
-
- def clear(self):
- self._backing.clear()
-
- return _SetFromMap(m)
-
- @staticmethod
- def asLifoQueue(deque) -> 'Collections._LifoQueue':
- class _LifoQueue:
- def __init__(self, dq):
- self._dq = dq
-
- def add(self, e):
- self._dq.addFirst(e)
- return True
-
- def offer(self, e):
- return self.add(e)
-
- def remove(self):
- if len(self._dq) == 0:
- raise NoSuchElementException()
- return self._dq.removeFirst()
-
- def poll(self):
- return self._dq.pollFirst()
-
- def element(self):
- if len(self._dq) == 0:
- raise NoSuchElementException()
- return self._dq.getFirst()
-
- def peek(self):
- return self._dq.peekFirst()
-
- def size(self):
- return self._dq.size()
-
- def isEmpty(self):
- return self._dq.isEmpty()
-
- return _LifoQueue(deque)
-
- @staticmethod
- def addAll(collection, *elements):
- for e in elements:
- collection.add(e)
- return len(elements) > 0
-
- @staticmethod
- def emptyList():
- return []
-
- @staticmethod
- def emptySet():
- return set()
-
- @staticmethod
- def emptyMap():
- return {}
-
- @staticmethod
- def reverseOrder(comparator=None):
- if comparator is None:
- return lambda a, b: -1 if a < b else (1 if a > b else 0)
- return lambda a, b: -comparator(a, b)
-
- @staticmethod
- def singletonSet(element):
- s = HashSet()
- s.add(element)
- return s
-
- @staticmethod
- def checkedList(lst, type_):
- return lst
-
- @staticmethod
- def checkedSet(s, type_):
- return s
-
- @staticmethod
- def checkedMap(m, keyType, valueType):
- return m
-
- @staticmethod
- def unmodifiableCollection(c):
- return c
-
- @staticmethod
- def unmodifiableQueue(q):
- return q
-
- @staticmethod
- def unmodifiableDeque(d):
- return d
-
-
-# ============================================================
-# Arrays
-# ============================================================
-
-class Arrays:
- """java.util.Arrays — static utility methods"""
- @staticmethod
- def asList(*args) -> ArrayList:
- if len(args) == 1 and isinstance(args[0], (list, tuple)):
- return ArrayList(args[0])
- return ArrayList(list(args))
-
- @staticmethod
- def sort(a, from_index: int = 0, to_index: int = None) -> None:
- if to_index is None:
- a.sort()
- else:
- a[from_index:to_index] = sorted(a[from_index:to_index])
-
- @staticmethod
- def parallelSort(a, from_index: int = 0, to_index: int = None) -> None:
- Arrays.sort(a, from_index, to_index)
-
- @staticmethod
- def binarySearch(a, key, from_index: int = 0, to_index: int = None) -> int:
- if to_index is None:
- lst = a
- else:
- lst = a[from_index:to_index]
- idx = _bisect.bisect_left(lst, key)
- if idx < len(lst) and lst[idx] == key:
- return idx + from_index
- return -(idx + from_index + 1)
-
- @staticmethod
- def fill(a, val, from_index: int = 0, to_index: int = None) -> None:
- if to_index is None:
- for i in range(len(a)):
- a[i] = val
- else:
- for i in range(from_index, to_index):
- a[i] = val
-
- @staticmethod
- def copyOf(original, new_length: int) -> list:
- return list(original[:new_length]) + [None] * max(0, new_length - len(original))
-
- @staticmethod
- def copyOfRange(original, from_index: int, to_index: int) -> list:
- return list(original[from_index:to_index])
-
- @staticmethod
- def equals(a, b) -> bool:
- if len(a) != len(b):
- return False
- return all(x == y for x, y in zip(a, b))
-
- @staticmethod
- def deepEquals(a, b) -> bool:
- if len(a) != len(b):
- return False
- return all(_deep_eq(x, y) for x, y in zip(a, b))
-
- @staticmethod
- def hashCode(a) -> int:
- if a is None:
- return 0
- h = 1
- for v in a:
- h = (31 * h + hash(v)) & 0x7FFFFFFF
- return h
-
- @staticmethod
- def deepHashCode(a) -> int:
- if a is None:
- return 0
- h = 1
- for v in a:
- if isinstance(v, (list, tuple)):
- h = (31 * h + Arrays.deepHashCode(v)) & 0x7FFFFFFF
- else:
- h = (31 * h + hash(v)) & 0x7FFFFFFF
- return h
-
- @staticmethod
- def toString(a) -> str:
- if a is None:
- return "null"
- return "[" + ", ".join(str(x) for x in a) + "]"
-
- @staticmethod
- def deepToString(a) -> str:
- if a is None:
- return "null"
- return "[" + ", ".join(_deep_str(x) for x in a) + "]"
-
- @staticmethod
- def stream(a) -> 'Arrays._ArrayStream':
- class _ArrayStream:
- def __init__(self, arr):
- self._arr = arr
- self._idx = 0
-
- def filter(self, pred):
- return _ArrayStream([x for x in self._arr if pred(x)])
-
- def map(self, func):
- return _ArrayStream([func(x) for x in self._arr])
-
- def forEach(self, action):
- for x in self._arr:
- action(x)
-
- def toArray(self):
- return list(self._arr)
-
- def count(self):
- return len(self._arr)
-
- return _ArrayStream(a)
-
- @staticmethod
- def setAll(a, generator) -> None:
- for i in range(len(a)):
- a[i] = generator(i)
-
- @staticmethod
- def parallelSetAll(a, generator) -> None:
- Arrays.setAll(a, generator)
-
- @staticmethod
- def spliterator(a) -> Iterator:
- return Iterator(a)
-
-
-def _deep_eq(x, y) -> bool:
- if isinstance(x, (list, tuple)) and isinstance(y, (list, tuple)):
- return Arrays.deepEquals(x, y)
- return x == y
-
-
-def _deep_str(x) -> str:
- if isinstance(x, (list, tuple)):
- return Arrays.deepToString(x)
- return str(x)
-
-
-# ============================================================
-# Date
-# ============================================================
-
-class Date(Stub):
- """java.util.Date — wraps Python datetime"""
- def __init__(self, *args):
- super().__init__()
- if len(args) == 0:
- self._dt = _datetime.datetime.now()
- elif len(args) == 1:
- if isinstance(args[0], (int, float)):
- self._dt = _datetime.datetime.fromtimestamp(args[0] / 1000.0)
- elif isinstance(args[0], str):
- self._dt = _datetime.datetime.fromisoformat(args[0])
- elif isinstance(args[0], _datetime.datetime):
- self._dt = args[0]
- elif isinstance(args[0], Date):
- self._dt = args[0]._dt
- else:
- self._dt = _datetime.datetime.now()
- elif len(args) >= 6:
- year = args[0] - 1900
- month = args[1]
- day = args[2]
- hour = args[3] if len(args) > 3 else 0
- minute = args[4] if len(args) > 4 else 0
- second = args[5] if len(args) > 5 else 0
- self._dt = _datetime.datetime(year + 1900, month + 1, day, hour, minute, second)
- else:
- self._dt = _datetime.datetime.now()
-
- def getTime(self) -> int:
- return int(self._dt.timestamp() * 1000)
-
- def setTime(self, time_millis: int) -> None:
- self._dt = _datetime.datetime.fromtimestamp(time_millis / 1000.0)
-
- def before(self, when: 'Date') -> bool:
- return self._dt < when._dt
-
- def after(self, when: 'Date') -> bool:
- return self._dt > when._dt
-
- def compareTo(self, another: 'Date') -> int:
- return (self._dt > another._dt) - (self._dt < another._dt)
-
- def equals(self, other) -> bool:
- if isinstance(other, Date):
- return self._dt == other._dt
- return False
-
- def hashCode(self) -> int:
- return hash(self._dt) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return self._dt.strftime("%a %b %d %H:%M:%S %z %Y")
-
- def clone(self) -> 'Date':
- return Date(self._dt)
-
- def getYear(self) -> int:
- return self._dt.year - 1900
-
- def getMonth(self) -> int:
- return self._dt.month - 1
-
- def getDay(self) -> int:
- return self._dt.weekday()
-
- def getHours(self) -> int:
- return self._dt.hour
-
- def getMinutes(self) -> int:
- return self._dt.minute
-
- def getSeconds(self) -> int:
- return self._dt.second
-
- def getDate(self) -> int:
- return self._dt.day
-
- def setYear(self, year: int) -> None:
- self._dt = self._dt.replace(year=year + 1900)
-
- def setMonth(self, month: int) -> None:
- self._dt = self._dt.replace(month=month + 1)
-
- def setDate(self, date: int) -> None:
- self._dt = self._dt.replace(day=date)
-
- def setHours(self, hours: int) -> None:
- self._dt = self._dt.replace(hour=hours)
-
- def setMinutes(self, minutes: int) -> None:
- self._dt = self._dt.replace(minute=minutes)
-
- def setSeconds(self, seconds: int) -> None:
- self._dt = self._dt.replace(second=seconds)
-
- def toGMTString(self) -> str:
- return self._dt.strftime("%d %b %Y %H:%M:%S GMT")
-
- def toLocaleString(self) -> str:
- return self._dt.strftime("%Y-%m-%d %H:%M:%S")
-
- @staticmethod
- def parse(s: str) -> 'Date':
- try:
- return Date(_datetime.datetime.fromisoformat(s))
- except ValueError:
- return Date()
-
- @staticmethod
- def fromInstant(instant) -> 'Date':
- return Date(instant.toEpochMilli())
-
- def toInstant(self):
- return self._dt
-
- def __str__(self):
- return self.toString()
-
- def __repr__(self):
- return f"Date({self.getTime()})"
-
-
-# ============================================================
-# Calendar / GregorianCalendar
-# ============================================================
-
-class Calendar(Stub):
- """java.util.Calendar — wraps Python datetime with Java field system"""
- # Field constants
- YEAR = 1
- MONTH = 2
- DAY_OF_MONTH = 5
- DAY_OF_YEAR = 6
- DAY_OF_WEEK = 7
- DAY_OF_WEEK_IN_MONTH = 8
- AM_PM = 9
- HOUR = 10
- HOUR_OF_DAY = 11
- MINUTE = 12
- SECOND = 13
- MILLISECOND = 14
- WEEK_OF_MONTH = 15
- WEEK_OF_YEAR = 16
- ERA = 17
- ZONE_OFFSET = 18
- DST_OFFSET = 19
- FIELD_COUNT = 20
-
- # Day of week constants
- SUNDAY = 1
- MONDAY = 2
- TUESDAY = 3
- WEDNESDAY = 4
- THURSDAY = 5
- FRIDAY = 6
- SATURDAY = 7
-
- # Month constants
- JANUARY = 0
- FEBRUARY = 1
- MARCH = 2
- APRIL = 3
- MAY = 4
- JUNE = 5
- JULY = 6
- AUGUST = 7
- SEPTEMBER = 8
- OCTOBER = 9
- NOVEMBER = 10
- DECEMBER = 11
- UNDECIMBER = 12
-
- # AM/PM
- AM = 0
- PM = 1
-
- def __init__(self):
- super().__init__()
- self._dt = _datetime.datetime.now()
- self._fields: Dict[int, int] = {}
- self._is_set: Dict[int, bool] = {}
- self._lenient = True
- self._first_day_of_week = Calendar.SUNDAY
- self._minimal_days_in_first_week = 1
- self._timezone = _datetime.timezone.utc
- self._set_fields_from_dt()
-
- def _set_fields_from_dt(self) -> None:
- self._fields[Calendar.YEAR] = self._dt.year
- self._fields[Calendar.MONTH] = self._dt.month - 1
- self._fields[Calendar.DAY_OF_MONTH] = self._dt.day
- self._fields[Calendar.DAY_OF_YEAR] = self._dt.timetuple().tm_yday
- self._fields[Calendar.DAY_OF_WEEK] = self._dt.isoweekday() % 7 + 1
- self._fields[Calendar.HOUR] = self._dt.hour % 12
- self._fields[Calendar.HOUR_OF_DAY] = self._dt.hour
- self._fields[Calendar.MINUTE] = self._dt.minute
- self._fields[Calendar.SECOND] = self._dt.second
- self._fields[Calendar.MILLISECOND] = self._dt.microsecond // 1000
- self._fields[Calendar.AM_PM] = Calendar.AM if self._dt.hour < 12 else Calendar.PM
- self._fields[Calendar.WEEK_OF_YEAR] = self._dt.isocalendar()[1]
- self._fields[Calendar.ERA] = 1 # AD = 1
-
- def get(self, field: int) -> int:
- return self._fields.get(field, 0)
-
- def set(self, field: int, value: int) -> None:
- self._fields[field] = value
- self._is_set[field] = True
-
- def setTime(self, date: 'Date') -> None:
- self._dt = date._dt
- self._set_fields_from_dt()
-
- def getTime(self) -> Date:
- return Date(self._dt)
-
- def getTimeInMillis(self) -> int:
- return int(self._dt.timestamp() * 1000)
-
- def setTimeInMillis(self, millis: int) -> None:
- self._dt = _datetime.datetime.fromtimestamp(millis / 1000.0)
- self._set_fields_from_dt()
-
- def add(self, field: int, amount: int) -> None:
- if field == Calendar.YEAR:
- self._dt = self._dt.replace(year=self._dt.year + amount)
- elif field == Calendar.MONTH:
- new_month = self._dt.month - 1 + amount
- new_year = self._dt.year + new_month // 12
- new_month = new_month % 12
- try:
- self._dt = self._dt.replace(year=new_year, month=new_month + 1)
- except ValueError:
- self._dt = self._dt.replace(year=new_year, month=new_month + 1, day=28)
- elif field == Calendar.DAY_OF_MONTH:
- self._dt += _datetime.timedelta(days=amount)
- elif field == Calendar.HOUR_OF_DAY or field == Calendar.HOUR:
- self._dt += _datetime.timedelta(hours=amount)
- elif field == Calendar.MINUTE:
- self._dt += _datetime.timedelta(minutes=amount)
- elif field == Calendar.SECOND:
- self._dt += _datetime.timedelta(seconds=amount)
- elif field == Calendar.MILLISECOND:
- self._dt += _datetime.timedelta(milliseconds=amount)
- elif field == Calendar.WEEK_OF_YEAR or field == Calendar.WEEK_OF_MONTH:
- self._dt += _datetime.timedelta(weeks=amount)
- self._set_fields_from_dt()
-
- def roll(self, field: int, amount: int) -> None:
- if field == Calendar.MONTH:
- old_month = self._dt.month
- new_month = ((old_month - 1 + amount) % 12) + 1
- try:
- self._dt = self._dt.replace(month=new_month)
- except ValueError:
- self._dt = self._dt.replace(month=new_month, day=28)
- elif field == Calendar.DAY_OF_MONTH:
- import calendar as _cal
- max_day = _cal.monthrange(self._dt.year, self._dt.month)[1]
- new_day = ((self._dt.day - 1 + amount) % max_day) + 1
- self._dt = self._dt.replace(day=new_day)
- else:
- self.add(field, amount)
- self._set_fields_from_dt()
-
- def before(self, when: 'Calendar') -> bool:
- return self._dt < when._dt
-
- def after(self, when: 'Calendar') -> bool:
- return self._dt > when._dt
-
- def compareTo(self, another: 'Calendar') -> int:
- return (self._dt > another._dt) - (self._dt < another._dt)
-
- def equals(self, other) -> bool:
- if isinstance(other, Calendar):
- return self._dt == other._dt
- return False
-
- def hashCode(self) -> int:
- return hash(self._dt) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return str(self._dt)
-
- def isLenient(self) -> bool:
- return self._lenient
-
- def setLenient(self, lenient: bool) -> None:
- self._lenient = lenient
-
- def getFirstDayOfWeek(self) -> int:
- return self._first_day_of_week
-
- def setFirstDayOfWeek(self, value: int) -> None:
- self._first_day_of_week = value
-
- def getMinimalDaysInFirstWeek(self) -> int:
- return self._minimal_days_in_first_week
-
- def setMinimalDaysInFirstWeek(self, value: int) -> None:
- self._minimal_days_in_first_week = value
-
- def getActualMaximum(self, field: int) -> int:
- import calendar as _cal
- if field == Calendar.DAY_OF_MONTH:
- return _cal.monthrange(self._dt.year, self._dt.month)[1]
- if field == Calendar.DAY_OF_YEAR:
- return 366 if self._dt.year % 4 == 0 and (self._dt.year % 100 != 0 or self._dt.year % 400 == 0) else 365
- if field == Calendar.MONTH:
- return 11
- if field == Calendar.HOUR:
- return 11
- if field == Calendar.HOUR_OF_DAY:
- return 23
- if field == Calendar.MINUTE:
- return 59
- if field == Calendar.SECOND:
- return 59
- if field == Calendar.MILLISECOND:
- return 999
- return 0
-
- def getActualMinimum(self, field: int) -> int:
- return 0
-
- def getDisplayName(self, field: int, style: int, locale: 'Locale') -> str:
- return str(self.get(field))
-
- @staticmethod
- def getInstance() -> 'GregorianCalendar':
- return GregorianCalendar()
-
- def clear(self, field=None):
- if field is None:
- self._fields = {}
- else:
- if field in self._fields:
- del self._fields[field]
-
- def isSet(self, field):
- return field in self._fields
-
- def getCalendarType(self):
- return "gregory"
-
- @staticmethod
- def getAvailableLocales():
- from .util import Locale
- return [Locale.US, Locale.CHINA, Locale.JAPAN, Locale.KOREA, Locale.GERMANY, Locale.FRANCE]
-
- def toInstant(self):
- from .time import Instant
- return Instant.ofEpochMilli(self.getTimeInMillis())
-
- def getWeekYear(self):
- return self.get(Calendar.YEAR)
-
- def isWeekDateSupported(self):
- return False
-
- def getWeeksInWeekYear(self):
- return 52
-
-
-class GregorianCalendar(Calendar):
- """java.util.GregorianCalendar"""
- BC = 0
- AD = 1
-
- def __init__(self, *args):
- super().__init__()
- if len(args) == 0:
- self._dt = _datetime.datetime.now()
- elif len(args) == 3:
- year, month, day = args
- self._dt = _datetime.datetime(year, month + 1, day)
- elif len(args) >= 5:
- year, month, day, hour, minute = args[:5]
- second = args[5] if len(args) > 5 else 0
- self._dt = _datetime.datetime(year, month + 1, day, hour, minute, second)
- else:
- self._dt = _datetime.datetime.now()
- self._set_fields_from_dt()
-
- def isLeapYear(self, year: int) -> bool:
- return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0
-
- def getGreatestMinimum(self, field: int) -> int:
- return self.getActualMinimum(field)
-
- def getLeastMaximum(self, field: int) -> int:
- return self.getActualMaximum(field)
-
- def getMaximum(self, field: int) -> int:
- if field == Calendar.DAY_OF_MONTH:
- return 31
- if field == Calendar.DAY_OF_YEAR:
- return 366
- if field == Calendar.MONTH:
- return 11
- return self.getActualMaximum(field)
-
- def getMinimum(self, field: int) -> int:
- return 0
-
-
-# ============================================================
-# UUID
-# ============================================================
-
-class UUID(Stub):
- """java.util.UUID — wraps Python uuid module"""
- def __init__(self, most_sig_bits: int, least_sig_bits: int):
- super().__init__()
- self._most_sig_bits = most_sig_bits & 0xFFFFFFFFFFFFFFFF
- self._least_sig_bits = least_sig_bits & 0xFFFFFFFFFFFFFFFF
- # Rebuild a Python UUID from the bits for string representation
- hex_str = f"{self._most_sig_bits:016x}{self._least_sig_bits:016x}"
- self._uuid = _uuid.UUID(hex_str)
-
- @staticmethod
- def randomUUID() -> 'UUID':
- u = _uuid.uuid4()
- most = u.int >> 64
- least = u.int & 0xFFFFFFFFFFFFFFFF
- return UUID(most, least)
-
- @staticmethod
- def nameUUIDFromBytes(name: bytes) -> 'UUID':
- u = _uuid.uuid3(_uuid.NAMESPACE_DNS, name.decode('utf-8', errors='replace'))
- most = u.int >> 64
- least = u.int & 0xFFFFFFFFFFFFFFFF
- return UUID(most, least)
-
- @staticmethod
- def fromString(name: str) -> 'UUID':
- u = _uuid.UUID(name)
- most = u.int >> 64
- least = u.int & 0xFFFFFFFFFFFFFFFF
- return UUID(most, least)
-
- def getMostSignificantBits(self) -> int:
- return self._most_sig_bits
-
- def getLeastSignificantBits(self) -> int:
- return self._least_sig_bits
-
- def version(self) -> int:
- return self._uuid.version
-
- def variant(self) -> int:
- return self._uuid.variant
-
- def timestamp(self) -> int:
- if self.version() != 1:
- raise UnsupportedOperationException("Not a time-based UUID")
- return self._uuid.time
-
- def clockSequence(self) -> int:
- if self.version() != 1:
- raise UnsupportedOperationException("Not a time-based UUID")
- return self._uuid.clock_seq
-
- def node(self) -> int:
- if self.version() != 1:
- raise UnsupportedOperationException("Not a time-based UUID")
- return self._uuid.node
-
- def compareTo(self, other: 'UUID') -> int:
- return (self._uuid.int > other._uuid.int) - (self._uuid.int < other._uuid.int)
-
- def equals(self, other) -> bool:
- if isinstance(other, UUID):
- return self._uuid == other._uuid
- return False
-
- def hashCode(self) -> int:
- return hash(self._uuid) & 0x7FFFFFFF
-
- def toString(self) -> str:
- return str(self._uuid)
-
- def __str__(self):
- return str(self._uuid)
-
- def __repr__(self):
- return f"UUID({str(self._uuid)})"
-
-
-# ============================================================
-# StringTokenizer
-# ============================================================
-
-class StringTokenizer(Stub):
- """java.util.StringTokenizer — simple tokenizer"""
- def __init__(self, s: str, delim: str = " \t\n\r\f", return_delims: bool = False):
- super().__init__()
- self._str = str(s)
- self._delim = delim
- self._return_delims = return_delims
- self._tokens = self._tokenize()
- self._index = 0
-
- def _tokenize(self):
- if self._return_delims:
- tokens = []
- buf = ""
- for ch in self._str:
- if ch in self._delim:
- if buf:
- tokens.append(buf)
- buf = ""
- tokens.append(ch)
- else:
- buf += ch
- if buf:
- tokens.append(buf)
- return tokens
- import re as _re
- pattern = f"[{_re.escape(self._delim)}]+"
- return [t for t in _re.split(pattern, self._str) if t]
-
- def countTokens(self) -> int:
- return len(self._tokens)
-
- def hasMoreTokens(self) -> bool:
- return self._index < len(self._tokens)
-
- def nextToken(self, delim: str = None) -> str:
- if delim is not None:
- self._delim = delim
- remaining = self._str[self._index:]
- st = StringTokenizer(remaining, delim, self._return_delims)
- self._tokens = st._tokens
- self._index = 0
- if not self.hasMoreTokens():
- raise NoSuchElementException()
- tok = self._tokens[self._index]
- self._index += 1
- return tok
-
- def hasMoreElements(self) -> bool:
- return self.hasMoreTokens()
-
- def nextElement(self):
- return self.nextToken()
-
- def __iter__(self):
- return self
-
- def __next__(self):
- if not self.hasMoreTokens():
- raise StopIteration
- return self.nextToken()
-
-
-# ============================================================
-# Optional
-# ============================================================
-
-class Optional(Stub):
- """java.util.Optional — wraps value or None"""
- def __init__(self, value=None):
- super().__init__()
- self._value = value
-
- @staticmethod
- def empty() -> 'Optional':
- return Optional(None)
-
- @staticmethod
- def of(value) -> 'Optional':
- if value is None:
- raise TypeError("value is null")
- return Optional(value)
-
- @staticmethod
- def ofNullable(value) -> 'Optional':
- return Optional(value)
-
- def get(self):
- if self._value is None:
- raise NoSuchElementException("No value present")
- return self._value
-
- def isPresent(self) -> bool:
- return self._value is not None
-
- def isEmpty(self) -> bool:
- return self._value is None
-
- def ifPresent(self, consumer) -> None:
- if self._value is not None:
- consumer(self._value)
-
- def ifPresentOrElse(self, action, empty_action) -> None:
- if self._value is not None:
- action(self._value)
- else:
- empty_action()
-
- def filter(self, predicate) -> 'Optional':
- if self._value is None:
- return self
- return Optional.ofNullable(self._value) if predicate(self._value) else Optional.empty()
-
- def map(self, mapper) -> 'Optional':
- if self._value is None:
- return Optional.empty()
- return Optional.ofNullable(mapper(self._value))
-
- def flatMap(self, mapper) -> 'Optional':
- if self._value is None:
- return Optional.empty()
- return mapper(self._value)
-
- def orElse(self, other):
- return self._value if self._value is not None else other
-
- def orElseGet(self, supplier):
- if self._value is not None:
- return self._value
- return supplier()
-
- def orElseThrow(self, exception_supplier=None):
- if self._value is not None:
- return self._value
- if exception_supplier:
- raise exception_supplier()
- raise NoSuchElementException("No value present")
-
- def stream(self):
- if self._value is not None:
- return [self._value]
- return []
-
- def equals(self, other) -> bool:
- if isinstance(other, Optional):
- return self._value == other._value
- return False
-
- def hashCode(self) -> int:
- return hash(self._value) & 0x7FFFFFFF if self._value is not None else 0
-
- def toString(self) -> str:
- if self._value is None:
- return "Optional.empty"
- return f"Optional[{self._value}]"
-
- def __str__(self):
- return self.toString()
-
- def __repr__(self):
- return self.toString()
-
- def __bool__(self):
- return self._value is not None
-
-
-# ============================================================
-# Random
-# ============================================================
-
-class Random(Stub):
- """java.util.Random — wraps Python random module"""
- def __init__(self, seed: _typing.Optional[int] = None):
- super().__init__()
- self._rng = _py_random.Random(seed)
-
- def setSeed(self, seed: int) -> None:
- self._rng.seed(seed)
-
- def nextInt(self, bound: _typing.Optional[int] = None) -> int:
- if bound is None:
- return self._rng.randint(-2147483648, 2147483647)
- if bound <= 0:
- raise IllegalArgumentException("bound must be positive")
- return self._rng.randrange(0, bound)
-
- def nextLong(self) -> int:
- return (self._rng.randint(-2147483648, 2147483647) << 32) | self._rng.randint(0, 0xFFFFFFFF)
-
- def nextBoolean(self) -> bool:
- return self._rng.random() < 0.5
-
- def nextFloat(self) -> float:
- return self._rng.random()
-
- def nextDouble(self) -> float:
- return self._rng.random()
-
- def nextGaussian(self) -> float:
- return self._rng.gauss(0.0, 1.0)
-
- def nextBytes(self, bytes_arr: bytearray) -> None:
- for i in range(len(bytes_arr)):
- bytes_arr[i] = self._rng.randint(0, 255)
-
- def next(self, bits: int) -> int:
- return self._rng.getrandbits(bits) & ((1 << bits) - 1)
-
- @staticmethod
- def create() -> 'Random':
- return Random()
-
-
-# ============================================================
-# Properties
-# ============================================================
-
-class Properties(HashMap):
- """java.util.Properties — extends Hashtable-like dict with load/store"""
- def __init__(self, defaults: 'Properties' = None):
- super().__init__()
- self._defaults = defaults
-
- def setProperty(self, key: str, value: str) -> None:
- self.put(str(key), str(value))
-
- def getProperty(self, key: str, default_value: str = None) -> _typing.Optional[str]:
- val = self._data.get(str(key))
- if val is not None:
- return str(val)
- if self._defaults is not None:
- return self._defaults.getProperty(key, default_value)
- return default_value
-
- def load(self, in_stream) -> None:
- if isinstance(in_stream, (str, bytes)):
- lines = in_stream.splitlines() if isinstance(in_stream, str) else in_stream.decode('utf-8').splitlines()
- else:
- lines = in_stream.read().splitlines() if hasattr(in_stream, 'read') else in_stream.splitlines()
- for line in lines:
- line = line.strip()
- if not line or line.startswith('#') or line.startswith('!'):
- continue
- if '=' in line:
- key, val = line.split('=', 1)
- elif ':' in line:
- key, val = line.split(':', 1)
- else:
- key = line
- val = ""
- key = key.strip()
- val = val.strip()
- self._data[key] = val
-
- def store(self, out_stream, comments: str = None) -> None:
- lines = []
- if comments:
- lines.append(f"#{comments}")
- lines.append(f"# {_datetime.datetime.now().isoformat()}")
- for k, v in self._data.items():
- escaped_val = str(v).replace("\\", "\\\\").replace(" ", "\\ ")
- lines.append(f"{k}={escaped_val}")
- content = "\n".join(lines) + "\n"
- if isinstance(out_stream, _io.IOBase):
- out_stream.write(content)
- else:
- out_stream.write(content) # type: ignore
-
- def list(self, out_stream) -> None:
- for k, v in self._data.items():
- out_stream.write(f"{k}={v}\n")
-
- def propertyNames(self):
- return Iterator(self._data.keys())
-
- def stringPropertyNames(self) -> set:
- names = set()
- for k in self._data.keys():
- if isinstance(k, str):
- names.add(k)
- if self._defaults:
- names.update(self._defaults.stringPropertyNames())
- return names
-
- def loadFromXML(self, in_stream) -> None:
- import xml.etree.ElementTree as _ET
- tree = _ET.parse(in_stream)
- root = tree.getroot()
- for entry in root.findall('entry'):
- key = entry.get('key', '')
- self._data[key] = entry.text or ''
-
- def storeToXML(self, out_stream, comment: str = None) -> None:
- import xml.etree.ElementTree as _ET
- root = _ET.Element('properties')
- if comment:
- c = _ET.SubElement(root, 'comment')
- c.text = comment
- for k, v in self._data.items():
- entry = _ET.SubElement(root, 'entry')
- entry.set('key', str(k))
- entry.text = str(v)
- tree = _ET.ElementTree(root)
- tree.write(out_stream, xml_declaration=True, encoding='UTF-8')
-
- def get(self, key):
- val = self._data.get(key)
- if val is not None:
- return val
- return self._defaults.get(key) if self._defaults else None
-
- def put(self, key, value):
- return super().put(str(key), str(value))
-
- def toString(self) -> str:
- items = ", ".join(f"{k}={v}" for k, v in self._data.items())
- return f"{{{items}}}"
-
-
-# ============================================================
-# EnumSet
-# ============================================================
-
-class EnumSet(HashSet):
- """java.util.EnumSet — simple implementation using set"""
- def __init__(self, c=None):
- super().__init__()
- self._element_type = None
- if c is not None:
- if isinstance(c, EnumSet):
- self._data = set(c._data)
- self._element_type = c._element_type
- elif isinstance(c, type):
- self._element_type = c
- elif isinstance(c, _IterableABC):
- for item in c:
- self._data.add(item)
- if self._element_type is None:
- self._element_type = item.__class__
-
- @staticmethod
- def allOf(element_type) -> 'EnumSet':
- es = EnumSet()
- es._element_type = element_type
- if hasattr(element_type, '_values'):
- for v in element_type._values():
- es._data.add(v)
- elif hasattr(element_type, '__members__'):
- for name, member in element_type.__members__.items():
- es._data.add(member)
- return es
-
- @staticmethod
- def noneOf(element_type) -> 'EnumSet':
- es = EnumSet()
- es._element_type = element_type
- return es
-
- @staticmethod
- def range(element_type, from_val, to_val) -> 'EnumSet':
- es = EnumSet()
- es._element_type = element_type
- started = False
- if hasattr(element_type, '_values'):
- for v in element_type._values():
- if v == from_val:
- started = True
- if started:
- es._data.add(v)
- if v == to_val:
- break
- elif hasattr(element_type, '__members__'):
- for name, member in element_type.__members__.items():
- if member == from_val:
- started = True
- if started:
- es._data.add(member)
- if member == to_val:
- break
- return es
-
- @staticmethod
- def copyOf(es) -> 'EnumSet':
- return EnumSet(es)
-
- def complementOf(self, other: 'EnumSet') -> 'EnumSet':
- result = EnumSet.noneOf(self._element_type)
- if self._element_type and hasattr(self._element_type, '_values'):
- for v in self._element_type._values():
- if v not in other._data:
- result._data.add(v)
- return result
-
-
-# ============================================================
-# EnumMap
-# ============================================================
-
-class EnumMap(HashMap):
- """java.util.EnumMap — simple implementation using dict"""
- def __init__(self, key_type=None, m=None):
- super().__init__()
- self._key_type = key_type
- if m is not None:
- if isinstance(m, EnumMap):
- self._data.update(m._data)
- self._key_type = m._key_type
- elif isinstance(m, dict):
- self._data.update(m)
- else:
- for k, v in m.items():
- self._data[k] = v
-
- def put(self, key, value):
- if self._key_type is None:
- self._key_type = key.__class__
- return super().put(key, value)
-
- def keySet(self):
- return set(self._data.keys())
-
-
-# ============================================================
-# Objects
-# ============================================================
-
-class Objects:
- """java.util.Objects — static helper methods"""
- @staticmethod
- def equals(a, b) -> bool:
- return a == b
-
- @staticmethod
- def deepEquals(a, b) -> bool:
- return _deep_eq(a, b)
-
- @staticmethod
- def hashCode(o) -> int:
- return 0 if o is None else (hash(o) & 0x7FFFFFFF)
-
- @staticmethod
- def hash(*values) -> int:
- return Arrays.hashCode(values)
-
- @staticmethod
- def toString(o, null_default: str = "null") -> str:
- if o is None:
- return null_default
- return str(o)
-
- @staticmethod
- def compare(a, b, cmp) -> int:
- if cmp:
- return cmp(a, b)
- return (a > b) - (a < b)
-
- @staticmethod
- def requireNonNull(obj, message: Any = None):
- if obj is None:
- if message is None:
- raise TypeError("null")
- raise TypeError(str(message) if not callable(message) else message.get())
- return obj
-
- @staticmethod
- def nonNull(obj) -> bool:
- return obj is not None
-
- @staticmethod
- def isNull(obj) -> bool:
- return obj is None
-
- @staticmethod
- def requireNonNullElse(obj, default):
- return obj if obj is not None else default
-
- @staticmethod
- def requireNonNullElseGet(obj, supplier):
- return obj if obj is not None else supplier()
-
- @staticmethod
- def checkIndex(index: int, length: int) -> int:
- if index < 0 or index >= length:
- raise IndexError(f"Index {index} out of bounds [0, {length})")
- return index
-
- @staticmethod
- def checkFromToIndex(from_index: int, to_index: int, length: int) -> int:
- if from_index < 0 or from_index > to_index or to_index > length:
- raise IndexError(f"Range [{from_index}, {to_index}) out of bounds [0, {length})")
- return from_index
-
- @staticmethod
- def checkFromIndexSize(from_index: int, size: int, length: int) -> int:
- if from_index < 0 or size < 0 or from_index + size > length:
- raise IndexError(f"Range [{from_index}, {from_index + size}) out of bounds [0, {length})")
- return from_index
-
-
-# ============================================================
-# Locale
-# ============================================================
-
-class Locale(Stub):
- """java.util.Locale — basic locale representation"""
- ENGLISH = None
- FRENCH = None
- GERMAN = None
- ITALIAN = None
- JAPANESE = None
- KOREAN = None
- CHINESE = None
- SIMPLIFIED_CHINESE = None
- TRADITIONAL_CHINESE = None
- FRANCE = None
- GERMANY = None
- ITALY = None
- JAPAN = None
- KOREA = None
- CHINA = None
- UK = None
- US = None
- CANADA = None
- CANADA_FRENCH = None
- ROOT = None
-
- def __init__(self, language: str = "", country: str = "", variant: str = ""):
- super().__init__()
- self._language = language
- self._country = country
- self._variant = variant
-
- @staticmethod
- def getDefault() -> 'Locale':
- return Locale("en", "US")
-
- @staticmethod
- def setDefault(locale: 'Locale') -> None:
- pass
-
- def getLanguage(self) -> str:
- return self._language
-
- def getCountry(self) -> str:
- return self._country
-
- def getVariant(self) -> str:
- return self._variant
-
- def getDisplayLanguage(self, locale: 'Locale' = None) -> str:
- return self._language
-
- def getDisplayCountry(self, locale: 'Locale' = None) -> str:
- return self._country
-
- def getDisplayName(self, locale: 'Locale' = None) -> str:
- parts = [self._language]
- if self._country:
- parts.append(self._country)
- if self._variant:
- parts.append(self._variant)
- return "_".join(parts)
-
- def toString(self) -> str:
- return self.getDisplayName()
-
- def toLanguageTag(self) -> str:
- tag = self._language
- if self._country:
- tag += "-" + self._country
- if self._variant:
- tag += "-" + self._variant
- return tag
-
- @staticmethod
- def forLanguageTag(tag: str) -> 'Locale':
- parts = tag.replace("-", "_").split("_")
- lang = parts[0] if len(parts) > 0 else ""
- country = parts[1] if len(parts) > 1 else ""
- variant = parts[2] if len(parts) > 2 else ""
- return Locale(lang, country, variant)
-
- def equals(self, other) -> bool:
- if isinstance(other, Locale):
- return (self._language == other._language and
- self._country == other._country and
- self._variant == other._variant)
- return False
-
- def hashCode(self) -> int:
- return hash((self._language, self._country, self._variant)) & 0x7FFFFFFF
-
-
-# Initialize Locale constants
-Locale.ENGLISH = Locale("en")
-Locale.FRENCH = Locale("fr")
-Locale.GERMAN = Locale("de")
-Locale.ITALIAN = Locale("it")
-Locale.JAPANESE = Locale("ja")
-Locale.KOREAN = Locale("ko")
-Locale.CHINESE = Locale("zh")
-Locale.SIMPLIFIED_CHINESE = Locale("zh", "CN")
-Locale.TRADITIONAL_CHINESE = Locale("zh", "TW")
-Locale.FRANCE = Locale("fr", "FR")
-Locale.GERMANY = Locale("de", "DE")
-Locale.ITALY = Locale("it", "IT")
-Locale.JAPAN = Locale("ja", "JP")
-Locale.KOREA = Locale("ko", "KR")
-Locale.CHINA = Locale("zh", "CN")
-Locale.UK = Locale("en", "GB")
-Locale.US = Locale("en", "US")
-Locale.CANADA = Locale("en", "CA")
-Locale.CANADA_FRENCH = Locale("fr", "CA")
-Locale.ROOT = Locale("", "")
-
-
-# ============================================================
-# BitSet
-# ============================================================
-
-class BitSet(Stub):
- """java.util.BitSet — bit manipulation"""
- def __init__(self, nbits: int = 0):
- super().__init__()
- if isinstance(nbits, int):
- self._bits = 0
- elif isinstance(nbits, BitSet):
- self._bits = nbits._bits
- else:
- self._bits = 0
-
- def _check(self, bit_index: int) -> None:
- if bit_index < 0:
- raise IndexError(f"bitIndex < 0: {bit_index}")
-
- def get(self, bit_index: int) -> bool:
- self._check(bit_index)
- return bool((self._bits >> bit_index) & 1)
-
- def getRange(self, from_index: int, to_index: int) -> 'BitSet':
- self._check(from_index)
- mask = ((1 << (to_index - from_index)) - 1) << from_index
- result = BitSet()
- result._bits = (self._bits & mask) >> from_index
- return result
-
- def set(self, bit_index: int, value: bool = True) -> None:
- self._check(bit_index)
- if value:
- self._bits |= (1 << bit_index)
- else:
- self._bits &= ~(1 << bit_index)
-
- def setRange(self, from_index: int, to_index: int, value: bool = True) -> None:
- self._check(from_index)
- mask = ((1 << (to_index - from_index)) - 1) << from_index
- if value:
- self._bits |= mask
- else:
- self._bits &= ~mask
-
- def clear(self, bit_index: int = None) -> None:
- if bit_index is None:
- self._bits = 0
- else:
- self._check(bit_index)
- self._bits &= ~(1 << bit_index)
-
- def clearRange(self, from_index: int, to_index: int) -> None:
- self.setRange(from_index, to_index, False)
-
- def flip(self, bit_index: int) -> None:
- self._check(bit_index)
- self._bits ^= (1 << bit_index)
-
- def flipRange(self, from_index: int, to_index: int) -> None:
- self._check(from_index)
- mask = ((1 << (to_index - from_index)) - 1) << from_index
- self._bits ^= mask
-
- def cardinality(self) -> int:
- return self._bits.bit_count()
-
- def intersects(self, bs: 'BitSet') -> bool:
- return (self._bits & bs._bits) != 0
-
- def and_(self, bs: 'BitSet') -> None:
- self._bits &= bs._bits
-
- def or_(self, bs: 'BitSet') -> None:
- self._bits |= bs._bits
-
- def xor(self, bs: 'BitSet') -> None:
- self._bits ^= bs._bits
-
- def andNot(self, bs: 'BitSet') -> None:
- self._bits &= ~bs._bits
-
- def size(self) -> int:
- return self._bits.bit_length() + (8 - (self._bits.bit_length() % 8)) % 8
-
- def length(self) -> int:
- return self._bits.bit_length()
-
- def isEmpty(self) -> bool:
- return self._bits == 0
-
- def nextSetBit(self, from_index: int) -> int:
- self._check(from_index)
- bits = self._bits >> from_index
- if bits == 0:
- return -1
- return (bits & -bits).bit_length() - 1 + from_index
-
- def nextClearBit(self, from_index: int) -> int:
- self._check(from_index)
- bits = ~(self._bits >> from_index)
- if bits == 0:
- return -1
- return (bits & -bits).bit_length() - 1 + from_index
-
- def previousSetBit(self, from_index: int) -> int:
- if from_index < 0:
- return -1
- mask = (1 << (from_index + 1)) - 1
- bits = self._bits & mask
- if bits == 0:
- return -1
- return bits.bit_length() - 1
-
- def previousClearBit(self, from_index: int) -> int:
- if from_index < 0:
- return -1
- mask = (1 << (from_index + 1)) - 1
- bits = (~self._bits) & mask
- if bits == 0:
- return -1
- return bits.bit_length() - 1
-
- def toByteArray(self) -> bytearray:
- if self._bits == 0:
- return bytearray()
- n_bytes = (self._bits.bit_length() + 7) // 8
- return bytearray(self._bits.to_bytes(n_bytes, 'little'))
-
- def toLongArray(self) -> list:
- if self._bits == 0:
- return []
- n_longs = (self._bits.bit_length() + 63) // 64
- result = []
- for i in range(n_longs):
- result.append((self._bits >> (i * 64)) & 0xFFFFFFFFFFFFFFFF)
- return result
-
- @staticmethod
- def valueOf(bytes_or_longs) -> 'BitSet':
- bs = BitSet()
- if isinstance(bytes_or_longs, (bytes, bytearray)):
- bs._bits = int.from_bytes(bytes_or_longs, 'little')
- elif isinstance(bytes_or_longs, list):
- for i, v in enumerate(bytes_or_longs):
- bs._bits |= (v & 0xFFFFFFFFFFFFFFFF) << (i * 64)
- return bs
-
- def stream(self):
- bits = []
- i = 0
- while True:
- idx = self.nextSetBit(i)
- if idx < 0:
- break
- bits.append(idx)
- i = idx + 1
- return bits
-
- def equals(self, other) -> bool:
- if isinstance(other, BitSet):
- return self._bits == other._bits
- return False
-
- def hashCode(self) -> int:
- return hash(self._bits) & 0x7FFFFFFF
-
- def toString(self) -> str:
- bits = []
- i = 0
- while True:
- idx = self.nextSetBit(i)
- if idx < 0:
- break
- bits.append(str(idx))
- i = idx + 1
- return "{" + ", ".join(bits) + "}"
-
- def clone(self) -> 'BitSet':
- return BitSet(self)
-
- def __repr__(self):
- return self.toString()
-
- def __eq__(self, other):
- return self.equals(other)
-
-
-# ============================================================
-# PriorityQueue
-# ============================================================
-
-class PriorityQueue(Stub):
- """java.util.PriorityQueue — using heapq"""
- def __init__(self, initial_capacity: Any = None, comparator=None):
- super().__init__()
- self._heap: list = []
- self._comparator = comparator
- if initial_capacity is not None and not isinstance(initial_capacity, (int, float)):
- if isinstance(initial_capacity, _IterableABC):
- for item in initial_capacity:
- self._heap.append(item)
- if comparator:
- self._heap.sort(key=comparator)
- else:
- self._heap.sort()
-
- def _wrap_key(self, obj):
- if self._comparator:
- return (self._comparator(obj), obj)
- return obj
-
- def add(self, obj) -> bool:
- _heapq.heappush(self._heap, self._wrap_key(obj))
- return True
-
- def offer(self, obj) -> bool:
- return self.add(obj)
-
- def peek(self):
- return self._heap[0][1] if self._heap and self._comparator else (self._heap[0] if self._heap else None)
-
- def element(self):
- val = self.peek()
- if val is None:
- raise NoSuchElementException()
- return val
-
- def poll(self):
- if not self._heap:
- return None
- val = _heapq.heappop(self._heap)
- return val[1] if self._comparator else val
-
- def remove(self, obj) -> bool:
- if self._comparator:
- wrapped = self._wrap_key(obj)
- for i, v in enumerate(self._heap):
- if v == wrapped:
- self._heap[i] = self._heap[-1]
- self._heap.pop()
- _heapq.heapify(self._heap)
- return True
- else:
- for i, v in enumerate(self._heap):
- if v == obj:
- self._heap[i] = self._heap[-1]
- self._heap.pop()
- _heapq.heapify(self._heap)
- return True
- return False
-
- def size(self) -> int:
- return len(self._heap)
-
- def isEmpty(self) -> bool:
- return len(self._heap) == 0
-
- def clear(self) -> None:
- self._heap.clear()
-
- def comparator(self):
- return self._comparator
-
- def iterator(self) -> Iterator:
- return Iterator(list(self._heap))
-
- def toArray(self, a=None):
- if self._comparator:
- items = sorted([v[1] for v in self._heap], key=self._comparator)
- else:
- items = sorted(self._heap)
- if a is None:
- return items
- return items[:len(a)]
-
- def forEach(self, action) -> None:
- for item in list(self._heap):
- action(item)
-
- def spliterator(self) -> _Spliterator:
- if self._comparator:
- items = [v[1] for v in self._heap]
- else:
- items = list(self._heap)
- return _Spliterator(items)
-
- def clone(self) -> 'PriorityQueue':
- result = PriorityQueue(comparator=self._comparator)
- result._heap = list(self._heap)
- return result
-
- def toString(self) -> str:
- items = ", ".join(str(x) for x in self._heap)
- return f"[{items}]"
-
- def __len__(self):
- return len(self._heap)
-
- def __repr__(self):
- return self.toString()
-
-
-# ============================================================
-# Vector
-# ============================================================
-
-class Vector(Stub):
- """java.util.Vector — synchronized list"""
- def __init__(self, initial_capacity: Any = None, capacity_increment: int = 0):
- super().__init__()
- if initial_capacity is None:
- self._data = []
- elif isinstance(initial_capacity, int):
- self._data = []
- elif isinstance(initial_capacity, _IterableABC):
- self._data = list(initial_capacity)
- else:
- self._data = []
- self._capacity_increment = capacity_increment
- self._lock = _threading.Lock()
-
- def _synchronized(self, func, *args, **kwargs):
- with self._lock:
- return func(*args, **kwargs)
-
- def add(self, obj) -> bool:
- with self._lock:
- self._data.append(obj)
- return True
-
- def addAt(self, index: int, obj) -> None:
- with self._lock:
- self._data.insert(index, obj)
-
- def addAll(self, c) -> bool:
- with self._lock:
- if isinstance(c, Vector):
- self._data.extend(c._data)
- else:
- self._data.extend(c)
- return True
-
- def addAllAt(self, index: int, c) -> bool:
- with self._lock:
- if isinstance(c, Vector):
- self._data[index:index] = c._data
- else:
- self._data[index:index] = list(c)
- return True
-
- def addElement(self, obj) -> None:
- self.add(obj)
-
- def capacity(self) -> int:
- with self._lock:
- return len(self._data)
-
- def clear(self) -> None:
- with self._lock:
- self._data.clear()
-
- def clone(self) -> 'Vector':
- with self._lock:
- return Vector(self._data)
-
- def contains(self, obj) -> bool:
- with self._lock:
- return obj in self._data
-
- def containsAll(self, c) -> bool:
- with self._lock:
- if isinstance(c, Vector):
- return all(x in self._data for x in c._data)
- return all(x in self._data for x in c)
-
- def copyInto(self, an_array: list) -> None:
- with self._lock:
- for i, v in enumerate(self._data):
- an_array[i] = v
-
- def elementAt(self, index: int):
- with self._lock:
- return self._data[index]
-
- def elements(self) -> Enumeration:
- with self._lock:
- return Enumeration(list(self._data))
-
- def ensureCapacity(self, min_capacity: int) -> None:
- pass
-
- def firstElement(self):
- with self._lock:
- if not self._data:
- raise NoSuchElementException()
- return self._data[0]
-
- def forEach(self, action) -> None:
- with self._lock:
- for item in list(self._data):
- action(item)
-
- def get(self, index: int):
- with self._lock:
- return self._data[index]
-
- def indexOf(self, obj, index: int = 0) -> int:
- with self._lock:
- try:
- return self._data.index(obj, index)
- except ValueError:
- return -1
-
- def insertElementAt(self, obj, index: int) -> None:
- with self._lock:
- self._data.insert(index, obj)
-
- def isEmpty(self) -> bool:
- with self._lock:
- return len(self._data) == 0
-
- def iterator(self) -> Iterator:
- with self._lock:
- return Iterator(list(self._data))
-
- def lastElement(self):
- with self._lock:
- if not self._data:
- raise NoSuchElementException()
- return self._data[-1]
-
- def lastIndexOf(self, obj, index: int = None) -> int:
- with self._lock:
- if index is None:
- index = len(self._data) - 1
- for i in range(index, -1, -1):
- if self._data[i] == obj:
- return i
- return -1
-
- def listIterator(self, index: int = 0) -> ListIterator:
- with self._lock:
- li = ListIterator(list(self._data))
- li._index = index
- return li
-
- def remove(self, obj) -> bool:
- with self._lock:
- if obj in self._data:
- self._data.remove(obj)
- return True
- return False
-
- def removeAt(self, index: int):
- with self._lock:
- return self._data.pop(index)
-
- def removeAll(self, c) -> bool:
- with self._lock:
- if isinstance(c, Vector):
- items = c._data
- else:
- items = list(c)
- old_len = len(self._data)
- self._data = [x for x in self._data if x not in items]
- return len(self._data) != old_len
-
- def removeAllElements(self) -> None:
- with self._lock:
- self._data.clear()
-
- def removeElement(self, obj) -> bool:
- return self.remove(obj)
-
- def removeElementAt(self, index: int) -> None:
- with self._lock:
- self._data.pop(index)
-
- def removeIf(self, predicate) -> bool:
- with self._lock:
- old_len = len(self._data)
- self._data = [x for x in self._data if not predicate(x)]
- return len(self._data) != old_len
-
- def replaceAll(self, operator) -> None:
- with self._lock:
- self._data = [operator(x) for x in self._data]
-
- def retainAll(self, c) -> bool:
- with self._lock:
- if isinstance(c, Vector):
- items = set(c._data)
- else:
- items = set(c)
- old_len = len(self._data)
- self._data = [x for x in self._data if x in items]
- return len(self._data) != old_len
-
- def set(self, index: int, obj):
- with self._lock:
- old = self._data[index]
- self._data[index] = obj
- return old
-
- def setElementAt(self, obj, index: int) -> None:
- with self._lock:
- self._data[index] = obj
-
- def setSize(self, new_size: int) -> None:
- with self._lock:
- while len(self._data) < new_size:
- self._data.append(None)
- while len(self._data) > new_size:
- self._data.pop()
-
- def size(self) -> int:
- with self._lock:
- return len(self._data)
-
- def sort(self, key=None, reverse: bool = False) -> None:
- with self._lock:
- self._data.sort(key=key, reverse=reverse)
-
- def subList(self, from_index: int, to_index: int) -> 'Vector':
- with self._lock:
- return Vector(self._data[from_index:to_index])
-
- def toArray(self, a=None):
- with self._lock:
- if a is None:
- return list(self._data)
- if len(a) < len(self._data):
- return list(self._data)
- for i, v in enumerate(self._data):
- a[i] = v
- if len(self._data) < len(a):
- a[len(self._data)] = None
- return a
-
- def toString(self) -> str:
- with self._lock:
- items = ", ".join(str(x) for x in self._data)
- return f"[{items}]"
-
- def trimToSize(self) -> None:
- pass
-
- def __len__(self):
- with self._lock:
- return len(self._data)
-
- def __getitem__(self, idx):
- with self._lock:
- return self._data[idx]
-
- def __setitem__(self, idx, val):
- with self._lock:
- self._data[idx] = val
-
- def __delitem__(self, idx):
- with self._lock:
- del self._data[idx]
-
- def __iter__(self):
- with self._lock:
- return iter(list(self._data))
-
- def __repr__(self):
- return self.toString()
-
- def __contains__(self, obj):
- with self._lock:
- return obj in self._data
-
- def __eq__(self, other):
- if isinstance(other, Vector):
- with self._lock:
- return self._data == other._data
- return False
-
-
-# ============================================================
-# Stack
-# ============================================================
-
-class Stack(Vector):
- """java.util.Stack — extends Vector"""
- def __init__(self):
- super().__init__()
-
- def push(self, item):
- with self._lock:
- self._data.append(item)
- return item
-
- def pop(self):
- with self._lock:
- if not self._data:
- raise EmptyStackException()
- return self._data.pop()
-
- def peek(self):
- with self._lock:
- if not self._data:
- raise EmptyStackException()
- return self._data[-1]
-
- def empty(self) -> bool:
- with self._lock:
- return len(self._data) == 0
-
- def search(self, obj) -> int:
- with self._lock:
- try:
- idx = len(self._data) - 1 - self._data[::-1].index(obj)
- return len(self._data) - idx
- except ValueError:
- return -1
-
- def add(self, obj) -> bool:
- self.push(obj)
- return True
-
- def remove(self, obj) -> bool:
- with self._lock:
- if obj in self._data:
- self._data.remove(obj)
- return True
- return False
\ No newline at end of file
diff --git a/android_pyapi/java/util_concurrent.py b/android_pyapi/java/util_concurrent.py
deleted file mode 100644
index fd2c16a..0000000
--- a/android_pyapi/java/util_concurrent.py
+++ /dev/null
@@ -1,2037 +0,0 @@
-"""
-Java util.concurrent standard library APIs implemented in Python.
-java.util.concurrent package - Executors, ThreadPoolExecutor, CountDownLatch, etc.
-"""
-
-from .._core import Stub
-from .lang import RuntimeException
-import threading as _threading
-import concurrent.futures as _futures
-import time as _time
-import queue as _queue
-import math as _py_math
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-CancellationException = type("CancellationException", (RuntimeException,), {})
-ExecutionException = type("ExecutionException", (RuntimeException,), {})
-RejectedExecutionException = type("RejectedExecutionException", (RuntimeException,), {})
-TimeoutException = type("TimeoutException", (RuntimeException,), {})
-BrokenBarrierException = type("BrokenBarrierException", (RuntimeException,), {})
-CompletionException = type("CompletionException", (RuntimeException,), {})
-
-__all__ = [
- "Executors", "ExecutorService", "Executor", "ExecutorCompletionService",
- "ThreadPoolExecutor", "AbstractExecutorService",
- "ScheduledExecutorService", "ScheduledThreadPoolExecutor",
- "FutureTask", "Future", "RunnableFuture", "RunnableScheduledFuture",
- "Callable", "CompletionService", "CompletionStage",
- "CountDownLatch", "CyclicBarrier", "Semaphore", "Phaser", "Exchanger",
- "TimeUnit",
- "TimeoutException", "CancellationException", "ExecutionException",
- "RejectedExecutionException", "BrokenBarrierException",
- "CompletionException",
- "ConcurrentHashMap", "CopyOnWriteArrayList", "CopyOnWriteArraySet",
- "ConcurrentLinkedQueue", "ConcurrentLinkedDeque",
- "DelayQueue", "SynchronousQueue", "LinkedBlockingQueue",
- "ArrayBlockingQueue", "PriorityBlockingQueue",
- "BlockingQueue", "BlockingDeque",
- "AtomicBoolean", "AtomicInteger", "AtomicLong", "AtomicReference",
- "AtomicIntegerArray", "AtomicLongArray", "AtomicReferenceArray",
- "AtomicIntegerFieldUpdater", "AtomicLongFieldUpdater",
- "AtomicReferenceFieldUpdater",
- "AtomicMarkableReference", "AtomicStampedReference",
- "DoubleAccumulator", "DoubleAdder",
- "LongAccumulator", "LongAdder",
- "Lock", "ReentrantLock", "ReentrantReadWriteLock",
- "ReadWriteLock", "Condition", "LockSupport",
- "AbstractQueuedSynchronizer", "AbstractQueuedLongSynchronizer",
- "Flow", "SubmissionPublisher",
- "RecursiveAction", "RecursiveTask", "ForkJoinPool",
- "ForkJoinTask", "ForkJoinWorkerThread",
- "CompletableFuture",
-]
-
-
-# ============================================================
-# Interfaces
-# ============================================================
-
-class Callable(Stub):
- def call(self):
- raise NotImplementedError
-
-
-class Future(Stub):
- def get(self, timeout=None, unit=None):
- raise NotImplementedError
-
- def cancel(self, may_interrupt):
- raise NotImplementedError
-
- def isCancelled(self):
- raise NotImplementedError
-
- def isDone(self):
- raise NotImplementedError
-
-
-class RunnableFuture(Future):
- def run(self):
- raise NotImplementedError
-
-
-class RunnableScheduledFuture(RunnableFuture):
- def isPeriodic(self):
- raise NotImplementedError
-
-
-class CompletionService(Stub):
- def submit(self, task):
- raise NotImplementedError
-
- def take(self):
- raise NotImplementedError
-
- def poll(self, timeout=0, unit=None):
- raise NotImplementedError
-
-
-class CompletionStage(Stub):
- pass
-
-
-class Executor(Stub):
- def execute(self, command):
- raise NotImplementedError
-
-
-class ExecutorService(Executor):
- def submit(self, task, *args):
- raise NotImplementedError
-
- def shutdown(self):
- raise NotImplementedError
-
- def shutdownNow(self):
- raise NotImplementedError
-
- def isShutdown(self):
- raise NotImplementedError
-
- def isTerminated(self):
- raise NotImplementedError
-
- def awaitTermination(self, timeout, unit):
- raise NotImplementedError
-
- def invokeAll(self, tasks):
- raise NotImplementedError
-
- def invokeAny(self, tasks):
- raise NotImplementedError
-
-
-class ScheduledExecutorService(ExecutorService):
- def schedule(self, command, delay, unit):
- raise NotImplementedError
-
- def scheduleAtFixedRate(self, command, initial_delay, period, unit):
- raise NotImplementedError
-
- def scheduleWithFixedDelay(self, command, initial_delay, delay, unit):
- raise NotImplementedError
-
-
-# ============================================================
-# Runnable
-# ============================================================
-
-class Runnable(Stub):
- def run(self):
- raise NotImplementedError
-
-
-# ============================================================
-# FutureTask
-# ============================================================
-
-class FutureTask(RunnableFuture):
- def __init__(self, callable_or_runnable, result=None):
- super().__init__()
- self._callable = callable_or_runnable if isinstance(callable_or_runnable, Callable) else None
- self._runnable = callable_or_runnable if isinstance(callable_or_runnable, Runnable) else None
- self._result = result
- self._done = False
- self._cancelled = False
- self._exception = None
- self._lock = _threading.RLock()
- self._done_event = _threading.Event()
-
- def run(self):
- if self._cancelled:
- return
- try:
- if self._callable:
- self._result = self._callable.call()
- elif self._runnable:
- self._runnable.run()
- with self._lock:
- self._done = True
- self._done_event.set()
- except Exception as e:
- with self._lock:
- self._exception = e
- self._done = True
- self._done_event.set()
-
- def get(self, timeout=None, unit=None):
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- if not self._done_event.wait(seconds):
- raise TimeoutException()
- else:
- self._done_event.wait()
- with self._lock:
- if self._exception:
- raise ExecutionException(str(self._exception))
- return self._result
-
- def cancel(self, may_interrupt):
- with self._lock:
- if self._done:
- return False
- self._cancelled = True
- self._done = True
- self._done_event.set()
- return True
-
- def isCancelled(self):
- return self._cancelled
-
- def isDone(self):
- return self._done
-
- def doneTask(self):
- pass
-
- def set(self, v):
- with self._lock:
- self._result = v
- self._done = True
- self._done_event.set()
-
- def setException(self, ex):
- with self._lock:
- self._exception = ex
- self._done = True
- self._done_event.set()
-
-
-# ============================================================
-# CompletableFuture
-# ============================================================
-
-class CompletableFuture(Future):
- def __init__(self):
- super().__init__()
- self._result = None
- self._exception = None
- self._done = False
- self._lock = _threading.RLock()
- self._done_event = _threading.Event()
- self._callbacks = []
-
- def _run_callbacks(self):
- for cb in self._callbacks:
- try:
- cb(self)
- except Exception:
- pass
-
- def complete(self, result):
- with self._lock:
- if self._done:
- return self
- self._result = result
- self._done = True
- self._done_event.set()
- self._run_callbacks()
- return self
-
- def completeExceptionally(self, ex):
- with self._lock:
- if self._done:
- return self
- self._exception = ex
- self._done = True
- self._done_event.set()
- self._run_callbacks()
- return self
-
- def cancel(self, may_interrupt):
- with self._lock:
- if self._done:
- return False
- self._cancelled = True
- self._done = True
- self._done_event.set()
- self._run_callbacks()
- return True
-
- def get(self, timeout=None, unit=None):
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- if not self._done_event.wait(seconds):
- raise TimeoutException()
- else:
- self._done_event.wait()
- with self._lock:
- if self._exception:
- raise ExecutionException(str(self._exception))
- return self._result
-
- def join(self):
- return self.get()
-
- def isDone(self):
- return self._done
-
- def isCancelled(self):
- return getattr(self, "_cancelled", False)
-
- def thenApply(self, fn):
- future = CompletableFuture()
- def cb(f):
- try:
- future.complete(fn(f.get()))
- except Exception as e:
- future.completeExceptionally(e)
- self._callbacks.append(cb)
- return future
-
- def thenAccept(self, fn):
- future = CompletableFuture()
- def cb(f):
- try:
- fn(f.get())
- future.complete(None)
- except Exception as e:
- future.completeExceptionally(e)
- self._callbacks.append(cb)
- return future
-
- def thenRun(self, action):
- future = CompletableFuture()
- def cb(f):
- try:
- action.run()
- future.complete(None)
- except Exception as e:
- future.completeExceptionally(e)
- self._callbacks.append(cb)
- return future
-
- def thenCombine(self, other, fn):
- future = CompletableFuture()
- def cb(f):
- try:
- other_result = other.get()
- future.complete(fn(f.get(), other_result))
- except Exception as e:
- future.completeExceptionally(e)
- self._callbacks.append(cb)
- return future
-
- def thenCompose(self, fn):
- future = CompletableFuture()
- def cb(f):
- try:
- next_future = fn(f.get())
- future.complete(next_future.get())
- except Exception as e:
- future.completeExceptionally(e)
- self._callbacks.append(cb)
- return future
-
- def exceptionally(self, fn):
- future = CompletableFuture()
- def cb(f):
- try:
- f.get()
- future.complete(f._result)
- except Exception as e:
- try:
- fallback = fn(e)
- future.complete(fallback)
- except Exception as e2:
- future.completeExceptionally(e2)
- self._callbacks.append(cb)
- return future
-
- @staticmethod
- def completedFuture(result):
- f = CompletableFuture()
- f.complete(result)
- return f
-
- @staticmethod
- def failedFuture(exception):
- f = CompletableFuture()
- f.completeExceptionally(exception)
- return f
-
- @staticmethod
- def supplyAsync(supplier, executor=None):
- f = CompletableFuture()
- def run():
- try:
- f.complete(supplier.get())
- except Exception as e:
- f.completeExceptionally(e)
- t = _threading.Thread(target=run, daemon=True)
- t.start()
- return f
-
- @staticmethod
- def runAsync(runnable, executor=None):
- f = CompletableFuture()
- def run():
- try:
- runnable.run()
- f.complete(None)
- except Exception as e:
- f.completeExceptionally(e)
- t = _threading.Thread(target=run, daemon=True)
- t.start()
- return f
-
- @staticmethod
- def allOf(*futures):
- result = CompletableFuture()
- def check_all():
- for f in futures:
- f.get()
- result.complete(None)
- t = _threading.Thread(target=check_all, daemon=True)
- t.start()
- return result
-
- @staticmethod
- def anyOf(*futures):
- result = CompletableFuture()
- def check_any():
- while True:
- for f in futures:
- if f.isDone():
- result.complete(f.get())
- return
- _time.sleep(0.01)
- t = _threading.Thread(target=check_any, daemon=True)
- t.start()
- return result
-
-
-# ============================================================
-# Executors
-# ============================================================
-
-class Executors(Stub):
- @staticmethod
- def newCachedThreadPool():
- pool = ThreadPoolExecutor(0, _futures.ThreadPoolExecutor(max_workers=10))
- pool._executor._max_workers = None
- return pool
-
- @staticmethod
- def newFixedThreadPool(n_threads):
- return ThreadPoolExecutor(n_threads, _futures.ThreadPoolExecutor(max_workers=n_threads))
-
- @staticmethod
- def newSingleThreadExecutor():
- return ThreadPoolExecutor(1, _futures.ThreadPoolExecutor(max_workers=1))
-
- @staticmethod
- def newScheduledThreadPool(core_pool_size):
- return ScheduledThreadPoolExecutor(core_pool_size)
-
- @staticmethod
- def newWorkStealingPool(parallelism=None):
- return ThreadPoolExecutor(parallelism or 4, _futures.ThreadPoolExecutor(max_workers=parallelism or 4))
-
- @staticmethod
- def defaultThreadFactory():
- return _threading.Thread
-
- @staticmethod
- def privilegedThreadFactory():
- return _threading.Thread
-
- @staticmethod
- def callable(runnable, result=None):
- class _Callable(Callable):
- def call(self):
- if runnable:
- runnable.run()
- return result
- return _Callable()
-
-
-# ============================================================
-# ThreadPoolExecutor
-# ============================================================
-
-class ThreadPoolExecutor(ExecutorService):
- def __init__(self, core_pool_size, executor=None):
- super().__init__()
- self._executor = executor or _futures.ThreadPoolExecutor(max_workers=core_pool_size)
- self._core_pool_size = core_pool_size
- self._max_pool_size = core_pool_size
- self._keep_alive_time = 60
- self._allow_core_thread_timeout = False
-
- def execute(self, command):
- def _run():
- try:
- command.run()
- except Exception:
- pass
- self._executor.submit(_run)
-
- def submit(self, task, *args):
- if isinstance(task, Callable):
- future = FutureTask(task)
- self._executor.submit(future.run)
- return future
- elif isinstance(task, Runnable):
- future = FutureTask(task)
- self._executor.submit(future.run)
- return future
- else:
- future = FutureTask(task)
- self._executor.submit(future.run)
- return future
-
- def shutdown(self):
- self._executor.shutdown(wait=False)
-
- def shutdownNow(self):
- self._executor.shutdown(wait=False)
-
- def isShutdown(self):
- return self._executor._shutdown
-
- def isTerminated(self):
- return self._executor._shutdown
-
- def awaitTermination(self, timeout, unit):
- seconds = unit.toMillis(timeout) / 1000.0
- self._executor.shutdown(wait=True)
-
- def getPoolSize(self):
- return self._core_pool_size
-
- def getActiveCount(self):
- return 0
-
- def getTaskCount(self):
- return 0
-
- def getCompletedTaskCount(self):
- return 0
-
- def getLargestPoolSize(self):
- return self._core_pool_size
-
- def setCorePoolSize(self, size):
- self._core_pool_size = size
-
- def setMaximumPoolSize(self, size):
- self._max_pool_size = size
-
- def setKeepAliveTime(self, time, unit):
- self._keep_alive_time = unit.toMillis(time) / 1000.0
-
- def prestartAllCoreThreads(self):
- pass
-
- def prestartCoreThread(self):
- pass
-
- def allowsCoreThreadTimeOut(self):
- return self._allow_core_thread_timeout
-
- def setRejectedExecutionHandler(self, handler):
- pass
-
- def getRejectedExecutionHandler(self):
- return None
-
-
-class AbstractExecutorService(ExecutorService):
- pass
-
-
-# ============================================================
-# ScheduledThreadPoolExecutor
-# ============================================================
-
-class ScheduledThreadPoolExecutor(ThreadPoolExecutor, ScheduledExecutorService):
- def __init__(self, core_pool_size):
- super().__init__(core_pool_size)
-
- def schedule(self, command, delay, unit):
- future = FutureTask(command)
- seconds = unit.toMillis(delay) / 1000.0
- t = _threading.Timer(seconds, future.run)
- t.daemon = True
- t.start()
- return future
-
- def scheduleAtFixedRate(self, command, initial_delay, period, unit):
- seconds = unit.toMillis(period) / 1000.0
- init_sec = unit.toMillis(initial_delay) / 1000.0
- def _run():
- _time.sleep(init_sec)
- while True:
- command.run()
- _time.sleep(seconds)
- t = _threading.Thread(target=_run, daemon=True)
- t.start()
- return FutureTask(command)
-
- def scheduleWithFixedDelay(self, command, initial_delay, delay, unit):
- return self.scheduleAtFixedRate(command, initial_delay, delay, unit)
-
-
-class ExecutorCompletionService(CompletionService):
- def __init__(self, executor):
- super().__init__()
- self._executor = executor
- self._queue = _queue.Queue()
-
- def submit(self, task):
- future = self._executor.submit(task)
- self._queue.put(future)
- return future
-
- def take(self):
- return self._queue.get()
-
- def poll(self, timeout=0, unit=None):
- if unit is not None:
- sec = unit.toMillis(timeout) / 1000.0
- else:
- sec = timeout
- try:
- return self._queue.get(timeout=sec)
- except _queue.Empty:
- return None
-
-
-# ============================================================
-# TimeUnit
-# ============================================================
-
-class TimeUnit(Stub):
- NANOSECONDS = None
- MICROSECONDS = None
- MILLISECONDS = None
- SECONDS = None
- MINUTES = None
- HOURS = None
- DAYS = None
-
- def __init__(self, name, scale):
- self._name = name
- self._scale = scale # nanos per unit
-
- def convert(self, source_duration, source_unit):
- return int(source_duration * source_unit._scale / self._scale)
-
- def toNanos(self, duration):
- return int(duration * self._scale)
-
- def toMicros(self, duration):
- return int(duration * self._scale // 1000)
-
- def toMillis(self, duration):
- return int(duration * self._scale // 1_000_000)
-
- def toSeconds(self, duration):
- return int(duration * self._scale // 1_000_000_000)
-
- def toMinutes(self, duration):
- return self.toSeconds(duration) // 60
-
- def toHours(self, duration):
- return self.toMinutes(duration) // 60
-
- def toDays(self, duration):
- return self.toHours(duration) // 24
-
- def sleep(self, timeout):
- _time.sleep(self.toMillis(timeout) / 1000.0)
-
- def timedJoin(self, thread, timeout):
- thread.join(self.toMillis(timeout) / 1000.0)
-
- def timedWait(self, obj, timeout):
- return True
-
- def toString(self):
- return self._name
-
-
-TimeUnit.NANOSECONDS = TimeUnit("NANOSECONDS", 1)
-TimeUnit.MICROSECONDS = TimeUnit("MICROSECONDS", 1000)
-TimeUnit.MILLISECONDS = TimeUnit("MILLISECONDS", 1_000_000)
-TimeUnit.SECONDS = TimeUnit("SECONDS", 1_000_000_000)
-TimeUnit.MINUTES = TimeUnit("MINUTES", 60_000_000_000)
-TimeUnit.HOURS = TimeUnit("HOURS", 3_600_000_000_000)
-TimeUnit.DAYS = TimeUnit("DAYS", 86_400_000_000_000)
-
-
-# ============================================================
-# CountDownLatch
-# ============================================================
-
-class CountDownLatch(Stub):
- def __init__(self, count):
- super().__init__()
- self._count = count
- self._condition = _threading.Condition()
-
- def await_(self, timeout=None, unit=None):
- with self._condition:
- if self._count == 0:
- return True
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- self._condition.wait(timeout=seconds)
- return self._count == 0
- self._condition.wait()
- return True
-
- def countDown(self):
- with self._condition:
- if self._count > 0:
- self._count -= 1
- if self._count == 0:
- self._condition.notify_all()
-
- def getCount(self):
- return self._count
-
- def toString(self):
- return f"CountDownLatch(count={self._count})"
-
-
-# ============================================================
-# CyclicBarrier
-# ============================================================
-
-class CyclicBarrier(Stub):
- def __init__(self, parties, barrier_action=None):
- super().__init__()
- self._parties = parties
- self._barrier_action = barrier_action
- self._count = parties
- self._broken = False
- self._lock = _threading.RLock()
- self._condition = _threading.Condition()
-
- def await_(self, timeout=None, unit=None):
- with self._condition:
- if self._broken:
- raise BrokenBarrierException()
- self._count -= 1
- if self._count == 0:
- if self._barrier_action:
- try:
- self._barrier_action.run()
- except Exception:
- self._broken = True
- self._condition.notify_all()
- raise BrokenBarrierException()
- self._count = self._parties
- self._condition.notify_all()
- return 0
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- self._condition.wait(timeout=seconds)
- if self._count > 0:
- self._broken = True
- raise BrokenBarrierException()
- else:
- self._condition.wait()
- return self._count
-
- def getNumberWaiting(self):
- return self._parties - self._count
-
- def getParties(self):
- return self._parties
-
- def isBroken(self):
- return self._broken
-
- def reset(self):
- with self._condition:
- self._broken = False
- self._count = self._parties
- self._condition.notify_all()
-
-
-# ============================================================
-# Semaphore
-# ============================================================
-
-class Semaphore(Stub):
- def __init__(self, permits, fair=False):
- super().__init__()
- self._sem = _threading.Semaphore(permits) if not fair else _threading.Semaphore(permits)
- self._fair = fair
- self._permits = permits
- self._lock = _threading.Lock()
-
- def acquire(self):
- self._sem.acquire()
-
- def acquireUninterruptibly(self):
- self._sem.acquire()
-
- def release(self):
- self._sem.release()
-
- def tryAcquire(self, timeout=None, unit=None):
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- return self._sem.acquire(blocking=True, timeout=seconds)
- return self._sem.acquire(blocking=False)
-
- def availablePermits(self):
- return self._sem._value
-
- def drainPermits(self):
- with self._lock:
- val = self._sem._value
- for _ in range(val):
- self._sem.acquire(blocking=False)
- return val
-
- def getQueueLength(self):
- return 0
-
- def hasQueuedThreads(self):
- return False
-
-
-# ============================================================
-# Phaser (stub)
-# ============================================================
-
-class Phaser(Stub):
- def __init__(self, parties=0):
- super().__init__()
- self._parties = parties
- self._phase = 0
- self._arrived = 0
-
- def register(self):
- self._parties += 1
-
- def arrive(self):
- self._arrived += 1
- return self._phase
-
- def arriveAndDeregister(self):
- self._arrived += 1
- self._parties -= 1
- return self._phase
-
- def arriveAndAwaitAdvance(self):
- self._arrived += 1
- if self._arrived >= self._parties:
- self._phase += 1
- self._arrived = 0
- return self._phase
-
- def awaitAdvance(self, phase):
- return self._phase
-
- def getPhase(self):
- return self._phase
-
- def getArrivedParties(self):
- return self._arrived
-
- def getRegisteredParties(self):
- return self._parties
-
- def getUnarrivedParties(self):
- return self._parties - self._arrived
-
- def isTerminated(self):
- return False
-
- def forceTermination(self):
- pass
-
-
-# ============================================================
-# Exchanger
-# ============================================================
-
-class Exchanger(Stub):
- def __init__(self):
- super().__init__()
- self._lock = _threading.Lock()
- self._item = None
- self._other_ready = _threading.Event()
-
- def exchange(self, x, timeout=None, unit=None):
- with self._lock:
- if self._item is None:
- self._item = x
- self._other_ready.set()
- else:
- result = self._item
- self._item = x
- self._other_ready.set()
- return result
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- self._other_ready.wait(timeout=seconds)
- else:
- self._other_ready.wait()
- with self._lock:
- result = self._item
- self._item = None
- return result
-
-
-# ============================================================
-# ConcurrentHashMap
-# ============================================================
-
-class ConcurrentHashMap(Stub):
- def __init__(self, initial_capacity=16):
- super().__init__()
- self._map = {}
- self._lock = _threading.RLock()
-
- def put(self, key, value):
- with self._lock:
- self._map[key] = value
- return None
-
- def get(self, key):
- with self._lock:
- return self._map.get(key)
-
- def containsKey(self, key):
- with self._lock:
- return key in self._map
-
- def containsValue(self, value):
- with self._lock:
- return value in self._map.values()
-
- def size(self):
- with self._lock:
- return len(self._map)
-
- def isEmpty(self):
- with self._lock:
- return len(self._map) == 0
-
- def remove(self, key):
- with self._lock:
- return self._map.pop(key, None)
-
- def clear(self):
- with self._lock:
- self._map.clear()
-
- def keySet(self):
- with self._lock:
- return set(self._map.keys())
-
- def values(self):
- with self._lock:
- return list(self._map.values())
-
- def entrySet(self):
- with self._lock:
- return set(self._map.items())
-
- def putAll(self, m):
- with self._lock:
- if hasattr(m, "_map"):
- self._map.update(m._map)
- elif isinstance(m, dict):
- self._map.update(m)
-
- def putIfAbsent(self, key, value):
- with self._lock:
- if key not in self._map:
- self._map[key] = value
- return None
- return self._map[key]
-
- def getOrDefault(self, key, default):
- with self._lock:
- return self._map.get(key, default)
-
- def forEach(self, action):
- with self._lock:
- for k, v in self._map.items():
- action(k, v)
-
-
-# ============================================================
-# CopyOnWriteArrayList / CopyOnWriteArraySet
-# ============================================================
-
-class CopyOnWriteArrayList(Stub):
- def __init__(self, *args):
- super().__init__()
- self._list = []
- self._lock = _threading.RLock()
- if args and isinstance(args[0], (list, tuple)):
- self._list = list(args[0])
-
- def add(self, e):
- with self._lock:
- self._list = list(self._list)
- self._list.append(e)
- return True
-
- def get(self, index):
- return self._list[index]
-
- def set(self, index, element):
- with self._lock:
- old = self._list[index]
- self._list = list(self._list)
- self._list[index] = element
- return old
-
- def remove(self, e):
- with self._lock:
- new_list = list(self._list)
- try:
- new_list.remove(e)
- self._list = new_list
- return True
- except ValueError:
- return False
-
- def size(self):
- return len(self._list)
-
- def isEmpty(self):
- return len(self._list) == 0
-
- def contains(self, e):
- return e in self._list
-
- def iterator(self):
- return iter(list(self._list))
-
- def toArray(self):
- return list(self._list)
-
- def clear(self):
- with self._lock:
- self._list = []
-
-
-class CopyOnWriteArraySet(Stub):
- def __init__(self):
- super().__init__()
- self._backend = CopyOnWriteArrayList()
-
- def add(self, e):
- if self._backend.contains(e):
- return False
- return self._backend.add(e)
-
- def remove(self, e):
- return self._backend.remove(e)
-
- def contains(self, e):
- return self._backend.contains(e)
-
- def size(self):
- return self._backend.size()
-
- def isEmpty(self):
- return self._backend.isEmpty()
-
- def iterator(self):
- return self._backend.iterator()
-
-
-# ============================================================
-# BlockingQueue / LinkedBlockingQueue / ArrayBlockingQueue
-# ============================================================
-
-class BlockingQueue(Stub):
- pass
-
-
-class LinkedBlockingQueue(BlockingQueue):
- def __init__(self, capacity=None):
- super().__init__()
- self._queue = _queue.Queue(maxsize=capacity if capacity else 0)
-
- def put(self, item):
- self._queue.put(item)
-
- def take(self):
- return self._queue.get()
-
- def offer(self, item, timeout=None, unit=None):
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- try:
- self._queue.put(item, timeout=seconds)
- return True
- except _queue.Full:
- return False
- try:
- self._queue.put_nowait(item)
- return True
- except _queue.Full:
- return False
-
- def poll(self, timeout=None, unit=None):
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- try:
- return self._queue.get(timeout=seconds)
- except _queue.Empty:
- return None
- try:
- return self._queue.get_nowait()
- except _queue.Empty:
- return None
-
- def size(self):
- return self._queue.qsize()
-
- def isEmpty(self):
- return self._queue.empty()
-
- def remainingCapacity(self):
- return self._queue.maxsize - self._queue.qsize()
-
- def clear(self):
- while not self._queue.empty():
- try:
- self._queue.get_nowait()
- except _queue.Empty:
- break
-
- def contains(self, item):
- return item in list(self._queue.queue)
-
-
-class ArrayBlockingQueue(LinkedBlockingQueue):
- def __init__(self, capacity, fair=False):
- super().__init__(capacity)
-
-
-class PriorityBlockingQueue(BlockingQueue):
- def __init__(self, capacity=None):
- super().__init__()
- self._heap = []
- self._lock = _threading.RLock()
- self._not_empty = _threading.Condition(self._lock)
-
- def put(self, item):
- with self._lock:
- _queue.heappush(self._heap, item)
- self._not_empty.notify()
-
- def take(self):
- with self._lock:
- while not self._heap:
- self._not_empty.wait()
- return _queue.heappop(self._heap)
-
- def offer(self, item, timeout=None, unit=None):
- self.put(item)
- return True
-
- def poll(self, timeout=None, unit=None):
- with self._lock:
- if not self._heap:
- return None
- return _queue.heappop(self._heap)
-
- def size(self):
- with self._lock:
- return len(self._heap)
-
- def isEmpty(self):
- with self._lock:
- return len(self._heap) == 0
-
- def clear(self):
- with self._lock:
- self._heap = []
-
-
-class SynchronousQueue(BlockingQueue):
- def __init__(self, fair=False):
- super().__init__()
- self._exchange = _queue.Queue(maxsize=1)
-
- def put(self, item):
- self._exchange.put(item)
-
- def take(self):
- return self._exchange.get()
-
- def offer(self, item, timeout=None, unit=None):
- try:
- self._exchange.put_nowait(item)
- return True
- except _queue.Full:
- return False
-
- def poll(self, timeout=None, unit=None):
- try:
- return self._exchange.get_nowait()
- except _queue.Empty:
- return None
-
-
-class DelayQueue(BlockingQueue):
- def __init__(self):
- super().__init__()
- self._queue = []
-
- def put(self, item):
- _queue.heappush(self._queue, item)
-
- def take(self):
- while True:
- if self._queue:
- item = self._queue[0]
- delay = item.getDelay(TimeUnit.MILLISECONDS)
- if delay <= 0:
- return _queue.heappop(self._queue)
- _time.sleep(delay / 1000.0)
- else:
- _time.sleep(0.1)
-
-
-class ConcurrentLinkedQueue(Stub):
- def __init__(self):
- super().__init__()
- self._queue = _queue.Queue()
-
- def add(self, item):
- self._queue.put(item)
- return True
-
- def offer(self, item):
- self._queue.put_nowait(item)
- return True
-
- def poll(self):
- try:
- return self._queue.get_nowait()
- except _queue.Empty:
- return None
-
- def peek(self):
- try:
- item = self._queue.get_nowait()
- self._queue.put_nowait(item)
- return item
- except _queue.Empty:
- return None
-
- def size(self):
- return self._queue.qsize()
-
- def isEmpty(self):
- return self._queue.empty()
-
- def contains(self, item):
- return item in list(self._queue.queue)
-
-
-class ConcurrentLinkedDeque(ConcurrentLinkedQueue):
- def addFirst(self, item):
- self._queue.put(item)
-
- def addLast(self, item):
- self._queue.put(item)
-
- def pollFirst(self):
- return self.poll()
-
- def pollLast(self):
- return self.poll()
-
-
-class BlockingDeque(BlockingQueue):
- pass
-
-
-# ============================================================
-# Atomic classes
-# ============================================================
-
-class AtomicBoolean(Stub):
- def __init__(self, initial=False):
- super().__init__()
- self._value = initial
- self._lock = _threading.Lock()
-
- def get(self):
- with self._lock:
- return self._value
-
- def set(self, new_value):
- with self._lock:
- self._value = new_value
-
- def compareAndSet(self, expect, update):
- with self._lock:
- if self._value == expect:
- self._value = update
- return True
- return False
-
- def getAndSet(self, new_value):
- with self._lock:
- old = self._value
- self._value = new_value
- return old
-
- def toString(self):
- return str(self._value)
-
-
-class AtomicInteger(Stub):
- def __init__(self, initial=0):
- super().__init__()
- self._value = int(initial)
- self._lock = _threading.Lock()
-
- def get(self):
- with self._lock:
- return self._value
-
- def set(self, new_value):
- with self._lock:
- self._value = int(new_value)
-
- def getAndSet(self, new_value):
- with self._lock:
- old = self._value
- self._value = int(new_value)
- return old
-
- def compareAndSet(self, expect, update):
- with self._lock:
- if self._value == expect:
- self._value = int(update)
- return True
- return False
-
- def weakCompareAndSet(self, expect, update):
- return self.compareAndSet(expect, update)
-
- def getAndIncrement(self):
- with self._lock:
- old = self._value
- self._value += 1
- return old
-
- def getAndDecrement(self):
- with self._lock:
- old = self._value
- self._value -= 1
- return old
-
- def getAndAdd(self, delta):
- with self._lock:
- old = self._value
- self._value += delta
- return old
-
- def incrementAndGet(self):
- with self._lock:
- self._value += 1
- return self._value
-
- def decrementAndGet(self):
- with self._lock:
- self._value -= 1
- return self._value
-
- def addAndGet(self, delta):
- with self._lock:
- self._value += delta
- return self._value
-
- def lazySet(self, new_value):
- with self._lock:
- self._value = int(new_value)
-
- def updateAndGet(self, func):
- with self._lock:
- self._value = func(self._value)
- return self._value
-
- def accumulateAndGet(self, x, func):
- with self._lock:
- self._value = func(self._value, x)
- return self._value
-
- def intValue(self):
- return self.get()
-
- def longValue(self):
- return self.get()
-
- def floatValue(self):
- return float(self.get())
-
- def doubleValue(self):
- return float(self.get())
-
- def toString(self):
- return str(self._value)
-
-
-class AtomicLong(AtomicInteger):
- pass
-
-
-class AtomicReference(Stub):
- def __init__(self, initial=None):
- super().__init__()
- self._value = initial
- self._lock = _threading.Lock()
-
- def get(self):
- with self._lock:
- return self._value
-
- def set(self, new_value):
- with self._lock:
- self._value = new_value
-
- def compareAndSet(self, expect, update):
- with self._lock:
- if self._value == expect:
- self._value = update
- return True
- return False
-
- def getAndSet(self, new_value):
- with self._lock:
- old = self._value
- self._value = new_value
- return old
-
- def getAndUpdate(self, func):
- with self._lock:
- old = self._value
- self._value = func(old)
- return old
-
- def updateAndGet(self, func):
- with self._lock:
- self._value = func(self._value)
- return self._value
-
- def accumulateAndGet(self, x, func):
- with self._lock:
- self._value = func(self._value, x)
- return self._value
-
-
-class AtomicIntegerArray(Stub):
- def __init__(self, length_or_array):
- super().__init__()
- if isinstance(length_or_array, int):
- self._array = [0] * length_or_array
- else:
- self._array = list(length_or_array)
-
- def get(self, i):
- return self._array[i]
-
- def set(self, i, new_value):
- self._array[i] = new_value
-
- def compareAndSet(self, i, expect, update):
- if self._array[i] == expect:
- self._array[i] = update
- return True
- return False
-
- def getAndAdd(self, i, delta):
- old = self._array[i]
- self._array[i] += delta
- return old
-
- def addAndGet(self, i, delta):
- self._array[i] += delta
- return self._array[i]
-
- def length(self):
- return len(self._array)
-
-
-class AtomicLongArray(AtomicIntegerArray):
- pass
-
-
-class AtomicReferenceArray(Stub):
- def __init__(self, length_or_array):
- super().__init__()
- if isinstance(length_or_array, int):
- self._array = [None] * length_or_array
- else:
- self._array = list(length_or_array)
-
- def get(self, i):
- return self._array[i]
-
- def set(self, i, new_value):
- self._array[i] = new_value
-
- def compareAndSet(self, i, expect, update):
- if self._array[i] == expect:
- self._array[i] = update
- return True
- return False
-
- def length(self):
- return len(self._array)
-
-
-class AtomicIntegerFieldUpdater(Stub):
- @staticmethod
- def newUpdater(tclass, field_name):
- return AtomicIntegerFieldUpdater()
-
- def get(self, obj):
- return 0
-
- def set(self, obj, new_value):
- pass
-
- def compareAndSet(self, obj, expect, update):
- return True
-
-
-class AtomicLongFieldUpdater(AtomicIntegerFieldUpdater):
- pass
-
-
-class AtomicReferenceFieldUpdater(Stub):
- @staticmethod
- def newUpdater(tclass, vclass, field_name):
- return AtomicReferenceFieldUpdater()
-
- def get(self, obj):
- return None
-
- def set(self, obj, new_value):
- pass
-
- def compareAndSet(self, obj, expect, update):
- return True
-
-
-class AtomicMarkableReference(Stub):
- def __init__(self, initial_ref, initial_mark):
- super().__init__()
- self._ref = initial_ref
- self._mark = initial_mark
-
- def getReference(self):
- return self._ref
-
- def isMarked(self):
- return self._mark
-
- def compareAndSet(self, expected_ref, new_ref, expected_mark, new_mark):
- if self._ref == expected_ref and self._mark == expected_mark:
- self._ref = new_ref
- self._mark = new_mark
- return True
- return False
-
- def attemptMark(self, expected_ref, new_mark):
- if self._ref == expected_ref:
- self._mark = new_mark
- return True
- return False
-
-
-class AtomicStampedReference(Stub):
- def __init__(self, initial_ref, initial_stamp):
- super().__init__()
- self._ref = initial_ref
- self._stamp = initial_stamp
-
- def getReference(self):
- return self._ref
-
- def getStamp(self):
- return self._stamp
-
- def compareAndSet(self, expected_ref, new_ref, expected_stamp, new_stamp):
- if self._ref == expected_ref and self._stamp == expected_stamp:
- self._ref = new_ref
- self._stamp = new_stamp
- return True
- return False
-
- def attemptStamp(self, expected_ref, new_stamp):
- if self._ref == expected_ref:
- self._stamp = new_stamp
- return True
- return False
-
- def set(self, new_ref, new_stamp):
- self._ref = new_ref
- self._stamp = new_stamp
-
-
-class DoubleAccumulator(Stub):
- def __init__(self, accumulator_function, identity):
- super().__init__()
- self._value = identity
- self._func = accumulator_function
-
- def accumulate(self, x):
- self._value = self._func(self._value, x)
-
- def get(self):
- return self._value
-
- def reset(self):
- self._value = 0.0
-
-
-class DoubleAdder(Stub):
- def __init__(self):
- super().__init__()
- self._value = 0.0
-
- def add(self, x):
- self._value += x
-
- def sum(self):
- return self._value
-
- def reset(self):
- self._value = 0.0
-
- def doubleValue(self):
- return self._value
-
- def toString(self):
- return str(self._value)
-
-
-class LongAccumulator(Stub):
- def __init__(self, accumulator_function, identity):
- super().__init__()
- self._value = identity
- self._func = accumulator_function
-
- def accumulate(self, x):
- self._value = self._func(self._value, x)
-
- def get(self):
- return self._value
-
- def reset(self):
- self._value = 0
-
-
-class LongAdder(Stub):
- def __init__(self):
- super().__init__()
- self._value = 0
-
- def add(self, x):
- self._value += x
-
- def sum(self):
- return self._value
-
- def reset(self):
- self._value = 0
-
- def intValue(self):
- return self._value
-
- def longValue(self):
- return self._value
-
- def toString(self):
- return str(self._value)
-
-
-# ============================================================
-# ReentrantLock
-# ============================================================
-
-class Lock(Stub):
- def lock(self):
- raise NotImplementedError
-
- def lockInterruptibly(self):
- raise NotImplementedError
-
- def tryLock(self, timeout=None, unit=None):
- raise NotImplementedError
-
- def unlock(self):
- raise NotImplementedError
-
- def newCondition(self):
- raise NotImplementedError
-
-
-class ReentrantLock(Lock):
- def __init__(self, fair=False):
- super().__init__()
- self._lock = _threading.RLock() if not fair else _threading.RLock()
-
- def lock(self):
- self._lock.acquire()
-
- def lockInterruptibly(self):
- self._lock.acquire()
-
- def tryLock(self, timeout=None, unit=None):
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- return self._lock.acquire(timeout=seconds)
- return self._lock.acquire(blocking=False)
-
- def unlock(self):
- self._lock.release()
-
- def newCondition(self):
- return Condition()
-
- def getHoldCount(self):
- return 1 if self._lock._is_owned() else 0
-
- def isHeldByCurrentThread(self):
- return self._lock._is_owned()
-
- def isLocked(self):
- return True
-
- def getQueueLength(self):
- return 0
-
- def hasQueuedThreads(self):
- return False
-
- def getOwner(self):
- return _threading.current_thread() if self.isHeldByCurrentThread() else None
-
-
-# ============================================================
-# ReadWriteLock
-# ============================================================
-
-class ReadWriteLock(Stub):
- def readLock(self):
- raise NotImplementedError
-
- def writeLock(self):
- raise NotImplementedError
-
-
-class ReentrantReadWriteLock(ReadWriteLock):
- class ReadLock(Lock):
- def __init__(self, rw_lock):
- super().__init__()
- self._rw_lock = rw_lock
-
- def lock(self):
- self._rw_lock._read_lock.acquire()
-
- def unlock(self):
- self._rw_lock._read_lock.release()
-
- def tryLock(self, timeout=None, unit=None):
- return self._rw_lock._read_lock.acquire(blocking=False)
-
- class WriteLock(Lock):
- def __init__(self, rw_lock):
- super().__init__()
- self._rw_lock = rw_lock
-
- def lock(self):
- self._rw_lock._write_lock.acquire()
-
- def unlock(self):
- self._rw_lock._write_lock.release()
-
- def tryLock(self, timeout=None, unit=None):
- return self._rw_lock._write_lock.acquire(blocking=False)
-
- def __init__(self, fair=False):
- super().__init__()
- self._read_lock_obj = _threading.RLock()
- self._write_lock_obj = _threading.Lock()
- self._read_lock = ReentrantReadWriteLock.ReadLock(self)
- self._write_lock = ReentrantReadWriteLock.WriteLock(self)
-
- def readLock(self):
- return self._read_lock
-
- def writeLock(self):
- return self._write_lock
-
-
-class Condition(Stub):
- def __init__(self):
- super().__init__()
- self._cond = _threading.Condition()
-
- def await_(self, timeout=None, unit=None):
- if timeout is not None and unit is not None:
- seconds = unit.toMillis(timeout) / 1000.0
- with self._cond:
- return self._cond.wait(timeout=seconds)
- with self._cond:
- self._cond.wait()
-
- def awaitUninterruptibly(self):
- with self._cond:
- self._cond.wait()
-
- def awaitNanos(self, nanos_timeout):
- seconds = nanos_timeout / 1_000_000_000.0
- with self._cond:
- self._cond.wait(timeout=seconds)
- return 0
-
- def awaitUntil(self, deadline):
- remaining = (deadline - _time.time()) * 1000
- if remaining > 0:
- self.await_(remaining, TimeUnit.MILLISECONDS)
-
- def signal(self):
- with self._cond:
- self._cond.notify()
-
- def signalAll(self):
- with self._cond:
- self._cond.notify_all()
-
-
-class LockSupport(Stub):
- @staticmethod
- def park():
- _time.sleep(1)
-
- @staticmethod
- def parkNanos(nanos):
- _time.sleep(nanos / 1_000_000_000.0)
-
- @staticmethod
- def parkUntil(deadline):
- remaining = deadline - _time.time()
- if remaining > 0:
- _time.sleep(remaining)
-
- @staticmethod
- def unpark(thread):
- pass
-
-
-# ============================================================
-# AbstractQueuedSynchronizer (stubs)
-# ============================================================
-
-class AbstractQueuedSynchronizer(Stub):
- def __init__(self):
- super().__init__()
- self._state = 0
-
- def getState(self):
- return self._state
-
- def setState(self, state):
- self._state = state
-
- def compareAndSetState(self, expect, update):
- if self._state == expect:
- self._state = update
- return True
- return False
-
- def acquire(self, arg):
- pass
-
- def acquireInterruptibly(self, arg):
- pass
-
- def tryAcquire(self, arg):
- return True
-
- def tryRelease(self, arg):
- return True
-
- def release(self, arg):
- return True
-
- def acquireShared(self, arg):
- pass
-
- def releaseShared(self, arg):
- return True
-
- def tryAcquireShared(self, arg):
- return 0
-
- def tryReleaseShared(self, arg):
- return True
-
- def hasQueuedThreads(self):
- return False
-
- def getQueueLength(self):
- return 0
-
-
-class AbstractQueuedLongSynchronizer(AbstractQueuedSynchronizer):
- pass
-
-
-# ============================================================
-# Flow / SubmissionPublisher (stubs)
-# ============================================================
-
-class Flow(Stub):
- class Publisher(Stub):
- def subscribe(self, subscriber):
- pass
-
- class Subscriber(Stub):
- def onSubscribe(self, subscription):
- pass
-
- def onNext(self, item):
- pass
-
- def onError(self, throwable):
- pass
-
- def onComplete(self):
- pass
-
- class Subscription(Stub):
- def request(self, n):
- pass
-
- def cancel(self):
- pass
-
- class Processor(Stub):
- pass
-
-
-class SubmissionPublisher(Flow.Publisher):
- def __init__(self):
- super().__init__()
- self._subscribers = []
-
- def subscribe(self, subscriber):
- self._subscribers.append(subscriber)
-
- def submit(self, item):
- for sub in self._subscribers:
- sub.onNext(item)
- return 1
-
- def close(self):
- for sub in self._subscribers:
- sub.onComplete()
-
-
-# ============================================================
-# ForkJoinPool / ForkJoinTask (stubs)
-# ============================================================
-
-class ForkJoinPool(Stub):
- def __init__(self, parallelism=None):
- super().__init__()
- self._parallelism = parallelism or _py_math.ceil(_threading._count / 2)
- self._pool = _futures.ThreadPoolExecutor(max_workers=self._parallelism)
-
- def execute(self, task):
- self._pool.submit(task.run)
-
- def submit(self, task):
- future = FutureTask(task)
- self._pool.submit(future.run)
- return future
-
- def invoke(self, task):
- return task.run()
-
- def shutdown(self):
- self._pool.shutdown(wait=False)
-
-
-class ForkJoinTask(Future):
- def fork(self):
- return self
-
- def join(self):
- return None
-
- def invoke(self):
- return None
-
- def adapt(self, callable_or_runnable):
- return ForkJoinTask()
-
-
-class RecursiveAction(ForkJoinTask):
- def compute(self):
- raise NotImplementedError
-
- def run(self):
- self.compute()
-
-
-class RecursiveTask(ForkJoinTask):
- def compute(self):
- raise NotImplementedError
-
- def run(self):
- self.compute()
-
-
-class ForkJoinWorkerThread(Stub):
- def __init__(self, pool):
- super().__init__()
- self._pool = pool
-
- def getPool(self):
- return self._pool
\ No newline at end of file
diff --git a/android_pyapi/java/util_concurrent_atomic.py b/android_pyapi/java/util_concurrent_atomic.py
deleted file mode 100644
index aca93c9..0000000
--- a/android_pyapi/java/util_concurrent_atomic.py
+++ /dev/null
@@ -1,1044 +0,0 @@
-"""
-Java java.util.concurrent.atomic standard library APIs implemented in Python.
-java.util.concurrent.atomic package - AtomicBoolean, AtomicInteger, AtomicLong, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub
-from ..java.lang import RuntimeException
-import threading as _threading
-import math as _py_math
-
-__all__ = [
- "AtomicBoolean", "AtomicInteger", "AtomicLong", "AtomicReference",
- "AtomicIntegerArray", "AtomicLongArray", "AtomicReferenceArray",
- "AtomicIntegerFieldUpdater", "AtomicLongFieldUpdater",
- "AtomicReferenceFieldUpdater",
- "AtomicMarkableReference", "AtomicStampedReference",
- "DoubleAccumulator", "DoubleAdder",
- "LongAccumulator", "LongAdder", "Striped64",
-]
-
-
-# ============================================================
-# AtomicBoolean
-# ============================================================
-
-class AtomicBoolean(Stub):
- """java.util.concurrent.atomic.AtomicBoolean"""
- def __init__(self, initial_value=False):
- super().__init__()
- self._lock = _threading.Lock()
- self._value = bool(initial_value)
-
- def get(self):
- with self._lock:
- return self._value
-
- def set(self, new_value):
- with self._lock:
- self._value = bool(new_value)
-
- def lazySet(self, new_value):
- self.set(new_value)
-
- def getAndSet(self, new_value):
- with self._lock:
- old = self._value
- self._value = bool(new_value)
- return old
-
- def compareAndSet(self, expect, update):
- with self._lock:
- if self._value == expect:
- self._value = update
- return True
- return False
-
- def weakCompareAndSet(self, expect, update):
- return self.compareAndSet(expect, update)
-
- def toString(self):
- return str(self._value)
-
- def hashCode(self):
- return hash(self._value)
-
- def equals(self, other):
- if not isinstance(other, AtomicBoolean):
- return False
- return self._value == other._value
-
-
-# ============================================================
-# AtomicInteger
-# ============================================================
-
-class AtomicInteger(Stub):
- """java.util.concurrent.atomic.AtomicInteger"""
- def __init__(self, initial_value=0):
- super().__init__()
- self._lock = _threading.Lock()
- self._value = int(initial_value)
-
- def get(self):
- with self._lock:
- return self._value
-
- def set(self, new_value):
- with self._lock:
- self._value = int(new_value)
-
- def lazySet(self, new_value):
- self.set(new_value)
-
- def getAndSet(self, new_value):
- with self._lock:
- old = self._value
- self._value = int(new_value)
- return old
-
- def compareAndSet(self, expect, update):
- with self._lock:
- if self._value == expect:
- self._value = int(update)
- return True
- return False
-
- def weakCompareAndSet(self, expect, update):
- return self.compareAndSet(expect, update)
-
- def getAndIncrement(self):
- with self._lock:
- old = self._value
- self._value += 1
- return old
-
- def getAndDecrement(self):
- with self._lock:
- old = self._value
- self._value -= 1
- return old
-
- def getAndAdd(self, delta):
- with self._lock:
- old = self._value
- self._value += delta
- return old
-
- def incrementAndGet(self):
- with self._lock:
- self._value += 1
- return self._value
-
- def decrementAndGet(self):
- with self._lock:
- self._value -= 1
- return self._value
-
- def addAndGet(self, delta):
- with self._lock:
- self._value += delta
- return self._value
-
- def getAndUpdate(self, update_func):
- with self._lock:
- old = self._value
- self._value = update_func.applyAsInt(old)
- return old
-
- def updateAndGet(self, update_func):
- with self._lock:
- self._value = update_func.applyAsInt(self._value)
- return self._value
-
- def getAndAccumulate(self, x, accumulator_func):
- with self._lock:
- old = self._value
- self._value = accumulator_func.applyAsInt(old, x)
- return old
-
- def accumulateAndGet(self, x, accumulator_func):
- with self._lock:
- self._value = accumulator_func.applyAsInt(self._value, x)
- return self._value
-
- def toString(self):
- return str(self.get())
-
- def intValue(self):
- return self.get()
-
- def longValue(self):
- return self.get()
-
- def floatValue(self):
- return float(self.get())
-
- def doubleValue(self):
- return float(self.get())
-
- def hashCode(self):
- return self.get()
-
-
-# ============================================================
-# AtomicLong
-# ============================================================
-
-class AtomicLong(Stub):
- """java.util.concurrent.atomic.AtomicLong"""
- def __init__(self, initial_value=0):
- super().__init__()
- self._lock = _threading.Lock()
- self._value = int(initial_value)
-
- def get(self):
- with self._lock:
- return self._value
-
- def set(self, new_value):
- with self._lock:
- self._value = int(new_value)
-
- def lazySet(self, new_value):
- self.set(new_value)
-
- def getAndSet(self, new_value):
- with self._lock:
- old = self._value
- self._value = int(new_value)
- return old
-
- def compareAndSet(self, expect, update):
- with self._lock:
- if self._value == expect:
- self._value = int(update)
- return True
- return False
-
- def weakCompareAndSet(self, expect, update):
- return self.compareAndSet(expect, update)
-
- def getAndIncrement(self):
- with self._lock:
- old = self._value
- self._value += 1
- return old
-
- def getAndDecrement(self):
- with self._lock:
- old = self._value
- self._value -= 1
- return old
-
- def getAndAdd(self, delta):
- with self._lock:
- old = self._value
- self._value += delta
- return old
-
- def incrementAndGet(self):
- with self._lock:
- self._value += 1
- return self._value
-
- def decrementAndGet(self):
- with self._lock:
- self._value -= 1
- return self._value
-
- def addAndGet(self, delta):
- with self._lock:
- self._value += delta
- return self._value
-
- def getAndUpdate(self, update_func):
- with self._lock:
- old = self._value
- self._value = update_func.applyAsLong(old)
- return old
-
- def updateAndGet(self, update_func):
- with self._lock:
- self._value = update_func.applyAsLong(self._value)
- return self._value
-
- def getAndAccumulate(self, x, accumulator_func):
- with self._lock:
- old = self._value
- self._value = accumulator_func.applyAsLong(old, x)
- return old
-
- def accumulateAndGet(self, x, accumulator_func):
- with self._lock:
- self._value = accumulator_func.applyAsLong(self._value, x)
- return self._value
-
- def toString(self):
- return str(self.get())
-
- def intValue(self):
- return int(self.get())
-
- def longValue(self):
- return self.get()
-
- def floatValue(self):
- return float(self.get())
-
- def doubleValue(self):
- return float(self.get())
-
- def hashCode(self):
- return hash(self.get())
-
-
-# ============================================================
-# AtomicReference
-# ============================================================
-
-class AtomicReference(Stub):
- """java.util.concurrent.atomic.AtomicReference"""
- def __init__(self, initial_value=None):
- super().__init__()
- self._lock = _threading.Lock()
- self._value = initial_value
-
- def get(self):
- with self._lock:
- return self._value
-
- def set(self, new_value):
- with self._lock:
- self._value = new_value
-
- def lazySet(self, new_value):
- self.set(new_value)
-
- def getAndSet(self, new_value):
- with self._lock:
- old = self._value
- self._value = new_value
- return old
-
- def compareAndSet(self, expect, update):
- with self._lock:
- if self._value is expect or (self._value == expect):
- self._value = update
- return True
- return False
-
- def weakCompareAndSet(self, expect, update):
- return self.compareAndSet(expect, update)
-
- def getAndUpdate(self, update_func):
- with self._lock:
- old = self._value
- self._value = update_func.apply(old)
- return old
-
- def updateAndGet(self, update_func):
- with self._lock:
- self._value = update_func.apply(self._value)
- return self._value
-
- def getAndAccumulate(self, x, accumulator_func):
- with self._lock:
- old = self._value
- self._value = accumulator_func.apply(old, x)
- return old
-
- def accumulateAndGet(self, x, accumulator_func):
- with self._lock:
- self._value = accumulator_func.apply(self._value, x)
- return self._value
-
- def toString(self):
- return str(self.get())
-
- def hashCode(self):
- return hash(self._value)
-
-
-# ============================================================
-# AtomicIntegerArray
-# ============================================================
-
-class AtomicIntegerArray(Stub):
- """java.util.concurrent.atomic.AtomicIntegerArray"""
- def __init__(self, length_or_array):
- super().__init__()
- if isinstance(length_or_array, int):
- self._array = [0] * length_or_array
- else:
- self._array = list(length_or_array)
- self._lock = _threading.Lock()
-
- def length(self):
- return len(self._array)
-
- def get(self, i):
- with self._lock:
- return self._array[i]
-
- def set(self, i, new_value):
- with self._lock:
- self._array[i] = int(new_value)
-
- def lazySet(self, i, new_value):
- self.set(i, new_value)
-
- def getAndSet(self, i, new_value):
- with self._lock:
- old = self._array[i]
- self._array[i] = int(new_value)
- return old
-
- def compareAndSet(self, i, expect, update):
- with self._lock:
- if self._array[i] == expect:
- self._array[i] = int(update)
- return True
- return False
-
- def weakCompareAndSet(self, i, expect, update):
- return self.compareAndSet(i, expect, update)
-
- def getAndIncrement(self, i):
- with self._lock:
- old = self._array[i]
- self._array[i] += 1
- return old
-
- def getAndDecrement(self, i):
- with self._lock:
- old = self._array[i]
- self._array[i] -= 1
- return old
-
- def getAndAdd(self, i, delta):
- with self._lock:
- old = self._array[i]
- self._array[i] += delta
- return old
-
- def incrementAndGet(self, i):
- with self._lock:
- self._array[i] += 1
- return self._array[i]
-
- def decrementAndGet(self, i):
- with self._lock:
- self._array[i] -= 1
- return self._array[i]
-
- def addAndGet(self, i, delta):
- with self._lock:
- self._array[i] += delta
- return self._array[i]
-
- def toString(self):
- return str(self._array)
-
-
-# ============================================================
-# AtomicLongArray
-# ============================================================
-
-class AtomicLongArray(Stub):
- """java.util.concurrent.atomic.AtomicLongArray"""
- def __init__(self, length_or_array):
- super().__init__()
- if isinstance(length_or_array, int):
- self._array = [0] * length_or_array
- else:
- self._array = list(length_or_array)
- self._lock = _threading.Lock()
-
- def length(self):
- return len(self._array)
-
- def get(self, i):
- with self._lock:
- return self._array[i]
-
- def set(self, i, new_value):
- with self._lock:
- self._array[i] = int(new_value)
-
- def lazySet(self, i, new_value):
- self.set(i, new_value)
-
- def getAndSet(self, i, new_value):
- with self._lock:
- old = self._array[i]
- self._array[i] = int(new_value)
- return old
-
- def compareAndSet(self, i, expect, update):
- with self._lock:
- if self._array[i] == expect:
- self._array[i] = int(update)
- return True
- return False
-
- def weakCompareAndSet(self, i, expect, update):
- return self.compareAndSet(i, expect, update)
-
- def getAndIncrement(self, i):
- with self._lock:
- old = self._array[i]
- self._array[i] += 1
- return old
-
- def getAndDecrement(self, i):
- with self._lock:
- old = self._array[i]
- self._array[i] -= 1
- return old
-
- def getAndAdd(self, i, delta):
- with self._lock:
- old = self._array[i]
- self._array[i] += delta
- return old
-
- def incrementAndGet(self, i):
- with self._lock:
- self._array[i] += 1
- return self._array[i]
-
- def decrementAndGet(self, i):
- with self._lock:
- self._array[i] -= 1
- return self._array[i]
-
- def addAndGet(self, i, delta):
- with self._lock:
- self._array[i] += delta
- return self._array[i]
-
- def toString(self):
- return str(self._array)
-
-
-# ============================================================
-# AtomicReferenceArray
-# ============================================================
-
-class AtomicReferenceArray(Stub):
- """java.util.concurrent.atomic.AtomicReferenceArray"""
- def __init__(self, length_or_array):
- super().__init__()
- if isinstance(length_or_array, int):
- self._array = [None] * length_or_array
- else:
- self._array = list(length_or_array)
- self._lock = _threading.Lock()
-
- def length(self):
- return len(self._array)
-
- def get(self, i):
- with self._lock:
- return self._array[i]
-
- def set(self, i, new_value):
- with self._lock:
- self._array[i] = new_value
-
- def lazySet(self, i, new_value):
- self.set(i, new_value)
-
- def getAndSet(self, i, new_value):
- with self._lock:
- old = self._array[i]
- self._array[i] = new_value
- return old
-
- def compareAndSet(self, i, expect, update):
- with self._lock:
- if self._array[i] is expect or self._array[i] == expect:
- self._array[i] = update
- return True
- return False
-
- def weakCompareAndSet(self, i, expect, update):
- return self.compareAndSet(i, expect, update)
-
- def toString(self):
- return str(self._array)
-
-
-# ============================================================
-# AtomicMarkableReference
-# ============================================================
-
-class AtomicMarkableReference(Stub):
- """java.util.concurrent.atomic.AtomicMarkableReference"""
- def __init__(self, initial_ref, initial_mark):
- super().__init__()
- self._lock = _threading.Lock()
- self._reference = initial_ref
- self._mark = bool(initial_mark)
-
- def getReference(self):
- with self._lock:
- return self._reference
-
- def isMarked(self):
- with self._lock:
- return self._mark
-
- def get(self):
- with self._lock:
- return [self._reference, self._mark]
-
- def attemptMark(self, expected_reference, new_mark):
- with self._lock:
- if self._reference is expected_reference or self._reference == expected_reference:
- self._mark = bool(new_mark)
- return True
- return False
-
- def compareAndSet(self, expected_reference, new_reference,
- expected_mark, new_mark):
- with self._lock:
- if (self._reference is expected_reference or self._reference == expected_reference):
- if self._mark == expected_mark:
- self._reference = new_reference
- self._mark = bool(new_mark)
- return True
- return False
-
- def weakCompareAndSet(self, expected_reference, new_reference,
- expected_mark, new_mark):
- return self.compareAndSet(expected_reference, new_reference,
- expected_mark, new_mark)
-
-
-# ============================================================
-# AtomicStampedReference
-# ============================================================
-
-class AtomicStampedReference(Stub):
- """java.util.concurrent.atomic.AtomicStampedReference"""
- def __init__(self, initial_ref, initial_stamp):
- super().__init__()
- self._lock = _threading.Lock()
- self._reference = initial_ref
- self._stamp = int(initial_stamp)
-
- def getReference(self):
- with self._lock:
- return self._reference
-
- def getStamp(self):
- with self._lock:
- return self._stamp
-
- def get(self):
- with self._lock:
- return [self._reference, self._stamp]
-
- def attemptStamp(self, expected_reference, new_stamp):
- with self._lock:
- if self._reference is expected_reference or self._reference == expected_reference:
- self._stamp = int(new_stamp)
- return True
- return False
-
- def compareAndSet(self, expected_reference, new_reference,
- expected_stamp, new_stamp):
- with self._lock:
- if (self._reference is expected_reference or self._reference == expected_reference):
- if self._stamp == expected_stamp:
- self._reference = new_reference
- self._stamp = int(new_stamp)
- return True
- return False
-
- def weakCompareAndSet(self, expected_reference, new_reference,
- expected_stamp, new_stamp):
- return self.compareAndSet(expected_reference, new_reference,
- expected_stamp, new_stamp)
-
-
-# ============================================================
-# Field Updaters
-# ============================================================
-
-class AtomicIntegerFieldUpdater(Stub):
- """java.util.concurrent.atomic.AtomicIntegerFieldUpdater"""
- def __init__(self, tclass, field_name):
- super().__init__()
- self._tclass = tclass
- self._field_name = field_name
-
- @staticmethod
- def newUpdater(tclass, field_name):
- return AtomicIntegerFieldUpdater(tclass, field_name)
-
- def get(self, obj):
- return getattr(obj, self._field_name, 0)
-
- def set(self, obj, new_value):
- setattr(obj, self._field_name, int(new_value))
-
- def lazySet(self, obj, new_value):
- self.set(obj, new_value)
-
- def getAndSet(self, obj, new_value):
- old = self.get(obj)
- self.set(obj, new_value)
- return old
-
- def compareAndSet(self, obj, expect, update):
- if self.get(obj) == expect:
- self.set(obj, update)
- return True
- return False
-
- def weakCompareAndSet(self, obj, expect, update):
- return self.compareAndSet(obj, expect, update)
-
- def getAndIncrement(self, obj):
- old = self.get(obj)
- self.set(obj, old + 1)
- return old
-
- def getAndDecrement(self, obj):
- old = self.get(obj)
- self.set(obj, old - 1)
- return old
-
- def getAndAdd(self, obj, delta):
- old = self.get(obj)
- self.set(obj, old + delta)
- return old
-
- def incrementAndGet(self, obj):
- val = self.get(obj) + 1
- self.set(obj, val)
- return val
-
- def decrementAndGet(self, obj):
- val = self.get(obj) - 1
- self.set(obj, val)
- return val
-
- def addAndGet(self, obj, delta):
- val = self.get(obj) + delta
- self.set(obj, val)
- return val
-
-
-class AtomicLongFieldUpdater(Stub):
- """java.util.concurrent.atomic.AtomicLongFieldUpdater"""
- def __init__(self, tclass, field_name):
- super().__init__()
- self._tclass = tclass
- self._field_name = field_name
-
- @staticmethod
- def newUpdater(tclass, field_name):
- return AtomicLongFieldUpdater(tclass, field_name)
-
- def get(self, obj):
- return getattr(obj, self._field_name, 0)
-
- def set(self, obj, new_value):
- setattr(obj, self._field_name, int(new_value))
-
- def lazySet(self, obj, new_value):
- self.set(obj, new_value)
-
- def getAndSet(self, obj, new_value):
- old = self.get(obj)
- self.set(obj, new_value)
- return old
-
- def compareAndSet(self, obj, expect, update):
- if self.get(obj) == expect:
- self.set(obj, update)
- return True
- return False
-
- def weakCompareAndSet(self, obj, expect, update):
- return self.compareAndSet(obj, expect, update)
-
- def getAndIncrement(self, obj):
- old = self.get(obj)
- self.set(obj, old + 1)
- return old
-
- def getAndDecrement(self, obj):
- old = self.get(obj)
- self.set(obj, old - 1)
- return old
-
- def getAndAdd(self, obj, delta):
- old = self.get(obj)
- self.set(obj, old + delta)
- return old
-
- def incrementAndGet(self, obj):
- val = self.get(obj) + 1
- self.set(obj, val)
- return val
-
- def decrementAndGet(self, obj):
- val = self.get(obj) - 1
- self.set(obj, val)
- return val
-
- def addAndGet(self, obj, delta):
- val = self.get(obj) + delta
- self.set(obj, val)
- return val
-
-
-class AtomicReferenceFieldUpdater(Stub):
- """java.util.concurrent.atomic.AtomicReferenceFieldUpdater"""
- def __init__(self, tclass, vclass, field_name):
- super().__init__()
- self._tclass = tclass
- self._vclass = vclass
- self._field_name = field_name
-
- @staticmethod
- def newUpdater(tclass, vclass, field_name):
- return AtomicReferenceFieldUpdater(tclass, vclass, field_name)
-
- def get(self, obj):
- return getattr(obj, self._field_name, None)
-
- def set(self, obj, new_value):
- setattr(obj, self._field_name, new_value)
-
- def lazySet(self, obj, new_value):
- self.set(obj, new_value)
-
- def getAndSet(self, obj, new_value):
- old = self.get(obj)
- self.set(obj, new_value)
- return old
-
- def compareAndSet(self, obj, expect, update):
- if self.get(obj) is expect or self.get(obj) == expect:
- self.set(obj, update)
- return True
- return False
-
- def weakCompareAndSet(self, obj, expect, update):
- return self.compareAndSet(obj, expect, update)
-
-
-# ============================================================
-# DoubleAccumulator
-# ============================================================
-
-class DoubleAccumulator(Stub):
- """java.util.concurrent.atomic.DoubleAccumulator"""
- def __init__(self, accumulator_func, identity):
- super().__init__()
- self._lock = _threading.Lock()
- self._value = float(identity)
- self._func = accumulator_func
-
- def accumulate(self, x):
- with self._lock:
- self._value = self._func.applyAsDouble(self._value, float(x))
-
- def get(self):
- with self._lock:
- return self._value
-
- def reset(self):
- with self._lock:
- self._value = 0.0
-
- def getThenReset(self):
- with self._lock:
- old = self._value
- self._value = 0.0
- return old
-
- def toString(self):
- return str(self.get())
-
- def doubleValue(self):
- return self.get()
-
- def floatValue(self):
- return float(self.get())
-
- def intValue(self):
- return int(self.get())
-
- def longValue(self):
- return int(self.get())
-
-
-# ============================================================
-# DoubleAdder
-# ============================================================
-
-class DoubleAdder(Stub):
- """java.util.concurrent.atomic.DoubleAdder"""
- def __init__(self):
- super().__init__()
- self._lock = _threading.Lock()
- self._value = 0.0
-
- def add(self, x):
- with self._lock:
- self._value += float(x)
-
- def sum(self):
- with self._lock:
- return self._value
-
- def reset(self):
- with self._lock:
- self._value = 0.0
-
- def sumThenReset(self):
- with self._lock:
- old = self._value
- self._value = 0.0
- return old
-
- def toString(self):
- return str(self.sum())
-
- def doubleValue(self):
- return self.sum()
-
- def floatValue(self):
- return float(self.sum())
-
- def intValue(self):
- return int(self.sum())
-
- def longValue(self):
- return int(self.sum())
-
-
-# ============================================================
-# LongAccumulator
-# ============================================================
-
-class LongAccumulator(Stub):
- """java.util.concurrent.atomic.LongAccumulator"""
- def __init__(self, accumulator_func, identity):
- super().__init__()
- self._lock = _threading.Lock()
- self._value = int(identity)
- self._func = accumulator_func
-
- def accumulate(self, x):
- with self._lock:
- self._value = self._func.applyAsLong(self._value, int(x))
-
- def get(self):
- with self._lock:
- return self._value
-
- def reset(self):
- with self._lock:
- self._value = 0
-
- def getThenReset(self):
- with self._lock:
- old = self._value
- self._value = 0
- return old
-
- def toString(self):
- return str(self.get())
-
- def intValue(self):
- return int(self.get())
-
- def longValue(self):
- return self.get()
-
- def floatValue(self):
- return float(self.get())
-
- def doubleValue(self):
- return float(self.get())
-
-
-# ============================================================
-# LongAdder
-# ============================================================
-
-class LongAdder(Stub):
- """java.util.concurrent.atomic.LongAdder"""
- def __init__(self):
- super().__init__()
- self._lock = _threading.Lock()
- self._value = 0
-
- def add(self, x):
- with self._lock:
- self._value += int(x)
-
- def increment(self):
- self.add(1)
-
- def decrement(self):
- self.add(-1)
-
- def sum(self):
- with self._lock:
- return self._value
-
- def reset(self):
- with self._lock:
- self._value = 0
-
- def sumThenReset(self):
- with self._lock:
- old = self._value
- self._value = 0
- return old
-
- def toString(self):
- return str(self.sum())
-
- def intValue(self):
- return int(self.sum())
-
- def longValue(self):
- return self.sum()
-
- def floatValue(self):
- return float(self.sum())
-
- def doubleValue(self):
- return float(self.sum())
-
-
-# ============================================================
-# Striped64
-# ============================================================
-
-class Striped64(Stub):
- """java.util.concurrent.atomic.Striped64"""
- def __init__(self):
- super().__init__()
- self._value = 0
- self._lock = _threading.Lock()
-
- def _get_value(self):
- with self._lock:
- return self._value
-
- def _set_value(self, v):
- with self._lock:
- self._value = v
\ No newline at end of file
diff --git a/android_pyapi/java/util_concurrent_locks.py b/android_pyapi/java/util_concurrent_locks.py
deleted file mode 100644
index 871b16c..0000000
--- a/android_pyapi/java/util_concurrent_locks.py
+++ /dev/null
@@ -1,681 +0,0 @@
-"""
-Java java.util.concurrent.locks standard library APIs implemented in Python.
-java.util.concurrent.locks package - Lock, ReadWriteLock, ReentrantLock, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub
-from ..java.lang import RuntimeException
-
-# InterruptedException (桌面模拟)
-class InterruptedException(RuntimeException):
- def __init__(self, message=""):
- super().__init__(message)
-import threading as _threading
-import time as _time
-import collections as _collections
-
-__all__ = [
- "Lock", "ReadWriteLock", "ReentrantLock",
- "ReentrantReadWriteLock",
- "ReentrantReadWriteLock_ReadLock",
- "ReentrantReadWriteLock_WriteLock",
- "Condition", "LockSupport",
- "AbstractQueuedSynchronizer",
- "AbstractQueuedLongSynchronizer",
- "AbstractOwnableSynchronizer",
-]
-
-
-# ============================================================
-# Lock interface
-# ============================================================
-
-class Lock(Stub):
- """java.util.concurrent.locks.Lock"""
- def lock(self):
- raise NotImplementedError
-
- def lockInterruptibly(self):
- raise NotImplementedError
-
- def tryLock(self, time_val=None, unit=None):
- raise NotImplementedError
-
- def unlock(self):
- raise NotImplementedError
-
- def newCondition(self):
- raise NotImplementedError
-
-
-class ReadWriteLock(Stub):
- """java.util.concurrent.locks.ReadWriteLock"""
- def readLock(self):
- raise NotImplementedError
-
- def writeLock(self):
- raise NotImplementedError
-
-
-# ============================================================
-# ReentrantLock
-# ============================================================
-
-class ReentrantLock(Lock):
- """java.util.concurrent.locks.ReentrantLock"""
- def __init__(self, fair=False):
- super().__init__()
- self._lock = _threading.RLock()
- self._fair = fair
- self._owner = None
- self._hold_count = 0
-
- def lock(self):
- self._lock.acquire()
- self._owner = _threading.current_thread()
- self._hold_count += 1
-
- def lockInterruptibly(self):
- self.lock()
-
- def tryLock(self, timeout=None, unit=None):
- if timeout is None:
- acquired = self._lock.acquire(blocking=False)
- else:
- if unit is not None:
- timeout = timeout
- acquired = self._lock.acquire(blocking=True, timeout=timeout)
- if acquired:
- self._owner = _threading.current_thread()
- self._hold_count += 1
- return True
- return False
-
- def unlock(self):
- self._hold_count -= 1
- if self._hold_count == 0:
- self._owner = None
- self._lock.release()
-
- def newCondition(self):
- return Condition(self)
-
- def getHoldCount(self):
- return self._hold_count
-
- def isHeldByCurrentThread(self):
- return self._owner is _threading.current_thread()
-
- def isLocked(self):
- return self._owner is not None
-
- def isFair(self):
- return self._fair
-
- def getOwner(self):
- return self._owner
-
- def getQueuedThreads(self):
- return []
-
- def getQueueLength(self):
- return 0
-
- def hasQueuedThreads(self):
- return False
-
- def hasQueuedThread(self, thread):
- return False
-
- def toString(self):
- status = "Locked" if self.isLocked() else "Unlocked"
- return f"ReentrantLock[{status}, hold={self._hold_count}]"
-
-
-# ============================================================
-# ReentrantReadWriteLock
-# ============================================================
-
-class ReentrantReadWriteLock(ReadWriteLock):
- """java.util.concurrent.locks.ReentrantReadWriteLock"""
- def __init__(self, fair=False):
- super().__init__()
- self._fair = fair
- self._read_lock = ReentrantReadWriteLock_ReadLock(self)
- self._write_lock = ReentrantReadWriteLock_WriteLock(self)
- self._read_hold_count = 0
- self._write_hold_count = 0
- self._write_owner = None
- self._lock = _threading.RLock()
- self._read_lock_obj = _threading.Lock()
- self._read_cond = _threading.Condition(self._read_lock_obj)
- self._readers = 0
- self._writers_waiting = 0
-
- def readLock(self):
- return self._read_lock
-
- def writeLock(self):
- return self._write_lock
-
- def isFair(self):
- return self._fair
-
- def getReadLockCount(self):
- return self._readers
-
- def isWriteLocked(self):
- return self._write_owner is not None
-
- def isWriteLockedByCurrentThread(self):
- return self._write_owner is _threading.current_thread()
-
- def getWriteHoldCount(self):
- return self._write_hold_count
-
- def getReadHoldCount(self):
- return self._read_hold_count
-
- def getOwner(self):
- return self._write_owner
-
- def getQueuedWriterThreads(self):
- return []
-
- def getQueuedReaderThreads(self):
- return []
-
- def getQueueLength(self):
- return 0
-
- def hasQueuedThreads(self):
- return False
-
- def hasQueuedThread(self, thread):
- return False
-
- def toString(self):
- w = self._write_hold_count
- r = self._readers
- return f"ReentrantReadWriteLock[read_locks={r}, write_locks={w}]"
-
- def _acquire_read(self):
- with self._lock:
- while self._write_owner is not None and self._write_owner != _threading.current_thread():
- self._read_cond.wait()
- self._readers += 1
- self._read_hold_count += 1
-
- def _release_read(self):
- with self._lock:
- self._readers -= 1
- self._read_hold_count -= 1
- if self._readers == 0:
- self._read_cond.notify_all()
-
- def _acquire_write(self):
- self._lock.acquire()
- self._write_owner = _threading.current_thread()
- self._write_hold_count += 1
-
- def _release_write(self):
- self._write_hold_count -= 1
- if self._write_hold_count == 0:
- self._write_owner = None
- self._read_cond.notify_all()
- self._lock.release()
-
-
-class ReentrantReadWriteLock_ReadLock(Lock):
- """java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock"""
- def __init__(self, rw_lock):
- super().__init__()
- self._rw_lock = rw_lock
-
- def lock(self):
- self._rw_lock._acquire_read()
-
- def lockInterruptibly(self):
- self.lock()
-
- def tryLock(self, timeout=None, unit=None):
- self.lock()
- return True
-
- def unlock(self):
- self._rw_lock._release_read()
-
- def newCondition(self):
- raise UnsupportedOperationException("Read locks do not support Condition")
-
-
-class ReentrantReadWriteLock_WriteLock(Lock):
- """java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock"""
- def __init__(self, rw_lock):
- super().__init__()
- self._rw_lock = rw_lock
-
- def lock(self):
- self._rw_lock._acquire_write()
-
- def lockInterruptibly(self):
- self.lock()
-
- def tryLock(self, timeout=None, unit=None):
- if timeout is None:
- acquired = self._rw_lock._lock.acquire(blocking=False)
- else:
- acquired = self._rw_lock._lock.acquire(blocking=True, timeout=timeout)
- if acquired:
- self._rw_lock._write_owner = _threading.current_thread()
- self._rw_lock._write_hold_count += 1
- return True
- return False
-
- def unlock(self):
- self._rw_lock._release_write()
-
- def newCondition(self):
- return Condition(self)
-
- def isHeldByCurrentThread(self):
- return self._rw_lock._write_owner is _threading.current_thread()
-
-
-# ============================================================
-# Condition
-# ============================================================
-
-class Condition(Stub):
- """java.util.concurrent.locks.Condition"""
- def __init__(self, lock=None):
- super().__init__()
- self._lock = lock
- self._cond = _threading.Condition(_threading.RLock()) if lock is None else _threading.Condition()
-
- def await_signal(self, time_val=None, unit=None):
- self._cond.acquire()
- try:
- if time_val is None:
- self._cond.wait()
- return True
- else:
- if unit is not None:
- secs = time_val / 1000.0 # milliseconds
- else:
- secs = float(time_val)
- self._cond.wait(timeout=secs)
- return True
- finally:
- self._cond.release()
-
- def awaitUninterruptibly(self):
- self.await_signal()
-
- def awaitNanos(self, nanos_timeout):
- self.await_signal(nanos_timeout / 1000000.0)
- return 0
-
- def awaitUntil(self, deadline):
- now = _time.time()
- diff = deadline - now
- if diff > 0:
- self.await_signal(diff)
- return True
-
- def signal(self):
- self._cond.acquire()
- try:
- self._cond.notify()
- finally:
- self._cond.release()
-
- def signalAll(self):
- self._cond.acquire()
- try:
- self._cond.notify_all()
- finally:
- self._cond.release()
-
-
-# ============================================================
-# LockSupport
-# ============================================================
-
-class LockSupport(Stub):
- """java.util.concurrent.locks.LockSupport"""
- _blocked = {}
-
- @staticmethod
- def park(blocker=None):
- if blocker is not None:
- LockSupport._blocked[_threading.current_thread().ident] = blocker
- _time.sleep(0.01)
- if blocker is not None:
- del LockSupport._blocked[_threading.current_thread().ident]
-
- @staticmethod
- def parkNanos(nanos, blocker=None):
- if blocker is not None:
- LockSupport._blocked[_threading.current_thread().ident] = blocker
- _time.sleep(nanos / 1000000000.0)
- if blocker is not None:
- del LockSupport._blocked[_threading.current_thread().ident]
-
- @staticmethod
- def parkUntil(deadline, blocker=None):
- now = _time.time()
- diff = deadline - now
- if diff > 0:
- if blocker is not None:
- LockSupport._blocked[_threading.current_thread().ident] = blocker
- _time.sleep(diff)
- if blocker is not None:
- del LockSupport._blocked[_threading.current_thread().ident]
-
- @staticmethod
- def unpark(thread):
- pass
-
- @staticmethod
- def getBlocker(thread):
- return LockSupport._blocked.get(thread.ident)
-
-
-# ============================================================
-# AbstractOwnableSynchronizer
-# ============================================================
-
-class AbstractOwnableSynchronizer(Stub):
- """java.util.concurrent.locks.AbstractOwnableSynchronizer"""
- def __init__(self):
- super().__init__()
- self._exclusive_owner_thread = None
-
- def setExclusiveOwnerThread(self, thread):
- self._exclusive_owner_thread = thread
-
- def getExclusiveOwnerThread(self):
- return self._exclusive_owner_thread
-
-
-# ============================================================
-# AbstractQueuedSynchronizer
-# ============================================================
-
-class AbstractQueuedSynchronizer(AbstractOwnableSynchronizer):
- """java.util.concurrent.locks.AbstractQueuedSynchronizer"""
- class ConditionObject(Condition):
- def __init__(self, sync):
- super().__init__()
- self._sync = sync
-
- def __init__(self):
- super().__init__()
- self._state = 0
- self._lock = _threading.Lock()
- self._cond = _threading.Condition(self._lock)
- self._head = None
- self._tail = None
- self._wait_queue = _collections.deque()
-
- def getState(self):
- with self._lock:
- return self._state
-
- def setState(self, new_state):
- with self._lock:
- self._state = new_state
-
- def compareAndSetState(self, expect, update):
- with self._lock:
- if self._state == expect:
- self._state = int(update)
- return True
- return False
-
- def acquire(self, arg):
- if not self.tryAcquire(arg):
- self._acquire_queued(self._add_waiter(), arg)
-
- def acquireInterruptibly(self, arg):
- self.acquire(arg)
-
- def tryAcquireNanos(self, arg, nanos_timeout):
- return self.tryAcquire(arg)
-
- def release(self, arg):
- if self.tryRelease(arg):
- self._signal_next()
- return True
- return False
-
- def acquireShared(self, arg):
- if self.tryAcquireShared(arg) < 0:
- self._acquire_shared_queued(self._add_waiter(), arg)
-
- def acquireSharedInterruptibly(self, arg):
- self.acquireShared(arg)
-
- def tryAcquireSharedNanos(self, arg, nanos_timeout):
- return self.tryAcquireShared(arg) >= 0
-
- def releaseShared(self, arg):
- if self.tryReleaseShared(arg):
- self._signal_next()
- return True
- return False
-
- def tryAcquire(self, arg):
- raise NotImplementedError
-
- def tryRelease(self, arg):
- raise NotImplementedError
-
- def tryAcquireShared(self, arg):
- return 1
-
- def tryReleaseShared(self, arg):
- return True
-
- def isHeldExclusively(self):
- return self.getExclusiveOwnerThread() is _threading.current_thread()
-
- def getQueuedThreads(self):
- return list(self._wait_queue)
-
- def getQueueLength(self):
- return len(self._wait_queue)
-
- def hasQueuedThreads(self):
- return len(self._wait_queue) > 0
-
- def hasContended(self):
- return len(self._wait_queue) > 0
-
- def getFirstQueuedThread(self):
- if self._wait_queue:
- return self._wait_queue[0]
- return None
-
- def owns(self, condition):
- return isinstance(condition, AbstractQueuedSynchronizer.ConditionObject)
-
- def hasWaiters(self, condition):
- return False
-
- def getWaitQueueLength(self, condition):
- return 0
-
- def getWaitingThreads(self, condition):
- return []
-
- def toString(self):
- return f"AbstractQueuedSynchronizer[state={self._state}]"
-
- def _add_waiter(self):
- thread = _threading.current_thread()
- with self._lock:
- self._wait_queue.append(thread)
- return thread
-
- def _acquire_queued(self, node, arg):
- while True:
- if self.tryAcquire(arg):
- with self._lock:
- if node in self._wait_queue:
- self._wait_queue.remove(node)
- return
- _time.sleep(0.001)
-
- def _acquire_shared_queued(self, node, arg):
- while True:
- if self.tryAcquireShared(arg) >= 0:
- with self._lock:
- if node in self._wait_queue:
- self._wait_queue.remove(node)
- return
- _time.sleep(0.001)
-
- def _signal_next(self):
- with self._lock:
- if self._wait_queue:
- self._cond.notify()
-
-
-# ============================================================
-# AbstractQueuedLongSynchronizer
-# ============================================================
-
-class AbstractQueuedLongSynchronizer(AbstractOwnableSynchronizer):
- """java.util.concurrent.locks.AbstractQueuedLongSynchronizer"""
- class ConditionObject(Condition):
- def __init__(self, sync):
- super().__init__()
- self._sync = sync
-
- def __init__(self):
- super().__init__()
- self._state = 0
- self._lock = _threading.Lock()
- self._cond = _threading.Condition(self._lock)
- self._wait_queue = _collections.deque()
-
- def getState(self):
- with self._lock:
- return self._state
-
- def setState(self, new_state):
- with self._lock:
- self._state = int(new_state)
-
- def compareAndSetState(self, expect, update):
- with self._lock:
- if self._state == expect:
- self._state = int(update)
- return True
- return False
-
- def acquire(self, arg):
- if not self.tryAcquire(arg):
- self._acquire_queued(self._add_waiter(), arg)
-
- def acquireInterruptibly(self, arg):
- self.acquire(arg)
-
- def tryAcquireNanos(self, arg, nanos_timeout):
- return self.tryAcquire(arg)
-
- def release(self, arg):
- if self.tryRelease(arg):
- self._signal_next()
- return True
- return False
-
- def acquireShared(self, arg):
- if self.tryAcquireShared(arg) < 0:
- self._acquire_shared_queued(self._add_waiter(), arg)
-
- def acquireSharedInterruptibly(self, arg):
- self.acquireShared(arg)
-
- def tryAcquireSharedNanos(self, arg, nanos_timeout):
- return self.tryAcquireShared(arg) >= 0
-
- def releaseShared(self, arg):
- if self.tryReleaseShared(arg):
- self._signal_next()
- return True
- return False
-
- def tryAcquire(self, arg):
- raise NotImplementedError
-
- def tryRelease(self, arg):
- raise NotImplementedError
-
- def tryAcquireShared(self, arg):
- return 1
-
- def tryReleaseShared(self, arg):
- return True
-
- def isHeldExclusively(self):
- return self.getExclusiveOwnerThread() is _threading.current_thread()
-
- def getQueuedThreads(self):
- return list(self._wait_queue)
-
- def getQueueLength(self):
- return len(self._wait_queue)
-
- def hasQueuedThreads(self):
- return len(self._wait_queue) > 0
-
- def getFirstQueuedThread(self):
- if self._wait_queue:
- return self._wait_queue[0]
- return None
-
- def toString(self):
- return f"AbstractQueuedLongSynchronizer[state={self._state}]"
-
- def _add_waiter(self):
- thread = _threading.current_thread()
- with self._lock:
- self._wait_queue.append(thread)
- return thread
-
- def _acquire_queued(self, node, arg):
- while True:
- if self.tryAcquire(arg):
- with self._lock:
- if node in self._wait_queue:
- self._wait_queue.remove(node)
- return
- _time.sleep(0.001)
-
- def _acquire_shared_queued(self, node, arg):
- while True:
- if self.tryAcquireShared(arg) >= 0:
- with self._lock:
- if node in self._wait_queue:
- self._wait_queue.remove(node)
- return
- _time.sleep(0.001)
-
- def _signal_next(self):
- with self._lock:
- if self._wait_queue:
- self._cond.notify()
-
-
-# ============================================================
-# UnsupportedOperationException
-# ============================================================
-
-class UnsupportedOperationException(RuntimeException):
- """java.lang.UnsupportedOperationException"""
- pass
\ No newline at end of file
diff --git a/android_pyapi/java/util_function.py b/android_pyapi/java/util_function.py
deleted file mode 100644
index 96becf7..0000000
--- a/android_pyapi/java/util_function.py
+++ /dev/null
@@ -1,599 +0,0 @@
-"""
-Java java.util.function standard library APIs implemented in Python.
-java.util.function package - Function, Consumer, Predicate, Supplier, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub
-from .lang import RuntimeException
-import typing as _typing
-
-__all__ = [
- "BiConsumer", "BiFunction", "BiPredicate", "BinaryOperator",
- "Consumer", "DoubleBinaryOperator", "DoubleConsumer",
- "DoubleFunction", "DoublePredicate", "DoubleSupplier",
- "DoubleToIntFunction", "DoubleToLongFunction",
- "Function", "IntBinaryOperator", "IntConsumer",
- "IntFunction", "IntPredicate", "IntSupplier",
- "IntToDoubleFunction", "IntToLongFunction",
- "LongBinaryOperator", "LongConsumer", "LongFunction",
- "LongPredicate", "LongSupplier", "LongToDoubleFunction",
- "LongToIntFunction",
- "ObjDoubleConsumer", "ObjIntConsumer", "ObjLongConsumer",
- "Predicate", "Supplier",
- "ToDoubleBiFunction", "ToDoubleFunction",
- "ToIntBiFunction", "ToIntFunction",
- "ToLongBiFunction", "ToLongFunction",
- "UnaryOperator",
-]
-
-T = _typing.TypeVar("T")
-R = _typing.TypeVar("R")
-
-
-# ============================================================
-# Core functional interfaces
-# ============================================================
-
-class Function(Stub):
- """java.util.function.Function"""
- def apply(self, t):
- raise NotImplementedError
-
- def compose(self, before):
- class Composed(Function):
- def apply(self, t):
- return self.apply(before.apply(t))
- return Composed()
-
- def andThen(self, after):
- class ComposedAndThen(Function):
- def apply(self, t):
- return after.apply(self.apply(t))
- return ComposedAndThen()
-
- @staticmethod
- def identity():
- class Identity(Function):
- def apply(self, t):
- return t
- return Identity()
-
-
-class BiFunction(Stub):
- """java.util.function.BiFunction"""
- def apply(self, t, u):
- raise NotImplementedError
-
- def andThen(self, after):
- class Composed(BiFunction):
- def apply(self, t, u):
- return after.apply(self.apply(t, u))
- return Composed()
-
-
-class UnaryOperator(Function):
- """java.util.function.UnaryOperator"""
- @staticmethod
- def identity():
- class Identity(UnaryOperator):
- def apply(self, t):
- return t
- return Identity()
-
-
-class BinaryOperator(BiFunction):
- """java.util.function.BinaryOperator"""
- @staticmethod
- def min_by(comparator):
- class MinBy(BinaryOperator):
- def apply(self, a, b):
- return a if comparator.compare(a, b) <= 0 else b
- return MinBy()
-
- @staticmethod
- def max_by(comparator):
- class MaxBy(BinaryOperator):
- def apply(self, a, b):
- return a if comparator.compare(a, b) >= 0 else b
- return MaxBy()
-
-
-class Predicate(Stub):
- """java.util.function.Predicate"""
- def test(self, t):
- raise NotImplementedError
-
- def and_(self, other):
- class And(Predicate):
- def test(self, t):
- return self.test(t) and other.test(t)
- return And()
-
- def negate(self):
- class Negate(Predicate):
- def test(self, t):
- return not self.test(t)
- return Negate()
-
- def or_(self, other):
- class Or(Predicate):
- def test(self, t):
- return self.test(t) or other.test(t)
- return Or()
-
- @staticmethod
- def is_equal(target_ref):
- class IsEqual(Predicate):
- def test(self, t):
- return t == target_ref
- return IsEqual()
-
- @staticmethod
- def not_(target):
- class Not(Predicate):
- def test(self, t):
- return not target.test(t)
- return Not()
-
-
-class BiPredicate(Stub):
- """java.util.function.BiPredicate"""
- def test(self, t, u):
- raise NotImplementedError
-
- def and_(self, other):
- class And(BiPredicate):
- def test(self, t, u):
- return self.test(t, u) and other.test(t, u)
- return And()
-
- def negate(self):
- class Negate(BiPredicate):
- def test(self, t, u):
- return not self.test(t, u)
- return Negate()
-
- def or_(self, other):
- class Or(BiPredicate):
- def test(self, t, u):
- return self.test(t, u) or other.test(t, u)
- return Or()
-
-
-class Consumer(Stub):
- """java.util.function.Consumer"""
- def accept(self, t):
- raise NotImplementedError
-
- def andThen(self, after):
- class Composed(Consumer):
- def accept(self, t):
- self.accept(t)
- after.accept(t)
- return Composed()
-
-
-class BiConsumer(Stub):
- """java.util.function.BiConsumer"""
- def accept(self, t, u):
- raise NotImplementedError
-
- def andThen(self, after):
- class Composed(BiConsumer):
- def accept(self, t, u):
- self.accept(t, u)
- after.accept(t, u)
- return Composed()
-
-
-class Supplier(Stub):
- """java.util.function.Supplier"""
- def get(self):
- raise NotImplementedError
-
-
-# ============================================================
-# Primitive specializations
-# ============================================================
-
-class IntFunction(Stub):
- """java.util.function.IntFunction"""
- def apply(self, value):
- raise NotImplementedError
-
-
-class LongFunction(Stub):
- """java.util.function.LongFunction"""
- def apply(self, value):
- raise NotImplementedError
-
-
-class DoubleFunction(Stub):
- """java.util.function.DoubleFunction"""
- def apply(self, value):
- raise NotImplementedError
-
-
-class IntConsumer(Stub):
- """java.util.function.IntConsumer"""
- def accept(self, value):
- raise NotImplementedError
-
- def andThen(self, after):
- class Composed(IntConsumer):
- def accept(self, value):
- self.accept(value)
- after.accept(value)
- return Composed()
-
-
-class LongConsumer(Stub):
- """java.util.function.LongConsumer"""
- def accept(self, value):
- raise NotImplementedError
-
- def andThen(self, after):
- class Composed(LongConsumer):
- def accept(self, value):
- self.accept(value)
- after.accept(value)
- return Composed()
-
-
-class DoubleConsumer(Stub):
- """java.util.function.DoubleConsumer"""
- def accept(self, value):
- raise NotImplementedError
-
- def andThen(self, after):
- class Composed(DoubleConsumer):
- def accept(self, value):
- self.accept(value)
- after.accept(value)
- return Composed()
-
-
-class IntPredicate(Stub):
- """java.util.function.IntPredicate"""
- def test(self, value):
- raise NotImplementedError
-
- def and_(self, other):
- class And(IntPredicate):
- def test(self, value):
- return self.test(value) and other.test(value)
- return And()
-
- def negate(self):
- class Negate(IntPredicate):
- def test(self, value):
- return not self.test(value)
- return Negate()
-
- def or_(self, other):
- class Or(IntPredicate):
- def test(self, value):
- return self.test(value) or other.test(value)
- return Or()
-
-
-class LongPredicate(Stub):
- """java.util.function.LongPredicate"""
- def test(self, value):
- raise NotImplementedError
-
- def and_(self, other):
- class And(LongPredicate):
- def test(self, value):
- return self.test(value) and other.test(value)
- return And()
-
- def negate(self):
- class Negate(LongPredicate):
- def test(self, value):
- return not self.test(value)
- return Negate()
-
- def or_(self, other):
- class Or(LongPredicate):
- def test(self, value):
- return self.test(value) or other.test(value)
- return Or()
-
-
-class DoublePredicate(Stub):
- """java.util.function.DoublePredicate"""
- def test(self, value):
- raise NotImplementedError
-
- def and_(self, other):
- class And(DoublePredicate):
- def test(self, value):
- return self.test(value) and other.test(value)
- return And()
-
- def negate(self):
- class Negate(DoublePredicate):
- def test(self, value):
- return not self.test(value)
- return Negate()
-
- def or_(self, other):
- class Or(DoublePredicate):
- def test(self, value):
- return self.test(value) or other.test(value)
- return Or()
-
-
-class IntSupplier(Stub):
- """java.util.function.IntSupplier"""
- def getAsInt(self):
- raise NotImplementedError
-
-
-class LongSupplier(Stub):
- """java.util.function.LongSupplier"""
- def getAsLong(self):
- raise NotImplementedError
-
-
-class DoubleSupplier(Stub):
- """java.util.function.DoubleSupplier"""
- def getAsDouble(self):
- raise NotImplementedError
-
-
-class IntBinaryOperator(Stub):
- """java.util.function.IntBinaryOperator"""
- def applyAsInt(self, left, right):
- raise NotImplementedError
-
-
-class LongBinaryOperator(Stub):
- """java.util.function.LongBinaryOperator"""
- def applyAsLong(self, left, right):
- raise NotImplementedError
-
-
-class DoubleBinaryOperator(Stub):
- """java.util.function.DoubleBinaryOperator"""
- def applyAsDouble(self, left, right):
- raise NotImplementedError
-
-
-# ============================================================
-# Int-Unary conversion functions
-# ============================================================
-
-class IntToDoubleFunction(Stub):
- """java.util.function.IntToDoubleFunction"""
- def applyAsDouble(self, value):
- raise NotImplementedError
-
-
-class IntToLongFunction(Stub):
- """java.util.function.IntToLongFunction"""
- def applyAsLong(self, value):
- raise NotImplementedError
-
-
-class LongToDoubleFunction(Stub):
- """java.util.function.LongToDoubleFunction"""
- def applyAsDouble(self, value):
- raise NotImplementedError
-
-
-class LongToIntFunction(Stub):
- """java.util.function.LongToIntFunction"""
- def applyAsInt(self, value):
- raise NotImplementedError
-
-
-class DoubleToIntFunction(Stub):
- """java.util.function.DoubleToIntFunction"""
- def applyAsInt(self, value):
- raise NotImplementedError
-
-
-class DoubleToLongFunction(Stub):
- """java.util.function.DoubleToLongFunction"""
- def applyAsLong(self, value):
- raise NotImplementedError
-
-
-# ============================================================
-# Obj*Consumer (mix of object and primitive)
-# ============================================================
-
-class ObjIntConsumer(Stub):
- """java.util.function.ObjIntConsumer"""
- def accept(self, t, value):
- raise NotImplementedError
-
-
-class ObjLongConsumer(Stub):
- """java.util.function.ObjLongConsumer"""
- def accept(self, t, value):
- raise NotImplementedError
-
-
-class ObjDoubleConsumer(Stub):
- """java.util.function.ObjDoubleConsumer"""
- def accept(self, t, value):
- raise NotImplementedError
-
-
-# ============================================================
-# To* functions
-# ============================================================
-
-class ToIntFunction(Stub):
- """java.util.function.ToIntFunction"""
- def applyAsInt(self, value):
- raise NotImplementedError
-
-
-class ToLongFunction(Stub):
- """java.util.function.ToLongFunction"""
- def applyAsLong(self, value):
- raise NotImplementedError
-
-
-class ToDoubleFunction(Stub):
- """java.util.function.ToDoubleFunction"""
- def applyAsDouble(self, value):
- raise NotImplementedError
-
-
-class ToIntBiFunction(Stub):
- """java.util.function.ToIntBiFunction"""
- def applyAsInt(self, t, u):
- raise NotImplementedError
-
-
-class ToLongBiFunction(Stub):
- """java.util.function.ToLongBiFunction"""
- def applyAsLong(self, t, u):
- raise NotImplementedError
-
-
-class ToDoubleBiFunction(Stub):
- """java.util.function.ToDoubleBiFunction"""
- def applyAsDouble(self, t, u):
- raise NotImplementedError
-
-
-# ============================================================
-# Convenience wrapper helpers
-# ============================================================
-
-class _FunctionWrapper(Function):
- """Wraps a Python callable as a java.util.function.Function"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def apply(self, t):
- return self._fn(t)
-
-
-class _ConsumerWrapper(Consumer):
- """Wraps a Python callable as a java.util.function.Consumer"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def accept(self, t):
- self._fn(t)
-
-
-class _PredicateWrapper(Predicate):
- """Wraps a Python callable as a java.util.function.Predicate"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def test(self, t):
- return self._fn(t)
-
-
-class _SupplierWrapper(Supplier):
- """Wraps a Python callable as a java.util.function.Supplier"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def get(self):
- return self._fn()
-
-
-class _BiFunctionWrapper(BiFunction):
- """Wraps a Python callable as a java.util.function.BiFunction"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def apply(self, t, u):
- return self._fn(t, u)
-
-
-class _BiConsumerWrapper(BiConsumer):
- """Wraps a Python callable as a java.util.function.BiConsumer"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def accept(self, t, u):
- self._fn(t, u)
-
-
-class _BiPredicateWrapper(BiPredicate):
- """Wraps a Python callable as a java.util.function.BiPredicate"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def test(self, t, u):
- return self._fn(t, u)
-
-
-class _IntFunctionWrapper(IntFunction):
- """Wraps a Python callable as a java.util.function.IntFunction"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def apply(self, value):
- return self._fn(value)
-
-
-class _LongFunctionWrapper(LongFunction):
- """Wraps a Python callable as a java.util.function.LongFunction"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def apply(self, value):
- return self._fn(value)
-
-
-class _DoubleFunctionWrapper(DoubleFunction):
- """Wraps a Python callable as a java.util.function.DoubleFunction"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def apply(self, value):
- return self._fn(value)
-
-
-class _IntConsumerWrapper(IntConsumer):
- """Wraps a Python callable as a java.util.function.IntConsumer"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def accept(self, value):
- self._fn(value)
-
-
-class _LongConsumerWrapper(LongConsumer):
- """Wraps a Python callable as a java.util.function.LongConsumer"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def accept(self, value):
- self._fn(value)
-
-
-class _DoubleConsumerWrapper(DoubleConsumer):
- """Wraps a Python callable as a java.util.function.DoubleConsumer"""
- def __init__(self, fn):
- super().__init__()
- self._fn = fn
-
- def accept(self, value):
- self._fn(value)
\ No newline at end of file
diff --git a/android_pyapi/java/util_logging.py b/android_pyapi/java/util_logging.py
deleted file mode 100644
index 24be054..0000000
--- a/android_pyapi/java/util_logging.py
+++ /dev/null
@@ -1,939 +0,0 @@
-"""
-Java java.util.logging standard library APIs implemented in Python.
-java.util.logging package - Logger, Level, Handler, Formatter, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub
-from .lang import RuntimeException, Exception as _JavaException
-from .security import BasicPermission
-import typing as _typing
-import sys as _sys
-import datetime as _datetime
-import io as _io
-import threading as _threading
-import traceback as _traceback
-import os as _os
-
-__all__ = [
- "Logger", "Level",
- "Handler", "ConsoleHandler", "FileHandler", "StreamHandler",
- "SocketHandler", "MemoryHandler",
- "Formatter", "SimpleFormatter", "XMLFormatter",
- "LogRecord", "LogManager", "Filter", "ErrorManager",
- "LoggingMXBean", "LoggingPermission",
- "OFF", "SEVERE", "WARNING", "INFO", "CONFIG", "FINE", "FINER", "FINEST", "ALL",
-]
-
-import sys as _sys
-import threading as _threading
-
-
-# ============================================================
-# Level Constants
-# ============================================================
-
-class _Integer:
- """Wrapper to emulate Integer.MIN_VALUE / MAX_VALUE"""
- MIN_VALUE = -2147483648
- MAX_VALUE = 2147483647
-
-
-OFF = _Integer.MAX_VALUE
-SEVERE = 1000
-WARNING = 900
-INFO = 800
-CONFIG = 700
-FINE = 500
-FINER = 400
-FINEST = 300
-ALL = _Integer.MIN_VALUE
-
-
-# ============================================================
-# Level
-# ============================================================
-
-class Level(Stub):
- """java.util.logging.Level"""
- def __init__(self, name, value, resource_bundle_name=None):
- super().__init__()
- self._name = name
- self._value = value
- self._resource_bundle_name = resource_bundle_name
-
- def getName(self):
- return self._name
-
- def intValue(self):
- return self._value
-
- def getResourceBundleName(self):
- return self._resource_bundle_name
-
- def toString(self):
- return self._name
-
- def hashCode(self):
- return self._value
-
- def equals(self, other):
- if not isinstance(other, Level):
- return False
- return self._value == other._value
-
- def parse(self, name):
- name_upper = name.upper()
- level_map = {
- "OFF": Level.OFF,
- "SEVERE": Level.SEVERE,
- "WARNING": Level.WARNING,
- "INFO": Level.INFO,
- "CONFIG": Level.CONFIG,
- "FINE": Level.FINE,
- "FINER": Level.FINER,
- "FINEST": Level.FINEST,
- "ALL": Level.ALL,
- }
- if name_upper in level_map:
- return level_map[name_upper]
- try:
- return Level(name, int(name))
- except ValueError:
- raise IllegalArgumentException(f"Bad level name: {name}")
-
- def __lt__(self, other):
- if isinstance(other, Level):
- return self._value < other._value
- return NotImplemented
-
- def __le__(self, other):
- if isinstance(other, Level):
- return self._value <= other._value
- return NotImplemented
-
- def __gt__(self, other):
- if isinstance(other, Level):
- return self._value > other._value
- return NotImplemented
-
- def __ge__(self, other):
- if isinstance(other, Level):
- return self._value >= other._value
- return NotImplemented
-
- # Static level instances
- OFF = None
- SEVERE = None
- WARNING = None
- INFO = None
- CONFIG = None
- FINE = None
- FINER = None
- FINEST = None
- ALL = None
-
-
-# ============================================================
-# Initialize static Level instances
-# ============================================================
-
-Level.OFF = Level("OFF", _Integer.MAX_VALUE)
-Level.SEVERE = Level("SEVERE", 1000)
-Level.WARNING = Level("WARNING", 900)
-Level.INFO = Level("INFO", 800)
-Level.CONFIG = Level("CONFIG", 700)
-Level.FINE = Level("FINE", 500)
-Level.FINER = Level("FINER", 400)
-Level.FINEST = Level("FINEST", 300)
-Level.ALL = Level("ALL", _Integer.MIN_VALUE)
-
-
-# ============================================================
-# LogRecord
-# ============================================================
-
-class LogRecord(Stub):
- """java.util.logging.LogRecord"""
- def __init__(self, level, msg):
- super().__init__()
- self._level = level if isinstance(level, Level) else Level.INFO
- self._logger_name = ""
- self._message = msg
- self._millis = _datetime.datetime.now().timestamp() * 1000
- self._thread_id = _threading.get_ident()
- self._source_class_name = None
- self._source_method_name = None
- self._thrown = None
- self._parameters = None
- self._resource_bundle = None
- self._resource_bundle_name = None
- self._sequence_number = id(self)
- self._long_thread_id = _threading.get_ident()
-
- def getLevel(self):
- return self._level
-
- def setLevel(self, level):
- self._level = level
-
- def getLoggerName(self):
- return self._logger_name
-
- def setLoggerName(self, name):
- self._logger_name = name
-
- def getMessage(self):
- return self._message
-
- def setMessage(self, msg):
- self._message = msg
-
- def getMillis(self):
- return self._millis
-
- def setMillis(self, millis):
- self._millis = millis
-
- def getThreadID(self):
- return self._thread_id
-
- def setThreadID(self, thread_id):
- self._thread_id = thread_id
-
- def getSourceClassName(self):
- return self._source_class_name
-
- def setSourceClassName(self, name):
- self._source_class_name = name
-
- def getSourceMethodName(self):
- return self._source_method_name
-
- def setSourceMethodName(self, name):
- self._source_method_name = name
-
- def getThrown(self):
- return self._thrown
-
- def setThrown(self, thrown):
- self._thrown = thrown
-
- def getParameters(self):
- return self._parameters
-
- def setParameters(self, params):
- self._parameters = params
-
- def getResourceBundle(self):
- return self._resource_bundle
-
- def setResourceBundle(self, bundle):
- self._resource_bundle = bundle
-
- def getResourceBundleName(self):
- return self._resource_bundle_name
-
- def setResourceBundleName(self, name):
- self._resource_bundle_name = name
-
- def getSequenceNumber(self):
- return self._sequence_number
-
- def setSequenceNumber(self, seq):
- self._sequence_number = seq
-
- def getLongThreadID(self):
- return self._long_thread_id
-
- def setLongThreadID(self, thread_id):
- self._long_thread_id = thread_id
-
-
-# ============================================================
-# Filter
-# ============================================================
-
-class Filter(Stub):
- """java.util.logging.Filter"""
- def isLoggable(self, record):
- return True
-
-
-# ============================================================
-# Formatter
-# ============================================================
-
-class Formatter(Stub):
- """java.util.logging.Formatter"""
- def format(self, record):
- raise NotImplementedError
-
- def getHead(self, handler):
- return ""
-
- def getTail(self, handler):
- return ""
-
- def formatMessage(self, record):
- msg = record.getMessage()
- params = record.getParameters()
- if params:
- try:
- return msg % params
- except Exception:
- pass
- return msg
-
-
-class SimpleFormatter(Formatter):
- """java.util.logging.SimpleFormatter"""
- def format(self, record):
- import datetime as dt
- ts = dt.datetime.fromtimestamp(record.getMillis() / 1000.0)
- ts_str = ts.strftime("%Y-%m-%d %H:%M:%S")
- msg = self.formatMessage(record)
- thrown = record.getThrown()
- result = f"{ts_str} {record.getLevel().getName()} {record.getLoggerName()}: {msg}"
- if thrown is not None:
- result += "\n" + "".join(_traceback.format_exception(
- type(thrown), thrown, getattr(thrown, '__traceback__', None)
- ))
- return result
-
-
-class XMLFormatter(Formatter):
- """java.util.logging.XMLFormatter"""
- def __init__(self):
- super().__init__()
- from xml.sax.saxutils import escape
-
- def format(self, record):
- ts = _datetime.datetime.fromtimestamp(record.getMillis() / 1000.0)
- ts_str = ts.strftime("%Y-%m-%dT%H:%M:%S")
- from xml.sax.saxutils import escape
- msg = escape(self.formatMessage(record))
- logger_name = escape(record.getLoggerName() or "")
- level_name = record.getLevel().getName()
-
- parts = [
- "",
- f" {ts_str}",
- f" {int(record.getMillis())}",
- f" {record.getSequenceNumber()}",
- f" {logger_name}",
- f" {level_name}",
- f" {escape(record.getSourceClassName() or '')}",
- f" {escape(record.getSourceMethodName() or '')}",
- f" {record.getThreadID()}",
- f" {msg}",
- ]
-
- thrown = record.getThrown()
- if thrown is not None:
- import traceback
- tb_str = "".join(traceback.format_exception(
- type(thrown), thrown, getattr(thrown, '__traceback__', None)
- ))
- parts.append(f" {escape(tb_str)}")
-
- parts.append("")
- return "\n".join(parts)
-
- def getHead(self, handler):
- return '\n\n\n'
-
- def getTail(self, handler):
- return "\n"
-
-
-# ============================================================
-# ErrorManager
-# ============================================================
-
-class ErrorManager(Stub):
- """java.util.logging.ErrorManager"""
- def __init__(self):
- super().__init__()
-
- def error(self, message, exception, error_code):
- _sys.stderr.write(f"ErrorManager: {message}\n")
- if exception:
- _traceback.print_exception(type(exception), exception,
- getattr(exception, '__traceback__', None))
-
- GENERIC_FAILURE = 0
- WRITE_FAILURE = 1
- FLUSH_FAILURE = 2
- CLOSE_FAILURE = 3
- OPEN_FAILURE = 4
- FORMAT_FAILURE = 5
-
-
-# ============================================================
-# Handler
-# ============================================================
-
-class Handler(Stub):
- """java.util.logging.Handler"""
- def __init__(self):
- super().__init__()
- self._level = Level.ALL
- self._filter = None
- self._formatter = None
- self._encoding = None
- self._error_manager = ErrorManager()
- self._closed = False
-
- def publish(self, record):
- raise NotImplementedError
-
- def flush(self):
- pass
-
- def close(self):
- self._closed = True
-
- def isLoggable(self, record):
- if self._closed:
- return False
- if record.getLevel().intValue() < self._level.intValue():
- return False
- if self._filter is not None:
- return self._filter.isLoggable(record)
- return True
-
- def setLevel(self, level):
- self._level = level
-
- def getLevel(self):
- return self._level
-
- def setFilter(self, filter_):
- self._filter = filter_
-
- def getFilter(self):
- return self._filter
-
- def setFormatter(self, formatter):
- self._formatter = formatter
-
- def getFormatter(self):
- return self._formatter
-
- def setEncoding(self, encoding):
- self._encoding = encoding
-
- def getEncoding(self):
- return self._encoding
-
- def setErrorManager(self, em):
- self._error_manager = em
-
- def getErrorManager(self):
- return self._error_manager
-
- def reportError(self, msg, ex, code):
- if self._error_manager:
- self._error_manager.error(msg, ex, code)
-
-
-class StreamHandler(Handler):
- """java.util.logging.StreamHandler"""
- def __init__(self, out=None, formatter=None):
- super().__init__()
- if formatter is None:
- formatter = SimpleFormatter()
- self.setFormatter(formatter)
- self._output = out or _sys.stderr
- self._writer = None
- if self._output is not None:
- if isinstance(self._output, _io.TextIOBase):
- self._writer = self._output
- elif isinstance(self._output, _io.BufferedWriter):
- self._writer = _io.TextIOWrapper(self._output)
- else:
- self._writer = _io.TextIOWrapper(_io.BufferedWriter(self._output))
-
- def publish(self, record):
- if not self.isLoggable(record):
- return
- try:
- msg = self.getFormatter().format(record)
- if self._writer is not None:
- self._writer.write(msg + "\n")
- else:
- print(msg, file=_sys.stderr)
- self.flush()
- except Exception as e:
- self.reportError("Error publishing record", e, ErrorManager.WRITE_FAILURE)
-
- def flush(self):
- if self._writer is not None:
- try:
- self._writer.flush()
- except Exception:
- pass
-
- def close(self):
- self.flush()
- if self._writer is not None:
- try:
- self._writer.close()
- except Exception:
- pass
- super().close()
-
- def setOutputStream(self, out):
- self._output = out
- if isinstance(out, _io.TextIOBase):
- self._writer = out
- elif isinstance(out, _io.BufferedWriter):
- self._writer = _io.TextIOWrapper(out)
- else:
- self._writer = _io.TextIOWrapper(_io.BufferedWriter(out))
-
-
-class ConsoleHandler(StreamHandler):
- """java.util.logging.ConsoleHandler"""
- def __init__(self):
- super().__init__(_sys.stderr, SimpleFormatter())
- self.setLevel(Level.INFO)
-
-
-class FileHandler(Handler):
- """java.util.logging.FileHandler"""
- def __init__(self, pattern=None, append=None, limit=0, count=1):
- super().__init__()
- self._pattern = pattern or "logging.log"
- self._limit = limit
- self._count = count
- self._append = append or False
- self._files = []
-
- if "%u" in self._pattern or "%g" in self._pattern:
- self._current_filename = self._pattern.replace("%u", "0").replace("%g", "0")
- else:
- self._current_filename = self._pattern
-
- try:
- mode = "a" if self._append else "w"
- self._file = open(self._current_filename, mode, encoding="utf-8")
- self._writer = self._file
- except Exception as e:
- self._file = None
- self._writer = None
- self.reportError("Cannot open file", e, ErrorManager.OPEN_FAILURE)
-
- self._formatter = SimpleFormatter()
-
- def publish(self, record):
- if not self.isLoggable(record):
- return
- if self._writer is None:
- return
- try:
- msg = self.getFormatter().format(record)
- self._writer.write(msg + "\n")
- self.flush()
- except Exception as e:
- self.reportError("Error publishing record", e, ErrorManager.WRITE_FAILURE)
-
- def flush(self):
- if self._writer is not None:
- try:
- self._writer.flush()
- except Exception:
- pass
-
- def close(self):
- self.flush()
- if self._writer is not None:
- try:
- self._writer.close()
- except Exception:
- pass
- super().close()
-
-
-class SocketHandler(Handler):
- """java.util.logging.SocketHandler"""
- def __init__(self, host, port):
- super().__init__()
- self._host = host
- self._port = port
- self._sock = None
- self._output_stream = None
-
- def connect(self):
- import socket
- self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self._sock.connect((self._host, self._port))
- self._output_stream = self._sock.makefile("wb")
-
- def publish(self, record):
- if not self.isLoggable(record):
- return
- if self._output_stream is None:
- try:
- self.connect()
- except Exception as e:
- self.reportError("Cannot connect", e, ErrorManager.OPEN_FAILURE)
- return
- try:
- msg = self.getFormatter().format(record)
- self._output_stream.write(msg.encode() + b"\n")
- self.flush()
- except Exception as e:
- self.reportError("Error sending record", e, ErrorManager.WRITE_FAILURE)
-
- def flush(self):
- if self._output_stream is not None:
- try:
- self._output_stream.flush()
- except Exception:
- pass
-
- def close(self):
- self.flush()
- if self._output_stream is not None:
- try:
- self._output_stream.close()
- except Exception:
- pass
- if self._sock is not None:
- try:
- self._sock.close()
- except Exception:
- pass
- super().close()
-
-
-class MemoryHandler(Handler):
- """java.util.logging.MemoryHandler"""
- def __init__(self, target=None, size=1000, push_level=Level.SEVERE):
- super().__init__()
- self._target = target
- self._size = size
- self._push_level = push_level
- self._buffer = []
-
- def publish(self, record):
- if not self.isLoggable(record):
- return
- self._buffer.append(record)
- if len(self._buffer) >= self._size:
- self.push()
- elif record.getLevel().intValue() >= self._push_level.intValue():
- self.push()
-
- def push(self):
- if self._target is not None:
- for rec in self._buffer:
- self._target.publish(rec)
- self._buffer.clear()
- self._target.flush()
-
- def flush(self):
- self.push()
-
- def close(self):
- self.push()
- if self._target is not None:
- self._target.close()
- super().close()
-
- def setPushLevel(self, level):
- self._push_level = level
-
- def getPushLevel(self):
- return self._push_level
-
- def setTarget(self, target):
- self._target = target
-
- def getTarget(self):
- return self._target
-
-
-# ============================================================
-# Logger
-# ============================================================
-
-class Logger(Stub):
- """java.util.logging.Logger"""
- _loggers = {}
- _root = None
- _global_logger = None
-
- def __init__(self, name, resource_bundle_name=None):
- super().__init__()
- self._name = name
- self._resource_bundle_name = resource_bundle_name
- self._level = None
- self._parent = None
- self._handlers = []
- self._filter = None
- self._use_parent_handlers = True
-
- @staticmethod
- def getGlobal():
- if Logger._global_logger is None:
- Logger._global_logger = Logger("global")
- return Logger._global_logger
-
- @staticmethod
- def getLogger(name, resource_bundle_name=None):
- if not name:
- if Logger._root is None:
- Logger._root = Logger("", resource_bundle_name)
- return Logger._root
- if name not in Logger._loggers:
- logger = Logger(name, resource_bundle_name)
- Logger._loggers[name] = logger
- logger._parent = Logger.getLogger("", None)
- return Logger._loggers[name]
-
- def getName(self):
- return self._name
-
- def getParent(self):
- return self._parent
-
- def setParent(self, parent):
- self._parent = parent
-
- def setLevel(self, level):
- self._level = level
-
- def getLevel(self):
- return self._level
-
- def isLoggable(self, level):
- if self._level is not None:
- return level.intValue() >= self._level.intValue()
- if self._parent is not None:
- return self._parent.isLoggable(level)
- return level.intValue() >= Level.INFO.intValue()
-
- def addHandler(self, handler):
- if handler not in self._handlers:
- self._handlers.append(handler)
-
- def removeHandler(self, handler):
- if handler in self._handlers:
- self._handlers.remove(handler)
-
- def getHandlers(self):
- return self._handlers
-
- def setUseParentHandlers(self, use):
- self._use_parent_handlers = use
-
- def getUseParentHandlers(self):
- return self._use_parent_handlers
-
- def setFilter(self, filter_):
- self._filter = filter_
-
- def getFilter(self):
- return self._filter
-
- def getResourceBundle(self):
- return None
-
- def getResourceBundleName(self):
- return self._resource_bundle_name
-
- def log(self, level, msg_or_supplier, *args):
- if isinstance(level, Level):
- if self.isLoggable(level):
- if callable(msg_or_supplier) and not args:
- msg = msg_or_supplier()
- else:
- msg = msg_or_supplier
- record = LogRecord(level, msg)
- record.setLoggerName(self._name)
- record.setParameters(args or None)
- self._log(record)
- else:
- # log(LogRecord)
- self._log(level)
-
- def _log(self, record):
- if self._filter is not None and not self._filter.isLoggable(record):
- return
- for handler in self._handlers:
- if handler.isLoggable(record):
- handler.publish(record)
- if self._use_parent_handlers and self._parent is not None:
- self._parent._log(record)
-
- def severe(self, msg):
- self.log(Level.SEVERE, msg)
-
- def warning(self, msg):
- self.log(Level.WARNING, msg)
-
- def info(self, msg):
- self.log(Level.INFO, msg)
-
- def config(self, msg):
- self.log(Level.CONFIG, msg)
-
- def fine(self, msg):
- self.log(Level.FINE, msg)
-
- def finer(self, msg):
- self.log(Level.FINER, msg)
-
- def finest(self, msg):
- self.log(Level.FINEST, msg)
-
- def entering(self, source_class, source_method, param=None):
- msg = f"ENTRY {source_class}.{source_method}"
- if param is not None:
- msg += f" {param}"
- self.log(Level.FINER, msg)
-
- def exiting(self, source_class, source_method, result=None):
- msg = f"RETURN {source_class}.{source_method}"
- if result is not None:
- msg += f" {result}"
- self.log(Level.FINER, msg)
-
- def throwing(self, source_class, source_method, thrown):
- record = LogRecord(Level.FINER, "THROW")
- record.setLoggerName(self._name)
- record.setSourceClassName(source_class)
- record.setSourceMethodName(source_method)
- record.setThrown(thrown)
- self._log(record)
-
- def logp(self, level, source_class, source_method, msg, *params):
- if self.isLoggable(level):
- record = LogRecord(level, msg)
- record.setLoggerName(self._name)
- record.setSourceClassName(source_class)
- record.setSourceMethodName(source_method)
- record.setParameters(params or None)
- self._log(record)
-
- def logrb(self, level, source_class, source_method, bundle_name, msg, *params):
- if self.isLoggable(level):
- record = LogRecord(level, msg)
- record.setLoggerName(self._name)
- record.setSourceClassName(source_class)
- record.setSourceMethodName(source_method)
- record.setResourceBundleName(bundle_name)
- record.setParameters(params or None)
- self._log(record)
-
- @staticmethod
- def getAnonymousLogger(resource_bundle_name=None):
- logger = Logger("", resource_bundle_name)
- return logger
-
-
-# ============================================================
-# LogManager
-# ============================================================
-
-class LogManager(Stub):
- """java.util.logging.LogManager"""
- _singleton = None
-
- def __init__(self):
- super().__init__()
- self._loggers = {}
- self._properties = {}
-
- @staticmethod
- def getLogManager():
- if LogManager._singleton is None:
- LogManager._singleton = LogManager()
- return LogManager._singleton
-
- def addLogger(self, logger):
- name = logger.getName()
- if name in self._loggers:
- return False
- self._loggers[name] = logger
- return True
-
- def getLogger(self, name):
- return self._loggers.get(name)
-
- def getLoggers(self):
- return list(self._loggers.values())
-
- def readConfiguration(self, input_stream=None):
- pass
-
- def readConfiguration(self, ins):
- pass
-
- def reset(self):
- for logger in self._loggers.values():
- for handler in logger.getHandlers()[:]:
- handler.close()
- logger.removeHandler(handler)
- logger.setLevel(None)
-
- def checkAccess(self):
- pass
-
- def addPropertyChangeListener(self, listener):
- pass
-
- def removePropertyChangeListener(self, listener):
- pass
-
- LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging"
-
- def getProperty(self, name):
- return self._properties.get(name)
-
-
-# ============================================================
-# LoggingMXBean
-# ============================================================
-
-class LoggingMXBean(Stub):
- """java.util.logging.LoggingMXBean"""
- def getLoggerLevel(self, logger_name):
- logger = LogManager.getLogManager().getLogger(logger_name)
- if logger and logger.getLevel():
- return logger.getLevel().getName()
- return ""
-
- def setLoggerLevel(self, logger_name, level_name):
- logger = LogManager.getLogManager().getLogger(logger_name)
- if logger:
- level = Level()
- logger.setLevel(level.parse(level_name))
-
- def getParentLogger(self, logger_name):
- logger = LogManager.getLogManager().getLogger(logger_name)
- if logger and logger.getParent():
- return logger.getParent().getName()
- return ""
-
- def getLoggerNames(self):
- return list(LogManager.getLogManager()._loggers.keys())
-
-
-# ============================================================
-# LoggingPermission
-# ============================================================
-
-class LoggingPermission(BasicPermission):
- """java.util.logging.LoggingPermission"""
- def __init__(self, name, actions=None):
- super().__init__(name, actions)
-
-
-class IllegalArgumentException(RuntimeException):
- """java.lang.IllegalArgumentException"""
- pass
\ No newline at end of file
diff --git a/android_pyapi/java/util_prefs.py b/android_pyapi/java/util_prefs.py
deleted file mode 100644
index 5511c7f..0000000
--- a/android_pyapi/java/util_prefs.py
+++ /dev/null
@@ -1,544 +0,0 @@
-"""
-Java java.util.prefs standard library APIs implemented in Python.
-java.util.prefs package - Preferences, PreferencesFactory, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub
-from ..java.lang import RuntimeException, Exception as _JavaException
-import typing as _typing
-import json as _json
-import os as _os
-import threading as _threading
-
-__all__ = [
- "Preferences", "PreferencesFactory", "AbstractPreferences",
- "NodeChangeEvent", "NodeChangeListener",
- "PreferenceChangeEvent", "PreferenceChangeListener",
- "BackingStoreException", "InvalidPreferencesFormatException",
-]
-
-# ============================================================
-# Exceptions
-# ============================================================
-
-class BackingStoreException(_JavaException):
- """java.util.prefs.BackingStoreException"""
- def __init__(self, message):
- super().__init__(message)
-
-
-class InvalidPreferencesFormatException(_JavaException):
- """java.util.prefs.InvalidPreferencesFormatException"""
- def __init__(self, message, cause=None):
- super().__init__(message)
- self._cause = cause
-
- def getCause(self):
- return self._cause
-
-
-# ============================================================
-# Event Classes
-# ============================================================
-
-class NodeChangeEvent(Stub):
- """java.util.prefs.NodeChangeEvent"""
- def __init__(self, parent, child):
- super().__init__()
- self._parent = parent
- self._child = child
-
- def getParent(self):
- return self._parent
-
- def getChild(self):
- return self._child
-
-
-class PreferenceChangeEvent(Stub):
- """java.util.prefs.PreferenceChangeEvent"""
- def __init__(self, node, key, new_value):
- super().__init__()
- self._node = node
- self._key = key
- self._new_value = new_value
-
- def getNode(self):
- return self._node
-
- def getKey(self):
- return self._key
-
- def getNewValue(self):
- return self._new_value
-
-
-class NodeChangeListener(Stub):
- """java.util.prefs.NodeChangeListener"""
- def childAdded(self, evt):
- pass
-
- def childRemoved(self, evt):
- pass
-
-
-class PreferenceChangeListener(Stub):
- """java.util.prefs.PreferenceChangeListener"""
- def preferenceChange(self, evt):
- pass
-
-
-# ============================================================
-# Preferences
-# ============================================================
-
-class Preferences(Stub):
- """java.util.prefs.Preferences"""
- MAX_KEY_LENGTH = 80
- MAX_VALUE_LENGTH = 8192
- MAX_NAME_LENGTH = 80
-
- def __init__(self, name="", parent=None):
- super().__init__()
- self._name = name
- self._parent = parent
- self._children = {}
- self._prefs = {}
- self._node_listeners = []
- self._pref_listeners = []
- self._absolute_path = self._build_path()
-
- def _build_path(self):
- if self._parent is None:
- return "/" + self._name if self._name else "/"
- parent_path = self._parent._absolute_path
- if parent_path == "/":
- return "/" + self._name
- return parent_path + "/" + self._name
-
- def put(self, key, value):
- if len(key) > Preferences.MAX_KEY_LENGTH:
- raise IllegalArgumentException(f"Key too long: {len(key)}")
- if len(value) > Preferences.MAX_VALUE_LENGTH:
- raise IllegalArgumentException(f"Value too long: {len(value)}")
- self._prefs[key] = value
- self._fire_preference_change(key, value)
-
- def get(self, key, default_value):
- return self._prefs.get(key, default_value)
-
- def remove(self, key):
- if key in self._prefs:
- old = self._prefs.pop(key)
- self._fire_preference_change(key, None)
-
- def clear(self):
- self._prefs.clear()
-
- def putInt(self, key, value):
- self.put(key, str(value))
-
- def getInt(self, key, default_value):
- val = self.get(key, None)
- if val is None:
- return default_value
- try:
- return int(val)
- except ValueError:
- return default_value
-
- def putLong(self, key, value):
- self.put(key, str(value))
-
- def getLong(self, key, default_value):
- val = self.get(key, None)
- if val is None:
- return default_value
- try:
- return int(val)
- except ValueError:
- return default_value
-
- def putFloat(self, key, value):
- self.put(key, str(value))
-
- def getFloat(self, key, default_value):
- val = self.get(key, None)
- if val is None:
- return default_value
- try:
- return float(val)
- except ValueError:
- return default_value
-
- def putDouble(self, key, value):
- self.put(key, str(value))
-
- def getDouble(self, key, default_value):
- val = self.get(key, None)
- if val is None:
- return default_value
- try:
- return float(val)
- except ValueError:
- return default_value
-
- def putBoolean(self, key, value):
- self.put(key, "true" if value else "false")
-
- def getBoolean(self, key, default_value):
- val = self.get(key, None)
- if val is None:
- return default_value
- return val.lower() == "true"
-
- def putByteArray(self, key, value):
- import base64
- self.put(key, base64.b64encode(value).decode())
-
- def getByteArray(self, key, default_value):
- import base64
- val = self.get(key, None)
- if val is None:
- return default_value
- try:
- return base64.b64decode(val)
- except Exception:
- return default_value
-
- def keys(self):
- return list(self._prefs.keys())
-
- def childrenNames(self):
- return list(self._children.keys())
-
- def parent(self):
- return self._parent
-
- def node(self, path_name):
- if path_name.startswith("/"):
- return self._root()._node_path(path_name[1:])
- return self._node_path(path_name)
-
- def nodeExists(self, path_name):
- try:
- self.node(path_name)
- return True
- except BackingStoreException:
- return False
-
- def removeNode(self):
- if self._parent is not None:
- self._parent._remove_child(self._name)
-
- def name(self):
- return self._name
-
- def absolutePath(self):
- return self._absolute_path
-
- def isUserNode(self):
- return False
-
- def toString(self):
- return self._absolute_path
-
- def flush(self):
- pass
-
- def sync(self):
- pass
-
- def addNodeChangeListener(self, listener):
- self._node_listeners.append(listener)
-
- def removeNodeChangeListener(self, listener):
- if listener in self._node_listeners:
- self._node_listeners.remove(listener)
-
- def addPreferenceChangeListener(self, listener):
- self._pref_listeners.append(listener)
-
- def removePreferenceChangeListener(self, listener):
- if listener in self._pref_listeners:
- self._pref_listeners.remove(listener)
-
- def exportNode(self, output_stream):
- data = self._to_dict()
- output_stream.write(_json.dumps(data, indent=2).encode())
-
- def exportSubtree(self, output_stream):
- data = self._to_dict(recursive=True)
- output_stream.write(_json.dumps(data, indent=2).encode())
-
- def _to_dict(self, recursive=False):
- result = {"prefs": dict(self._prefs)}
- if recursive:
- result["children"] = {
- name: child._to_dict(recursive=True)
- for name, child in self._children.items()
- }
- return result
-
- def _root(self):
- if self._parent is None:
- return self
- return self._parent._root()
-
- def _node_path(self, path):
- if not path:
- return self
- parts = path.split("/")
- current = self
- for part in parts:
- if not part:
- continue
- if part == "..":
- if current._parent is not None:
- current = current._parent
- continue
- if part not in current._children:
- current._children[part] = Preferences(part, current)
- current = current._children[part]
- return current
-
- def _remove_child(self, name):
- if name in self._children:
- child = self._children.pop(name)
- evt = NodeChangeEvent(self, child)
- for listener in self._node_listeners:
- listener.childRemoved(evt)
-
- def _fire_preference_change(self, key, value):
- evt = PreferenceChangeEvent(self, key, value)
- for listener in self._pref_listeners:
- listener.preferenceChange(evt)
-
- @staticmethod
- def userRoot():
- if Preferences._user_root is None:
- Preferences._user_root = Preferences("")
- return Preferences._user_root
-
- @staticmethod
- def systemRoot():
- if Preferences._system_root is None:
- Preferences._system_root = Preferences("")
- return Preferences._system_root
-
- @staticmethod
- def importPreferences(input_stream):
- data = _json.loads(input_stream.read())
- root = Preferences("")
- root._prefs = data.get("prefs", {})
- return root
-
- _user_root = None
- _system_root = None
-
-
-# ============================================================
-# AbstractPreferences
-# ============================================================
-
-class AbstractPreferences(Preferences):
- """java.util.prefs.AbstractPreferences"""
- def __init__(self, parent, name):
- super().__init__(name, parent)
- self._is_removed = False
- self._lock = _threading.RLock()
-
- def put(self, key, value):
- with self._lock:
- if self._is_removed:
- raise BackingStoreException("Node has been removed")
- super().put(key, value)
-
- def get(self, key, default_value):
- with self._lock:
- if self._is_removed:
- raise BackingStoreException("Node has been removed")
- return super().get(key, default_value)
-
- def remove(self, key):
- with self._lock:
- super().remove(key)
-
- def keys(self):
- with self._lock:
- return super().keys()
-
- def childrenNames(self):
- with self._lock:
- return super().childrenNames()
-
- def node(self, path_name):
- with self._lock:
- return super().node(path_name)
-
- def removeNode(self):
- with self._lock:
- super().removeNode()
- self._is_removed = True
-
- def flush(self):
- pass
-
- def sync(self):
- pass
-
- def isUserNode(self):
- return False
-
-
-# ============================================================
-# PreferencesFactory
-# ============================================================
-
-class PreferencesFactory(Stub):
- """java.util.prefs.PreferencesFactory"""
- def systemRoot(self):
- return Preferences.systemRoot()
-
- def userRoot(self):
- return Preferences.userRoot()
-
-
-# ============================================================
-# IllegalArgumentException
-# ============================================================
-
-class IllegalArgumentException(RuntimeException):
- """java.lang.IllegalArgumentException"""
- pass
-
-
-# ============================================================
-# Preferences utility helpers
-# ============================================================
-
-class _PreferencesService(Stub):
- """Helper to manage Preferences with file-backed storage"""
- def __init__(self, root_path=None):
- super().__init__()
- if root_path is None:
- import os
- root_path = os.path.join(os.path.expanduser("~"), ".java", "prefs")
- self._root_path = root_path
- self._cache = {}
-
- def loadPreferences(self, node_path):
- import os
- import json
- file_path = os.path.join(self._root_path, node_path.replace("/", "_") + ".json")
- prefs = Preferences(node_path)
- if os.path.exists(file_path):
- try:
- with open(file_path, "r") as f:
- data = json.load(f)
- for key, val in data.items():
- prefs.put(key, val)
- except Exception:
- pass
- self._cache[node_path] = prefs
- return prefs
-
- def savePreferences(self, prefs):
- import os
- import json
- file_path = os.path.join(self._root_path,
- prefs.absolutePath().replace("/", "_") + ".json")
- os.makedirs(os.path.dirname(file_path), exist_ok=True)
- data = {}
- for key in prefs.keys():
- data[key] = prefs.get(key, None)
- with open(file_path, "w") as f:
- json.dump(data, f, indent=2)
-
- def clearCache(self):
- self._cache.clear()
-
-
-class _EventDispatchThread(Stub):
- """Helper for dispatching preference change events"""
- def __init__(self):
- super().__init__()
- self._listeners = []
- import threading
- self._lock = threading.Lock()
-
- def addListener(self, listener):
- with self._lock:
- self._listeners.append(listener)
-
- def removeListener(self, listener):
- with self._lock:
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def dispatchEvent(self, event):
- with self._lock:
- for listener in self._listeners:
- try:
- if hasattr(listener, 'preferenceChange'):
- listener.preferenceChange(event)
- elif callable(listener):
- listener(event)
- except Exception:
- pass
-
- def getListeners(self):
- with self._lock:
- return list(self._listeners)
-
-
-# ============================================================
-# FileSystemPreferences - persistent Preferences backed by file
-# ============================================================
-
-class FileSystemPreferences(AbstractPreferences):
- """java.util.prefs.FileSystemPreferences - persistent file-backed preferences"""
- def __init__(self, parent, name, storage_path=None):
- super().__init__(parent, name)
- import os
- if storage_path is None:
- storage_path = os.path.join(os.path.expanduser("~"), ".java", "user_prefs")
- self._storage_path = os.path.join(
- storage_path, self.absolutePath().replace("/", "_") + ".xml"
- )
- self._loaded = False
- self._service = _PreferencesService(storage_path)
-
- def _ensureLoaded(self):
- if not self._loaded:
- try:
- import os
- if os.path.exists(self._storage_path):
- node = self._service.loadPreferences(self.absolutePath())
- for key in node.keys():
- self._prefs[key] = node.get(key, "")
- self._loaded = True
- except Exception:
- self._loaded = True
-
- def put(self, key, value):
- self._ensureLoaded()
- super().put(key, value)
-
- def get(self, key, default_value):
- self._ensureLoaded()
- return super().get(key, default_value)
-
- def keys(self):
- self._ensureLoaded()
- return super().keys()
-
- def flush(self):
- self._service.savePreferences(self)
- super().flush()
-
- def sync(self):
- self._ensureLoaded()
- self._service.savePreferences(self)
\ No newline at end of file
diff --git a/android_pyapi/java/util_regex.py b/android_pyapi/java/util_regex.py
deleted file mode 100644
index 53e9b7b..0000000
--- a/android_pyapi/java/util_regex.py
+++ /dev/null
@@ -1,287 +0,0 @@
-"""
-Java regex standard library APIs implemented in Python.
-java.util.regex package - Pattern, Matcher, MatchResult, PatternSyntaxException.
-"""
-
-from .._core import Stub
-from .io import IOException
-from .lang import RuntimeException
-import re as _re
-
-IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
-IllegalStateException = type("IllegalStateException", (RuntimeException,), {})
-
-__all__ = [
- "Pattern", "Matcher", "MatchResult", "PatternSyntaxException",
-]
-
-
-# ============================================================
-# PatternSyntaxException
-# ============================================================
-
-class PatternSyntaxException(IllegalArgumentException):
- def __init__(self, desc, regex, index):
- super().__init__(f"{desc}: {regex} at index {index}")
- self._desc = desc
- self._regex = regex
- self._index = index
-
- def getDescription(self):
- return self._desc
-
- def getPattern(self):
- return self._regex
-
- def getIndex(self):
- return self._index
-
- def getMessage(self):
- return f"{self._desc} near index {self._index}: {self._regex}"
-
-
-# ============================================================
-# MatchResult
-# ============================================================
-
-class MatchResult(Stub):
- def start(self, group=None):
- raise NotImplementedError
-
- def end(self, group=None):
- raise NotImplementedError
-
- def group(self, group=None):
- raise NotImplementedError
-
- def groupCount(self):
- raise NotImplementedError
-
-
-# ============================================================
-# Matcher
-# ============================================================
-
-class Matcher(MatchResult):
- def __init__(self, pattern, input_str):
- super().__init__()
- self._pattern = pattern
- self._input = input_str
- self._re_pattern = pattern._pattern
- self._match = None
- self._region_start = 0
- self._region_end = len(input_str)
- self._transparent_bounds = False
- self._anchoring_bounds = True
- self._last_match = None
-
- def matches(self):
- self._match = self._re_pattern.fullmatch(self._input, self._region_start, self._region_end)
- self._last_match = self._match
- return self._match is not None
-
- def find(self, start=None):
- if start is not None:
- self._match = self._re_pattern.search(self._input, start, self._region_end)
- else:
- if self._match is None:
- self._match = self._re_pattern.search(self._input, self._region_start, self._region_end)
- else:
- pos = self._match.end()
- self._match = self._re_pattern.search(self._input, pos, self._region_end)
- if self._match:
- self._last_match = self._match
- return self._match is not None
-
- def lookingAt(self):
- self._match = self._re_pattern.match(self._input, self._region_start, self._region_end)
- self._last_match = self._match
- return self._match is not None
-
- def start(self, group=0):
- if self._match is None:
- raise IllegalStateException("No match available")
- if group == 0:
- return self._match.start()
- return self._match.start(group)
-
- def end(self, group=0):
- if self._match is None:
- raise IllegalStateException("No match available")
- if group == 0:
- return self._match.end()
- return self._match.end(group)
-
- def group(self, group=0):
- if self._match is None:
- raise IllegalStateException("No match available")
- if isinstance(group, str):
- return self._match.group(group)
- return self._match.group(group)
-
- def groupCount(self):
- return self._re_pattern.groups
-
- def replaceAll(self, replacement):
- return self._re_pattern.sub(replacement, self._input)
-
- def replaceFirst(self, replacement):
- return self._re_pattern.sub(replacement, self._input, count=1)
-
- def appendReplacement(self, sb, replacement):
- if self._match is None:
- raise IllegalStateException("No match available")
- self._append_pos = getattr(self, '_append_pos', 0)
- sb.append(self._input[self._append_pos:self._match.start()])
- sb.append(self._re_pattern.sub(replacement, self._match.group(), count=1))
- self._append_pos = self._match.end()
- return self
-
- def appendTail(self, sb):
- self._append_pos = getattr(self, '_append_pos', 0)
- sb.append(self._input[self._append_pos:])
- return sb
-
- def reset(self, input_str=None):
- if input_str is not None:
- self._input = input_str
- self._region_end = len(input_str)
- self._match = None
- self._last_match = None
- return self
-
- def region(self, start, end):
- self._region_start = start
- self._region_end = end
- return self
-
- def regionStart(self):
- return self._region_start
-
- def regionEnd(self):
- return self._region_end
-
- def hasTransparentBounds(self):
- return self._transparent_bounds
-
- def hasAnchoringBounds(self):
- return self._anchoring_bounds
-
- def useAnchoringBounds(self, value):
- self._anchoring_bounds = value
- return self
-
- def useTransparentBounds(self, value):
- self._transparent_bounds = value
- return self
-
- def hitEnd(self):
- return self._match is not None and self._match.end() >= self._region_end
-
- def requireEnd(self):
- return self._match is not None and not self.hitEnd()
-
- def toMatchResult(self):
- result = Matcher(self._pattern, self._input)
- result._match = self._match
- result._last_match = self._last_match
- return result
-
- def pattern(self):
- return self._pattern
-
- def toString(self):
- return f"Matcher[pattern={self._pattern.pattern()}]"
-
- def namedGroups(self):
- return self._re_pattern.groupindex
-
-
-class IllegalStateException(RuntimeException):
- pass
-
-
-# ============================================================
-# Pattern
-# ============================================================
-
-class Pattern(Stub):
- CANON_EQ = 128
- CASE_INSENSITIVE = 2
- COMMENTS = 4
- DOTALL = 32
- LITERAL = 16
- MULTILINE = 8
- UNICODE_CASE = 64
- UNICODE_CHARACTER_CLASS = 256
- UNIX_LINES = 1
-
- _re_flags_map = {
- 0: 0, # default
- 2: _re.IGNORECASE,
- 8: _re.MULTILINE,
- 32: _re.DOTALL,
- 64: _re.UNICODE,
- 4: _re.VERBOSE,
- }
-
- def __init__(self, regex, flags=0):
- super().__init__()
- self._regex = str(regex)
- self._flags = flags
- re_flags = 0
- for java_flag, py_flag in self._re_flags_map.items():
- if flags & java_flag:
- re_flags |= py_flag
- try:
- self._pattern = _re.compile(self._regex, re_flags)
- except _re.error as e:
- raise PatternSyntaxException(str(e), self._regex, e.pos if hasattr(e, 'pos') else 0)
-
- @staticmethod
- def compile(regex, flags=0):
- return Pattern(regex, flags)
-
- def matcher(self, input_str):
- return Matcher(self, input_str)
-
- def split(self, input_str, limit=0):
- if limit <= 0:
- parts = self._pattern.split(str(input_str))
- if limit == 0:
- while parts and parts[-1] == "":
- parts.pop()
- else:
- parts = self._pattern.split(str(input_str), maxsplit=limit - 1)
- while len(parts) < limit:
- parts.append("")
- return parts
-
- def splitAsStream(self, input_str):
- return iter(self.split(input_str))
-
- @staticmethod
- def matches(regex, input_str):
- return bool(_re.fullmatch(regex, str(input_str)))
-
- @staticmethod
- def quote(s):
- return _re.escape(str(s))
-
- def flags(self):
- return self._flags
-
- def pattern(self):
- return self._regex
-
- def toString(self):
- return self._regex
-
- def predicate(self):
- return lambda s: bool(self._pattern.fullmatch(str(s)))
-
- def asPredicate(self):
- return self.predicate()
-
- def asMatchPredicate(self):
- return lambda s: bool(self._pattern.fullmatch(str(s)))
\ No newline at end of file
diff --git a/android_pyapi/java/util_stream.py b/android_pyapi/java/util_stream.py
deleted file mode 100644
index 096cd6c..0000000
--- a/android_pyapi/java/util_stream.py
+++ /dev/null
@@ -1,1380 +0,0 @@
-"""
-Java java.util.stream standard library APIs implemented in Python.
-java.util.stream package - Stream, IntStream, LongStream, DoubleStream, Collectors, etc.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub
-from ..java.util import Optional, NoSuchElementException
-from ..java.lang import RuntimeException
-import typing as _typing
-import itertools as _itertools
-import functools as _functools
-import math as _py_math
-
-__all__ = [
- "Stream", "IntStream", "LongStream", "DoubleStream",
- "Collector", "Collectors", "StreamSupport",
- "BaseStream", "Sink", "TerminalOp", "TerminalSink",
- "AbstractPipeline", "ReferencePipeline",
- "IntPipeline", "LongPipeline", "DoublePipeline",
- "SliceOps", "WhileOps", "DistinctOps", "SortedOps",
- "FindOps", "MatchOps", "ReduceOps", "ForEachOps",
- "MapOps", "FilterOps", "FlatMapOps", "PeekOps",
-]
-
-T = _typing.TypeVar("T")
-R = _typing.TypeVar("R")
-A = _typing.TypeVar("A")
-
-
-# ============================================================
-# BaseStream
-# ============================================================
-
-class BaseStream(Stub):
- """java.util.stream.BaseStream"""
- def __init__(self):
- super().__init__()
- self._closed = False
- self._parallel = False
-
- def iterator(self):
- raise NotImplementedError
-
- def spliterator(self):
- raise NotImplementedError
-
- def isParallel(self):
- return self._parallel
-
- def sequential(self):
- self._parallel = False
- return self
-
- def parallel(self):
- self._parallel = True
- return self
-
- def unordered(self):
- return self
-
- def onClose(self, close_handler):
- return self
-
- def close(self):
- self._closed = True
-
-
-# ============================================================
-# Builder
-# ============================================================
-
-class StreamBuilder(Stub):
- """java.util.stream.Stream.Builder"""
- def __init__(self):
- super().__init__()
- self._elements = []
-
- def accept(self, t):
- self._elements.append(t)
-
- def add(self, t):
- self._elements.append(t)
- return self
-
- def build(self):
- return Stream(self._elements[:])
-
- def toString(self):
- return "Stream.Builder"
-
-
-class IntStreamBuilder(Stub):
- """java.util.stream.IntStream.Builder"""
- def __init__(self):
- super().__init__()
- self._elements = []
-
- def accept(self, t):
- self._elements.append(int(t))
-
- def add(self, t):
- self._elements.append(int(t))
- return self
-
- def build(self):
- return IntStream(self._elements[:])
-
-
-class LongStreamBuilder(Stub):
- """java.util.stream.LongStream.Builder"""
- def __init__(self):
- super().__init__()
- self._elements = []
-
- def accept(self, t):
- self._elements.append(int(t))
-
- def add(self, t):
- self._elements.append(int(t))
- return self
-
- def build(self):
- return LongStream(self._elements[:])
-
-
-class DoubleStreamBuilder(Stub):
- """java.util.stream.DoubleStream.Builder"""
- def __init__(self):
- super().__init__()
- self._elements = []
-
- def accept(self, t):
- self._elements.append(float(t))
-
- def add(self, t):
- self._elements.append(float(t))
- return self
-
- def build(self):
- return DoubleStream(self._elements[:])
-
-
-# ============================================================
-# Stream
-# ============================================================
-
-class Stream(BaseStream):
- """java.util.stream.Stream"""
- def __init__(self, data=None):
- super().__init__()
- self._data = list(data) if data is not None else []
- self._intermediate_ops = []
-
- def filter(self, predicate):
- result = [x for x in self._get_data() if predicate.test(x)]
- return Stream(result)
-
- def map(self, mapper):
- result = [mapper.apply(x) for x in self._get_data()]
- return Stream(result)
-
- def mapToInt(self, mapper):
- result = [mapper.applyAsInt(x) for x in self._get_data()]
- return IntStream(result)
-
- def mapToLong(self, mapper):
- result = [mapper.applyAsLong(x) for x in self._get_data()]
- return LongStream(result)
-
- def mapToDouble(self, mapper):
- result = [mapper.applyAsDouble(x) for x in self._get_data()]
- return DoubleStream(result)
-
- def flatMap(self, mapper):
- results = []
- for x in self._get_data():
- stream = mapper.apply(x)
- if isinstance(stream, Stream):
- results.extend(stream._get_data())
- elif hasattr(stream, '__iter__'):
- results.extend(stream)
- return Stream(results)
-
- def distinct(self):
- seen = set()
- result = []
- for x in self._get_data():
- if x not in seen:
- seen.add(x)
- result.append(x)
- return Stream(result)
-
- def sorted(self, comparator=None):
- result = list(self._get_data())
- if comparator:
- from functools import cmp_to_key
- result.sort(key=cmp_to_key(
- lambda a, b: comparator.compare(a, b)
- ))
- else:
- result.sort()
- return Stream(result)
-
- def peek(self, action):
- for x in self._get_data():
- action.accept(x)
- return Stream(self._get_data())
-
- def limit(self, max_size):
- return Stream(self._get_data()[:max_size])
-
- def skip(self, n):
- return Stream(self._get_data()[n:])
-
- def forEach(self, action):
- for x in self._get_data():
- action.accept(x)
-
- def forEachOrdered(self, action):
- self.forEach(action)
-
- def toArray(self, generator=None):
- data = self._get_data()
- if generator is not None:
- arr = generator.apply(len(data))
- for i, x in enumerate(data):
- arr[i] = x
- return arr
- return list(data)
-
- def reduce(self, identity_or_accumulator, accumulator=None, combiner=None):
- data = self._get_data()
- if accumulator is None:
- # reduce(BinaryOperator)
- acc = identity_or_accumulator
- if not data:
- return Optional.empty()
- result = data[0]
- for x in data[1:]:
- result = acc.apply(result, x)
- return Optional.of(result)
- else:
- # reduce(identity, accumulator)
- result = identity_or_accumulator
- for x in data:
- result = accumulator.apply(result, x)
- if combiner:
- result = combiner.apply(result, result)
- return result
-
- def collect(self, supplier_or_collector, accumulator=None, combiner=None):
- data = self._get_data()
- if accumulator is None:
- return supplier_or_collector # Collector
- container = supplier_or_collector.get()
- for x in data:
- accumulator.accept(container, x)
- return container
-
- def min(self, comparator):
- data = self._get_data()
- if not data:
- return Optional.empty()
- return Optional.of(min(data, key=_functools.cmp_to_key(
- lambda a, b: comparator.compare(a, b)
- )))
-
- def max(self, comparator):
- data = self._get_data()
- if not data:
- return Optional.empty()
- return Optional.of(max(data, key=_functools.cmp_to_key(
- lambda a, b: comparator.compare(a, b)
- )))
-
- def count(self):
- return len(self._get_data())
-
- def anyMatch(self, predicate):
- return any(predicate.test(x) for x in self._get_data())
-
- def allMatch(self, predicate):
- return all(predicate.test(x) for x in self._get_data())
-
- def noneMatch(self, predicate):
- return not any(predicate.test(x) for x in self._get_data())
-
- def findFirst(self):
- data = self._get_data()
- if data:
- return Optional.of(data[0])
- return Optional.empty()
-
- def findAny(self):
- data = self._get_data()
- if data:
- return Optional.of(data[0])
- return Optional.empty()
-
- def flatMapToInt(self, mapper):
- results = []
- for x in self._get_data():
- stream = mapper.apply(x)
- if isinstance(stream, IntStream):
- results.extend(stream._get_data())
- return IntStream(results)
-
- def flatMapToLong(self, mapper):
- results = []
- for x in self._get_data():
- stream = mapper.apply(x)
- if isinstance(stream, LongStream):
- results.extend(stream._get_data())
- return LongStream(results)
-
- def flatMapToDouble(self, mapper):
- results = []
- for x in self._get_data():
- stream = mapper.apply(x)
- if isinstance(stream, DoubleStream):
- results.extend(stream._get_data())
- return DoubleStream(results)
-
- def iterator(self):
- return iter(self._get_data())
-
- def spliterator(self):
- return Spliterator(self._get_data())
-
- def isParallel(self):
- return self._parallel
-
- def _get_data(self):
- return self._data
-
- @staticmethod
- def of(*args):
- return Stream(list(args))
-
- @staticmethod
- def empty():
- return Stream([])
-
- @staticmethod
- def concat(a, b):
- return Stream(list(a._get_data()) + list(b._get_data()))
-
- @staticmethod
- def generate(supplier):
- return Stream([])
-
- @staticmethod
- def iterate(seed, has_next_or_predicate, next_fn=None):
- if next_fn is None:
- fn = seed
- return Stream([])
- result = []
- current = seed
- while has_next_or_predicate.test(current):
- result.append(current)
- current = next_fn.apply(current)
- return Stream(result)
-
- # Nested Builder class
- class Builder:
- def __init__(self):
- self._impl = StreamBuilder()
-
- def accept(self, t):
- self._impl.accept(t)
-
- def add(self, t):
- self._impl.add(t)
- return self
-
- def build(self):
- return self._impl.build()
-
-
-# ============================================================
-# IntStream
-# ============================================================
-
-class IntStream(BaseStream):
- """java.util.stream.IntStream"""
- def __init__(self, data=None):
- super().__init__()
- self._data = [int(x) for x in (data or [])]
-
- def filter(self, predicate):
- return IntStream([x for x in self._data if predicate.test(x)])
-
- def map(self, mapper):
- return IntStream([mapper.applyAsInt(x) for x in self._data])
-
- def mapToObj(self, mapper):
- return Stream([mapper.apply(x) for x in self._data])
-
- def mapToLong(self, mapper):
- return LongStream([mapper.applyAsLong(x) for x in self._data])
-
- def mapToDouble(self, mapper):
- return DoubleStream([mapper.applyAsDouble(x) for x in self._data])
-
- def flatMap(self, mapper):
- results = []
- for x in self._data:
- stream = mapper.apply(x)
- if isinstance(stream, IntStream):
- results.extend(stream._data)
- return IntStream(results)
-
- def distinct(self):
- return IntStream(list(set(self._data)))
-
- def sorted(self):
- return IntStream(sorted(self._data))
-
- def peek(self, action):
- for x in self._data:
- action.accept(x)
- return IntStream(self._data[:])
-
- def limit(self, max_size):
- return IntStream(self._data[:max_size])
-
- def skip(self, n):
- return IntStream(self._data[n:])
-
- def forEach(self, action):
- for x in self._data:
- action.accept(x)
-
- def forEachOrdered(self, action):
- self.forEach(action)
-
- def toArray(self):
- return list(self._data)
-
- def reduce(self, identity_or_op, op=None):
- if op is None:
- if not self._data:
- return Optional.empty()
- result = self._data[0]
- for x in self._data[1:]:
- result = identity_or_op.applyAsInt(result, x)
- return Optional.of(result)
- result = identity_or_op
- for x in self._data:
- result = op.applyAsInt(result, x)
- return result
-
- def collect(self, supplier, accumulator, combiner):
- container = supplier.get()
- for x in self._data:
- accumulator.accept(container, x)
- return container
-
- def sum(self):
- return sum(self._data)
-
- def min(self):
- if not self._data:
- return Optional.empty()
- return Optional.of(min(self._data))
-
- def max(self):
- if not self._data:
- return Optional.empty()
- return Optional.of(max(self._data))
-
- def count(self):
- return len(self._data)
-
- def average(self):
- if not self._data:
- return Optional.empty()
- return Optional.of(sum(self._data) / len(self._data))
-
- def summaryStatistics(self):
- return IntSummaryStatistics(self._data)
-
- def anyMatch(self, predicate):
- return any(predicate.test(x) for x in self._data)
-
- def allMatch(self, predicate):
- return all(predicate.test(x) for x in self._data)
-
- def noneMatch(self, predicate):
- return not any(predicate.test(x) for x in self._data)
-
- def findFirst(self):
- if self._data:
- return Optional.of(self._data[0])
- return Optional.empty()
-
- def findAny(self):
- return self.findFirst()
-
- def asDoubleStream(self):
- return DoubleStream([float(x) for x in self._data])
-
- def asLongStream(self):
- return LongStream(self._data[:])
-
- def boxed(self):
- return Stream(self._data[:])
-
- def iterator(self):
- return iter(self._data)
-
- def _get_data(self):
- return self._data
-
- @staticmethod
- def of(*args):
- return IntStream(list(args))
-
- @staticmethod
- def empty():
- return IntStream([])
-
- @staticmethod
- def concat(a, b):
- return IntStream(list(a._data) + list(b._data))
-
- @staticmethod
- def range(start, end):
- return IntStream(list(range(start, end)))
-
- @staticmethod
- def rangeClosed(start, end):
- return IntStream(list(range(start, end + 1)))
-
- @staticmethod
- def generate(supplier):
- return IntStream([])
-
- @staticmethod
- def iterate(seed, has_next, next_fn):
- return IntStream([])
-
- class Builder:
- def __init__(self):
- self._impl = IntStreamBuilder()
-
- def accept(self, t):
- self._impl.accept(t)
-
- def add(self, t):
- self._impl.add(t)
- return self
-
- def build(self):
- return self._impl.build()
-
-
-# ============================================================
-# LongStream
-# ============================================================
-
-class LongStream(BaseStream):
- """java.util.stream.LongStream"""
- def __init__(self, data=None):
- super().__init__()
- self._data = [int(x) for x in (data or [])]
-
- def filter(self, predicate):
- return LongStream([x for x in self._data if predicate.test(x)])
-
- def map(self, mapper):
- return LongStream([mapper.applyAsLong(x) for x in self._data])
-
- def mapToObj(self, mapper):
- return Stream([mapper.apply(x) for x in self._data])
-
- def mapToInt(self, mapper):
- return IntStream([mapper.applyAsInt(x) for x in self._data])
-
- def mapToDouble(self, mapper):
- return DoubleStream([mapper.applyAsDouble(x) for x in self._data])
-
- def flatMap(self, mapper):
- results = []
- for x in self._data:
- stream = mapper.apply(x)
- if isinstance(stream, LongStream):
- results.extend(stream._data)
- return LongStream(results)
-
- def distinct(self):
- return LongStream(list(set(self._data)))
-
- def sorted(self):
- return LongStream(sorted(self._data))
-
- def peek(self, action):
- for x in self._data:
- action.accept(x)
- return LongStream(self._data[:])
-
- def limit(self, max_size):
- return LongStream(self._data[:max_size])
-
- def skip(self, n):
- return LongStream(self._data[n:])
-
- def forEach(self, action):
- for x in self._data:
- action.accept(x)
-
- def forEachOrdered(self, action):
- self.forEach(action)
-
- def toArray(self):
- return list(self._data)
-
- def reduce(self, identity_or_op, op=None):
- if op is None:
- if not self._data:
- return Optional.empty()
- result = self._data[0]
- for x in self._data[1:]:
- result = identity_or_op.applyAsLong(result, x)
- return Optional.of(result)
- result = identity_or_op
- for x in self._data:
- result = op.applyAsLong(result, x)
- return result
-
- def sum(self):
- return sum(self._data)
-
- def min(self):
- if not self._data:
- return Optional.empty()
- return Optional.of(min(self._data))
-
- def max(self):
- if not self._data:
- return Optional.empty()
- return Optional.of(max(self._data))
-
- def count(self):
- return len(self._data)
-
- def average(self):
- if not self._data:
- return Optional.empty()
- return Optional.of(sum(self._data) / len(self._data))
-
- def summaryStatistics(self):
- return LongSummaryStatistics(self._data)
-
- def anyMatch(self, predicate):
- return any(predicate.test(x) for x in self._data)
-
- def allMatch(self, predicate):
- return all(predicate.test(x) for x in self._data)
-
- def noneMatch(self, predicate):
- return not any(predicate.test(x) for x in self._data)
-
- def findFirst(self):
- if self._data:
- return Optional.of(self._data[0])
- return Optional.empty()
-
- def findAny(self):
- return self.findFirst()
-
- def asDoubleStream(self):
- return DoubleStream([float(x) for x in self._data])
-
- def boxed(self):
- return Stream(self._data[:])
-
- def iterator(self):
- return iter(self._data)
-
- def _get_data(self):
- return self._data
-
- @staticmethod
- def of(*args):
- return LongStream(list(args))
-
- @staticmethod
- def empty():
- return LongStream([])
-
- @staticmethod
- def concat(a, b):
- return LongStream(list(a._data) + list(b._data))
-
- @staticmethod
- def range(start, end):
- return LongStream(list(range(start, end)))
-
- @staticmethod
- def rangeClosed(start, end):
- return LongStream(list(range(start, end + 1)))
-
- class Builder:
- def __init__(self):
- self._impl = LongStreamBuilder()
-
- def accept(self, t):
- self._impl.accept(t)
-
- def add(self, t):
- self._impl.add(t)
- return self
-
- def build(self):
- return self._impl.build()
-
-
-# ============================================================
-# DoubleStream
-# ============================================================
-
-class DoubleStream(BaseStream):
- """java.util.stream.DoubleStream"""
- def __init__(self, data=None):
- super().__init__()
- self._data = [float(x) for x in (data or [])]
-
- def filter(self, predicate):
- return DoubleStream([x for x in self._data if predicate.test(x)])
-
- def map(self, mapper):
- return DoubleStream([mapper.applyAsDouble(x) for x in self._data])
-
- def mapToObj(self, mapper):
- return Stream([mapper.apply(x) for x in self._data])
-
- def mapToInt(self, mapper):
- return IntStream([mapper.applyAsInt(x) for x in self._data])
-
- def mapToLong(self, mapper):
- return LongStream([mapper.applyAsLong(x) for x in self._data])
-
- def flatMap(self, mapper):
- results = []
- for x in self._data:
- stream = mapper.apply(x)
- if isinstance(stream, DoubleStream):
- results.extend(stream._data)
- return DoubleStream(results)
-
- def distinct(self):
- return DoubleStream(list(set(self._data)))
-
- def sorted(self):
- return DoubleStream(sorted(self._data))
-
- def peek(self, action):
- for x in self._data:
- action.accept(x)
- return DoubleStream(self._data[:])
-
- def limit(self, max_size):
- return DoubleStream(self._data[:max_size])
-
- def skip(self, n):
- return DoubleStream(self._data[n:])
-
- def forEach(self, action):
- for x in self._data:
- action.accept(x)
-
- def forEachOrdered(self, action):
- self.forEach(action)
-
- def toArray(self):
- return list(self._data)
-
- def reduce(self, identity_or_op, op=None):
- if op is None:
- if not self._data:
- return Optional.empty()
- result = self._data[0]
- for x in self._data[1:]:
- result = identity_or_op.applyAsDouble(result, x)
- return Optional.of(result)
- result = identity_or_op
- for x in self._data:
- result = op.applyAsDouble(result, x)
- return result
-
- def sum(self):
- return sum(self._data)
-
- def min(self):
- if not self._data:
- return Optional.empty()
- return Optional.of(min(self._data))
-
- def max(self):
- if not self._data:
- return Optional.empty()
- return Optional.of(max(self._data))
-
- def count(self):
- return len(self._data)
-
- def average(self):
- if not self._data:
- return Optional.empty()
- return Optional.of(sum(self._data) / len(self._data))
-
- def summaryStatistics(self):
- return DoubleSummaryStatistics(self._data)
-
- def anyMatch(self, predicate):
- return any(predicate.test(x) for x in self._data)
-
- def allMatch(self, predicate):
- return all(predicate.test(x) for x in self._data)
-
- def noneMatch(self, predicate):
- return not any(predicate.test(x) for x in self._data)
-
- def findFirst(self):
- if self._data:
- return Optional.of(self._data[0])
- return Optional.empty()
-
- def findAny(self):
- return self.findFirst()
-
- def iterator(self):
- return iter(self._data)
-
- def _get_data(self):
- return self._data
-
- @staticmethod
- def of(*args):
- return DoubleStream(list(args))
-
- @staticmethod
- def empty():
- return DoubleStream([])
-
- @staticmethod
- def concat(a, b):
- return DoubleStream(list(a._data) + list(b._data))
-
- @staticmethod
- def generate(supplier):
- return DoubleStream([])
-
- class Builder:
- def __init__(self):
- self._impl = DoubleStreamBuilder()
-
- def accept(self, t):
- self._impl.accept(t)
-
- def add(self, t):
- self._impl.add(t)
- return self
-
- def build(self):
- return self._impl.build()
-
-
-# ============================================================
-# Collector
-# ============================================================
-
-class Collector(Stub):
- """java.util.stream.Collector"""
- class Characteristics:
- CONCURRENT = "CONCURRENT"
- UNORDERED = "UNORDERED"
- IDENTITY_FINISH = "IDENTITY_FINISH"
-
- def __init__(self, supplier, accumulator, combiner, finisher=None,
- characteristics=None):
- super().__init__()
- self._supplier = supplier
- self._accumulator = accumulator
- self._combiner = combiner
- self._finisher = finisher
- self._characteristics = characteristics or []
-
- def supplier(self):
- return self._supplier
-
- def accumulator(self):
- return self._accumulator
-
- def combiner(self):
- return self._combiner
-
- def finisher(self):
- return self._finisher
-
- def characteristics(self):
- return self._characteristics
-
-
-# ============================================================
-# Collectors
-# ============================================================
-
-class Collectors(Stub):
- """java.util.stream.Collectors"""
- @staticmethod
- def toList():
- class ToListCollector(Collector):
- def __init__(self):
- s = lambda: []
- a = lambda lst, item: lst.append(item) or lst
- c = lambda l1, l2: l1 + l2
- super().__init__(s, a, c)
- return ToListCollector()
-
- @staticmethod
- def toSet():
- class ToSetCollector(Collector):
- def __init__(self):
- s = lambda: set()
- a = lambda st, item: st.add(item) or st
- c = lambda s1, s2: s1 | s2
- super().__init__(s, a, c)
- return ToSetCollector()
-
- @staticmethod
- def joining(delimiter="", prefix="", suffix=""):
- class JoiningCollector(Collector):
- def __init__(self):
- s = lambda: []
- a = lambda lst, item: lst.append(str(item)) or lst
- c = lambda l1, l2: l1 + l2
- f = lambda lst: prefix + delimiter.join(lst) + suffix
- super().__init__(s, a, c, f)
- return JoiningCollector()
-
- @staticmethod
- def mapping(mapper, downstream):
- class MappingCollector(Collector):
- def __init__(self):
- s = downstream.supplier()
- a = lambda container, item: downstream.accumulator()(container, mapper(item))
- c = downstream.combiner()
- f = downstream.finisher()
- super().__init__(s, a, c, f)
- return MappingCollector()
-
- @staticmethod
- def filtering(predicate, downstream):
- class FilteringCollector(Collector):
- def __init__(self):
- s = downstream.supplier()
- a = lambda container, item: (
- downstream.accumulator()(container, item)
- if predicate(item) else container
- )
- c = downstream.combiner()
- f = downstream.finisher()
- super().__init__(s, a, c, f)
- return FilteringCollector()
-
- @staticmethod
- def collectingAndThen(downstream, finisher):
- class CollectingAndThenCollector(Collector):
- def __init__(self):
- s = downstream.supplier()
- a = downstream.accumulator()
- c = downstream.combiner()
- f = lambda result: finisher(downstream.finisher()(result)) if downstream.finisher() else finisher(result)
- super().__init__(s, a, c, f)
- return CollectingAndThenCollector()
-
- @staticmethod
- def counting():
- class CountingCollector(Collector):
- def __init__(self):
- s = lambda: [0]
- a = lambda cnt, item: [cnt[0] + 1]
- c = lambda c1, c2: [c1[0] + c2[0]]
- f = lambda cnt: cnt[0]
- super().__init__(s, a, c, f)
- return CountingCollector()
-
- @staticmethod
- def summingInt(mapper):
- class SummingIntCollector(Collector):
- def __init__(self):
- s = lambda: [0]
- a = lambda total, item: [total[0] + mapper(item)]
- c = lambda t1, t2: [t1[0] + t2[0]]
- f = lambda total: total[0]
- super().__init__(s, a, c, f)
- return SummingIntCollector()
-
- @staticmethod
- def summingLong(mapper):
- class SummingLongCollector(Collector):
- def __init__(self):
- s = lambda: [0]
- a = lambda total, item: [total[0] + mapper(item)]
- c = lambda t1, t2: [t1[0] + t2[0]]
- f = lambda total: total[0]
- super().__init__(s, a, c, f)
- return SummingLongCollector()
-
- @staticmethod
- def summingDouble(mapper):
- class SummingDoubleCollector(Collector):
- def __init__(self):
- s = lambda: [0.0]
- a = lambda total, item: [total[0] + mapper(item)]
- c = lambda t1, t2: [t1[0] + t2[0]]
- f = lambda total: total[0]
- super().__init__(s, a, c, f)
- return SummingDoubleCollector()
-
- @staticmethod
- def averagingInt(mapper):
- class AveragingIntCollector(Collector):
- def __init__(self):
- s = lambda: [0, 0] # [sum, count]
- a = lambda acc, item: [acc[0] + mapper(item), acc[1] + 1]
- c = lambda a1, a2: [a1[0] + a2[0], a1[1] + a2[1]]
- f = lambda acc: acc[0] / acc[1] if acc[1] > 0 else 0.0
- super().__init__(s, a, c, f)
- return AveragingIntCollector()
-
- @staticmethod
- def averagingLong(mapper):
- class AveragingLongCollector(Collector):
- def __init__(self):
- s = lambda: [0, 0]
- a = lambda acc, item: [acc[0] + mapper(item), acc[1] + 1]
- c = lambda a1, a2: [a1[0] + a2[0], a1[1] + a2[1]]
- f = lambda acc: acc[0] / acc[1] if acc[1] > 0 else 0.0
- super().__init__(s, a, c, f)
- return AveragingLongCollector()
-
- @staticmethod
- def averagingDouble(mapper):
- class AveragingDoubleCollector(Collector):
- def __init__(self):
- s = lambda: [0.0, 0]
- a = lambda acc, item: [acc[0] + mapper(item), acc[1] + 1]
- c = lambda a1, a2: [a1[0] + a2[0], a1[1] + a2[1]]
- f = lambda acc: acc[0] / acc[1] if acc[1] > 0 else 0.0
- super().__init__(s, a, c, f)
- return AveragingDoubleCollector()
-
- @staticmethod
- def reducing(identity, mapper_or_op, op=None):
- class ReducingCollector(Collector):
- def __init__(self):
- if op is None:
- s = lambda: [identity]
- a = lambda acc, item: [acc[0] + mapper_or_op(item)]
- c = lambda a1, a2: [a1[0] + a2[0]]
- f = lambda acc: acc[0]
- else:
- s = lambda: [identity]
- a = lambda acc, item: [mapper_or_op.apply(acc[0], item)]
- c = lambda a1, a2: [a1[0] + a2[0]]
- f = lambda acc: acc[0]
- super().__init__(s, a, c, f)
- return ReducingCollector()
-
- @staticmethod
- def groupingBy(classifier, downstream_or_map_factory=None, downstream=None):
- class GroupingByCollector(Collector):
- def __init__(self):
- s = lambda: {}
- a = lambda m, item: (
- m.setdefault(classifier(item), []).append(item) or m
- )
- c = lambda m1, m2: (
- {k: m1.get(k, []) + m2.get(k, []) for k in set(m1) | set(m2)}
- )
- f = None
- super().__init__(s, a, c, f)
- return GroupingByCollector()
-
- @staticmethod
- def partitioningBy(predicate, downstream=None):
- class PartitioningByCollector(Collector):
- def __init__(self):
- s = lambda: {True: [], False: []}
- a = lambda m, item: (
- m[True].append(item) if predicate(item) else m[False].append(item)
- ) or m
- c = lambda m1, m2: {
- True: m1[True] + m2[True],
- False: m1[False] + m2[False]
- }
- super().__init__(s, a, c)
- return PartitioningByCollector()
-
- @staticmethod
- def toMap(key_mapper, value_mapper, merge_function=None, map_supplier=None):
- class ToMapCollector(Collector):
- def __init__(self):
- s = map_supplier or dict
- a = lambda m, item: (
- m.__setitem__(key_mapper(item), value_mapper(item)) or m
- )
- c = lambda m1, m2: {**m1, **m2}
- super().__init__(s, a, c)
- return ToMapCollector()
-
-
-# ============================================================
-# StreamSupport
-# ============================================================
-
-class StreamSupport(Stub):
- """java.util.stream.StreamSupport"""
- @staticmethod
- def stream(spliterator, parallel=False):
- return Stream([])
-
- @staticmethod
- def intStream(spliterator, parallel=False):
- return IntStream([])
-
- @staticmethod
- def longStream(spliterator, parallel=False):
- return LongStream([])
-
- @staticmethod
- def doubleStream(spliterator, parallel=False):
- return DoubleStream([])
-
-
-# ============================================================
-# Spliterator
-# ============================================================
-
-class Spliterator(Stub):
- """java.util.Spliterator"""
- def __init__(self, data):
- super().__init__()
- self._data = list(data)
- self._index = 0
-
- def tryAdvance(self, action):
- if self._index < len(self._data):
- action.accept(self._data[self._index])
- self._index += 1
- return True
- return False
-
- def forEachRemaining(self, action):
- while self._index < len(self._data):
- action.accept(self._data[self._index])
- self._index += 1
-
- def estimateSize(self):
- return len(self._data) - self._index
-
- def getExactSizeIfKnown(self):
- return self.estimateSize()
-
- def characteristics(self):
- return 0
-
- ORDERED = 16
- DISTINCT = 1
- SORTED = 4
- SIZED = 64
- NONNULL = 256
- IMMUTABLE = 1024
- CONCURRENT = 4096
- SUBSIZED = 16384
-
-
-# ============================================================
-# Summary Statistics
-# ============================================================
-
-class IntSummaryStatistics(Stub):
- def __init__(self, data=None):
- super().__init__()
- self._data = list(data) if data else []
-
- def getCount(self):
- return len(self._data)
-
- def getSum(self):
- return sum(self._data)
-
- def getMin(self):
- return min(self._data) if self._data else 0
-
- def getMax(self):
- return max(self._data) if self._data else 0
-
- def getAverage(self):
- return sum(self._data) / len(self._data) if self._data else 0.0
-
- def accept(self, value):
- self._data.append(int(value))
-
- def combine(self, other):
- self._data.extend(other._data)
-
-
-class LongSummaryStatistics(Stub):
- def __init__(self, data=None):
- super().__init__()
- self._data = list(data) if data else []
-
- def getCount(self):
- return len(self._data)
-
- def getSum(self):
- return sum(self._data)
-
- def getMin(self):
- return min(self._data) if self._data else 0
-
- def getMax(self):
- return max(self._data) if self._data else 0
-
- def getAverage(self):
- return sum(self._data) / len(self._data) if self._data else 0.0
-
- def accept(self, value):
- self._data.append(int(value))
-
- def combine(self, other):
- self._data.extend(other._data)
-
-
-class DoubleSummaryStatistics(Stub):
- def __init__(self, data=None):
- super().__init__()
- self._data = list(data) if data else []
-
- def getCount(self):
- return len(self._data)
-
- def getSum(self):
- return sum(self._data)
-
- def getMin(self):
- return min(self._data) if self._data else 0.0
-
- def getMax(self):
- return max(self._data) if self._data else 0.0
-
- def getAverage(self):
- return sum(self._data) / len(self._data) if self._data else 0.0
-
- def accept(self, value):
- self._data.append(float(value))
-
- def combine(self, other):
- self._data.extend(other._data)
-
-
-# ============================================================
-# Pipeline / Operations stubs
-# ============================================================
-
-class AbstractPipeline(BaseStream):
- """java.util.stream.AbstractPipeline"""
- pass
-
-
-class ReferencePipeline(AbstractPipeline):
- """java.util.stream.ReferencePipeline"""
- pass
-
-
-class IntPipeline(AbstractPipeline):
- """java.util.stream.IntPipeline"""
- pass
-
-
-class LongPipeline(AbstractPipeline):
- """java.util.stream.LongPipeline"""
- pass
-
-
-class DoublePipeline(AbstractPipeline):
- """java.util.stream.DoublePipeline"""
- pass
-
-
-class Sink(Stub):
- """java.util.stream.Sink"""
- def begin(self, size):
- pass
-
- def end(self):
- pass
-
- def cancellationRequested(self):
- return False
-
- def accept(self, t):
- pass
-
-
-class TerminalOp(Stub):
- """java.util.stream.TerminalOp"""
- pass
-
-
-class TerminalSink(Sink):
- """java.util.stream.TerminalSink"""
- def get(self):
- return None
-
-
-class SliceOps(Stub):
- """java.util.stream.SliceOps"""
- pass
-
-
-class WhileOps(Stub):
- """java.util.stream.WhileOps"""
- pass
-
-
-class DistinctOps(Stub):
- """java.util.stream.DistinctOps"""
- pass
-
-
-class SortedOps(Stub):
- """java.util.stream.SortedOps"""
- pass
-
-
-class FindOps(Stub):
- """java.util.stream.FindOps"""
- pass
-
-
-class MatchOps(Stub):
- """java.util.stream.MatchOps"""
- pass
-
-
-class ReduceOps(Stub):
- """java.util.stream.ReduceOps"""
- pass
-
-
-class ForEachOps(Stub):
- """java.util.stream.ForEachOps"""
- pass
-
-
-class MapOps(Stub):
- """java.util.stream.MapOps"""
- pass
-
-
-class FilterOps(Stub):
- """java.util.stream.FilterOps"""
- pass
-
-
-class FlatMapOps(Stub):
- """java.util.stream.FlatMapOps"""
- pass
-
-
-class PeekOps(Stub):
- """java.util.stream.PeekOps"""
- pass
\ No newline at end of file
diff --git a/android_pyapi/java/util_zip.py b/android_pyapi/java/util_zip.py
deleted file mode 100644
index 034616c..0000000
--- a/android_pyapi/java/util_zip.py
+++ /dev/null
@@ -1,697 +0,0 @@
-"""
-Java zip standard library APIs implemented in Python.
-java.util.zip package - ZipFile, ZipEntry, GZIP, CRC, Deflater, Inflater.
-"""
-
-from .._core import Stub
-from .io import IOException, Closeable, Flushable
-import zipfile as _zipfile
-import gzip as _gzip
-import zlib as _zlib
-import io as _pyio
-import os as _os
-from datetime import datetime as _datetime
-
-__all__ = [
- "ZipFile", "ZipEntry", "ZipOutputStream", "ZipInputStream",
- "GZIPInputStream", "GZIPOutputStream",
- "CRC32", "CheckedInputStream", "CheckedOutputStream",
- "Adler32",
- "DataFormatException", "ZipException",
- "Deflater", "Inflater",
- "DeflaterOutputStream", "InflaterInputStream",
-]
-
-
-# ============================================================
-# Exception classes
-# ============================================================
-
-class ZipException(IOException):
- pass
-
-class DataFormatException(Exception):
- pass
-
-
-# ============================================================
-# CRC32
-# ============================================================
-
-class CRC32(Stub):
- def __init__(self):
- super().__init__()
- self._value = 0
-
- def getValue(self):
- return self._value
-
- def reset(self):
- self._value = 0
-
- def update(self, b, off=None, length=None):
- if isinstance(b, int):
- self._value = _zlib.crc32(bytes([b & 0xFF]), self._value) & 0xFFFFFFFF
- elif isinstance(b, (bytes, bytearray)):
- if off is not None and length is not None:
- self._value = _zlib.crc32(bytes(b[off:off+length]), self._value) & 0xFFFFFFFF
- else:
- self._value = _zlib.crc32(bytes(b), self._value) & 0xFFFFFFFF
-
-
-# ============================================================
-# Adler32
-# ============================================================
-
-class Adler32(Stub):
- def __init__(self):
- super().__init__()
- self._value = 1
-
- def getValue(self):
- return self._value
-
- def reset(self):
- self._value = 1
-
- def update(self, b, off=None, length=None):
- if isinstance(b, int):
- self._value = _zlib.adler32(bytes([b & 0xFF]), self._value) & 0xFFFFFFFF
- elif isinstance(b, (bytes, bytearray)):
- if off is not None and length is not None:
- self._value = _zlib.adler32(bytes(b[off:off+length]), self._value) & 0xFFFFFFFF
- else:
- self._value = _zlib.adler32(bytes(b), self._value) & 0xFFFFFFFF
-
-
-# ============================================================
-# CheckedInputStream / CheckedOutputStream
-# ============================================================
-
-class CheckedInputStream(Closeable):
- def __init__(self, inp, cksum):
- super().__init__()
- self._in = inp
- self._cksum = cksum
-
- def read(self, b=None, off=None, length=None):
- if b is None:
- result = self._in.read()
- if result >= 0:
- self._cksum.update(result)
- return result
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- result = self._in.read(b, off, length)
- if result > 0:
- self._cksum.update(b[off:off+result])
- return result
-
- def getChecksum(self):
- return self._cksum
-
- def close(self):
- self._in.close()
-
- def skip(self, n):
- return self._in.skip(n)
-
-
-class CheckedOutputStream(Closeable, Flushable):
- def __init__(self, out, cksum):
- super().__init__()
- self._out = out
- self._cksum = cksum
-
- def write(self, b, off=None, length=None):
- if isinstance(b, int):
- self._out.write(b)
- self._cksum.update(b)
- else:
- if off is not None and length is not None:
- data = bytes(b[off:off+length])
- else:
- data = bytes(b)
- self._out.write(data)
- self._cksum.update(data)
-
- def getChecksum(self):
- return self._cksum
-
- def flush(self):
- self._out.flush()
-
- def close(self):
- self._out.close()
-
-
-# ============================================================
-# ZipEntry
-# ============================================================
-
-class ZipEntry(Stub):
- STORED = 0
- DEFLATED = 8
-
- def __init__(self, name):
- super().__init__()
- self._name = name
- self._method = ZipEntry.DEFLATED
- self._size = 0
- self._compressed_size = 0
- self._crc = 0
- self._comment = ""
- self._time = 0
- self._extra = b""
- self._is_directory = name.endswith("/")
-
- def getName(self):
- return self._name
-
- def getMethod(self):
- return self._method
-
- def setMethod(self, method):
- self._method = method
-
- def getSize(self):
- return self._size
-
- def setSize(self, size):
- self._size = size
-
- def getCompressedSize(self):
- return self._compressed_size
-
- def setCompressedSize(self, size):
- self._compressed_size = size
-
- def getCrc(self):
- return self._crc
-
- def setCrc(self, crc):
- self._crc = crc
-
- def getComment(self):
- return self._comment
-
- def setComment(self, comment):
- self._comment = comment
-
- def getTime(self):
- return self._time
-
- def setTime(self, time):
- self._time = time
-
- def getExtra(self):
- return self._extra
-
- def setExtra(self, extra):
- self._extra = extra
-
- def isDirectory(self):
- return self._is_directory
-
- def toString(self):
- return self._name
-
- def __str__(self):
- return self._name
-
-
-# ============================================================
-# ZipFile
-# ============================================================
-
-class ZipFile(Closeable):
- OPEN_READ = 1
- OPEN_DELETE = 2
-
- def __init__(self, file, mode="r"):
- super().__init__()
- if isinstance(file, str):
- path = file
- else:
- path = file.getPath()
- self._path = path
- self._mode = mode
- try:
- self._zfile = _zipfile.ZipFile(path, mode)
- except Exception as e:
- raise ZipException(str(e))
-
- def entries(self):
- return iter(self._zfile.infolist())
-
- def getEntry(self, name):
- try:
- info = self._zfile.getinfo(name)
- entry = ZipEntry(info.filename)
- entry.setMethod(info.compress_type)
- entry.setSize(info.file_size)
- entry.setCompressedSize(info.compress_size)
- entry.setCrc(info.CRC)
- entry.setTime(int(_datetime(*info.date_time).timestamp() * 1000) if info.date_time else 0)
- return entry
- except KeyError:
- return None
-
- def getInputStream(self, entry):
- try:
- data = self._zfile.read(entry.getName() if isinstance(entry, ZipEntry) else entry)
- from ..io import ByteArrayInputStream
- return ByteArrayInputStream(data)
- except Exception as e:
- raise ZipException(str(e))
-
- def close(self):
- self._zfile.close()
-
- def size(self):
- return len(self._zfile.namelist())
-
- def getName(self):
- return self._path
-
- def getComment(self):
- return ""
-
-
-# ============================================================
-# ZipOutputStream
-# ============================================================
-
-class ZipOutputStream(Closeable, Flushable):
- STORED = 0
- DEFLATED = 8
-
- def __init__(self, out):
- super().__init__()
- self._out = out
- self._zfile = _zipfile.ZipFile(out, "w", _zipfile.ZIP_DEFLATED)
- self._method = ZipOutputStream.DEFLATED
- self._level = -1
- self._comment = ""
-
- def putNextEntry(self, entry):
- zi = _zipfile.ZipInfo(entry.getName() if isinstance(entry, ZipEntry) else str(entry))
- if hasattr(entry, 'getTime') and entry.getTime():
- dt = _datetime.fromtimestamp(entry.getTime() / 1000.0)
- zi.date_time = dt.timetuple()[:6]
- self._zfile.writestr(zi, b"")
-
- def closeEntry(self):
- pass
-
- def write(self, b, off=None, length=None):
- if off is not None and length is not None:
- self._zfile._zout.write(bytes(b[off:off+length]))
- else:
- self._zfile._zout.write(bytes(b) if not isinstance(b, (bytes, bytearray)) else b)
-
- def finish(self):
- self._zfile.close()
-
- def close(self):
- self._zfile.close()
-
- def setMethod(self, method):
- self._method = method
-
- def setLevel(self, level):
- self._level = level
-
- def setComment(self, comment):
- self._comment = comment
-
- def flush(self):
- self._zfile._zout.flush() if hasattr(self._zfile._zout, 'flush') else None
-
-
-# ============================================================
-# ZipInputStream
-# ============================================================
-
-class ZipInputStream(Closeable):
- def __init__(self, inp):
- super().__init__()
- self._inp = inp
- self._zfile = _zipfile.ZipFile(inp)
- self._entries = iter(self._zfile.infolist())
- self._current_entry = None
- self._current_data = b""
- self._current_pos = 0
-
- def getNextEntry(self):
- try:
- info = next(self._entries)
- entry = ZipEntry(info.filename)
- entry.setMethod(info.compress_type)
- entry.setSize(info.file_size)
- entry.setCompressedSize(info.compress_size)
- entry.setCrc(info.CRC)
- self._current_entry = info
- self._current_data = self._zfile.read(info)
- self._current_pos = 0
- return entry
- except StopIteration:
- self._current_entry = None
- self._current_data = b""
- return None
-
- def read(self, b=None, off=None, length=None):
- if self._current_entry is None:
- return -1
- avail = len(self._current_data) - self._current_pos
- if avail <= 0:
- return -1
- if b is None:
- val = self._current_data[self._current_pos]
- self._current_pos += 1
- return val
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- n = min(length, avail)
- if isinstance(b, bytearray):
- b[off:off+n] = self._current_data[self._current_pos:self._current_pos+n]
- self._current_pos += n
- return n
-
- def closeEntry(self):
- self._current_entry = None
- self._current_data = b""
-
- def available(self):
- if self._current_entry is None:
- return 0
- return len(self._current_data) - self._current_pos
-
- def close(self):
- self._zfile.close()
-
-
-# ============================================================
-# GZIPInputStream
-# ============================================================
-
-class GZIPInputStream(Closeable):
- def __init__(self, inp, size=512):
- super().__init__()
- self._inp = inp
- self._gzip_file = _gzip.GzipFile(fileobj=_pyio.BufferedReader(inp) if hasattr(inp, 'read') else inp)
-
- def read(self, b=None, off=None, length=None):
- if b is None:
- data = self._gzip_file.read(1)
- return data[0] if data else -1
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- data = self._gzip_file.read(length)
- if not data:
- return -1
- n = len(data)
- if isinstance(b, bytearray):
- b[off:off+n] = data
- else:
- ba = bytearray(b)
- ba[off:off+n] = data
- b[:] = bytes(ba)
- return n
-
- def close(self):
- self._gzip_file.close()
-
-
-# ============================================================
-# GZIPOutputStream
-# ============================================================
-
-class GZIPOutputStream(Closeable, Flushable):
- def __init__(self, out, size=512):
- super().__init__()
- self._out = out
- self._gzip_file = _gzip.GzipFile(fileobj=out, mode="wb")
-
- def write(self, b, off=None, length=None):
- if isinstance(b, int):
- self._gzip_file.write(bytes([b & 0xFF]))
- elif isinstance(b, (bytes, bytearray)):
- if off is not None and length is not None:
- self._gzip_file.write(bytes(b[off:off+length]))
- else:
- self._gzip_file.write(bytes(b))
-
- def finish(self):
- self._gzip_file.close()
-
- def close(self):
- self._gzip_file.close()
-
- def flush(self):
- self._gzip_file.flush()
-
-
-# ============================================================
-# Deflater
-# ============================================================
-
-class Deflater(Stub):
- BEST_COMPRESSION = 9
- BEST_SPEED = 1
- DEFAULT_COMPRESSION = -1
- DEFAULT_STRATEGY = 0
- FILTERED = 1
- HUFFMAN_ONLY = 2
- NO_COMPRESSION = 0
- NO_FLUSH = 0
- SYNC_FLUSH = 2
- FULL_FLUSH = 3
-
- def __init__(self, level=-1, nowrap=False):
- super().__init__()
- self._level = level
- self._nowrap = nowrap
- self._compress = _zlib.compressobj(level=level if level >= 0 else 6,
- method=_zlib.DEFLATED,
- wbits=-_zlib.MAX_WBITS if nowrap else _zlib.MAX_WBITS)
- self._input_buffer = b""
- self._finished = False
-
- def setInput(self, data, off=0, length=-1):
- if length < 0:
- length = len(data) - off
- self._input_buffer = bytes(data[off:off+length])
-
- def needsInput(self):
- return len(self._input_buffer) == 0
-
- def setDictionary(self, dictionary):
- pass
-
- def getTotalIn(self):
- return len(self._input_buffer)
-
- def getTotalOut(self):
- return 0
-
- def deflate(self, output, off=0, length=-1):
- if length < 0:
- length = len(output) - off
- data = self._compress.compress(self._input_buffer)
- self._input_buffer = b""
- n = min(len(data), length)
- if isinstance(output, bytearray):
- output[off:off+n] = data[:n]
- else:
- ba = bytearray(output)
- ba[off:off+n] = data[:n]
- output[:] = bytes(ba)
- return n
-
- def finish(self):
- self._finished = True
-
- def finished(self):
- return self._finished
-
- def end(self):
- pass
-
- def getAdler(self):
- return 1
-
- def reset(self):
- self._compress = _zlib.compressobj(level=self._level if self._level >= 0 else 6,
- method=_zlib.DEFLATED,
- wbits=-_zlib.MAX_WBITS if self._nowrap else _zlib.MAX_WBITS)
- self._input_buffer = b""
- self._finished = False
-
-
-# ============================================================
-# Inflater
-# ============================================================
-
-class Inflater(Stub):
- def __init__(self, nowrap=False):
- super().__init__()
- self._nowrap = nowrap
- wbits = -_zlib.MAX_WBITS if nowrap else _zlib.MAX_WBITS
- self._decompress = _zlib.decompressobj(wbits)
- self._input_buffer = b""
- self._finished = False
-
- def setInput(self, data, off=0, length=-1):
- if length < 0:
- length = len(data) - off
- self._input_buffer = bytes(data[off:off+length])
-
- def needsInput(self):
- return len(self._input_buffer) == 0
-
- def setDictionary(self, dictionary):
- pass
-
- def getTotalIn(self):
- return len(self._input_buffer)
-
- def getTotalOut(self):
- return 0
-
- def inflate(self, output, off=0, length=-1):
- if length < 0:
- length = len(output) - off
- try:
- data = self._decompress.decompress(self._input_buffer)
- self._input_buffer = b""
- n = min(len(data), length)
- if isinstance(output, bytearray):
- output[off:off+n] = data[:n]
- else:
- ba = bytearray(output)
- ba[off:off+n] = data[:n]
- output[:] = bytes(ba)
- return n
- except _zlib.error as e:
- raise DataFormatException(str(e))
-
- def finished(self):
- return self._finished
-
- def end(self):
- pass
-
- def getAdler(self):
- return 1
-
- def needsDictionary(self):
- return False
-
- def reset(self):
- wbits = -_zlib.MAX_WBITS if self._nowrap else _zlib.MAX_WBITS
- self._decompress = _zlib.decompressobj(wbits)
- self._input_buffer = b""
- self._finished = False
-
-
-# ============================================================
-# DeflaterOutputStream
-# ============================================================
-
-class DeflaterOutputStream(Closeable, Flushable):
- def __init__(self, out, deflater=None, size=512):
- super().__init__()
- self._out = out
- self._deflater = deflater or Deflater()
- self._buffer = bytearray(size)
-
- def write(self, b, off=None, length=None):
- if isinstance(b, int):
- self._out.write(bytes([b & 0xFF]))
- else:
- if off is not None and length is not None:
- self._out.write(bytes(b[off:off+length]))
- else:
- self._deflater.setInput(bytes(b) if isinstance(b, (bytes, bytearray)) else bytes(b))
- while not self._deflater.needsInput():
- n = self._deflater.deflate(self._buffer)
- if n > 0:
- self._out.write(bytes(self._buffer[:n]))
-
- def finish(self):
- self._deflater.finish()
- while not self._deflater.finished():
- n = self._deflater.deflate(self._buffer)
- if n > 0:
- self._out.write(bytes(self._buffer[:n]))
-
- def close(self):
- self.finish()
- self._deflater.end()
- self._out.close()
-
- def flush(self):
- self._out.flush()
-
-
-# ============================================================
-# InflaterInputStream
-# ============================================================
-
-class InflaterInputStream(Closeable):
- def __init__(self, inp, inflater=None, size=512):
- super().__init__()
- self._in = inp
- self._inflater = inflater or Inflater()
- self._buffer = bytearray(size)
-
- def read(self, b=None, off=None, length=None):
- if b is None:
- buf = bytearray(1)
- n = self._read_from_inflater(buf, 0, 1)
- return buf[0] if n > 0 else -1
- if off is None:
- off = 0
- if length is None:
- length = len(b)
- return self._read_from_inflater(b, off, length)
-
- def _read_from_inflater(self, b, off, length):
- while not self._inflater.finished():
- if self._inflater.needsInput():
- data = self._in.read(self._buffer)
- if data is None or data == -1 or data == 0:
- break
- if isinstance(data, int):
- break
- self._inflater.setInput(data)
- try:
- n = self._inflater.inflate(b, off, length)
- if n > 0:
- return n
- except DataFormatException:
- break
- return -1
-
- def available(self):
- return 0
-
- def close(self):
- self._inflater.end()
- self._in.close()
-
- def mark(self, readlimit):
- pass
-
- def reset(self):
- raise IOException("mark/reset not supported")
-
- def markSupported(self):
- return False
\ No newline at end of file
diff --git a/android_pyapi/javax/__init__.py b/android_pyapi/javax/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/android_pyapi/javax/crypto.py b/android_pyapi/javax/crypto.py
deleted file mode 100644
index 4b02b7b..0000000
--- a/android_pyapi/javax/crypto.py
+++ /dev/null
@@ -1,1031 +0,0 @@
-"""
-Java javax.crypto APIs implemented in Python.
-javax.crypto package - Cipher, KeyGenerator, Mac, KeyAgreement, SecretKey, etc.
-Wraps Python cryptography library.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-from typing import List, Optional, Any
-
-# Optional cryptography dependency
-try:
- from cryptography.fernet import Fernet as _Fernet
- from cryptography.hazmat.primitives.ciphers import Cipher as _Cipher, algorithms as _algorithms, modes as _modes
- from cryptography.hazmat.primitives import hashes as _hashes, hmac as _hmac, padding as _padding
- from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC as _PBKDF2HMAC
- HAS_CRYPTOGRAPHY = True
-except ImportError:
- HAS_CRYPTOGRAPHY = False
-
-__all__ = [
- "Cipher", "KeyGenerator", "SecretKey", "SecretKeySpec",
- "Mac", "KeyAgreement", "ExemptionMechanism",
- "EncryptedPrivateKeyInfo", "SealedObject", "NullCipher",
- "PBEParameterSpec", "IvParameterSpec", "OAEPParameterSpec",
- "PSource", "MGF1ParameterSpec", "DESedeKeySpec", "DESKeySpec",
- "SecretKeyFactory", "CipherInputStream", "CipherOutputStream",
- "BadPaddingException", "IllegalBlockSizeException",
- "NoSuchPaddingException", "ShortBufferException",
-]
-
-
-# ============================================================
-# Exceptions
-# ============================================================
-
-class BadPaddingException(Exception, Stub):
- def __init__(self, message: str = None):
- super().__init__(message or "Bad padding")
- self._message = message
-
- def toString(self) -> str:
- return f"BadPaddingException: {self._message}" if self._message else "BadPaddingException"
-
- def equals(self, other) -> bool:
- return isinstance(other, BadPaddingException) and self._message == other._message
-
- def hashCode(self) -> int:
- return hash(self._message) & 0x7FFFFFFF
-
-
-class IllegalBlockSizeException(Exception, Stub):
- def __init__(self, message: str = None):
- super().__init__(message or "Illegal block size")
- self._message = message
-
- def toString(self) -> str:
- return f"IllegalBlockSizeException: {self._message}" if self._message else "IllegalBlockSizeException"
-
- def equals(self, other) -> bool:
- return isinstance(other, IllegalBlockSizeException) and self._message == other._message
-
- def hashCode(self) -> int:
- return hash(self._message) & 0x7FFFFFFF
-
-
-class NoSuchPaddingException(Exception, Stub):
- def __init__(self, message: str = None):
- super().__init__(message or "No such padding")
- self._message = message
-
- def toString(self) -> str:
- return f"NoSuchPaddingException: {self._message}" if self._message else "NoSuchPaddingException"
-
- def equals(self, other) -> bool:
- return isinstance(other, NoSuchPaddingException) and self._message == other._message
-
- def hashCode(self) -> int:
- return hash(self._message) & 0x7FFFFFFF
-
-
-class ShortBufferException(Exception, Stub):
- def __init__(self, message: str = None):
- super().__init__(message or "Output buffer too short")
- self._message = message
-
- def toString(self) -> str:
- return f"ShortBufferException: {self._message}" if self._message else "ShortBufferException"
-
- def equals(self, other) -> bool:
- return isinstance(other, ShortBufferException) and self._message == other._message
-
- def hashCode(self) -> int:
- return hash(self._message) & 0x7FFFFFFF
-
-
-# ============================================================
-# SecretKey
-# ============================================================
-
-class SecretKey(Stub):
- """
- javax.crypto.SecretKey
- A secret (symmetric) key.
- """
- serialVersionUID: int = -4795878709
-
- def __init__(self, encoded: bytes = None, algorithm: str = None):
- super().__init__()
- self._encoded = encoded or b''
- self._algorithm = algorithm or "RAW"
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def getFormat(self) -> str:
- return "RAW"
-
- def getEncoded(self) -> bytes:
- return self._encoded
-
- def toString(self) -> str:
- return f"SecretKey@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- if isinstance(other, SecretKey):
- return self._encoded == other._encoded and self._algorithm == other._algorithm
- return False
-
- def hashCode(self) -> int:
- return hash((bytes(self._encoded), self._algorithm)) & 0x7FFFFFFF
-
-
-# ============================================================
-# SecretKeySpec
-# ============================================================
-
-class SecretKeySpec(SecretKey):
- """
- javax.crypto.spec.SecretKeySpec
- A secret key specification.
- """
-
- def __init__(self, key: bytes, algorithm: str):
- super().__init__(key, algorithm)
- self._key = key
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def getFormat(self) -> str:
- return "RAW"
-
- def getEncoded(self) -> bytes:
- return self._key
-
- def toString(self) -> str:
- return f"SecretKeySpec@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- if isinstance(other, SecretKeySpec):
- return self._key == other._key and self._algorithm == other._algorithm
- return False
-
- def hashCode(self) -> int:
- return hash((bytes(self._key), self._algorithm)) & 0x7FFFFFFF
-
-
-# ============================================================
-# Cipher
-# ============================================================
-
-class Cipher(Stub):
- """
- javax.crypto.Cipher
- Engine for encryption/decryption.
- """
- ENCRYPT_MODE: int = 1
- DECRYPT_MODE: int = 2
- WRAP_MODE: int = 3
- UNWRAP_MODE: int = 4
- PUBLIC_KEY: int = 1
- PRIVATE_KEY: int = 2
- SECRET_KEY: int = 3
-
- def __init__(self, transformation: str = None):
- super().__init__()
- self._transformation = transformation
- self._opmode = None
- self._key = None
- self._iv = None
- self._provider = None
-
- @staticmethod
- def getInstance(transformation: str) -> "Cipher":
- return Cipher(transformation)
-
- def init(self, opmode: int, key: Any, params: Any = None, random: Any = None):
- """Initializes this cipher with a key and optional parameters."""
- self._opmode = opmode
- self._key = key
- if params and hasattr(params, 'getIV'):
- self._iv = params.getIV()
-
- def doFinal(self, input_data: bytes = None) -> bytes:
- """Performs the final encryption/decryption operation."""
- if input_data is None:
- return b''
- if not HAS_CRYPTOGRAPHY:
- # Fallback simple XOR for demonstration
- if self._key and hasattr(self._key, 'getEncoded'):
- key_bytes = self._key.getEncoded()
- if key_bytes:
- result = bytearray()
- for i, b in enumerate(input_data):
- result.append(b ^ key_bytes[i % len(key_bytes)])
- return bytes(result)
- return input_data
-
- # Try using cryptography library
- try:
- if self._key and hasattr(self._key, 'getEncoded'):
- key_bytes = self._key.getEncoded()
- if self._transformation and "AES" in self._transformation.upper():
- if len(key_bytes) in (16, 24, 32):
- if self._opmode == Cipher.ENCRYPT_MODE:
- from cryptography.hazmat.primitives.ciphers import Cipher as _CryptCipher, algorithms as _alg, modes as _mod
- iv = self._iv or b'\x00' * 16
- c = _CryptCipher(_alg.AES(key_bytes), _mod.CBC(iv))
- encryptor = c.encryptor()
- padder = _padding.PKCS7(128).padder()
- padded = padder.update(input_data) + padder.finalize()
- return encryptor.update(padded) + encryptor.finalize()
- elif self._opmode == Cipher.DECRYPT_MODE:
- iv = self._iv or b'\x00' * 16
- c = _CryptCipher(_alg.AES(key_bytes), _mod.CBC(iv))
- decryptor = c.decryptor()
- padded = decryptor.update(input_data) + decryptor.finalize()
- unpadder = _padding.PKCS7(128).unpadder()
- return unpadder.update(padded) + unpadder.finalize()
- except Exception:
- pass
- return input_data
-
- def update(self, input_data: bytes) -> bytes:
- """Continues a multi-part encryption/decryption operation."""
- return input_data
-
- def wrap(self, key: Any) -> bytes:
- """Wraps a key (stub)."""
- if isinstance(key, SecretKey):
- return key.getEncoded()
- return b''
-
- def unwrap(self, wrapped_key: bytes, wrapped_key_algorithm: str, wrapped_key_type: int) -> Any:
- """Unwraps a key (stub)."""
- return SecretKey(wrapped_key, wrapped_key_algorithm)
-
- def getBlockSize(self) -> int:
- """Returns the block size (bytes)."""
- if self._transformation and "AES" in self._transformation.upper():
- return 16
- if self._transformation and "DES" in self._transformation.upper():
- return 8
- return 0
-
- def getIV(self) -> Optional[bytes]:
- return self._iv
-
- def getParameters(self):
- return None
-
- def getAlgorithm(self) -> str:
- return self._transformation or "NONE"
-
- def getProvider(self):
- return self._provider
-
- def getExemptionMechanism(self):
- return None
-
- def getOutputSize(self, input_len: int) -> int:
- """Returns the output buffer size for a given input length."""
- bs = self.getBlockSize()
- if bs > 0:
- return input_len + (bs - input_len % bs)
- return input_len
-
- @staticmethod
- def getMaxAllowedKeyLength(transformation: str) -> int:
- """Returns the maximum key length for the given transformation."""
- return 2147483647 # Integer.MAX_VALUE
-
- def toString(self) -> str:
- return f"Cipher@{hex(id(self))}[algorithm={self._transformation}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# NullCipher
-# ============================================================
-
-class NullCipher(Cipher):
- """
- javax.crypto.NullCipher
- A cipher that performs no transformation (identity).
- """
- def __init__(self):
- super().__init__("NULL")
-
- def getBlockSize(self) -> int:
- return 1
-
- def getOutputSize(self, input_len: int) -> int:
- return input_len
-
- def getIV(self) -> Optional[bytes]:
- return None
-
- def getParameters(self):
- return None
-
- def getExemptionMechanism(self):
- return None
-
- def update(self, input_data: bytes) -> bytes:
- return input_data
-
- def doFinal(self, input_data: bytes = None) -> bytes:
- return input_data if input_data else b''
-
- def toString(self) -> str:
- return "NullCipher"
-
-
-# ============================================================
-# KeyGenerator
-# ============================================================
-
-class KeyGenerator(Stub):
- """
- javax.crypto.KeyGenerator
- Key generator for symmetric algorithms.
- """
-
- def __init__(self, algorithm: str = None):
- super().__init__()
- self._algorithm = algorithm or "AES"
- self._provider = None
- self._key_size = 128
-
- @staticmethod
- def getInstance(algorithm: str) -> "KeyGenerator":
- return KeyGenerator(algorithm)
-
- def init(self, key_size_or_random: Any, random: Any = None):
- """Initializes the key generator."""
- if isinstance(key_size_or_random, int):
- self._key_size = key_size_or_random
- elif key_size_or_random is not None and hasattr(key_size_or_random, 'nextBytes'):
- pass
-
- def generateKey(self) -> SecretKey:
- """Generates a secret key."""
- import os
- key_bytes = os.urandom(self._key_size // 8)
- return SecretKey(key_bytes, self._algorithm)
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def getProvider(self):
- return self._provider
-
- def toString(self) -> str:
- return f"KeyGenerator@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Mac
-# ============================================================
-
-class Mac(Stub):
- """
- javax.crypto.Mac
- Message Authentication Code engine.
- """
-
- def __init__(self, algorithm: str = None):
- super().__init__()
- self._algorithm = algorithm or "HmacSHA256"
- self._provider = None
- self._key = None
- self._hmac = None
- self._initialized = False
-
- @staticmethod
- def getInstance(algorithm: str) -> "Mac":
- return Mac(algorithm)
-
- def init(self, key: Any, params: Any = None):
- """Initializes the MAC with a key."""
- self._key = key
- self._initialized = True
- if HAS_CRYPTOGRAPHY and key and hasattr(key, 'getEncoded'):
- key_bytes = key.getEncoded()
- hash_algo = _hashes.SHA256()
- self._hmac = _hmac.HMAC(key_bytes, hash_algo)
-
- def update(self, input_data: bytes):
- """Processes the given byte array."""
- if self._hmac:
- self._hmac.update(input_data)
-
- def doFinal(self, input_data: bytes = None) -> bytes:
- """Finishes the MAC operation."""
- if self._hmac:
- if input_data:
- self._hmac.update(input_data)
- return self._hmac.finalize()
- if input_data:
- import hashlib
- return hashlib.sha256(input_data).digest()
- return b'\x00' * 32
-
- def getMacLength(self) -> int:
- """Returns the output length of the MAC."""
- return 32 # SHA-256
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def getProvider(self):
- return self._provider
-
- def reset(self):
- """Resets the MAC."""
- if self._key and hasattr(self._key, 'getEncoded') and HAS_CRYPTOGRAPHY:
- key_bytes = self._key.getEncoded()
- hash_algo = _hashes.SHA256()
- self._hmac = _hmac.HMAC(key_bytes, hash_algo)
-
- def clone(self):
- return Mac(self._algorithm)
-
- def toString(self) -> str:
- return f"Mac@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# KeyAgreement
-# ============================================================
-
-class KeyAgreement(Stub):
- """
- javax.crypto.KeyAgreement
- Key agreement protocol engine (e.g., Diffie-Hellman).
- """
-
- def __init__(self, algorithm: str = None):
- super().__init__()
- self._algorithm = algorithm or "DH"
- self._provider = None
-
- @staticmethod
- def getInstance(algorithm: str) -> "KeyAgreement":
- return KeyAgreement(algorithm)
-
- def init(self, key: Any, params: Any = None):
- """Initializes this key agreement with a key."""
- pass
-
- def doPhase(self, key: Any, last_phase: bool) -> Any:
- """Executes the next phase of the key agreement."""
- return self
-
- def generateSecret(self, shared_secret: Any = None) -> bytes:
- """Generates the shared secret."""
- import os
- return os.urandom(32)
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def getProvider(self):
- return self._provider
-
- def toString(self) -> str:
- return f"KeyAgreement@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# ExemptionMechanism
-# ============================================================
-
-class ExemptionMechanism(Stub):
- """
- javax.crypto.ExemptionMechanism
- Exemption mechanism for key recovery.
- """
-
- def __init__(self, algorithm: str = None):
- super().__init__()
- self._algorithm = algorithm or "KeyRecovery"
- self._initialized = False
-
- @staticmethod
- def getInstance(algorithm: str) -> "ExemptionMechanism":
- return ExemptionMechanism(algorithm)
-
- def init(self, key: Any):
- self._initialized = True
-
- def genExemptionBlob(self, input_data: bytes = None) -> bytes:
- return b'\x00' * 32
-
- def isCryptoAllowed(self, key: Any) -> bool:
- return True
-
- def getOutputSize(self, input_len: int) -> int:
- return input_len
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def getProvider(self):
- return None
-
- def getName(self) -> str:
- return self._algorithm
-
- def toString(self) -> str:
- return f"ExemptionMechanism@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# EncryptedPrivateKeyInfo
-# ============================================================
-
-class EncryptedPrivateKeyInfo(Stub):
- """
- javax.crypto.EncryptedPrivateKeyInfo
- Represents encrypted private key info from PKCS #8.
- """
-
- def __init__(self, alg_params=None, encrypted_data: bytes = None):
- super().__init__()
- self._alg_params = alg_params
- self._encrypted_data = encrypted_data or b''
-
- def getAlgParameters(self):
- return self._alg_params
-
- def getEncryptedData(self) -> bytes:
- return self._encrypted_data
-
- def getEncoded(self) -> bytes:
- return self._encrypted_data
-
- def getName(self) -> str:
- return "PKCS#8"
-
- def toString(self) -> str:
- return f"EncryptedPrivateKeyInfo@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# SealedObject
-# ============================================================
-
-class SealedObject(Stub):
- """
- javax.crypto.SealedObject
- Enables protection of a serializable object using encryption.
- """
-
- def __init__(self, obj: Any = None, cipher: Cipher = None):
- super().__init__()
- self._encrypted_data = b''
- self._algorithm = "NONE"
- if cipher and obj is not None:
- import pickle
- serialized = pickle.dumps(obj)
- self._encrypted_data = cipher.doFinal(serialized)
- self._algorithm = cipher.getAlgorithm()
-
- def getObject(self, cipher_or_key: Any = None) -> Any:
- """Unseals the object."""
- import pickle
- try:
- if isinstance(cipher_or_key, Cipher):
- decrypted = cipher_or_key.doFinal(self._encrypted_data)
- else:
- decrypted = self._encrypted_data
- return pickle.loads(decrypted)
- except Exception:
- return None
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def getEncoded(self) -> bytes:
- return self._encrypted_data
-
- def toString(self) -> str:
- return f"SealedObject@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# ParameterSpec classes
-# ============================================================
-
-class IvParameterSpec(Stub):
- """
- javax.crypto.spec.IvParameterSpec
- Initialization vector specification.
- """
- def __init__(self, iv: bytes):
- super().__init__()
- self._iv = iv
-
- def getIV(self) -> bytes:
- return self._iv
-
- def toString(self) -> str:
- return f"IvParameterSpec@{hex(id(self))}[iv={self._iv.hex()[:16]}...]"
-
-
-class PBEParameterSpec(Stub):
- """
- javax.crypto.spec.PBEParameterSpec
- Password-based encryption parameter specification.
- """
- def __init__(self, salt: bytes, iteration_count: int):
- super().__init__()
- self._salt = salt
- self._iteration_count = iteration_count
-
- def getSalt(self) -> bytes:
- return self._salt
-
- def getIterationCount(self) -> int:
- return self._iteration_count
-
- def toString(self) -> str:
- return f"PBEParameterSpec@{hex(id(self))}[iterations={self._iteration_count}]"
-
-
-class PSource(Stub):
- """
- javax.crypto.spec.PSource
- Source of the label for OAEP padding.
- """
- class PSpecified(Stub):
- DEFAULT: "PSource.PSpecified" = None
- def __init__(self, value: bytes = b''):
- super().__init__()
- self._value = value
- def getValue(self) -> bytes:
- return self._value
- def toString(self) -> str:
- return "PSpecified"
-
- def __init__(self, algorithm: str = None):
- super().__init__()
- self._algorithm = algorithm
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def toString(self) -> str:
- return f"PSource.{self._algorithm}" if self._algorithm else "PSource"
-
- def equals(self, other) -> bool:
- if isinstance(other, PSource):
- return self._algorithm == other._algorithm
- return False
-
- def hashCode(self) -> int:
- return hash(self._algorithm) & 0x7FFFFFFF
-
-
-PSource.PSpecified.DEFAULT = PSource.PSpecified(b'')
-
-
-class OAEPParameterSpec(Stub):
- """
- javax.crypto.spec.OAEPParameterSpec
- OAEP padding parameter specification.
- """
- DEFAULT: "OAEPParameterSpec" = None
-
- def __init__(self, digest_algorithm: str = "SHA-256",
- mgf_algorithm: str = "MGF1",
- mgf_parameters: Any = None,
- p_source: PSource = None):
- super().__init__()
- self._digest_algorithm = digest_algorithm
- self._mgf_algorithm = mgf_algorithm
- self._mgf_parameters = mgf_parameters
- self._p_source = p_source or PSource.PSpecified.DEFAULT
-
- def getDigestAlgorithm(self) -> str:
- return self._digest_algorithm
-
- def getMGFAlgorithm(self) -> str:
- return self._mgf_algorithm
-
- def getMGFParameters(self):
- return self._mgf_parameters
-
- def getPSource(self) -> PSource:
- return self._p_source
-
- def getPSourceAlgorithm(self) -> str:
- return self._p_source.getAlgorithm() if self._p_source else ""
-
- def toString(self) -> str:
- return f"OAEPParameterSpec@{hex(id(self))}[digest={self._digest_algorithm}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-OAEPParameterSpec.DEFAULT = OAEPParameterSpec()
-
-
-class MGF1ParameterSpec(Stub):
- """
- javax.crypto.spec.MGF1ParameterSpec
- MGF1 parameter specification.
- """
- SHA1: "MGF1ParameterSpec" = None
- SHA224: "MGF1ParameterSpec" = None
- SHA256: "MGF1ParameterSpec" = None
- SHA384: "MGF1ParameterSpec" = None
- SHA512: "MGF1ParameterSpec" = None
- SHA512_224: "MGF1ParameterSpec" = None
- SHA512_256: "MGF1ParameterSpec" = None
- SHA3_224: "MGF1ParameterSpec" = None
- SHA3_256: "MGF1ParameterSpec" = None
- SHA3_384: "MGF1ParameterSpec" = None
- SHA3_512: "MGF1ParameterSpec" = None
-
- def __init__(self, digest_algorithm: str = "SHA-1"):
- super().__init__()
- self._digest_algorithm = digest_algorithm
-
- def getDigestAlgorithm(self) -> str:
- return self._digest_algorithm
-
- def toString(self) -> str:
- return f"MGF1ParameterSpec[{self._digest_algorithm}]"
-
- def equals(self, other) -> bool:
- if isinstance(other, MGF1ParameterSpec):
- return self._digest_algorithm == other._digest_algorithm
- return False
-
- def hashCode(self) -> int:
- return hash(self._digest_algorithm) & 0x7FFFFFFF
-
-
-MGF1ParameterSpec.SHA1 = MGF1ParameterSpec("SHA-1")
-MGF1ParameterSpec.SHA224 = MGF1ParameterSpec("SHA-224")
-MGF1ParameterSpec.SHA256 = MGF1ParameterSpec("SHA-256")
-MGF1ParameterSpec.SHA384 = MGF1ParameterSpec("SHA-384")
-MGF1ParameterSpec.SHA512 = MGF1ParameterSpec("SHA-512")
-MGF1ParameterSpec.SHA512_224 = MGF1ParameterSpec("SHA-512/224")
-MGF1ParameterSpec.SHA512_256 = MGF1ParameterSpec("SHA-512/256")
-MGF1ParameterSpec.SHA3_224 = MGF1ParameterSpec("SHA3-224")
-MGF1ParameterSpec.SHA3_256 = MGF1ParameterSpec("SHA3-256")
-MGF1ParameterSpec.SHA3_384 = MGF1ParameterSpec("SHA3-384")
-MGF1ParameterSpec.SHA3_512 = MGF1ParameterSpec("SHA3-512")
-
-
-class DESedeKeySpec(Stub):
- """
- javax.crypto.spec.DESedeKeySpec
- Key specification for DES-EDE (Triple DES) keys.
- """
- DES_EDE_KEY_LEN: int = 24
-
- def __init__(self, key: bytes):
- super().__init__()
- self._key = key
-
- def getKey(self) -> bytes:
- return self._key
-
- @staticmethod
- def isParityAdjusted(key: bytes) -> bool:
- return True
-
- def toString(self) -> str:
- return f"DESedeKeySpec@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class DESKeySpec(Stub):
- """
- javax.crypto.spec.DESKeySpec
- Key specification for DES keys.
- """
- DES_KEY_LEN: int = 8
-
- def __init__(self, key: bytes):
- super().__init__()
- self._key = key
-
- def getKey(self) -> bytes:
- return self._key
-
- @staticmethod
- def isParityAdjusted(key: bytes) -> bool:
- return True
-
- @staticmethod
- def isWeak(key: bytes) -> bool:
- return False
-
- def toString(self) -> str:
- return f"DESKeySpec@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# SecretKeyFactory
-# ============================================================
-
-class SecretKeyFactory(Stub):
- """
- javax.crypto.SecretKeyFactory
- Factory for converting between opaque and transparent keys.
- """
-
- def __init__(self, algorithm: str = None):
- super().__init__()
- self._algorithm = algorithm or "AES"
- self._provider = None
-
- @staticmethod
- def getInstance(algorithm: str) -> "SecretKeyFactory":
- return SecretKeyFactory(algorithm)
-
- def translateKey(self, key: SecretKey) -> SecretKey:
- return key
-
- def generateSecret(self, key_spec: Any) -> SecretKey:
- if isinstance(key_spec, SecretKeySpec):
- return key_spec
- return SecretKey(b'', self._algorithm)
-
- def getKeySpec(self, key: SecretKey, key_spec_cls: type) -> Any:
- if key_spec_cls == SecretKeySpec:
- return SecretKeySpec(key.getEncoded(), key.getAlgorithm())
- return key
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def getProvider(self):
- return self._provider
-
- def toString(self) -> str:
- return f"SecretKeyFactory@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# CipherInputStream
-# ============================================================
-
-class CipherInputStream(Stub):
- """
- javax.crypto.CipherInputStream
- A CipherInputStream is composed of an InputStream and a Cipher.
- """
- def __init__(self, istream, cipher: Cipher):
- super().__init__()
- self._istream = istream
- self._cipher = cipher
- self._buffer = b''
-
- def read(self, b: bytearray = None, off: int = 0, le: int = 0) -> int:
- data = self._istream.read(le) if le else self._istream.read()
- if not data:
- return -1
- decrypted = self._cipher.update(data)
- self._buffer += decrypted
- if b is not None and le > 0:
- n = min(le, len(self._buffer))
- b[off:off + n] = self._buffer[:n]
- self._buffer = self._buffer[n:]
- return n
- return len(data)
-
- def available(self) -> int:
- return len(self._buffer)
-
- def skip(self, n: int) -> int:
- self._buffer = self._buffer[n:]
- return n
-
- def close(self):
- if hasattr(self._istream, 'close'):
- self._istream.close()
-
- def markSupported(self) -> bool:
- return False
-
- def mark(self, read_limit: int):
- pass
-
- def reset(self):
- pass
-
- def toString(self) -> str:
- return f"CipherInputStream@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# CipherOutputStream
-# ============================================================
-
-class CipherOutputStream(Stub):
- """
- javax.crypto.CipherOutputStream
- A CipherOutputStream is composed of an OutputStream and a Cipher.
- """
- def __init__(self, ostream, cipher: Cipher):
- super().__init__()
- self._ostream = ostream
- self._cipher = cipher
-
- def write(self, b: Any, off: int = None, le: int = None):
- if isinstance(b, int):
- data = bytes([b])
- elif off is not None and le is not None:
- data = bytes(b[off:off + le])
- else:
- data = bytes(b) if not isinstance(b, bytes) else b
- encrypted = self._cipher.update(data)
- if hasattr(self._ostream, 'write'):
- self._ostream.write(encrypted)
-
- def flush(self):
- if hasattr(self._ostream, 'flush'):
- self._ostream.flush()
-
- def close(self):
- final = self._cipher.doFinal()
- if final and hasattr(self._ostream, 'write'):
- self._ostream.write(final)
- if hasattr(self._ostream, 'close'):
- self._ostream.close()
-
- def toString(self) -> str:
- return f"CipherOutputStream@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/javax/net.py b/android_pyapi/javax/net.py
deleted file mode 100644
index 29dc880..0000000
--- a/android_pyapi/javax/net.py
+++ /dev/null
@@ -1,785 +0,0 @@
-"""
-Java javax.net APIs implemented in Python.
-javax.net package - SocketFactory, SSLServerSocket, SSLSocket, SSLContext, etc.
-Wraps Python ssl module.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-import ssl as _ssl
-import socket as _socket
-import threading as _threading
-from typing import List, Optional
-
-__all__ = [
- "ServerSocketFactory", "SocketFactory", "SSLServerSocketFactory",
- "SSLSocketFactory", "SSLServerSocket", "SSLSocket",
- "HandshakeCompletedEvent", "HandshakeCompletedListener",
- "HostnameVerifier", "HttpsURLConnection",
- "TrustManager", "X509TrustManager", "KeyManager", "X509KeyManager",
- "TrustManagerFactory", "KeyManagerFactory", "SSLContext",
-]
-
-
-# ============================================================
-# SocketFactory
-# ============================================================
-
-class SocketFactory(Stub):
- """
- javax.net.SocketFactory
- Factory for creating sockets.
- """
-
- _default = None
-
- @classmethod
- def getDefault(cls) -> "SocketFactory":
- if cls._default is None:
- cls._default = SocketFactory()
- return cls._default
-
- def createSocket(self, host: str = None, port: int = None,
- host_inet: Any = None, local_port: int = None,
- stream: bool = True) -> _socket.socket:
- """Creates a socket."""
- sock = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- if host and port is not None:
- sock.connect((host, port))
- return sock
-
- def toString(self) -> str:
- return f"SocketFactory@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# ServerSocketFactory
-# ============================================================
-
-class ServerSocketFactory(Stub):
- """
- javax.net.ServerSocketFactory
- Factory for creating server sockets.
- """
-
- _default = None
-
- @classmethod
- def getDefault(cls) -> "ServerSocketFactory":
- if cls._default is None:
- cls._default = ServerSocketFactory()
- return cls._default
-
- def createServerSocket(self, port: int = 0, backlog: int = 50,
- ifAddress: Any = None) -> _socket.socket:
- """Creates a server socket."""
- sock = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- sock.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1)
- if ifAddress:
- sock.bind((ifAddress, port))
- else:
- sock.bind(('0.0.0.0', port))
- sock.listen(backlog)
- return sock
-
- def toString(self) -> str:
- return f"ServerSocketFactory@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# SSLServerSocketFactory
-# ============================================================
-
-class SSLServerSocketFactory(ServerSocketFactory):
- """
- javax.net.ssl.SSLServerSocketFactory
- Factory for creating SSL server sockets.
- """
-
- _default = None
-
- @classmethod
- def getDefault(cls) -> "SSLServerSocketFactory":
- if cls._default is None:
- cls._default = SSLServerSocketFactory()
- return cls._default
-
- def getDefaultCipherSuites(self) -> List[str]:
- try:
- ctx = _ssl.create_default_context(_ssl.Purpose.CLIENT_AUTH)
- return ctx.get_ciphers()
- except Exception:
- return []
-
- def getSupportedCipherSuites(self) -> List[str]:
- try:
- ctx = _ssl.create_default_context(_ssl.Purpose.CLIENT_AUTH)
- return ctx.get_ciphers()
- except Exception:
- return []
-
- def createServerSocket(self, port: int = 0, backlog: int = 50,
- ifAddress: Any = None) -> "SSLServerSocket":
- sock = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- sock.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1)
- context = _ssl.create_default_context(_ssl.Purpose.CLIENT_AUTH)
- ssl_sock = context.wrap_socket(sock, server_side=True)
- ssl_ss = SSLServerSocket()
- ssl_ss._socket = ssl_sock
- if ifAddress:
- ssl_ss._socket.bind((ifAddress, port))
- else:
- ssl_ss._socket.bind(('0.0.0.0', port))
- ssl_ss._socket.listen(backlog)
- return ssl_ss
-
- def toString(self) -> str:
- return f"SSLServerSocketFactory@{hex(id(self))}"
-
-
-# ============================================================
-# SSLSocketFactory
-# ============================================================
-
-class SSLSocketFactory(SocketFactory):
- """
- javax.net.ssl.SSLSocketFactory
- Factory for creating SSL sockets.
- """
-
- _default = None
-
- @classmethod
- def getDefault(cls) -> "SSLSocketFactory":
- if cls._default is None:
- cls._default = SSLSocketFactory()
- return cls._default
-
- def getDefaultCipherSuites(self) -> List[str]:
- try:
- ctx = _ssl.create_default_context()
- return [c['name'] for c in ctx.get_ciphers()]
- except Exception:
- return []
-
- def getSupportedCipherSuites(self) -> List[str]:
- try:
- ctx = _ssl.create_default_context()
- return [c['name'] for c in ctx.get_ciphers()]
- except Exception:
- return []
-
- def createSocket(self, host: str = None, port: int = None,
- host_inet: Any = None, local_port: int = None,
- stream: bool = True) -> "SSLSocket":
- sock = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
- context = _ssl.create_default_context()
- ssl_sock_impl = context.wrap_socket(sock, server_hostname=host)
- if host and port is not None:
- ssl_sock_impl.connect((host, port))
- ss = SSLSocket()
- ss._socket = ssl_sock_impl
- ss._connected = True
- return ss
-
- def toString(self) -> str:
- return f"SSLSocketFactory@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# SSLServerSocket
-# ============================================================
-
-class SSLServerSocket(Stub):
- """
- javax.net.ssl.SSLServerSocket
- A server socket that supports SSL/TLS.
- """
-
- def __init__(self):
- super().__init__()
- self._socket = None
- self._enabled_cipher_suites = []
- self._enabled_protocols = []
- self._need_client_auth = False
- self._use_client_mode = False
- self._want_client_auth = False
- self._enable_session_creation = True
-
- def getEnabledCipherSuites(self) -> List[str]:
- return self._enabled_cipher_suites
-
- def setEnabledCipherSuites(self, suites: List[str]):
- self._enabled_cipher_suites = suites
-
- def getSupportedCipherSuites(self) -> List[str]:
- return ["TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256",
- "TLS_AES_128_GCM_SHA256", "ECDHE-RSA-AES256-GCM-SHA384"]
-
- def setEnabledProtocols(self, protocols: List[str]):
- self._enabled_protocols = protocols
-
- def getEnabledProtocols(self) -> List[str]:
- return self._enabled_protocols or ["TLSv1.3", "TLSv1.2"]
-
- def getSupportedProtocols(self) -> List[str]:
- return ["TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"]
-
- def getNeedClientAuth(self) -> bool:
- return self._need_client_auth
-
- def setNeedClientAuth(self, need: bool):
- self._need_client_auth = need
-
- def getUseClientMode(self) -> bool:
- return self._use_client_mode
-
- def setUseClientMode(self, mode: bool):
- self._use_client_mode = mode
-
- def getWantClientAuth(self) -> bool:
- return self._want_client_auth
-
- def setWantClientAuth(self, want: bool):
- self._want_client_auth = want
-
- def getEnableSessionCreation(self) -> bool:
- return self._enable_session_creation
-
- def setEnableSessionCreation(self, flag: bool):
- self._enable_session_creation = flag
-
- def accept(self) -> "SSLSocket":
- if self._socket:
- conn, addr = self._socket.accept()
- ss = SSLSocket()
- ss._socket = conn
- ss._connected = True
- ss._remote_address = addr
- return ss
- return SSLSocket()
-
- def close(self):
- if self._socket:
- self._socket.close()
-
- def toString(self) -> str:
- return f"SSLServerSocket@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# SSLSocket
-# ============================================================
-
-class SSLSocket(Stub):
- """
- javax.net.ssl.SSLSocket
- A socket that supports SSL/TLS.
- """
-
- def __init__(self):
- super().__init__()
- self._socket = None
- self._connected = False
- self._remote_address = None
- self._enabled_cipher_suites = []
- self._enabled_protocols = []
- self._need_client_auth = False
- self._use_client_mode = False
- self._want_client_auth = False
- self._enable_session_creation = True
- self._handshake_listeners = []
- self._session = None
-
- def getEnabledCipherSuites(self) -> List[str]:
- return self._enabled_cipher_suites or ["TLS_AES_256_GCM_SHA384"]
-
- def setEnabledCipherSuites(self, suites: List[str]):
- self._enabled_cipher_suites = suites
-
- def getSupportedCipherSuites(self) -> List[str]:
- return ["TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256",
- "TLS_AES_128_GCM_SHA256", "ECDHE-RSA-AES256-GCM-SHA384"]
-
- def setEnabledProtocols(self, protocols: List[str]):
- self._enabled_protocols = protocols
-
- def getEnabledProtocols(self) -> List[str]:
- return self._enabled_protocols or ["TLSv1.3", "TLSv1.2"]
-
- def getSupportedProtocols(self) -> List[str]:
- return ["TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"]
-
- def getNeedClientAuth(self) -> bool:
- return self._need_client_auth
-
- def setNeedClientAuth(self, need: bool):
- self._need_client_auth = need
-
- def getUseClientMode(self) -> bool:
- return self._use_client_mode
-
- def setUseClientMode(self, mode: bool):
- self._use_client_mode = mode
-
- def getWantClientAuth(self) -> bool:
- return self._want_client_auth
-
- def setWantClientAuth(self, want: bool):
- self._want_client_auth = want
-
- def getEnableSessionCreation(self) -> bool:
- return self._enable_session_creation
-
- def setEnableSessionCreation(self, flag: bool):
- self._enable_session_creation = flag
-
- def getSession(self):
- """Returns the SSL session."""
- return self._session
-
- def startHandshake(self):
- """Starts or re-starts the SSL handshake."""
- if self._socket and hasattr(self._socket, 'do_handshake'):
- try:
- self._socket.do_handshake()
- self._session = {"cipher": "TLS_AES_256_GCM_SHA384",
- "protocol": "TLSv1.3"}
- for listener in self._handshake_listeners:
- listener.handshakeCompleted(
- HandshakeCompletedEvent(self, self._session))
- except Exception:
- pass
-
- def addHandshakeCompletedListener(self, listener: "HandshakeCompletedListener"):
- self._handshake_listeners.append(listener)
-
- def removeHandshakeCompletedListener(self, listener: "HandshakeCompletedListener"):
- if listener in self._handshake_listeners:
- self._handshake_listeners.remove(listener)
-
- def getHandshakeApplicationProtocol(self) -> str:
- return "http/1.1"
-
- def getApplicationProtocol(self) -> str:
- return "http/1.1"
-
- def getHandshakeSession(self):
- return self._session
-
- def setHandshakeApplicationProtocolSelector(self, selector):
- pass
-
- def getHandshakeApplicationProtocolSelector(self):
- return None
-
- def close(self):
- if self._socket:
- self._socket.close()
- self._connected = False
-
- def toString(self) -> str:
- return f"SSLSocket@{hex(id(self))}[connected={self._connected}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HandshakeCompletedEvent
-# ============================================================
-
-class HandshakeCompletedEvent(Stub):
- """
- javax.net.ssl.HandshakeCompletedEvent
- An event indicating that an SSL handshake completed.
- """
-
- def __init__(self, sock: SSLSocket = None, session: Any = None):
- super().__init__()
- self._socket = sock
- self._session = session
-
- def getSession(self):
- return self._session
-
- def getCipherSuite(self) -> str:
- if self._session and isinstance(self._session, dict):
- return self._session.get("cipher", "UNKNOWN")
- return "UNKNOWN"
-
- def getLocalCertificates(self) -> List:
- return []
-
- def getPeerCertificates(self) -> List:
- return []
-
- def getPeerPrincipal(self):
- return None
-
- def getLocalPrincipal(self):
- return None
-
- def getSocket(self) -> SSLSocket:
- return self._socket
-
- def toString(self) -> str:
- return f"HandshakeCompletedEvent@{hex(id(self))}[cipher={self.getCipherSuite()}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HandshakeCompletedListener
-# ============================================================
-
-class HandshakeCompletedListener(Stub):
- """
- javax.net.ssl.HandshakeCompletedListener
- A listener for SSL handshake completion events.
- """
- def handshakeCompleted(self, event: HandshakeCompletedEvent):
- raise NotImplementedError
-
-
-# ============================================================
-# HostnameVerifier
-# ============================================================
-
-class HostnameVerifier(Stub):
- """
- javax.net.ssl.HostnameVerizer
- A hostname verifier for HTTPS connections.
- """
- def verify(self, hostname: str, session: Any) -> bool:
- return True
-
- def toString(self) -> str:
- return f"HostnameVerifier@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HttpsURLConnection
-# ============================================================
-
-class HttpsURLConnection(Stub):
- """
- javax.net.ssl.HttpsURLConnection
- An HTTP URL connection with SSL/TLS support.
- """
- _default_hostname_verifier = HostnameVerifier()
- _default_sslsocket_factory = SSLSocketFactory()
-
- def __init__(self):
- super().__init__()
- self._hostname_verifier = None
- self._ssl_socket_factory = None
-
- @classmethod
- def getDefaultHostnameVerifier(cls) -> HostnameVerifier:
- return cls._default_hostname_verifier
-
- @classmethod
- def setDefaultHostnameVerifier(cls, verifier: HostnameVerifier):
- cls._default_hostname_verifier = verifier
-
- @classmethod
- def getDefaultSSLSocketFactory(cls) -> SSLSocketFactory:
- return cls._default_sslsocket_factory
-
- @classmethod
- def setDefaultSSLSocketFactory(cls, factory: SSLSocketFactory):
- cls._default_sslsocket_factory = factory
-
- def getHostnameVerifier(self) -> HostnameVerifier:
- return self._hostname_verifier or self._default_hostname_verifier
-
- def setHostnameVerifier(self, verifier: HostnameVerifier):
- self._hostname_verifier = verifier
-
- def getSSLSocketFactory(self) -> SSLSocketFactory:
- return self._ssl_socket_factory or self._default_sslsocket_factory
-
- def setSSLSocketFactory(self, factory: SSLSocketFactory):
- self._ssl_socket_factory = factory
-
- def toString(self) -> str:
- return f"HttpsURLConnection@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# TrustManager
-# ============================================================
-
-class TrustManager(Stub):
- """
- javax.net.ssl.TrustManager
- Base interface for trust managers.
- """
- pass
-
-
-# ============================================================
-# X509TrustManager
-# ============================================================
-
-class X509TrustManager(TrustManager):
- """
- javax.net.ssl.X509TrustManager
- Trust manager for X.509 certificates.
- """
- def checkClientTrusted(self, chain: List, auth_type: str):
- """Checks if a client certificate is trusted."""
- pass
-
- def checkServerTrusted(self, chain: List, auth_type: str):
- """Checks if a server certificate is trusted."""
- pass
-
- def getAcceptedIssuers(self) -> List:
- """Returns the list of accepted issuer certificates."""
- return []
-
- def toString(self) -> str:
- return f"X509TrustManager@{hex(id(self))}"
-
-
-# ============================================================
-# KeyManager
-# ============================================================
-
-class KeyManager(Stub):
- """
- javax.net.ssl.KeyManager
- Base interface for key managers.
- """
- pass
-
-
-# ============================================================
-# X509KeyManager
-# ============================================================
-
-class X509KeyManager(KeyManager):
- """
- javax.net.ssl.X509KeyManager
- Key manager for X.509 keys.
- """
- def getClientAliases(self, key_type: str, issuers: List) -> List[str]:
- return []
-
- def chooseClientAlias(self, key_types: List, issuers: List, sockets: List) -> str:
- return None
-
- def getServerAliases(self, key_type: str, issuers: List) -> List[str]:
- return []
-
- def chooseServerAlias(self, key_type: str, issuers: List, sockets: List) -> str:
- return None
-
- def getCertificateChain(self, alias: str) -> List:
- return []
-
- def getPrivateKey(self, alias: str):
- return None
-
- def toString(self) -> str:
- return f"X509KeyManager@{hex(id(self))}"
-
-
-# ============================================================
-# TrustManagerFactory
-# ============================================================
-
-class TrustManagerFactory(Stub):
- """
- javax.net.ssl.TrustManagerFactory
- Factory for TrustManager instances.
- """
-
- def __init__(self, algorithm: str = None):
- super().__init__()
- self._algorithm = algorithm or "PKIX"
- self._trust_managers = []
-
- @staticmethod
- def getInstance(algorithm: str) -> "TrustManagerFactory":
- return TrustManagerFactory(algorithm)
-
- @staticmethod
- def getDefaultAlgorithm() -> str:
- return "PKIX"
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def init(self, ks: Any = None):
- """Initializes this factory with a key store."""
- self._trust_managers = [X509TrustManager()]
-
- def getTrustManagers(self) -> List[TrustManager]:
- return list(self._trust_managers)
-
- def toString(self) -> str:
- return f"TrustManagerFactory@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# KeyManagerFactory
-# ============================================================
-
-class KeyManagerFactory(Stub):
- """
- javax.net.ssl.KeyManagerFactory
- Factory for KeyManager instances.
- """
-
- def __init__(self, algorithm: str = None):
- super().__init__()
- self._algorithm = algorithm or "PKIX"
- self._key_managers = []
-
- @staticmethod
- def getInstance(algorithm: str) -> "KeyManagerFactory":
- return KeyManagerFactory(algorithm)
-
- @staticmethod
- def getDefaultAlgorithm() -> str:
- return "PKIX"
-
- def getAlgorithm(self) -> str:
- return self._algorithm
-
- def init(self, ks: Any = None, password: Any = None):
- """Initializes this factory with a key store."""
- self._key_managers = [X509KeyManager()]
-
- def getKeyManagers(self) -> List[KeyManager]:
- return list(self._key_managers)
-
- def toString(self) -> str:
- return f"KeyManagerFactory@{hex(id(self))}[algorithm={self._algorithm}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# SSLContext
-# ============================================================
-
-class SSLContext(Stub):
- """
- javax.net.ssl.SSLContext
- An implementation of a secure socket protocol.
- """
-
- _default = None
-
- def __init__(self, protocol: str = "TLS"):
- super().__init__()
- self._protocol = protocol
- self._provider = None
- self._ssl_context = None
-
- @staticmethod
- def getInstance(protocol: str) -> "SSLContext":
- ctx = SSLContext(protocol)
- try:
- ctx._ssl_context = _ssl.create_default_context()
- except Exception:
- pass
- return ctx
-
- def init(self, km: List[KeyManager] = None, tm: List[TrustManager] = None,
- random: Any = None):
- """Initializes this context with key managers, trust managers, and randomness."""
- pass
-
- def getSocketFactory(self) -> SSLSocketFactory:
- return SSLSocketFactory()
-
- def getServerSocketFactory(self) -> SSLServerSocketFactory:
- return SSLServerSocketFactory()
-
- def createSSLEngine(self, host: str = None, port: int = None):
- """Creates a new SSLEngine (stub)."""
- return None
-
- def getProtocol(self) -> str:
- return self._protocol
-
- def getProvider(self):
- return self._provider
-
- @staticmethod
- def getDefault() -> "SSLContext":
- if SSLContext._default is None:
- SSLContext._default = SSLContext("TLS")
- return SSLContext._default
-
- @staticmethod
- def setDefault(ctx: "SSLContext"):
- SSLContext._default = ctx
-
- def toString(self) -> str:
- return f"SSLContext@{hex(id(self))}[protocol={self._protocol}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/javax/security.py b/android_pyapi/javax/security.py
deleted file mode 100644
index a916f42..0000000
--- a/android_pyapi/javax/security.py
+++ /dev/null
@@ -1,768 +0,0 @@
-"""
-Java javax.security APIs implemented in Python.
-javax.security package - Subject, Principal, Policy, Permission, etc.
-Desktop stub implementation.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-from typing import List, Set, Optional
-
-__all__ = [
- "AuthProvider", "Subject", "Principal", "Policy",
- "PrivateCredentialPermission", "SubjectDomainCombiner",
- "Refreshable", "Destroyable",
- "RefreshFailedException", "DestroyFailedException",
- "CredentialException", "CredentialExpiredException",
- "CredentialNotFoundException", "UnrecoverableKeyException",
- "UnrecoverableEntryException", "KeyStoreCallbackHandler",
- "DomainLoadStoreParameter",
- "Certificate", "CodeSource", "ProtectionDomain",
- "Permissions", "AllPermission", "BasicPermission",
- "Permission", "PermissionCollection", "UnresolvedPermission",
- "PermissionsEnumerator", "Guard", "GuardedObject",
-]
-
-
-# ============================================================
-# Principal
-# ============================================================
-
-class Principal(Stub):
- """
- java.security.Principal
- Represents a principal (entity) such as a user or group.
- """
-
- def __init__(self, name: str = ""):
- super().__init__()
- self._name = name
-
- def getName(self) -> str:
- return self._name
-
- def implies(self, subject: "Subject") -> bool:
- return False
-
- def toString(self) -> str:
- return self._name
-
- def equals(self, other) -> bool:
- if isinstance(other, Principal):
- return self._name == other._name
- return False
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
-
-# ============================================================
-# Subject
-# ============================================================
-
-class Subject(Stub):
- """
- javax.security.auth.Subject
- Represents a grouping of related information for a single entity.
- """
-
- def __init__(self, read_only: bool = False,
- principals: Set[Principal] = None,
- pub_creds: Set = None,
- priv_creds: Set = None):
- super().__init__()
- self._read_only = read_only
- self._principals = set(principals) if principals else set()
- self._public_credentials = set(pub_creds) if pub_creds else set()
- self._private_credentials = set(priv_creds) if priv_creds else set()
-
- def getPrincipals(self) -> Set[Principal]:
- return set(self._principals)
-
- def getPrivateCredentials(self) -> Set:
- return set(self._private_credentials)
-
- def getPublicCredentials(self) -> Set:
- return set(self._public_credentials)
-
- def setReadOnly(self):
- self._read_only = True
-
- def isReadOnly(self) -> bool:
- return self._read_only
-
- @staticmethod
- def doAs(subject: "Subject", action: callable) -> Any:
- return action()
-
- @staticmethod
- def doAsPrivileged(subject: "Subject", action: callable, access: Any) -> Any:
- return action()
-
- def toString(self) -> str:
- return (f"Subject@{hex(id(self))}[principals={len(self._principals)}, "
- f"read_only={self._read_only}]")
-
- def equals(self, other) -> bool:
- if not isinstance(other, Subject):
- return False
- return (self._principals == other._principals and
- self._read_only == other._read_only)
-
- def hashCode(self) -> int:
- return hash(frozenset(self._principals)) & 0x7FFFFFFF
-
-
-# ============================================================
-# Policy
-# ============================================================
-
-class Policy(Stub):
- """
- java.security.Policy
- Policy for permissions (stub).
- """
- _policy = None
-
- def __init__(self):
- super().__init__()
- self._parameters = None
-
- @staticmethod
- def getPolicy() -> "Policy":
- if Policy._policy is None:
- Policy._policy = Policy()
- return Policy._policy
-
- @staticmethod
- def setPolicy(policy: "Policy"):
- Policy._policy = policy
-
- def getParameters(self):
- return self._parameters
-
- def setParameters(self, params):
- self._parameters = params
-
- def implies(self, domain: "ProtectionDomain", permission: "Permission") -> bool:
- return True
-
- def toString(self) -> str:
- return f"Policy@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# AuthProvider
-# ============================================================
-
-class AuthProvider(Stub):
- """
- javax.security.auth.AuthProvider
- Provider for authentication services.
- """
- def __init__(self):
- super().__init__()
-
- def login(self, subject: Subject, handler: Any):
- pass
-
- def logout(self, subject: Subject):
- pass
-
- def setCallbackHandler(self, handler: Any):
- pass
-
- def toString(self) -> str:
- return f"AuthProvider@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# PrivateCredentialPermission
-# ============================================================
-
-class PrivateCredentialPermission(Stub):
- """
- javax.security.auth.PrivateCredentialPermission
- Permission to access private credentials.
- """
- def __init__(self, name: str = "", actions: str = "read"):
- super().__init__()
- self._name = name
- self._actions = actions
-
- def getName(self) -> str:
- return self._name
-
- def getActions(self) -> str:
- return self._actions
-
- def getCredentialClass(self) -> str:
- return self._name
-
- def getPrincipals(self) -> List[List]:
- return []
-
- def implies(self, permission: "Permission") -> bool:
- return isinstance(permission, PrivateCredentialPermission) and self._name == permission._name
-
- def toString(self) -> str:
- return f'PrivateCredentialPermission "{self._name}" "{self._actions}"'
-
- def equals(self, other) -> bool:
- if isinstance(other, PrivateCredentialPermission):
- return self._name == other._name and self._actions == other._actions
- return False
-
- def hashCode(self) -> int:
- return hash((self._name, self._actions)) & 0x7FFFFFFF
-
-
-# ============================================================
-# SubjectDomainCombiner
-# ============================================================
-
-class SubjectDomainCombiner(Stub):
- """
- javax.security.auth.SubjectDomainCombiner
- Combines ProtectionDomains with Subject context.
- """
- def __init__(self, subject: Subject):
- super().__init__()
- self._subject = subject
-
- def combine(self, current_domains: List, assigned_domains: List) -> List:
- return list(current_domains or []) + list(assigned_domains or [])
-
- def getSubject(self) -> Subject:
- return self._subject
-
- def toString(self) -> str:
- return f"SubjectDomainCombiner@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Refreshable / Destroyable interfaces
-# ============================================================
-
-class Refreshable(Stub):
- """
- javax.security.auth.Refreshable
- Interface for refreshable credentials.
- """
- def isCurrent(self) -> bool:
- return True
-
- def refresh(self):
- raise AndroidOnlyError("refresh not supported on desktop")
-
-
-class Destroyable(Stub):
- """
- javax.security.auth.Destroyable
- Interface for destroyable credentials.
- """
- def isDestroyed(self) -> bool:
- return False
-
- def destroy(self):
- pass
-
-
-# ============================================================
-# Exceptions
-# ============================================================
-
-class RefreshFailedException(Exception, Stub):
- def __init__(self, message: str = None):
- super().__init__(message or "Refresh failed")
- self._message = message
- def toString(self) -> str:
- return f"RefreshFailedException: {self._message}"
- def equals(self, other) -> bool:
- return isinstance(other, RefreshFailedException) and self._message == other._message
- def hashCode(self) -> int:
- return hash(self._message) & 0x7FFFFFFF
-
-
-class DestroyFailedException(Exception, Stub):
- def __init__(self, message: str = None):
- super().__init__(message or "Destroy failed")
- self._message = message
- def toString(self) -> str:
- return f"DestroyFailedException: {self._message}"
- def equals(self, other) -> bool:
- return isinstance(other, DestroyFailedException) and self._message == other._message
- def hashCode(self) -> int:
- return hash(self._message) & 0x7FFFFFFF
-
-
-class CredentialException(Exception, Stub):
- def __init__(self, message: str = None):
- super().__init__(message or "Credential error")
- self._message = message
- def toString(self) -> str:
- return f"CredentialException: {self._message}"
-
-
-class CredentialExpiredException(CredentialException):
- def __init__(self, message: str = None):
- super().__init__(message or "Credential expired")
-
-
-class CredentialNotFoundException(CredentialException):
- def __init__(self, message: str = None):
- super().__init__(message or "Credential not found")
-
-
-class UnrecoverableKeyException(Exception, Stub):
- def __init__(self, message: str = None):
- super().__init__(message or "Unrecoverable key")
- self._message = message
- def toString(self) -> str:
- return f"UnrecoverableKeyException: {self._message}"
-
-
-class UnrecoverableEntryException(Exception, Stub):
- def __init__(self, message: str = None):
- super().__init__(message or "Unrecoverable entry")
- self._message = message
- def toString(self) -> str:
- return f"UnrecoverableEntryException: {self._message}"
-
-
-# ============================================================
-# KeyStoreCallbackHandler
-# ============================================================
-
-class KeyStoreCallbackHandler(Stub):
- """
- javax.security.auth.callback.KeyStoreCallbackHandler
- Handler for key store callbacks.
- """
- def __init__(self):
- super().__init__()
-
- def handle(self, callbacks: List):
- pass
-
- def toString(self) -> str:
- return f"KeyStoreCallbackHandler@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DomainLoadStoreParameter
-# ============================================================
-
-class DomainLoadStoreParameter(Stub):
- """
- java.security.DomainLoadStoreParameter
- Configuration data for loading/storing keystore domains.
- """
- def __init__(self, config: dict = None):
- super().__init__()
- self._config = config or {}
-
- def getConfiguration(self) -> dict:
- return self._config
-
- def toString(self) -> str:
- return f"DomainLoadStoreParameter@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Certificate
-# ============================================================
-
-class Certificate(Stub):
- """
- java.security.cert.Certificate
- Abstract class for managing certificates.
- """
- def __init__(self, cert_type: str = "X.509", encoded: bytes = None):
- super().__init__()
- self._cert_type = cert_type
- self._encoded = encoded or b''
-
- def getType(self) -> str:
- return self._cert_type
-
- def getEncoded(self) -> bytes:
- return self._encoded
-
- def getPublicKey(self):
- return None
-
- def toString(self) -> str:
- return f"Certificate@{hex(id(self))}[type={self._cert_type}]"
-
- def equals(self, other) -> bool:
- if isinstance(other, Certificate):
- return self._encoded == other._encoded
- return False
-
- def hashCode(self) -> int:
- return hash(bytes(self._encoded)) & 0x7FFFFFFF
-
-
-# ============================================================
-# Permission & PermissionCollection
-# ============================================================
-
-class Permission(Stub):
- """
- java.security.Permission
- Abstract class for representing access to a system resource.
- """
- def __init__(self, name: str = ""):
- super().__init__()
- self._name = name
-
- def getName(self) -> str:
- return self._name
-
- def getActions(self) -> str:
- return ""
-
- def implies(self, permission: "Permission") -> bool:
- return self.equals(permission)
-
- def toString(self) -> str:
- return f'Permission "{self._name}"'
-
- def equals(self, other) -> bool:
- if isinstance(other, Permission):
- return self._name == other._name
- return False
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
-
-class PermissionCollection(Stub):
- """
- java.security.PermissionCollection
- Abstract class for holding a collection of Permission objects.
- """
- def __init__(self):
- super().__init__()
- self._permissions = []
- self._read_only = False
-
- def add(self, permission: Permission):
- if not self._read_only:
- self._permissions.append(permission)
-
- def implies(self, permission: Permission) -> bool:
- for p in self._permissions:
- if p.implies(permission):
- return True
- return False
-
- def elements(self):
- return iter(self._permissions)
-
- def isReadOnly(self) -> bool:
- return self._read_only
-
- def setReadOnly(self):
- self._read_only = True
-
- def toString(self) -> str:
- return f"PermissionCollection@{hex(id(self))}[size={len(self._permissions)}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class Permissions(PermissionCollection):
- """
- java.security.Permissions
- A collection of Permission objects.
- """
- def add(self, permission: Permission):
- super().add(permission)
-
- def implies(self, permission: Permission) -> bool:
- return super().implies(permission)
-
- def elements(self):
- return super().elements()
-
- def toString(self) -> str:
- return f"Permissions@{hex(id(self))}[size={len(self._permissions)}]"
-
-
-class AllPermission(Permission):
- """
- java.security.AllPermission
- A permission that implies all other permissions.
- """
- def __init__(self):
- super().__init__("")
-
- def implies(self, permission: Permission) -> bool:
- return True
-
- def getActions(self) -> str:
- return ""
-
- def toString(self) -> str:
- return "AllPermission"
-
-
-class BasicPermission(Permission):
- """
- java.security.BasicPermission
- Base class for basic permissions.
- """
- def __init__(self, name: str = "", actions: str = ""):
- super().__init__(name)
- self._actions = actions
-
- def implies(self, permission: Permission) -> bool:
- if isinstance(permission, BasicPermission):
- return self._name == permission._name or permission._name.startswith(self._name + ".")
- return False
-
- def getActions(self) -> str:
- return self._actions
-
- def toString(self) -> str:
- return f'BasicPermission "{self._name}"'
-
- def equals(self, other) -> bool:
- if isinstance(other, BasicPermission):
- return self._name == other._name
- return False
-
- def hashCode(self) -> int:
- return hash(self._name) & 0x7FFFFFFF
-
-
-class UnresolvedPermission(Permission):
- """
- java.security.UnresolvedPermission
- A permission that was not resolved when the PermissionCollection was built.
- """
- def __init__(self, perm_type: str = "", name: str = "", actions: str = "",
- certs: List = None):
- super().__init__(name)
- self._unresolved_type = perm_type
- self._unresolved_actions = actions
- self._unresolved_certs = certs or []
-
- def getUnresolvedType(self) -> str:
- return self._unresolved_type
-
- def getUnresolvedName(self) -> str:
- return self._name
-
- def getUnresolvedActions(self) -> str:
- return self._unresolved_actions
-
- def getUnresolvedCerts(self) -> List:
- return list(self._unresolved_certs)
-
- def implies(self, permission: Permission) -> bool:
- return False
-
- def toString(self) -> str:
- return f'UnresolvedPermission "{self._unresolved_type}" "{self._name}" "{self._unresolved_actions}"'
-
- def equals(self, other) -> bool:
- if isinstance(other, UnresolvedPermission):
- return (self._unresolved_type == other._unresolved_type and
- self._name == other._name)
- return False
-
- def hashCode(self) -> int:
- return hash((self._unresolved_type, self._name)) & 0x7FFFFFFF
-
-
-class PermissionsEnumerator(Stub):
- """
- java.security.PermissionsEnumerator
- Enumerator over Permission objects.
- """
- def __init__(self, permissions: List):
- super().__init__()
- self._permissions = list(permissions)
- self._index = 0
-
- def hasMoreElements(self) -> bool:
- return self._index < len(self._permissions)
-
- def nextElement(self) -> Permission:
- if self._index < len(self._permissions):
- p = self._permissions[self._index]
- self._index += 1
- return p
- return None
-
- def toString(self) -> str:
- return f"PermissionsEnumerator@{hex(id(self))}"
-
-
-# ============================================================
-# CodeSource
-# ============================================================
-
-class CodeSource(Stub):
- """
- java.security.CodeSource
- Represents the codebase and certificates from which code originated.
- """
- def __init__(self, location: str = None, certs: List = None,
- code_signers: List = None):
- super().__init__()
- self._location = location
- self._certificates = certs or []
- self._code_signers = code_signers or []
-
- def getCertificates(self) -> List:
- return list(self._certificates)
-
- def getCodeSigners(self) -> List:
- return list(self._code_signers)
-
- def getLocation(self) -> str:
- return self._location
-
- def implies(self, codesource: "CodeSource") -> bool:
- return self._location == codesource._location
-
- def toString(self) -> str:
- return f"CodeSource@{hex(id(self))}[location={self._location}]"
-
- def equals(self, other) -> bool:
- if isinstance(other, CodeSource):
- return self._location == other._location
- return False
-
- def hashCode(self) -> int:
- return hash(self._location) & 0x7FFFFFFF
-
-
-# ============================================================
-# ProtectionDomain
-# ============================================================
-
-class ProtectionDomain(Stub):
- """
- java.security.ProtectionDomain
- Groups a CodeSource and Permissions for code access control.
- """
- def __init__(self, codesource: CodeSource = None,
- permissions: PermissionCollection = None,
- principals: List[Principal] = None,
- static_permissions: bool = False):
- super().__init__()
- self._codesource = codesource
- self._permissions = permissions or Permissions()
- self._principals = principals or []
- self._static_permissions = static_permissions
-
- def getCodeSource(self) -> CodeSource:
- return self._codesource
-
- def getPermissions(self) -> PermissionCollection:
- return self._permissions
-
- def getPrincipals(self) -> List[Principal]:
- return list(self._principals)
-
- def implies(self, permission: Permission) -> bool:
- return self._permissions.implies(permission) if self._permissions else False
-
- def toString(self) -> str:
- return f"ProtectionDomain@{hex(id(self))}[codesource={self._codesource}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Guard & GuardedObject
-# ============================================================
-
-class Guard(Stub):
- """
- java.security.Guard
- Interface for objects that guard access to another object.
- """
- def checkGuard(self, obj: Any):
- raise NotImplementedError
-
- def toString(self) -> str:
- return f"Guard@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class GuardedObject(Stub):
- """
- java.security.GuardedObject
- Wraps an object and guards access to it with a Guard.
- """
- def __init__(self, obj: Any = None, guard: Guard = None):
- super().__init__()
- self._object = obj
- self._guard = guard
-
- def getObject(self) -> Any:
- if self._guard:
- self._guard.checkGuard(self._object)
- return self._object
-
- def setGuard(self, guard: Guard):
- self._guard = guard
-
- def toString(self) -> str:
- return f"GuardedObject@{hex(id(self))}[guarded={self._guard is not None}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/javax/sql.py b/android_pyapi/javax/sql.py
deleted file mode 100644
index e1a3f02..0000000
--- a/android_pyapi/javax/sql.py
+++ /dev/null
@@ -1,1248 +0,0 @@
-"""
-Java javax.sql APIs implemented in Python.
-javax.sql package - DataSource, RowSet, RowSetListener, ConnectionEvent, etc.
-Desktop implementation wrapping Python sqlite3 module.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-import sqlite3 as _sqlite3
-from typing import List, Optional, Any
-
-__all__ = [
- "DataSource", "RowSet", "RowSetListener", "RowSetMetaData",
- "CachedRowSet", "WebRowSet", "FilteredRowSet", "JoinRowSet",
- "Predicate", "SyncProvider", "SyncFactory",
- "RowSetWriter", "RowSetReader",
- "ConnectionEvent", "ConnectionEventListener",
- "PooledConnection", "StatementEvent", "StatementEventListener",
- "XADataSource", "XAConnection", "XAResource",
-]
-
-
-# ============================================================
-# DataSource
-# ============================================================
-
-class DataSource(Stub):
- """
- javax.sql.DataSource
- A factory for connections to a physical data source.
- Wraps Python sqlite3.
- """
-
- def __init__(self, db_path: str = ":memory:"):
- super().__init__()
- self._db_path = db_path
- self._log_writer = None
- self._login_timeout = 0
- self._connection = None
-
- def getConnection(self, username: str = None, password: str = None) -> Any:
- """Gets a connection to the data source."""
- self._connection = _sqlite3.connect(self._db_path)
- return self._connection
-
- def getLogWriter(self):
- return self._log_writer
-
- def setLogWriter(self, writer):
- self._log_writer = writer
-
- def getLoginTimeout(self) -> int:
- return self._login_timeout
-
- def setLoginTimeout(self, seconds: int):
- self._login_timeout = seconds
-
- def getParentLogger(self):
- return None
-
- def createConnectionBuilder(self):
- return None
-
- def createPooledConnectionBuilder(self):
- return None
-
- def unwrap(self, iface: type) -> Any:
- return self
-
- def isWrapperFor(self, iface: type) -> bool:
- return iface == DataSource
-
- def toString(self) -> str:
- return f"DataSource@{hex(id(self))}[db={self._db_path}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# RowSetListener
-# ============================================================
-
-class RowSetListener(Stub):
- """
- javax.sql.RowSetListener
- Listener for RowSet events.
- """
- def cursorMoved(self, event: Any):
- pass
-
- def rowChanged(self, event: Any):
- pass
-
- def rowSetChanged(self, event: Any):
- pass
-
- def toString(self) -> str:
- return f"RowSetListener@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# RowSet
-# ============================================================
-
-class RowSet(Stub):
- """
- javax.sql.RowSet
- A row set interface that wraps a result set.
- """
-
- def __init__(self):
- super().__init__()
- self._url = ""
- self._data_source_name = ""
- self._username = ""
- self._password = ""
- self._command = ""
- self._query_timeout = 0
- self._max_rows = 0
- self._max_field_size = 0
- self._escape_processing = True
- self._fetch_direction = 1000 # FETCH_FORWARD
- self._fetch_size = 0
- self._type = 1003 # TYPE_FORWARD_ONLY
- self._concurrency = 1007 # CONCUR_READ_ONLY
- self._show_deleted = False
- self._read_only = True
- self._table_name = ""
- self._transaction_isolation = 0
- self._type_map = None
- self._key_columns = []
- self._match_column = ""
- self._filter = None
- self._cursor = None
- self._listeners = []
- self._params = []
- self._rows = []
- self._current_row = -1
-
- def setUrl(self, url: str):
- self._url = url
-
- def getUrl(self) -> str:
- return self._url
-
- def setDataSourceName(self, name: str):
- self._data_source_name = name
-
- def getDataSourceName(self) -> str:
- return self._data_source_name
-
- def setUsername(self, name: str):
- self._username = name
-
- def getUsername(self) -> str:
- return self._username
-
- def setPassword(self, pwd: str):
- self._password = pwd
-
- def getPassword(self) -> str:
- return self._password
-
- def setCommand(self, cmd: str):
- self._command = cmd
-
- def getCommand(self) -> str:
- return self._command
-
- def setQueryTimeout(self, seconds: int):
- self._query_timeout = seconds
-
- def getQueryTimeout(self) -> int:
- return self._query_timeout
-
- def setMaxRows(self, max_rows: int):
- self._max_rows = max_rows
-
- def getMaxRows(self) -> int:
- return self._max_rows
-
- def setMaxFieldSize(self, max_size: int):
- self._max_field_size = max_size
-
- def getMaxFieldSize(self) -> int:
- return self._max_field_size
-
- def setEscapeProcessing(self, enable: bool):
- self._escape_processing = enable
-
- def getEscapeProcessing(self) -> bool:
- return self._escape_processing
-
- def setFetchDirection(self, direction: int):
- self._fetch_direction = direction
-
- def getFetchDirection(self) -> int:
- return self._fetch_direction
-
- def setFetchSize(self, size: int):
- self._fetch_size = size
-
- def getFetchSize(self) -> int:
- return self._fetch_size
-
- def setType(self, rowset_type: int):
- self._type = rowset_type
-
- def getType(self) -> int:
- return self._type
-
- def setConcurrency(self, concurrency: int):
- self._concurrency = concurrency
-
- def getConcurrency(self) -> int:
- return self._concurrency
-
- def execute(self):
- """Executes the command and populates the row set."""
- self._rows = []
- self._current_row = -1
- for listener in self._listeners:
- listener.rowSetChanged(self)
-
- def rowSetListeners(self) -> List[RowSetListener]:
- return list(self._listeners)
-
- def addRowSetListener(self, listener: RowSetListener):
- self._listeners.append(listener)
-
- def removeRowSetListener(self, listener: RowSetListener):
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def setShowDeleted(self, show: bool):
- self._show_deleted = show
-
- def isShowDeleted(self) -> bool:
- return self._show_deleted
-
- def setReadOnly(self, read_only: bool):
- self._read_only = read_only
-
- def isReadOnly(self) -> bool:
- return self._read_only
-
- def setTableName(self, name: str):
- self._table_name = name
-
- def getTableName(self) -> str:
- return self._table_name
-
- def setTransactionIsolation(self, level: int):
- self._transaction_isolation = level
-
- def getTransactionIsolation(self) -> int:
- return self._transaction_isolation
-
- def setTypeMap(self, type_map: Any):
- self._type_map = type_map
-
- def getTypeMap(self):
- return self._type_map
-
- def setKeyColumns(self, columns: List[int]):
- self._key_columns = columns
-
- def getKeyColumns(self) -> List[int]:
- return list(self._key_columns)
-
- def setMatchColumn(self, column: Any):
- self._match_column = str(column)
-
- def getMatchColumn(self) -> Any:
- return self._match_column
-
- def setFilter(self, f: Any):
- self._filter = f
-
- def getFilter(self):
- return self._filter
-
- def setCursor(self, cursor: Any):
- self._cursor = cursor
-
- def getCursor(self):
- return self._cursor
-
- def clearParameters(self):
- self._params = []
-
- def validate(self) -> bool:
- return True
-
- def getParams(self) -> List:
- return list(self._params)
-
- def toString(self) -> str:
- return f"RowSet@{hex(id(self))}[command={self._command}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# RowSetMetaData
-# ============================================================
-
-class RowSetMetaData(Stub):
- """
- javax.sql.RowSetMetaData
- Metadata for a RowSet.
- """
-
- def __init__(self):
- super().__init__()
- self._column_count = 0
- self._auto_increment = {}
- self._case_sensitive = {}
- self._searchable = {}
- self._currency = {}
- self._nullable = {}
- self._signed = {}
- self._display_size = {}
- self._labels = {}
- self._column_names = {}
- self._schema_names = {}
- self._precision = {}
- self._scale = {}
- self._table_names = {}
- self._catalog_names = {}
- self._column_types = {}
- self._column_type_names = {}
- self._column_class_names = {}
-
- def setColumnCount(self, count: int):
- self._column_count = count
-
- def getColumnCount(self) -> int:
- return self._column_count
-
- def setAutoIncrement(self, column: int, value: bool):
- self._auto_increment[column] = value
-
- def isAutoIncrement(self, column: int) -> bool:
- return self._auto_increment.get(column, False)
-
- def setCaseSensitive(self, column: int, value: bool):
- self._case_sensitive[column] = value
-
- def isCaseSensitive(self, column: int) -> bool:
- return self._case_sensitive.get(column, False)
-
- def setSearchable(self, column: int, value: bool):
- self._searchable[column] = value
-
- def isSearchable(self, column: int) -> bool:
- return self._searchable.get(column, True)
-
- def setCurrency(self, column: int, value: bool):
- self._currency[column] = value
-
- def isCurrency(self, column: int) -> bool:
- return self._currency.get(column, False)
-
- def setNullable(self, column: int, value: int):
- self._nullable[column] = value
-
- def isNullable(self, column: int) -> int:
- return self._nullable.get(column, 1)
-
- def setSigned(self, column: int, value: bool):
- self._signed[column] = value
-
- def isSigned(self, column: int) -> bool:
- return self._signed.get(column, False)
-
- def setDisplaySize(self, column: int, size: int):
- self._display_size[column] = size
-
- def getDisplaySize(self, column: int) -> int:
- return self._display_size.get(column, 0)
-
- def setLabel(self, column: int, label: str):
- self._labels[column] = label
-
- def getColumnLabel(self, column: int) -> str:
- return self._labels.get(column, "")
-
- def setColumnName(self, column: int, name: str):
- self._column_names[column] = name
-
- def getColumnName(self, column: int) -> str:
- return self._column_names.get(column, "")
-
- def setSchemaName(self, column: int, name: str):
- self._schema_names[column] = name
-
- def getSchemaName(self, column: int) -> str:
- return self._schema_names.get(column, "")
-
- def setPrecision(self, column: int, precision: int):
- self._precision[column] = precision
-
- def getPrecision(self, column: int) -> int:
- return self._precision.get(column, 0)
-
- def setScale(self, column: int, scale: int):
- self._scale[column] = scale
-
- def getScale(self, column: int) -> int:
- return self._scale.get(column, 0)
-
- def setTableName(self, column: int, name: str):
- self._table_names[column] = name
-
- def getTableName(self, column: int) -> str:
- return self._table_names.get(column, "")
-
- def setCatalogName(self, column: int, name: str):
- self._catalog_names[column] = name
-
- def getCatalogName(self, column: int) -> str:
- return self._catalog_names.get(column, "")
-
- def setColumnType(self, column: int, sql_type: int):
- self._column_types[column] = sql_type
-
- def getColumnType(self, column: int) -> int:
- return self._column_types.get(column, 0)
-
- def setColumnTypeName(self, column: int, name: str):
- self._column_type_names[column] = name
-
- def getColumnTypeName(self, column: int) -> str:
- return self._column_type_names.get(column, "")
-
- def setColumnClassName(self, column: int, name: str):
- self._column_class_names[column] = name
-
- def getColumnClassName(self, column: int) -> str:
- return self._column_class_names.get(column, "")
-
- def toString(self) -> str:
- return f"RowSetMetaData@{hex(id(self))}[columns={self._column_count}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# CachedRowSet
-# ============================================================
-
-class CachedRowSet(RowSet):
- """
- javax.sql.rowset.CachedRowSet
- A row set that caches its data in memory.
- """
-
- def __init__(self):
- super().__init__()
- self._sync_provider = None
- self._page_size = 0
- self._cached_data = []
- self._original_data = []
-
- def execute(self):
- super().execute()
- self._cached_data = list(self._rows)
- self._original_data = list(self._rows)
-
- def populate(self, result_set: Any):
- """Populates the row set from a ResultSet."""
- pass
-
- def acceptChanges(self):
- """Accepts changes to the row set."""
- self._original_data = list(self._cached_data)
-
- def commit(self):
- """Commits changes."""
- pass
-
- def rollback(self, savepoint: Any = None):
- """Rolls back changes."""
- self._cached_data = list(self._original_data)
-
- def setSyncProvider(self, provider: str):
- self._sync_provider = provider
-
- def getSyncProvider(self) -> str:
- return self._sync_provider or "com.sun.rowset.providers.RIOptimisticProvider"
-
- def sync(self) -> bool:
- """Syncs changes to the data source."""
- return True
-
- def size(self) -> int:
- return len(self._cached_data)
-
- def createCopy(self) -> "CachedRowSet":
- copy = CachedRowSet()
- copy._cached_data = list(self._cached_data)
- return copy
-
- def createCopySchema(self) -> "CachedRowSet":
- return CachedRowSet()
-
- def createCopyNoConstraints(self) -> "CachedRowSet":
- return CachedRowSet()
-
- def getOriginal(self):
- """Returns the original value of the current row."""
- return None
-
- def getOriginalRow(self):
- """Returns the original row."""
- return None
-
- def setPageSize(self, size: int):
- self._page_size = size
-
- def getPageSize(self) -> int:
- return self._page_size
-
- def nextPage(self) -> bool:
- return False
-
- def previousPage(self) -> bool:
- return False
-
- def release(self):
- self._cached_data = []
-
- def originalContents(self):
- """Returns the original contents."""
- return self._original_data
-
- def getBookmark(self):
- return None
-
- def setBookmark(self, bookmark):
- pass
-
- def getShowDeleted(self) -> bool:
- return self._show_deleted
-
- def setShowDeleted(self, show: bool):
- self._show_deleted = show
-
- def isBeforeFirst(self) -> bool:
- return self._current_row < 0 and len(self._cached_data) > 0
-
- def isAfterLast(self) -> bool:
- return self._current_row >= len(self._cached_data)
-
- def isFirst(self) -> bool:
- return self._current_row == 0
-
- def isLast(self) -> bool:
- return self._current_row == len(self._cached_data) - 1
-
- def beforeFirst(self):
- self._current_row = -1
-
- def afterLast(self):
- self._current_row = len(self._cached_data)
-
- def first(self) -> bool:
- if self._cached_data:
- self._current_row = 0
- return True
- return False
-
- def last(self) -> bool:
- if self._cached_data:
- self._current_row = len(self._cached_data) - 1
- return True
- return False
-
- def next(self) -> bool:
- if self._current_row < len(self._cached_data) - 1:
- self._current_row += 1
- return True
- self._current_row = len(self._cached_data)
- return False
-
- def previous(self) -> bool:
- if self._current_row > 0:
- self._current_row -= 1
- return True
- return False
-
- def absolute(self, row: int) -> bool:
- if 0 < row <= len(self._cached_data):
- self._current_row = row - 1
- return True
- return False
-
- def relative(self, rows: int) -> bool:
- new_row = self._current_row + rows
- if 0 <= new_row < len(self._cached_data):
- self._current_row = new_row
- return True
- return False
-
- def getRow(self) -> int:
- return self._current_row + 1 if 0 <= self._current_row < len(self._cached_data) else 0
-
- def setMetaData(self, md: RowSetMetaData):
- pass
-
- def getMetaData(self):
- return None
-
- def findColumn(self, column_name: str) -> int:
- return 1
-
- # Data retrieval methods (stub)
- def getObject(self, column: int) -> Any:
- if 0 <= self._current_row < len(self._cached_data):
- row = self._cached_data[self._current_row]
- if isinstance(row, (list, tuple)) and column <= len(row):
- return row[column - 1]
- return None
-
- def getString(self, column: int) -> str:
- return str(self.getObject(column) or "")
-
- def getInt(self, column: int) -> int:
- val = self.getObject(column)
- return int(val) if val else 0
-
- def getLong(self, column: int) -> int:
- return self.getInt(column)
-
- def getFloat(self, column: int) -> float:
- val = self.getObject(column)
- return float(val) if val else 0.0
-
- def getDouble(self, column: int) -> float:
- return self.getFloat(column)
-
- def getShort(self, column: int) -> int:
- return self.getInt(column)
-
- def getByte(self, column: int) -> int:
- return self.getInt(column) & 0xFF
-
- def getBytes(self, column: int) -> bytes:
- val = self.getObject(column)
- if isinstance(val, bytes):
- return val
- return b''
-
- def getBoolean(self, column: int) -> bool:
- val = self.getObject(column)
- return bool(val) if val else False
-
- def getDate(self, column: int):
- return self.getObject(column)
-
- def getTime(self, column: int):
- return self.getObject(column)
-
- def getTimestamp(self, column: int):
- return self.getObject(column)
-
- def getBigDecimal(self, column: int):
- return self.getObject(column)
-
- def getAsciiStream(self, column: int):
- return None
-
- def getUnicodeStream(self, column: int):
- return None
-
- def getBinaryStream(self, column: int):
- return None
-
- def getCharacterStream(self, column: int):
- return None
-
- def getClob(self, column: int):
- return None
-
- def getBlob(self, column: int):
- return None
-
- def getArray(self, column: int):
- return None
-
- def getRef(self, column: int):
- return None
-
- def getRowId(self, column: int):
- return None
-
- def getNClob(self, column: int):
- return None
-
- def getNString(self, column: int) -> str:
- return self.getString(column)
-
- def getNCharacterStream(self, column: int):
- return None
-
- def getSQLXML(self, column: int):
- return None
-
- def wasNull(self) -> bool:
- return False
-
- # Update methods (stub)
- def updateNull(self, column: int):
- pass
- def updateBoolean(self, column: int, value: bool): pass
- def updateByte(self, column: int, value: int): pass
- def updateShort(self, column: int, value: int): pass
- def updateInt(self, column: int, value: int): pass
- def updateLong(self, column: int, value: int): pass
- def updateFloat(self, column: int, value: float): pass
- def updateDouble(self, column: int, value: float): pass
- def updateBigDecimal(self, column: int, value): pass
- def updateString(self, column: int, value: str): pass
- def updateBytes(self, column: int, value: bytes): pass
- def updateDate(self, column: int, value): pass
- def updateTime(self, column: int, value): pass
- def updateTimestamp(self, column: int, value): pass
- def updateAsciiStream(self, column: int, stream, length: int = None): pass
- def updateBinaryStream(self, column: int, stream, length: int = None): pass
- def updateCharacterStream(self, column: int, stream, length: int = None): pass
- def updateObject(self, column: int, value, scale_or_target: Any = None): pass
- def updateNull(self, column: int, type_name: str = None): pass
- def updateRow(self): pass
- def deleteRow(self): pass
- def insertRow(self): pass
- def cancelRowUpdates(self): pass
- def moveToInsertRow(self): pass
- def moveToCurrentRow(self): pass
- def rowUpdated(self) -> bool: return False
- def rowInserted(self) -> bool: return False
- def rowDeleted(self) -> bool: return False
- def close(self): pass
- def clearWarnings(self): pass
- def getWarnings(self): return None
-
- # Parameter setters (stub)
- def setURL(self, col: int, url: str): pass
- def setAsciiStream(self, col: int, stream, length: int = None): pass
- def setBigDecimal(self, col: int, value): pass
- def setBinaryStream(self, col: int, stream, length: int = None): pass
- def setBlob(self, col: int, blob, length: int = None): pass
- def setBoolean(self, col: int, value: bool): pass
- def setByte(self, col: int, value: int): pass
- def setBytes(self, col: int, value: bytes): pass
- def setCharacterStream(self, col: int, stream, length: int = None): pass
- def setClob(self, col: int, clob, length: int = None): pass
- def setDate(self, col: int, value): pass
- def setDouble(self, col: int, value: float): pass
- def setFloat(self, col: int, value: float): pass
- def setInt(self, col: int, value: int): pass
- def setLong(self, col: int, value: int): pass
- def setNCharacterStream(self, col: int, stream, length: int = None): pass
- def setNClob(self, col: int, value, length: int = None): pass
- def setNString(self, col: int, value: str): pass
- def setNull(self, col: int, sql_type: int, type_name: str = None): pass
- def setObject(self, col: int, value, target_type: Any = None, scale: int = None): pass
- def setRef(self, col: int, ref): pass
- def setRowId(self, col: int, row_id): pass
- def setShort(self, col: int, value: int): pass
- def setSQLXML(self, col: int, xml): pass
- def setString(self, col: int, value: str): pass
- def setTime(self, col: int, value): pass
- def setTimestamp(self, col: int, value): pass
- def setUnicodeStream(self, col: int, stream, length: int): pass
-
- def toString(self) -> str:
- return f"CachedRowSet@{hex(id(self))}[size={self.size()}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class WebRowSet(CachedRowSet):
- """javax.sql.rowset.WebRowSet - Web-oriented row set."""
- pass
-
-class FilteredRowSet(CachedRowSet):
- """javax.sql.rowset.FilteredRowSet - Filtered row set."""
- pass
-
-class JoinRowSet(CachedRowSet):
- """javax.sql.rowset.JoinRowSet - Join row set."""
- pass
-
-
-# ============================================================
-# Predicate
-# ============================================================
-
-class Predicate(Stub):
- """
- javax.sql.rowset.Predicate
- A filter for row set contents.
- """
- def evaluate(self, row_set: CachedRowSet) -> bool:
- return True
-
- def evaluate(self, value: Any, column: int) -> bool:
- return True
-
- def evaluates(self, value: Any, column_name: str) -> bool:
- return True
-
- def toString(self) -> str:
- return f"Predicate@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# SyncProvider
-# ============================================================
-
-class SyncProvider(Stub):
- """
- javax.sql.rowset.spi.SyncProvider
- Service provider for synchronization.
- """
- GRADE_NONE: int = 1
- GRADE_LOCK_WHEN_MODIFIED: int = 2
- GRADE_LOCK_MODIFIED_WHEN_GRANTED: int = 3
- GRADE_CHECK_MODIFIED_AT_COMMIT: int = 4
- GRADE_CHECK_ALL_AT_COMMIT: int = 5
- DATASOURCE_NO_LOCK: int = 1
- DATASOURCE_LOCK: int = 2
- DATASOURCE_ROW_LOCK: int = 3
-
- def getProviderID(self) -> str:
- return "com.sun.rowset.providers.RIOptimisticProvider"
-
- def getProviderGrade(self) -> int:
- return self.GRADE_CHECK_MODIFIED_AT_COMMIT
-
- def setProviderGrade(self, grade: int):
- pass
-
- def getDataSourceLock(self) -> int:
- return self.DATASOURCE_NO_LOCK
-
- def setDataSourceLock(self, lock: int):
- pass
-
- def getRowSetWriter(self):
- return None
-
- def getRowSetReader(self):
- return None
-
- def supportsUpdatableView(self) -> bool:
- return True
-
- def toString(self) -> str:
- return f"SyncProvider@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# SyncFactory
-# ============================================================
-
-class SyncFactory(Stub):
- """
- javax.sql.rowset.spi.SyncFactory
- Factory for SyncProvider instances.
- """
- PROVIDER: str = "rowset.provider"
- ROWSET_SYNC_PROVIDER: str = "rowset.syncProvider"
- ROWSET_SYNC_VENDOR: str = "rowset.syncVendor"
- ROWSET_SYNC_PROVIDER_GRADE: str = "rowset.syncProviderGrade"
- DATASOURCE_LOCK: str = "rowset.datasourceLock"
-
- _instance = None
- _logger = None
-
- @classmethod
- def getInstance(cls) -> "SyncFactory":
- if cls._instance is None:
- cls._instance = SyncFactory()
- return cls._instance
-
- def getSyncProvider(self, provider_id: str = None) -> SyncProvider:
- return SyncProvider()
-
- def registerSyncProvider(self, provider_id: str):
- pass
-
- def setJNDIContext(self, ctx):
- pass
-
- def getJNDIContext(self):
- return None
-
- def unregisterSyncProvider(self, provider_id: str):
- pass
-
- def syncProviderRegistered(self, provider_id: str) -> bool:
- return True
-
- def syncProviderAdded(self, provider_id: str) -> bool:
- return True
-
- def syncProviderRemoved(self, provider_id: str) -> bool:
- return True
-
- @classmethod
- def setLogger(cls, logger):
- cls._logger = logger
-
- @classmethod
- def getLogger(cls):
- return cls._logger
-
- def toString(self) -> str:
- return f"SyncFactory@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# RowSetWriter / RowSetReader
-# ============================================================
-
-class RowSetWriter(Stub):
- """
- javax.sql.RowSetWriter
- Writes the contents of a RowSet to the data source.
- """
- def writeData(self, caller: CachedRowSet) -> bool:
- return True
-
- def toString(self) -> str:
- return f"RowSetWriter@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class RowSetReader(Stub):
- """
- javax.sql.RowSetReader
- Reads the contents of a RowSet from the data source.
- """
- def readData(self, caller: CachedRowSet):
- pass
-
- def toString(self) -> str:
- return f"RowSetReader@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# ConnectionEvent / ConnectionEventListener
-# ============================================================
-
-class ConnectionEvent(Stub):
- """
- javax.sql.ConnectionEvent
- An event that provides information about connection events.
- """
- def __init__(self, conn, exception: Exception = None):
- super().__init__()
- self._connection = conn
- self._exception = exception
-
- def getSQLException(self):
- return self._exception
-
- def toString(self) -> str:
- return f"ConnectionEvent@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class ConnectionEventListener(Stub):
- """
- javax.sql.ConnectionEventListener
- Listener for connection events on a PooledConnection.
- """
- def connectionClosed(self, event: ConnectionEvent):
- pass
-
- def connectionErrorOccurred(self, event: ConnectionEvent):
- pass
-
- def toString(self) -> str:
- return f"ConnectionEventListener@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# PooledConnection
-# ============================================================
-
-class PooledConnection(Stub):
- """
- javax.sql.PooledConnection
- A connection pool management interface.
- """
- def __init__(self, db_path: str = ":memory:"):
- super().__init__()
- self._db_path = db_path
- self._connection = None
- self._listeners = []
- self._statement_pool_size = 0
-
- def getConnection(self) -> Any:
- self._connection = _sqlite3.connect(self._db_path)
- return self._connection
-
- def close(self):
- if self._connection:
- self._connection.close()
- event = ConnectionEvent(self)
- for listener in self._listeners:
- listener.connectionClosed(event)
-
- def addConnectionEventListener(self, listener: ConnectionEventListener):
- self._listeners.append(listener)
-
- def removeConnectionEventListener(self, listener: ConnectionEventListener):
- if listener in self._listeners:
- self._listeners.remove(listener)
-
- def setStatementPoolingCacheSize(self, size: int):
- self._statement_pool_size = size
-
- def getStatementPoolingCacheSize(self) -> int:
- return self._statement_pool_size
-
- def setConnectionEventListener(self, listener: ConnectionEventListener):
- self.addConnectionEventListener(listener)
-
- def setStatementEventListener(self, listener):
- pass
-
- def removeStatementEventListener(self, listener):
- pass
-
- def addStatementEventListener(self, listener):
- pass
-
- def removeStatementEventListener(self, listener):
- pass
-
- def toString(self) -> str:
- return f"PooledConnection@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# StatementEvent / StatementEventListener
-# ============================================================
-
-class StatementEvent(Stub):
- """
- javax.sql.StatementEvent
- An event for statement-related events.
- """
- def __init__(self, conn, statement: Any = None, exception: Exception = None):
- super().__init__()
- self._connection = conn
- self._statement = statement
- self._exception = exception
-
- def getStatement(self):
- return self._statement
-
- def getSQLException(self):
- return self._exception
-
- def toString(self) -> str:
- return f"StatementEvent@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class StatementEventListener(Stub):
- """
- javax.sql.StatementEventListener
- Listener for statement pool events.
- """
- def statementClosed(self, event: StatementEvent):
- pass
-
- def statementErrorOccurred(self, event: StatementEvent):
- pass
-
- def toString(self) -> str:
- return f"StatementEventListener@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# XA stubs
-# ============================================================
-
-class XADataSource(Stub):
- """
- javax.sql.XADataSource
- Factory for XAConnection objects.
- """
- def getXAConnection(self, user: str = None, password: str = None) -> "XAConnection":
- return XAConnection()
-
- def toString(self) -> str:
- return f"XADataSource@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class XAConnection(PooledConnection):
- """
- javax.sql.XAConnection
- Connection for distributed transactions (stub).
- """
- def __init__(self):
- super().__init__()
-
- def getXAResource(self) -> "XAResource":
- return XAResource()
-
- def toString(self) -> str:
- return f"XAConnection@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class XAResource(Stub):
- """
- javax.transaction.xa.XAResource
- Resource manager for distributed transactions (stub).
- """
- TMENDRSCAN: int = 8388608
- TMFAIL: int = 536870912
- TMJOIN: int = 2097152
- TMNOFLAGS: int = 0
- TMONEPHASE: int = 1073741824
- TMRESUME: int = 134217728
- TMSTARTRSCAN: int = 16777216
- TMSUCCESS: int = 67108864
- TMSUSPEND: int = 33554432
- XA_RDONLY: int = 3
- XA_OK: int = 0
-
- def start(self, xid: Any, flags: int): pass
- def end(self, xid: Any, flags: int): pass
- def prepare(self, xid: Any) -> int: return XA_OK
- def commit(self, xid: Any, one_phase: bool): pass
- def rollback(self, xid: Any): pass
- def recover(self, flag: int) -> List: return []
- def forget(self, xid: Any): pass
- def getTransactionTimeout(self) -> int: return 0
- def setTransactionTimeout(self, timeout: int) -> bool: return True
- def isSameRM(self, xares: "XAResource") -> bool: return self is xares
-
- def toString(self) -> str:
- return f"XAResource@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/org/__init__.py b/android_pyapi/org/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/android_pyapi/org/apache/__init__.py b/android_pyapi/org/apache/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/android_pyapi/org/apache/http.py b/android_pyapi/org/apache/http.py
deleted file mode 100644
index 68f4a0f..0000000
--- a/android_pyapi/org/apache/http.py
+++ /dev/null
@@ -1,1109 +0,0 @@
-"""
-Apache HTTP (legacy Android) APIs implemented in Python.
-org.apache.http package - HttpEntity, HttpResponse, HttpClient, DefaultHttpClient, etc.
-Desktop implementation wrapping Python requests module.
-"""
-
-from __future__ import annotations
-
-from ..._core import Stub, AndroidOnlyError
-from typing import List, Optional, Any
-
-# Optional requests dependency
-try:
- import requests as _requests
- HAS_REQUESTS = True
-except ImportError:
- HAS_REQUESTS = False
-
-__all__ = [
- "HttpEntity", "HttpResponse", "HttpGet", "HttpPost", "HttpPut",
- "HttpDelete", "HttpHead", "HttpOptions", "HttpTrace", "HttpPatch",
- "HttpRequest", "HttpRequestInterceptor", "HttpResponseInterceptor",
- "HttpContext", "HttpClient", "DefaultHttpClient",
- "BasicHttpContext", "BasicHttpResponse",
- "HttpVersion", "StatusLine", "Header", "BasicHeader",
- "HeaderElement", "NameValuePair", "BasicNameValuePair",
- "HttpResponseException", "HttpHost",
- "HttpConnection", "HttpConnectionParams",
- "HttpEntityEnclosingRequest", "RequestLine", "HttpParams",
-]
-
-
-# ============================================================
-# HttpVersion
-# ============================================================
-
-class HttpVersion(Stub):
- """
- org.apache.http.HttpVersion
- Represents an HTTP version.
- """
- HTTP: "HttpVersion" = None
- HTTP_0_9: "HttpVersion" = None
- HTTP_1_0: "HttpVersion" = None
- HTTP_1_1: "HttpVersion" = None
-
- def __init__(self, major: int = 1, minor: int = 1):
- super().__init__()
- self._major = major
- self._minor = minor
- self._protocol = "HTTP"
-
- def getProtocol(self) -> str:
- return self._protocol
-
- def getMajor(self) -> int:
- return self._major
-
- def getMinor(self) -> int:
- return self._minor
-
- def toString(self) -> str:
- return f"HTTP/{self._major}.{self._minor}"
-
- def equals(self, other) -> bool:
- if isinstance(other, HttpVersion):
- return self._major == other._major and self._minor == other._minor
- return False
-
- def hashCode(self) -> int:
- return hash((self._major, self._minor)) & 0x7FFFFFFF
-
-
-HttpVersion.HTTP = HttpVersion(1, 1)
-HttpVersion.HTTP_0_9 = HttpVersion(0, 9)
-HttpVersion.HTTP_1_0 = HttpVersion(1, 0)
-HttpVersion.HTTP_1_1 = HttpVersion(1, 1)
-
-
-# ============================================================
-# StatusLine
-# ============================================================
-
-class StatusLine(Stub):
- """
- org.apache.http.StatusLine
- Represents an HTTP status line.
- """
- def __init__(self, version: HttpVersion = None, status_code: int = 200,
- reason_phrase: str = "OK"):
- super().__init__()
- self._version = version or HttpVersion.HTTP_1_1
- self._status_code = status_code
- self._reason_phrase = reason_phrase
-
- def getProtocolVersion(self) -> HttpVersion:
- return self._version
-
- def getStatusCode(self) -> int:
- return self._status_code
-
- def getReasonPhrase(self) -> str:
- return self._reason_phrase
-
- def toString(self) -> str:
- return f"HTTP/{self._version._major}.{self._version._minor} {self._status_code} {self._reason_phrase}"
-
- def equals(self, other) -> bool:
- if isinstance(other, StatusLine):
- return (self._status_code == other._status_code and
- self._reason_phrase == other._reason_phrase)
- return False
-
- def hashCode(self) -> int:
- return hash(self._status_code) & 0x7FFFFFFF
-
-
-# ============================================================
-# Header
-# ============================================================
-
-class Header(Stub):
- """
- org.apache.http.Header
- Represents an HTTP header.
- """
- def __init__(self, name: str = "", value: str = ""):
- super().__init__()
- self._name = name
- self._value = value
-
- def getName(self) -> str:
- return self._name
-
- def getValue(self) -> str:
- return self._value
-
- def getElements(self) -> List["HeaderElement"]:
- elements = []
- for part in self._value.split(","):
- part = part.strip()
- if part:
- elements.append(HeaderElement(part))
- return elements
-
- def toString(self) -> str:
- return f"{self._name}: {self._value}"
-
- def equals(self, other) -> bool:
- if isinstance(other, Header):
- return self._name == other._name and self._value == other._value
- return False
-
- def hashCode(self) -> int:
- return hash((self._name, self._value)) & 0x7FFFFFFF
-
-
-class BasicHeader(Header):
- """
- org.apache.http.message.BasicHeader
- A basic implementation of an HTTP header.
- """
- def __init__(self, name: str = "", value: str = ""):
- super().__init__(name, value)
-
- def clone(self) -> "BasicHeader":
- return BasicHeader(self._name, self._value)
-
- def toString(self) -> str:
- return super().toString()
-
- def equals(self, other) -> bool:
- return isinstance(other, BasicHeader) and super().equals(other)
-
- def hashCode(self) -> int:
- return super().hashCode()
-
-
-# ============================================================
-# HeaderElement
-# ============================================================
-
-class HeaderElement(Stub):
- """
- org.apache.http.HeaderElement
- Represents an element of an HTTP header.
- """
- def __init__(self, value: str = ""):
- super().__init__()
- self._name = value.split("=")[0] if "=" in value else value
- self._value = value.split("=", 1)[1] if "=" in value else None
- self._parameters = []
-
- def getName(self) -> str:
- return self._name
-
- def getValue(self) -> Optional[str]:
- return self._value
-
- def getParameterCount(self) -> int:
- return len(self._parameters)
-
- def getParameters(self) -> List["NameValuePair"]:
- return list(self._parameters)
-
- def getParameterByName(self, name: str) -> Optional["NameValuePair"]:
- for p in self._parameters:
- if p.getName() == name:
- return p
- return None
-
- def getParameter(self, index: int) -> Optional["NameValuePair"]:
- if 0 <= index < len(self._parameters):
- return self._parameters[index]
- return None
-
- def toString(self) -> str:
- return self._name
-
- def equals(self, other) -> bool:
- if isinstance(other, HeaderElement):
- return self._name == other._name and self._value == other._value
- return False
-
- def hashCode(self) -> int:
- return hash((self._name, self._value)) & 0x7FFFFFFF
-
-
-# ============================================================
-# NameValuePair
-# ============================================================
-
-class NameValuePair(Stub):
- """
- org.apache.http.NameValuePair
- Represents a name-value pair.
- """
- def __init__(self, name: str = "", value: str = ""):
- super().__init__()
- self._name = name
- self._value = value
-
- def getName(self) -> str:
- return self._name
-
- def getValue(self) -> str:
- return self._value
-
- def toString(self) -> str:
- return f"{self._name}={self._value}"
-
- def equals(self, other) -> bool:
- if isinstance(other, NameValuePair):
- return self._name == other._name and self._value == other._value
- return False
-
- def hashCode(self) -> int:
- return hash((self._name, self._value)) & 0x7FFFFFFF
-
-
-class BasicNameValuePair(NameValuePair):
- """
- org.apache.http.message.BasicNameValuePair
- A basic implementation of a name-value pair.
- """
- def __init__(self, name: str = "", value: str = ""):
- super().__init__(name, value)
-
- def clone(self) -> "BasicNameValuePair":
- return BasicNameValuePair(self._name, self._value)
-
- def toString(self) -> str:
- return super().toString()
-
- def equals(self, other) -> bool:
- return isinstance(other, BasicNameValuePair) and super().equals(other)
-
- def hashCode(self) -> int:
- return super().hashCode()
-
-
-# ============================================================
-# HttpHost
-# ============================================================
-
-class HttpHost(Stub):
- """
- org.apache.http.HttpHost
- Represents an HTTP host.
- """
- def __init__(self, hostname: str = "", port: int = -1, scheme: str = "http"):
- super().__init__()
- self._hostname = hostname
- self._port = port
- self._scheme = scheme
-
- def getHostName(self) -> str:
- return self._hostname
-
- def getPort(self) -> int:
- return self._port
-
- def getSchemeName(self) -> str:
- return self._scheme
-
- def toURI(self) -> str:
- port_suffix = f":{self._port}" if self._port > 0 else ""
- return f"{self._scheme}://{self._hostname}{port_suffix}"
-
- def toString(self) -> str:
- return self.toURI()
-
- def equals(self, other) -> bool:
- if isinstance(other, HttpHost):
- return (self._hostname == other._hostname and
- self._port == other._port and
- self._scheme == other._scheme)
- return False
-
- def hashCode(self) -> int:
- return hash((self._hostname, self._port, self._scheme)) & 0x7FFFFFFF
-
- def clone(self) -> "HttpHost":
- return HttpHost(self._hostname, self._port, self._scheme)
-
-
-# ============================================================
-# RequestLine
-# ============================================================
-
-class RequestLine(Stub):
- """
- org.apache.http.RequestLine
- Represents an HTTP request line.
- """
- def __init__(self, method: str = "GET", uri: str = "/",
- version: HttpVersion = None):
- super().__init__()
- self._method = method
- self._uri = uri
- self._version = version or HttpVersion.HTTP_1_1
-
- def getMethod(self) -> str:
- return self._method
-
- def getUri(self) -> str:
- return self._uri
-
- def getProtocolVersion(self) -> HttpVersion:
- return self._version
-
- def toString(self) -> str:
- return f"{self._method} {self._uri} {self._version}"
-
- def equals(self, other) -> bool:
- if isinstance(other, RequestLine):
- return (self._method == other._method and
- self._uri == other._uri)
- return False
-
- def hashCode(self) -> int:
- return hash((self._method, self._uri)) & 0x7FFFFFFF
-
-
-# ============================================================
-# HttpParams
-# ============================================================
-
-class HttpParams(Stub):
- """
- org.apache.http.params.HttpParams
- Collection of HTTP parameters.
- """
- def __init__(self):
- super().__init__()
- self._params = {}
-
- def getParameter(self, name: str) -> Any:
- return self._params.get(name)
-
- def setParameter(self, name: str, value: Any) -> "HttpParams":
- self._params[name] = value
- return self
-
- def removeParameter(self, name: str) -> bool:
- return self._params.pop(name, None) is not None
-
- def getNamesParameter(self) -> List[str]:
- return list(self._params.keys())
-
- def setLongParameter(self, name: str, value: int) -> "HttpParams":
- return self.setParameter(name, value)
-
- def getBooleanParameter(self, name: str, default: bool = False) -> bool:
- return bool(self._params.get(name, default))
-
- def setBooleanParameter(self, name: str, value: bool) -> "HttpParams":
- return self.setParameter(name, value)
-
- def getIntParameter(self, name: str, default: int = 0) -> int:
- return int(self._params.get(name, default))
-
- def setIntParameter(self, name: str, value: int) -> "HttpParams":
- return self.setParameter(name, value)
-
- def getLongParameter(self, name: str, default: int = 0) -> int:
- return int(self._params.get(name, default))
-
- def getDoubleParameter(self, name: str, default: float = 0.0) -> float:
- return float(self._params.get(name, default))
-
- def setDoubleParameter(self, name: str, value: float) -> "HttpParams":
- return self.setParameter(name, value)
-
- def getShortParameter(self, name: str, default: int = 0) -> int:
- return int(self._params.get(name, default))
-
- def setShortParameter(self, name: str, value: int) -> "HttpParams":
- return self.setParameter(name, value)
-
- def getByteParameter(self, name: str, default: int = 0) -> int:
- return int(self._params.get(name, default))
-
- def setByteParameter(self, name: str, value: int) -> "HttpParams":
- return self.setParameter(name, value)
-
- def toString(self) -> str:
- return f"HttpParams@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HttpEntity
-# ============================================================
-
-class HttpEntity(Stub):
- """
- org.apache.http.HttpEntity
- Represents an HTTP entity body.
- """
- def __init__(self, content: bytes = b'', content_type: Header = None,
- content_encoding: Header = None, chunked: bool = False):
- super().__init__()
- self._content = content
- self._content_type = content_type
- self._content_encoding = content_encoding
- self._chunked = chunked
- self._streaming = False
-
- def getContent(self) -> bytes:
- return self._content
-
- def getContentLength(self) -> int:
- return len(self._content)
-
- def getContentType(self) -> Optional[Header]:
- return self._content_type
-
- def getContentEncoding(self) -> Optional[Header]:
- return self._content_encoding
-
- def isChunked(self) -> bool:
- return self._chunked
-
- def isStreaming(self) -> bool:
- return self._streaming
-
- def consumeContent(self):
- pass
-
- def writeTo(self, out_stream):
- if hasattr(out_stream, 'write'):
- out_stream.write(self._content)
-
- def toString(self) -> str:
- return f"HttpEntity@{hex(id(self))}[length={len(self._content)}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HttpRequest
-# ============================================================
-
-class HttpRequest(Stub):
- """
- org.apache.http.HttpRequest
- Represents an HTTP request message.
- """
- def __init__(self, method: str = "GET", uri: str = "/"):
- super().__init__()
- self._method = method
- self._uri = uri
- self._headers = []
- self._params = HttpParams()
- self._version = HttpVersion.HTTP_1_1
-
- def getRequestLine(self) -> RequestLine:
- return RequestLine(self._method, self._uri, self._version)
-
- def getMethod(self) -> str:
- return self._method
-
- def getProtocolVersion(self) -> HttpVersion:
- return self._version
-
- def addHeader(self, header: Header):
- self._headers.append(header)
-
- def setHeader(self, header: Header):
- self.removeHeaders(header.getName())
- self._headers.append(header)
-
- def setHeaders(self, headers: List[Header]):
- self._headers = list(headers)
-
- def getAllHeaders(self) -> List[Header]:
- return list(self._headers)
-
- def getHeaders(self, name: str) -> List[Header]:
- return [h for h in self._headers if h.getName().lower() == name.lower()]
-
- def getFirstHeader(self, name: str) -> Optional[Header]:
- for h in self._headers:
- if h.getName().lower() == name.lower():
- return h
- return None
-
- def getLastHeader(self, name: str) -> Optional[Header]:
- result = None
- for h in self._headers:
- if h.getName().lower() == name.lower():
- result = h
- return result
-
- def removeHeader(self, header: Header):
- if header in self._headers:
- self._headers.remove(header)
-
- def removeHeaders(self, name: str):
- self._headers = [h for h in self._headers if h.getName().lower() != name.lower()]
-
- def containsHeader(self, name: str) -> bool:
- return any(h.getName().lower() == name.lower() for h in self._headers)
-
- def headerIterator(self, name: str = None):
- if name:
- return iter(self.getHeaders(name))
- return iter(self._headers)
-
- def getParams(self) -> HttpParams:
- return self._params
-
- def setParams(self, params: HttpParams):
- self._params = params
-
- def getURI(self) -> str:
- return self._uri
-
- def setURI(self, uri: str):
- self._uri = uri
-
- def toString(self) -> str:
- return f"{self._method} {self._uri} HTTP/{self._version._major}.{self._version._minor}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HTTP method classes
-# ============================================================
-
-class HttpGet(HttpRequest):
- """org.apache.http.client.methods.HttpGet"""
- def __init__(self, uri: str = "/"):
- super().__init__("GET", uri)
-
-
-class HttpPost(HttpRequest):
- """org.apache.http.client.methods.HttpPost"""
- def __init__(self, uri: str = "/"):
- super().__init__("POST", uri)
-
-
-class HttpPut(HttpRequest):
- """org.apache.http.client.methods.HttpPut"""
- def __init__(self, uri: str = "/"):
- super().__init__("PUT", uri)
-
-
-class HttpDelete(HttpRequest):
- """org.apache.http.client.methods.HttpDelete"""
- def __init__(self, uri: str = "/"):
- super().__init__("DELETE", uri)
-
-
-class HttpHead(HttpRequest):
- """org.apache.http.client.methods.HttpHead"""
- def __init__(self, uri: str = "/"):
- super().__init__("HEAD", uri)
-
-
-class HttpOptions(HttpRequest):
- """org.apache.http.client.methods.HttpOptions"""
- def __init__(self, uri: str = "/"):
- super().__init__("OPTIONS", uri)
-
-
-class HttpTrace(HttpRequest):
- """org.apache.http.client.methods.HttpTrace"""
- def __init__(self, uri: str = "/"):
- super().__init__("TRACE", uri)
-
-
-class HttpPatch(HttpRequest):
- """org.apache.http.client.methods.HttpPatch"""
- def __init__(self, uri: str = "/"):
- super().__init__("PATCH", uri)
-
-
-# ============================================================
-# HttpEntityEnclosingRequest
-# ============================================================
-
-class HttpEntityEnclosingRequest(HttpRequest):
- """
- org.apache.http.HttpEntityEnclosingRequest
- An HTTP request that can contain an entity.
- """
- def __init__(self, method: str = "POST", uri: str = "/"):
- super().__init__(method, uri)
- self._entity = None
-
- def expectContinue(self) -> bool:
- return self.containsHeader("Expect")
-
- def getEntity(self) -> HttpEntity:
- return self._entity
-
- def setEntity(self, entity: HttpEntity):
- self._entity = entity
-
- def toString(self) -> str:
- return f"{self._method} {self._uri} [entity={self._entity is not None}]"
-
-
-# ============================================================
-# HttpResponse
-# ============================================================
-
-class HttpResponse(Stub):
- """
- org.apache.http.HttpResponse
- Represents an HTTP response message.
- """
- def __init__(self, status_line: StatusLine = None):
- super().__init__()
- self._status_line = status_line or StatusLine()
- self._entity = None
- self._headers = []
- self._params = HttpParams()
- self._locale = "en_US"
- self._protocol_version = HttpVersion.HTTP_1_1
-
- def getStatusLine(self) -> StatusLine:
- return self._status_line
-
- def setStatusLine(self, status_line: StatusLine):
- self._status_line = status_line
-
- def getEntity(self) -> HttpEntity:
- return self._entity
-
- def setEntity(self, entity: HttpEntity):
- self._entity = entity
-
- def getAllHeaders(self) -> List[Header]:
- return list(self._headers)
-
- def getFirstHeader(self, name: str) -> Optional[Header]:
- for h in self._headers:
- if h.getName().lower() == name.lower():
- return h
- return None
-
- def getHeaders(self, name: str) -> List[Header]:
- return [h for h in self._headers if h.getName().lower() == name.lower()]
-
- def getLastHeader(self, name: str) -> Optional[Header]:
- result = None
- for h in self._headers:
- if h.getName().lower() == name.lower():
- result = h
- return result
-
- def setHeaders(self, headers: List[Header]):
- self._headers = list(headers)
-
- def addHeader(self, header: Header):
- self._headers.append(header)
-
- def removeHeader(self, header: Header):
- if header in self._headers:
- self._headers.remove(header)
-
- def containsHeader(self, name: str) -> bool:
- return any(h.getName().lower() == name.lower() for h in self._headers)
-
- def headerIterator(self, name: str = None):
- if name:
- return iter(self.getHeaders(name))
- return iter(self._headers)
-
- def getParams(self) -> HttpParams:
- return self._params
-
- def setParams(self, params: HttpParams):
- self._params = params
-
- def getProtocolVersion(self) -> HttpVersion:
- return self._protocol_version
-
- def getLocale(self) -> str:
- return self._locale
-
- def setLocale(self, locale: str):
- self._locale = locale
-
- def toString(self) -> str:
- return f"HTTP/{self._protocol_version._major}.{self._protocol_version._minor} {self._status_line.getStatusCode()}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# BasicHttpResponse
-# ============================================================
-
-class BasicHttpResponse(HttpResponse):
- """org.apache.http.message.BasicHttpResponse"""
- def __init__(self, status_line: StatusLine = None):
- super().__init__(status_line)
-
- def toString(self) -> str:
- return super().toString()
-
- def equals(self, other) -> bool:
- return isinstance(other, BasicHttpResponse) and super().equals(other)
-
- def hashCode(self) -> int:
- return super().hashCode()
-
-
-# ============================================================
-# HttpRequestInterceptor
-# ============================================================
-
-class HttpRequestInterceptor(Stub):
- """org.apache.http.HttpRequestInterceptor"""
- def process(self, request: HttpRequest, context: "HttpContext"):
- pass
- def toString(self) -> str:
- return f"HttpRequestInterceptor@{hex(id(self))}"
- def equals(self, other) -> bool:
- return self is other
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class HttpResponseInterceptor(Stub):
- """org.apache.http.HttpResponseInterceptor"""
- def process(self, response: HttpResponse, context: "HttpContext"):
- pass
- def toString(self) -> str:
- return f"HttpResponseInterceptor@{hex(id(self))}"
- def equals(self, other) -> bool:
- return self is other
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HttpContext
-# ============================================================
-
-class HttpContext(Stub):
- """
- org.apache.http.protocol.HttpContext
- Represents an execution context for HTTP requests.
- """
- RESERVED_PREFIX: str = "http."
- def __init__(self):
- super().__init__()
- self._attributes = {}
- def getAttribute(self, name: str) -> Any:
- return self._attributes.get(name)
- def setAttribute(self, name: str, value: Any):
- self._attributes[name] = value
- def removeAttribute(self, name: str) -> bool:
- return self._attributes.pop(name, None) is not None
- def toString(self) -> str:
- return f"HttpContext@{hex(id(self))}"
- def equals(self, other) -> bool:
- return self is other
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class BasicHttpContext(HttpContext):
- """org.apache.http.protocol.BasicHttpContext"""
- def __init__(self):
- super().__init__()
- def toString(self) -> str:
- return f"BasicHttpContext@{hex(id(self))}"
- def equals(self, other) -> bool:
- return isinstance(other, BasicHttpContext)
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HttpClient
-# ============================================================
-
-class HttpClient(Stub):
- """
- org.apache.http.client.HttpClient
- Interface for HTTP client implementations.
- Wraps Python requests library.
- """
- def __init__(self):
- super().__init__()
- self._connection_manager = None
- self._params = HttpParams()
-
- def execute(self, target: Any, request: HttpRequest = None,
- context: HttpContext = None, response_handler: Any = None) -> Any:
- """Executes an HTTP request."""
- if isinstance(target, HttpHost):
- host = target
- req = request or HttpGet("/")
- url = f"{host.getSchemeName()}://{host.getHostName()}"
- if host.getPort() > 0:
- url += f":{host.getPort()}"
- url += req.getURI()
- elif isinstance(target, HttpRequest):
- req = target
- url = req.getURI()
- else:
- url = str(target)
- req = request or HttpGet("/")
-
- method = req.getMethod().upper() if hasattr(req, 'getMethod') else "GET"
-
- # Build headers dict
- headers = {}
- for h in req.getAllHeaders():
- headers[h.getName()] = h.getValue()
-
- try:
- if HAS_REQUESTS:
- resp = _requests.request(method, url, headers=headers, timeout=30)
- # Build response
- response = BasicHttpResponse(
- StatusLine(HttpVersion.HTTP_1_1, resp.status_code, resp.reason))
- entity = HttpEntity(resp.content,
- BasicHeader("Content-Type", resp.headers.get("Content-Type", "")))
- response.setEntity(entity)
- for k, v in resp.headers.items():
- response.addHeader(BasicHeader(k, v))
- return response
- except Exception:
- pass
-
- # Fallback: create a stub response
- response = BasicHttpResponse(StatusLine(HttpVersion.HTTP_1_1, 200, "OK"))
- response.setEntity(HttpEntity(b'{}'))
- return response
-
- def getParams(self) -> HttpParams:
- return self._params
-
- def getConnectionManager(self):
- return self._connection_manager
-
-
-# ============================================================
-# DefaultHttpClient
-# ============================================================
-
-class DefaultHttpClient(HttpClient):
- """
- org.apache.http.impl.client.DefaultHttpClient
- Default implementation of HttpClient.
- """
- def __init__(self):
- super().__init__()
- self._credentials_provider = None
- self._cookie_store = None
- self._retry_handler = None
- self._redirect_handler = None
-
- def getCredentialsProvider(self):
- return self._credentials_provider
-
- def setCredentialsProvider(self, provider):
- self._credentials_provider = provider
-
- def getCookieStore(self):
- return self._cookie_store
-
- def setCookieStore(self, store):
- self._cookie_store = store
-
- def getHttpRequestRetryHandler(self):
- return self._retry_handler
-
- def setHttpRequestRetryHandler(self, handler):
- self._retry_handler = handler
-
- def getRedirectHandler(self):
- return self._redirect_handler
-
- def setRedirectHandler(self, handler):
- self._redirect_handler = handler
-
- def toString(self) -> str:
- return f"DefaultHttpClient@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HttpResponseException
-# ============================================================
-
-class HttpResponseException(Exception, Stub):
- """
- org.apache.http.client.HttpResponseException
- Exception for HTTP response errors.
- """
- def __init__(self, status_code: int = 500, reason_phrase: str = "Internal Server Error"):
- super().__init__(f"{status_code}: {reason_phrase}")
- self._status_code = status_code
- self._reason_phrase = reason_phrase
-
- def getStatusCode(self) -> int:
- return self._status_code
-
- def getReasonPhrase(self) -> str:
- return self._reason_phrase
-
- def toString(self) -> str:
- return f"HttpResponseException: {self._status_code} {self._reason_phrase}"
-
- def equals(self, other) -> bool:
- if isinstance(other, HttpResponseException):
- return (self._status_code == other._status_code and
- self._reason_phrase == other._reason_phrase)
- return False
-
- def hashCode(self) -> int:
- return hash((self._status_code, self._reason_phrase)) & 0x7FFFFFFF
-
-
-# ============================================================
-# HttpConnection
-# ============================================================
-
-class HttpConnection(Stub):
- """
- org.apache.http.HttpConnection
- Represents an HTTP connection.
- """
- def __init__(self):
- super().__init__()
- self._open = True
- self._socket_timeout = 0
- self._local_address = None
- self._local_port = 0
- self._remote_address = None
- self._remote_port = 0
-
- def isOpen(self) -> bool:
- return self._open
-
- def isStale(self) -> bool:
- return not self._open
-
- def setSocketTimeout(self, timeout: int):
- self._socket_timeout = timeout
-
- def getSocketTimeout(self) -> int:
- return self._socket_timeout
-
- def close(self):
- self._open = False
-
- def shutdown(self):
- self._open = False
-
- def getLocalAddress(self):
- return self._local_address
-
- def getLocalPort(self) -> int:
- return self._local_port
-
- def getRemoteAddress(self):
- return self._remote_address
-
- def getRemotePort(self) -> int:
- return self._remote_port
-
- def toString(self) -> str:
- return f"HttpConnection@{hex(id(self))}[open={self._open}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HttpConnectionParams
-# ============================================================
-
-class HttpConnectionParams(Stub):
- """
- org.apache.http.params.HttpConnectionParams
- Parameters for HTTP connections.
- """
- @staticmethod
- def setConnectionTimeout(params: HttpParams, timeout: int):
- params.setIntParameter("http.connection.timeout", timeout)
-
- @staticmethod
- def getConnectionTimeout(params: HttpParams) -> int:
- return params.getIntParameter("http.connection.timeout", 0)
-
- @staticmethod
- def setSoTimeout(params: HttpParams, timeout: int):
- params.setIntParameter("http.socket.timeout", timeout)
-
- @staticmethod
- def getSoTimeout(params: HttpParams) -> int:
- return params.getIntParameter("http.socket.timeout", 0)
-
- @staticmethod
- def setLinger(params: HttpParams, linger: int):
- params.setIntParameter("http.socket.linger", linger)
-
- @staticmethod
- def getLinger(params: HttpParams) -> int:
- return params.getIntParameter("http.socket.linger", 0)
-
- @staticmethod
- def setTcpNoDelay(params: HttpParams, value: bool):
- params.setBooleanParameter("http.tcp.nodelay", value)
-
- @staticmethod
- def getTcpNoDelay(params: HttpParams) -> bool:
- return params.getBooleanParameter("http.tcp.nodelay", True)
-
- @staticmethod
- def setSocketBufferSize(params: HttpParams, size: int):
- params.setIntParameter("http.socket.buffer-size", size)
-
- @staticmethod
- def getSocketBufferSize(params: HttpParams) -> int:
- return params.getIntParameter("http.socket.buffer-size", 8192)
-
- @staticmethod
- def setStaleCheckingEnabled(params: HttpParams, value: bool):
- params.setBooleanParameter("http.connection.stalecheck", value)
-
- @staticmethod
- def isStaleCheckingEnabled(params: HttpParams) -> bool:
- return params.getBooleanParameter("http.connection.stalecheck", True)
-
- def toString(self) -> str:
- return "HttpConnectionParams"
-
- def equals(self, other) -> bool:
- return isinstance(other, HttpConnectionParams)
-
- def hashCode(self) -> int:
- return hash("HttpConnectionParams") & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/org/json.py b/android_pyapi/org/json.py
deleted file mode 100644
index 2838e4e..0000000
--- a/android_pyapi/org/json.py
+++ /dev/null
@@ -1,910 +0,0 @@
-"""
-Java JSON standard library APIs implemented in Python.
-org.json package - JSONObject, JSONArray, JSONTokener, JSONStringer, JSONWriter, etc.
-"""
-
-from .._core import Stub
-import json as _json
-
-__all__ = [
- "JSONObject", "JSONArray", "JSONTokener",
- "JSONStringer", "JSONWriter", "JSONException", "JSONPointer",
- "JSONPointerBuilder",
-]
-
-
-# ============================================================
-# JSONException
-# ============================================================
-
-class JSONException(Exception):
- def __init__(self, *args):
- if len(args) == 1 and isinstance(args[0], Exception):
- super().__init__(str(args[0]))
- self._cause = args[0]
- else:
- super().__init__(*args)
- self._cause = None
-
- def getCause(self):
- return self._cause
-
-
-# ============================================================
-# JSONObject.NULL
-# ============================================================
-
-class _JSONNull(Stub):
- def __init__(self):
- super().__init__()
-
- def equals(self, other):
- return other is None or isinstance(other, _JSONNull)
-
- def hashCode(self):
- return 0
-
- def toString(self):
- return "null"
-
-
-# ============================================================
-# JSONObject
-# ============================================================
-
-class JSONObject(Stub):
- NULL = _JSONNull()
-
- def __init__(self, *args):
- super().__init__()
- self._map = {}
- if len(args) == 1:
- arg = args[0]
- if isinstance(arg, str):
- tokener = JSONTokener(arg)
- obj = tokener.nextValue()
- if isinstance(obj, JSONObject):
- self._map = obj._map
- else:
- raise JSONException("String is not a JSONObject")
- elif isinstance(arg, dict):
- for k, v in arg.items():
- self._map[str(k)] = JSONObject._wrap(v)
- elif isinstance(arg, JSONObject):
- names = None
- self._map = dict(arg._map)
-
- def _wrap(val):
- if val is None:
- return JSONObject.NULL
- if isinstance(val, (bool, int, float)):
- return val
- if isinstance(val, str):
- return val
- if isinstance(val, (list, tuple)):
- arr = JSONArray()
- for item in val:
- arr.put(JSONObject._wrap(item))
- return arr
- if isinstance(val, dict):
- obj = JSONObject()
- for k, v in val.items():
- obj.put(str(k), JSONObject._wrap(v))
- return obj
- if isinstance(val, JSONObject) or isinstance(val, JSONArray):
- return val
- return val
-
- def put(self, key, value):
- self._map[str(key)] = JSONObject._wrap(value)
- return self
-
- def accumulate(self, key, value):
- k = str(key)
- current = self._map.get(k)
- if current is None:
- arr = JSONArray()
- arr.put(value)
- self._map[k] = arr
- elif isinstance(current, JSONArray):
- current.put(value)
- else:
- arr = JSONArray()
- arr.put(current)
- arr.put(value)
- self._map[k] = arr
- return self
-
- def append(self, key, value):
- """Append value to the JSONArray under key.
-
- If the key is not present a new JSONArray containing value is created.
- If the key maps to a JSONArray the value is appended to it.
- Otherwise the existing value and the new value are placed into a new
- JSONArray.
- """
- k = str(key)
- current = self._map.get(k)
- if isinstance(current, JSONArray):
- current.put(value)
- else:
- arr = JSONArray()
- if current is not None and current is not JSONObject.NULL:
- arr.put(current)
- arr.put(value)
- self._map[k] = arr
- return self
-
- def putOnce(self, key, value):
- """Put a key/value pair only if the key is not already present."""
- if key is None:
- raise JSONException("Null key.")
- k = str(key)
- if k not in self._map:
- self._map[k] = JSONObject._wrap(value)
- return self
-
- def putOpt(self, key, value):
- """Put a key/value pair, but only if key and value are both non-null."""
- if key is not None and value is not None:
- return self.put(key, value)
- return self
-
- def get(self, key):
- k = str(key)
- if k not in self._map:
- raise JSONException(f"JSONObject[\"{k}\"] not found")
- val = self._map[k]
- if val is JSONObject.NULL:
- raise JSONException(f"JSONObject[\"{k}\"] is null")
- return val
-
- def opt(self, key, default=None):
- k = str(key)
- val = self._map.get(k)
- if val is None or val is JSONObject.NULL:
- return default
- return val
-
- def getString(self, key):
- val = self.get(key)
- if isinstance(val, str):
- return val
- raise JSONException(f"JSONObject[\"{key}\"] is not a string")
-
- def getInt(self, key):
- val = self.get(key)
- if isinstance(val, int):
- return val
- if isinstance(val, float):
- return int(val)
- raise JSONException(f"JSONObject[\"{key}\"] is not an int")
-
- def getLong(self, key):
- val = self.get(key)
- if isinstance(val, int):
- return val
- if isinstance(val, float):
- return int(val)
- raise JSONException(f"JSONObject[\"{key}\"] is not a long")
-
- def getDouble(self, key):
- val = self.get(key)
- if isinstance(val, (int, float)):
- return float(val)
- raise JSONException(f"JSONObject[\"{key}\"] is not a double")
-
- def getBoolean(self, key):
- val = self.get(key)
- if isinstance(val, bool):
- return val
- if val == "true":
- return True
- if val == "false":
- return False
- raise JSONException(f"JSONObject[\"{key}\"] is not a boolean")
-
- def getJSONArray(self, key):
- val = self.get(key)
- if isinstance(val, JSONArray):
- return val
- raise JSONException(f"JSONObject[\"{key}\"] is not a JSONArray")
-
- def getJSONObject(self, key):
- val = self.get(key)
- if isinstance(val, JSONObject):
- return val
- raise JSONException(f"JSONObject[\"{key}\"] is not a JSONObject")
-
- def optString(self, key, default=""):
- val = self.opt(key)
- if val is None or val is JSONObject.NULL:
- return default
- return str(val)
-
- def optInt(self, key, default=0):
- val = self.opt(key)
- if val is None or val is JSONObject.NULL:
- return default
- if isinstance(val, int):
- return val
- if isinstance(val, float):
- return int(val)
- try:
- return int(val)
- except (ValueError, TypeError):
- return default
-
- def optLong(self, key, default=0):
- return self.optInt(key, default)
-
- def optDouble(self, key, default=0.0):
- val = self.opt(key)
- if val is None or val is JSONObject.NULL:
- return default
- if isinstance(val, (int, float)):
- return float(val)
- try:
- return float(val)
- except (ValueError, TypeError):
- return default
-
- def optBoolean(self, key, default=False):
- val = self.opt(key)
- if val is None or val is JSONObject.NULL:
- return default
- if isinstance(val, bool):
- return val
- if isinstance(val, str):
- return val.lower() == "true"
- return default
-
- def optJSONArray(self, key):
- val = self.opt(key)
- if isinstance(val, JSONArray):
- return val
- return None
-
- def optJSONObject(self, key):
- val = self.opt(key)
- if isinstance(val, JSONObject):
- return val
- return None
-
- def has(self, key):
- return str(key) in self._map
-
- def isNull(self, key):
- """Returns true if this object has no mapping for key or if it has a
- mapping whose value is JSONObject.NULL."""
- k = str(key)
- if k not in self._map:
- return True
- return self._map[k] is JSONObject.NULL
-
- def remove(self, key):
- k = str(key)
- if k in self._map:
- del self._map[k]
-
- def keys(self):
- return iter(self._map.keys())
-
- def names(self):
- if not self._map:
- return None
- arr = JSONArray()
- for k in self._map:
- arr.put(k)
- return arr
-
- @staticmethod
- def getNames(jsonObject):
- """Returns an array of field names, or None if the object is None/empty."""
- if jsonObject is None:
- return None
- if not jsonObject._map:
- return None
- return [str(k) for k in jsonObject._map.keys()]
-
- def length(self):
- return len(self._map)
-
- def toString(self, indent_factor=None):
- if indent_factor is None:
- return self._to_json_string()
- return self._to_json_pretty(indent_factor)
-
- def _to_json_string(self):
- parts = ["{"]
- for i, (k, v) in enumerate(self._map.items()):
- parts.append('"' + k + '": ' + JSONObject._value_to_string(v))
- if i < len(self._map) - 1:
- parts.append(", ")
- parts.append("}")
- return "".join(parts)
-
- def _to_json_pretty(self, indent):
- parts = ["{"]
- for i, (k, v) in enumerate(self._map.items()):
- parts.append("\n" + " " * indent + '"' + k + '": ' + JSONObject._value_to_string(v))
- if i < len(self._map) - 1:
- parts.append(",")
- parts.append("\n}")
- return "".join(parts)
-
- def _value_to_string(val):
- if val is None or val is JSONObject.NULL:
- return "null"
- if isinstance(val, bool):
- return "true" if val else "false"
- if isinstance(val, (int, float)):
- return str(val)
- if isinstance(val, str):
- return _json.dumps(val)
- if isinstance(val, JSONObject):
- return val._to_json_string()
- if isinstance(val, JSONArray):
- return val._to_json_string()
- return str(val)
-
- def toMap(self):
- result = {}
- for k, v in self._map.items():
- if isinstance(v, JSONObject):
- result[k] = v.toMap()
- elif isinstance(v, JSONArray):
- result[k] = v.toList()
- elif v is JSONObject.NULL:
- result[k] = None
- else:
- result[k] = v
- return result
-
- def write(self, writer):
- writer._write(self._to_json_string())
-
- def toJSONArray(self, names):
- if names is None or names.length() == 0:
- return None
- arr = JSONArray()
- for i in range(names.length()):
- arr.put(self.opt(names.getString(i)))
- return arr
-
- def hashCode(self):
- return hash(frozenset(self._map.items()))
-
- def equals(self, other):
- if isinstance(other, JSONObject):
- return self._map == other._map
- return False
-
-
-# ============================================================
-# JSONArray
-# ============================================================
-
-class JSONArray(Stub):
- def __init__(self, *args):
- super().__init__()
- self._list = []
- if len(args) == 1:
- arg = args[0]
- if isinstance(arg, str):
- tokener = JSONTokener(arg)
- val = tokener.nextValue()
- if isinstance(val, JSONArray):
- self._list = val._list
- else:
- raise JSONException("String is not a JSONArray")
- elif isinstance(arg, (list, tuple)):
- for item in arg:
- self.put(JSONObject._wrap(item))
-
- def put(self, *args):
- if len(args) == 1:
- self._list.append(JSONObject._wrap(args[0]))
- elif len(args) == 2:
- index, value = args
- while len(self._list) <= index:
- self._list.append(None)
- self._list[index] = JSONObject._wrap(value)
- return self
-
- def get(self, index):
- if index < 0 or index >= len(self._list):
- raise JSONException(f"JSONArray[{index}] not found")
- val = self._list[index]
- if val is JSONObject.NULL:
- raise JSONException(f"JSONArray[{index}] is null")
- return val
-
- def getString(self, index):
- val = self.get(index)
- if isinstance(val, str):
- return val
- raise JSONException(f"JSONArray[{index}] is not a string")
-
- def getInt(self, index):
- val = self.get(index)
- if isinstance(val, int):
- return val
- if isinstance(val, float):
- return int(val)
- raise JSONException(f"JSONArray[{index}] is not an int")
-
- def getLong(self, index):
- val = self.get(index)
- if isinstance(val, int):
- return val
- if isinstance(val, float):
- return int(val)
- raise JSONException(f"JSONArray[{index}] is not a long")
-
- def getDouble(self, index):
- val = self.get(index)
- if isinstance(val, (int, float)):
- return float(val)
- raise JSONException(f"JSONArray[{index}] is not a double")
-
- def getBoolean(self, index):
- val = self.get(index)
- if isinstance(val, bool):
- return val
- if val == "true":
- return True
- if val == "false":
- return False
- raise JSONException(f"JSONArray[{index}] is not a boolean")
-
- def getJSONArray(self, index):
- val = self.get(index)
- if isinstance(val, JSONArray):
- return val
- raise JSONException(f"JSONArray[{index}] is not a JSONArray")
-
- def getJSONObject(self, index):
- val = self.get(index)
- if isinstance(val, JSONObject):
- return val
- raise JSONException(f"JSONArray[{index}] is not a JSONObject")
-
- def opt(self, index, default=None):
- if index < 0 or index >= len(self._list):
- return default
- val = self._list[index]
- if val is JSONObject.NULL:
- return default
- return val
-
- def optString(self, index, default=""):
- val = self.opt(index)
- if val is None:
- return default
- return str(val)
-
- def optInt(self, index, default=0):
- val = self.opt(index)
- if val is None:
- return default
- if isinstance(val, int):
- return val
- if isinstance(val, float):
- return int(val)
- try:
- return int(val)
- except (ValueError, TypeError):
- return default
-
- def optLong(self, index, default=0):
- return self.optInt(index, default)
-
- def optDouble(self, index, default=0.0):
- val = self.opt(index)
- if val is None:
- return default
- if isinstance(val, (int, float)):
- return float(val)
- try:
- return float(val)
- except (ValueError, TypeError):
- return default
-
- def optBoolean(self, index, default=False):
- val = self.opt(index)
- if val is None:
- return default
- if isinstance(val, bool):
- return val
- if isinstance(val, str):
- return val.lower() == "true"
- return default
-
- def optJSONArray(self, index):
- val = self.opt(index)
- if isinstance(val, JSONArray):
- return val
- return None
-
- def optJSONObject(self, index):
- val = self.opt(index)
- if isinstance(val, JSONObject):
- return val
- return None
-
- def remove(self, index):
- if 0 <= index < len(self._list):
- return self._list.pop(index)
- return None
-
- def length(self):
- return len(self._list)
-
- def isNull(self, index):
- if 0 <= index < len(self._list):
- return self._list[index] is JSONObject.NULL or self._list[index] is None
- return True
-
- def toString(self, indent_factor=None):
- if indent_factor is None:
- return self._to_json_string()
- return self._to_json_pretty(indent_factor)
-
- def _to_json_string(self):
- parts = ["["]
- for i, v in enumerate(self._list):
- parts.append(JSONObject._value_to_string(v))
- if i < len(self._list) - 1:
- parts.append(", ")
- parts.append("]")
- return "".join(parts)
-
- def _to_json_pretty(self, indent):
- parts = ["["]
- for i, v in enumerate(self._list):
- parts.append("\n" + " " * indent + JSONObject._value_to_string(v))
- if i < len(self._list) - 1:
- parts.append(",")
- parts.append("\n]")
- return "".join(parts)
-
- def toList(self):
- result = []
- for v in self._list:
- if isinstance(v, JSONObject):
- result.append(v.toMap())
- elif isinstance(v, JSONArray):
- result.append(v.toList())
- elif v is JSONObject.NULL:
- result.append(None)
- else:
- result.append(v)
- return result
-
- def join(self, separator):
- parts = []
- for v in self._list:
- parts.append(JSONObject._value_to_string(v))
- return separator.join(parts)
-
-
-# ============================================================
-# JSONTokener
-# ============================================================
-
-class JSONTokener(Stub):
- def __init__(self, source):
- super().__init__()
- if hasattr(source, "read"):
- self._source = source.read()
- else:
- self._source = str(source)
- self._index = 0
-
- def nextValue(self):
- self._skipWhitespace()
- if self._index >= len(self._source):
- raise JSONException("Unexpected end of input")
- ch = self._source[self._index]
- if ch == "{":
- return self._readObject()
- if ch == "[":
- return self._readArray()
- if ch == '"':
- return self._readString()
- if ch == "'":
- return self._readString("'")
- if ch == "t" or ch == "f":
- return self._readLiteral()
- if ch == "n":
- return self._readNull()
- return self._readNumber()
-
- def _skipWhitespace(self):
- while self._index < len(self._source) and self._source[self._index] in " \t\n\r":
- self._index += 1
-
- def _readObject(self):
- self._index += 1 # skip {
- obj = JSONObject()
- self._skipWhitespace()
- if self._index < len(self._source) and self._source[self._index] == "}":
- self._index += 1
- return obj
- while True:
- self._skipWhitespace()
- key = self.nextValue()
- self._skipWhitespace()
- if self._index < len(self._source) and self._source[self._index] == ":":
- self._index += 1
- self._skipWhitespace()
- val = self.nextValue()
- obj.put(str(key), val)
- self._skipWhitespace()
- if self._index < len(self._source) and self._source[self._index] == ",":
- self._index += 1
- elif self._index < len(self._source) and self._source[self._index] == "}":
- self._index += 1
- return obj
- else:
- raise JSONException("Expected ',' or '}' in object")
-
- def _readArray(self):
- self._index += 1 # skip [
- arr = JSONArray()
- self._skipWhitespace()
- if self._index < len(self._source) and self._source[self._index] == "]":
- self._index += 1
- return arr
- while True:
- self._skipWhitespace()
- val = self.nextValue()
- arr.put(val)
- self._skipWhitespace()
- if self._index < len(self._source) and self._source[self._index] == ",":
- self._index += 1
- elif self._index < len(self._source) and self._source[self._index] == "]":
- self._index += 1
- return arr
- else:
- raise JSONException("Expected ',' or ']' in array")
-
- def _readString(self, quote='"'):
- self._index += 1 # skip quote
- result = []
- while self._index < len(self._source):
- ch = self._source[self._index]
- if ch == "\\":
- self._index += 1
- if self._index >= len(self._source):
- raise JSONException("Unterminated string escape")
- esc = self._source[self._index]
- if esc == '"':
- result.append('"')
- elif esc == "\\":
- result.append("\\")
- elif esc == "/":
- result.append("/")
- elif esc == "b":
- result.append("\b")
- elif esc == "f":
- result.append("\f")
- elif esc == "n":
- result.append("\n")
- elif esc == "r":
- result.append("\r")
- elif esc == "t":
- result.append("\t")
- elif esc == "u":
- hex_str = self._source[self._index+1:self._index+5]
- result.append(chr(int(hex_str, 16)))
- self._index += 4
- else:
- result.append(esc)
- self._index += 1
- elif ch == quote:
- self._index += 1
- return "".join(result)
- else:
- result.append(ch)
- self._index += 1
- raise JSONException("Unterminated string")
-
- def _readLiteral(self):
- for lit in ("true", "false"):
- if self._source[self._index:self._index+len(lit)] == lit:
- self._index += len(lit)
- return lit == "true"
- raise JSONException(f"Unexpected literal at {self._index}")
-
- def _readNull(self):
- if self._source[self._index:self._index+4] == "null":
- self._index += 4
- return JSONObject.NULL
- raise JSONException(f"Unexpected token at {self._index}")
-
- def _readNumber(self):
- start = self._index
- while self._index < len(self._source) and self._source[self._index] in "-+0123456789.eE":
- self._index += 1
- num_str = self._source[start:self._index]
- if "." in num_str or "e" in num_str or "E" in num_str:
- return float(num_str)
- return int(num_str)
-
- def nextString(self, quote='"'):
- return self._readString(quote)
-
- def nextChar(self, c):
- self._skipWhitespace()
- if self._index < len(self._source) and self._source[self._index] == c:
- self._index += 1
- return c
- raise JSONException(f"Expected '{c}'")
-
- def nextTo(self, delimiter):
- start = self._index
- while self._index < len(self._source) and self._source[self._index] not in delimiter:
- self._index += 1
- return self._source[start:self._index]
-
- def skipPast(self, text):
- idx = self._source.find(text, self._index)
- if idx >= 0:
- self._index = idx + len(text)
-
- def skipTo(self, c):
- idx = self._source.find(c, self._index)
- if idx >= 0:
- self._index = idx
- return idx
- return -1
-
- def back(self):
- self._index -= 1
-
- def more(self):
- self._skipWhitespace()
- return self._index < len(self._source)
-
- def readString(self):
- return self._readString()
-
-
-# ============================================================
-# JSONWriter
-# ============================================================
-
-class JSONWriter(Stub):
- def __init__(self, writer):
- super().__init__()
- self._writer = writer
- self._stack = []
- self._in_object = False
- self._need_comma = False
-
- def _write(self, s):
- self._writer.write(s)
-
- def array(self):
- self._beforeValue()
- self._stack.append(("array", False))
- self._write("[")
- return self
-
- def endArray(self):
- self._write("]")
- self._stack.pop()
- return self
-
- def object(self):
- self._beforeValue()
- self._stack.append(("object", False))
- self._write("{")
- return self
-
- def endObject(self):
- self._write("}")
- self._stack.pop()
- return self
-
- def key(self, s):
- if not self._stack or self._stack[-1][0] != "object":
- raise JSONException("Can't set key outside object")
- self._beforeKey()
- self._write('"' + s + '":')
- return self
-
- def value(self, v):
- self._beforeValue()
- self._write(JSONObject._value_to_string(v))
- return self
-
- def _beforeValue(self):
- if self._stack and self._stack[-1][0] == "object":
- raise JSONException("Expected key in object")
-
- def _beforeKey(self):
- if self._stack and self._stack[-1][1]:
- self._write(",")
- self._stack[-1] = (self._stack[-1][0], True)
-
-
-# ============================================================
-# JSONStringer
-# ============================================================
-
-class JSONStringer(JSONWriter):
- def __init__(self):
- from io import StringIO
- super().__init__(StringIO())
-
- def toString(self):
- return self._writer.getvalue()
-
-
-# ============================================================
-# JSONPointer
-# ============================================================
-
-class JSONPointer(Stub):
- def __init__(self, pointer):
- super().__init__()
- if not pointer or pointer == "":
- self._tokens = []
- elif pointer.startswith("#"):
- pointer = pointer[1:]
- pointer = pointer.replace("~1", "/").replace("~0", "~")
- import urllib.parse
- pointer = urllib.parse.unquote(pointer)
- self._tokens = pointer.split("/")[1:] if len(pointer) > 1 else []
- else:
- self._tokens = pointer.split("/")[1:] if len(pointer) > 0 else []
-
- def query(self, root):
- current = root
- for token in self._tokens:
- token = token.replace("~1", "/").replace("~0", "~")
- if isinstance(current, JSONObject):
- current = current.get(token)
- elif isinstance(current, JSONArray):
- try:
- idx = int(token)
- current = current.get(idx)
- except (ValueError, IndexError):
- raise JSONException(f"Invalid index: {token}")
- else:
- raise JSONException(f"Cannot index into {type(current)}")
- return current
-
- def queryFrom(self, root):
- return self.query(root)
-
- def toString(self):
- return "#/" + "/".join(t.replace("~", "~0").replace("/", "~1") for t in self._tokens)
-
- def hashCode(self):
- return hash(tuple(self._tokens))
-
- def equals(self, other):
- if isinstance(other, JSONPointer):
- return self._tokens == other._tokens
- return False
-
-
-# ============================================================
-# JSONPointerBuilder
-# ============================================================
-
-class JSONPointerBuilder(Stub):
- def __init__(self):
- super().__init__()
- self._tokens = []
-
- def append(self, token):
- self._tokens.append(str(token))
- return self
-
- def build(self):
- return JSONPointer("#/" + "/".join(t.replace("~", "~0").replace("/", "~1") for t in self._tokens))
\ No newline at end of file
diff --git a/android_pyapi/org/w3c_dom.py b/android_pyapi/org/w3c_dom.py
deleted file mode 100644
index 7e14d74..0000000
--- a/android_pyapi/org/w3c_dom.py
+++ /dev/null
@@ -1,1292 +0,0 @@
-"""
-Java org.w3c.dom APIs implemented in Python.
-org.w3c.dom package - Document, Node, Element, Attr, Text, etc.
-Wraps Python xml.dom module.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-import xml.dom as _dom
-import xml.dom.minidom as _minidom
-from typing import List, Optional
-
-__all__ = [
- "Document", "Node", "Element", "Attr", "Text", "Comment",
- "CDATASection", "DocumentType", "Notation", "Entity",
- "EntityReference", "ProcessingInstruction", "NodeList",
- "NamedNodeMap", "DOMImplementation", "DOMConfiguration",
- "DOMException", "UserDataHandler", "DOMError", "DOMLocator",
- "DOMErrorHandler", "TypeInfo",
-]
-
-
-# ============================================================
-# Constants
-# ============================================================
-
-class NodeConstants:
- ELEMENT_NODE: int = 1
- ATTRIBUTE_NODE: int = 2
- TEXT_NODE: int = 3
- CDATA_SECTION_NODE: int = 4
- ENTITY_REFERENCE_NODE: int = 5
- ENTITY_NODE: int = 6
- PROCESSING_INSTRUCTION_NODE: int = 7
- COMMENT_NODE: int = 8
- DOCUMENT_NODE: int = 9
- DOCUMENT_TYPE_NODE: int = 10
- DOCUMENT_FRAGMENT_NODE: int = 11
- NOTATION_NODE: int = 12
-
- DOCUMENT_POSITION_DISCONNECTED: int = 0x01
- DOCUMENT_POSITION_PRECEDING: int = 0x02
- DOCUMENT_POSITION_FOLLOWING: int = 0x04
- DOCUMENT_POSITION_CONTAINS: int = 0x08
- DOCUMENT_POSITION_CONTAINED_BY: int = 0x10
- DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: int = 0x20
-
-
-# ============================================================
-# DOMException
-# ============================================================
-
-class DOMException(Exception, Stub):
- """
- org.w3c.dom.DOMException
- Exception for DOM operations.
- """
- INDEX_SIZE_ERR: int = 1
- DOMSTRING_SIZE_ERR: int = 2
- HIERARCHY_REQUEST_ERR: int = 3
- WRONG_DOCUMENT_ERR: int = 4
- INVALID_CHARACTER_ERR: int = 5
- NO_DATA_ALLOWED_ERR: int = 6
- NO_MODIFICATION_ALLOWED_ERR: int = 7
- NOT_FOUND_ERR: int = 8
- NOT_SUPPORTED_ERR: int = 9
- INUSE_ATTRIBUTE_ERR: int = 10
- INVALID_STATE_ERR: int = 11
- SYNTAX_ERR: int = 12
- INVALID_MODIFICATION_ERR: int = 13
- NAMESPACE_ERR: int = 14
- INVALID_ACCESS_ERR: int = 15
- VALIDATION_ERR: int = 16
- TYPE_MISMATCH_ERR: int = 17
-
- def __init__(self, code: int = 0, message: str = None):
- super().__init__(message or f"DOM error code {code}")
- self._code = code
- self._message = message
-
- def code(self) -> int:
- return self._code
-
- def toString(self) -> str:
- return f"DOMException[{self._code}]: {self._message}"
-
- def equals(self, other) -> bool:
- if isinstance(other, DOMException):
- return self._code == other._code
- return False
-
- def hashCode(self) -> int:
- return hash(self._code) & 0x7FFFFFFF
-
-
-# ============================================================
-# NodeList
-# ============================================================
-
-class NodeList(Stub):
- """
- org.w3c.dom.NodeList
- Ordered list of nodes.
- """
- def __init__(self, nodes: List = None):
- super().__init__()
- self._nodes = list(nodes) if nodes else []
-
- def getLength(self) -> int:
- return len(self._nodes)
-
- def item(self, index: int) -> Optional["Node"]:
- if 0 <= index < len(self._nodes):
- return self._nodes[index]
- return None
-
- def __len__(self):
- return len(self._nodes)
-
- def __iter__(self):
- return iter(self._nodes)
-
- def __getitem__(self, index):
- return self._nodes[index]
-
- def toString(self) -> str:
- return f"NodeList@{hex(id(self))}[length={len(self._nodes)}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# NamedNodeMap
-# ============================================================
-
-class NamedNodeMap(Stub):
- """
- org.w3c.dom.NamedNodeMap
- Collection of nodes accessible by name.
- """
- def __init__(self):
- super().__init__()
- self._nodes = {}
-
- def getNamedItem(self, name: str) -> Optional["Node"]:
- return self._nodes.get(name)
-
- def setNamedItem(self, arg: "Node") -> Optional["Node"]:
- name = arg.getNodeName()
- old = self._nodes.get(name)
- self._nodes[name] = arg
- return old
-
- def removeNamedItem(self, name: str) -> Optional["Node"]:
- return self._nodes.pop(name, None)
-
- def item(self, index: int) -> Optional["Node"]:
- keys = list(self._nodes.keys())
- if 0 <= index < len(keys):
- return self._nodes[keys[index]]
- return None
-
- def getLength(self) -> int:
- return len(self._nodes)
-
- def getNamedItemNS(self, namespace_uri: str, local_name: str) -> Optional["Node"]:
- for name, node in self._nodes.items():
- if node.getNamespaceURI() == namespace_uri and node.getLocalName() == local_name:
- return node
- return None
-
- def setNamedItemNS(self, arg: "Node") -> Optional["Node"]:
- return self.setNamedItem(arg)
-
- def removeNamedItemNS(self, namespace_uri: str, local_name: str) -> Optional["Node"]:
- for name, node in list(self._nodes.items()):
- if node.getNamespaceURI() == namespace_uri and node.getLocalName() == local_name:
- return self._nodes.pop(name, None)
- return None
-
- def toString(self) -> str:
- return f"NamedNodeMap@{hex(id(self))}[length={len(self._nodes)}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Node
-# ============================================================
-
-class Node(Stub):
- """
- org.w3c.dom.Node
- The primary datatype for the DOM.
- """
- ELEMENT_NODE: int = NodeConstants.ELEMENT_NODE
- ATTRIBUTE_NODE: int = NodeConstants.ATTRIBUTE_NODE
- TEXT_NODE: int = NodeConstants.TEXT_NODE
- CDATA_SECTION_NODE: int = NodeConstants.CDATA_SECTION_NODE
- ENTITY_REFERENCE_NODE: int = NodeConstants.ENTITY_REFERENCE_NODE
- ENTITY_NODE: int = NodeConstants.ENTITY_NODE
- PROCESSING_INSTRUCTION_NODE: int = NodeConstants.PROCESSING_INSTRUCTION_NODE
- COMMENT_NODE: int = NodeConstants.COMMENT_NODE
- DOCUMENT_NODE: int = NodeConstants.DOCUMENT_NODE
- DOCUMENT_TYPE_NODE: int = NodeConstants.DOCUMENT_TYPE_NODE
- DOCUMENT_FRAGMENT_NODE: int = NodeConstants.DOCUMENT_FRAGMENT_NODE
- NOTATION_NODE: int = NodeConstants.NOTATION_NODE
- DOCUMENT_POSITION_DISCONNECTED: int = NodeConstants.DOCUMENT_POSITION_DISCONNECTED
- DOCUMENT_POSITION_PRECEDING: int = NodeConstants.DOCUMENT_POSITION_PRECEDING
- DOCUMENT_POSITION_FOLLOWING: int = NodeConstants.DOCUMENT_POSITION_FOLLOWING
- DOCUMENT_POSITION_CONTAINS: int = NodeConstants.DOCUMENT_POSITION_CONTAINS
- DOCUMENT_POSITION_CONTAINED_BY: int = NodeConstants.DOCUMENT_POSITION_CONTAINED_BY
- DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: int = NodeConstants.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
-
- def __init__(self, node_type: int = ELEMENT_NODE, node_name: str = "",
- node_value: str = None):
- super().__init__()
- self._node_type = node_type
- self._node_name = node_name
- self._node_value = node_value
- self._parent_node = None
- self._child_nodes = []
- self._first_child = None
- self._last_child = None
- self._previous_sibling = None
- self._next_sibling = None
- self._attributes = NamedNodeMap()
- self._owner_document = None
- self._namespace_uri = None
- self._prefix = None
- self._local_name = None
- self._user_data = {}
-
- def getNodeName(self) -> str:
- return self._node_name
-
- def getNodeValue(self) -> Optional[str]:
- return self._node_value
-
- def setNodeValue(self, value: str):
- self._node_value = value
-
- def getNodeType(self) -> int:
- return self._node_type
-
- def getParentNode(self) -> Optional["Node"]:
- return self._parent_node
-
- def getChildNodes(self) -> NodeList:
- return NodeList(self._child_nodes)
-
- def getFirstChild(self) -> Optional["Node"]:
- return self._child_nodes[0] if self._child_nodes else None
-
- def getLastChild(self) -> Optional["Node"]:
- return self._child_nodes[-1] if self._child_nodes else None
-
- def getPreviousSibling(self) -> Optional["Node"]:
- return self._previous_sibling
-
- def getNextSibling(self) -> Optional["Node"]:
- return self._next_sibling
-
- def getAttributes(self) -> NamedNodeMap:
- return self._attributes
-
- def getOwnerDocument(self) -> Optional["Document"]:
- return self._owner_document
-
- def insertBefore(self, new_child: "Node", ref_child: Optional["Node"]) -> "Node":
- if ref_child is None:
- return self.appendChild(new_child)
- idx = self._child_nodes.index(ref_child) if ref_child in self._child_nodes else len(self._child_nodes)
- self._child_nodes.insert(idx, new_child)
- new_child._parent_node = self
- self._update_siblings()
- return new_child
-
- def replaceChild(self, new_child: "Node", old_child: "Node") -> "Node":
- if old_child in self._child_nodes:
- idx = self._child_nodes.index(old_child)
- self._child_nodes[idx] = new_child
- new_child._parent_node = self
- self._update_siblings()
- return old_child
- return None
-
- def removeChild(self, old_child: "Node") -> "Node":
- if old_child in self._child_nodes:
- self._child_nodes.remove(old_child)
- old_child._parent_node = None
- self._update_siblings()
- return old_child
- return None
-
- def appendChild(self, new_child: "Node") -> "Node":
- self._child_nodes.append(new_child)
- new_child._parent_node = self
- self._update_siblings()
- return new_child
-
- def hasChildNodes(self) -> bool:
- return len(self._child_nodes) > 0
-
- def cloneNode(self, deep: bool) -> "Node":
- cloned = Node(self._node_type, self._node_name, self._node_value)
- if deep:
- for child in self._child_nodes:
- cloned.appendChild(child.cloneNode(True))
- return cloned
-
- def normalize(self):
- """Merges adjacent text nodes."""
- i = 0
- while i < len(self._child_nodes) - 1:
- if (self._child_nodes[i].getNodeType() == Node.TEXT_NODE and
- self._child_nodes[i + 1].getNodeType() == Node.TEXT_NODE):
- combined = self._child_nodes[i].getNodeValue() + self._child_nodes[i + 1].getNodeValue()
- self._child_nodes[i].setNodeValue(combined)
- self._child_nodes.pop(i + 1)
- self._update_siblings()
- else:
- i += 1
-
- def isSupported(self, feature: str, version: str) -> bool:
- return feature in ("XML", "DOM", "Core")
-
- def getNamespaceURI(self) -> Optional[str]:
- return self._namespace_uri
-
- def getPrefix(self) -> Optional[str]:
- return self._prefix
-
- def setPrefix(self, prefix: str):
- self._prefix = prefix
-
- def getLocalName(self) -> Optional[str]:
- return self._local_name
-
- def hasAttributes(self) -> bool:
- return self._attributes.getLength() > 0
-
- def lookupNamespaceURI(self, prefix: str) -> Optional[str]:
- if self._prefix == prefix:
- return self._namespace_uri
- if self._parent_node:
- return self._parent_node.lookupNamespaceURI(prefix)
- return None
-
- def lookupPrefix(self, namespace_uri: str) -> Optional[str]:
- if self._namespace_uri == namespace_uri:
- return self._prefix
- if self._parent_node:
- return self._parent_node.lookupPrefix(namespace_uri)
- return None
-
- def isDefaultNamespace(self, namespace_uri: str) -> bool:
- return self._namespace_uri == namespace_uri
-
- def getBaseURI(self) -> Optional[str]:
- return None
-
- def compareDocumentPosition(self, other: "Node") -> int:
- """Compares the document position of two nodes."""
- return Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
-
- def getTextContent(self) -> str:
- parts = []
- for child in self._child_nodes:
- if child.getNodeType() == Node.TEXT_NODE or child.getNodeType() == Node.CDATA_SECTION_NODE:
- parts.append(child.getNodeValue() or "")
- parts.append(child.getTextContent() or "")
- return "".join(parts)
-
- def setTextContent(self, text: str):
- self._child_nodes = [Text(text)]
- self._update_siblings()
-
- def isSameNode(self, other: "Node") -> bool:
- return self is other
-
- def isEqualNode(self, other: "Node") -> bool:
- if self._node_type != other._node_type or self._node_name != other._node_name:
- return False
- return self._node_value == other._node_value
-
- def getFeature(self, feature: str, version: str):
- return None
-
- def setUserData(self, key: str, data: Any, handler: Any = None) -> Any:
- old = self._user_data.get(key)
- self._user_data[key] = data
- return old
-
- def getUserData(self, key: str) -> Any:
- return self._user_data.get(key)
-
- def _update_siblings(self):
- for i, child in enumerate(self._child_nodes):
- child._previous_sibling = self._child_nodes[i - 1] if i > 0 else None
- child._next_sibling = self._child_nodes[i + 1] if i < len(self._child_nodes) - 1 else None
-
- def toString(self) -> str:
- return f"Node[{self._node_name}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Document
-# ============================================================
-
-class Document(Node):
- """
- org.w3c.dom.Document
- Represents an XML document.
- """
-
- def __init__(self):
- super().__init__(Node.DOCUMENT_NODE, "#document", None)
- self._document_element = None
- self._doctype = None
- self._implementation = DOMImplementation()
- self._input_encoding = "UTF-8"
- self._xml_encoding = "UTF-8"
- self._xml_standalone = False
- self._xml_version = "1.0"
- self._strict_error_checking = True
- self._document_uri = None
- self._dom_config = DOMConfiguration()
-
- def getDocumentElement(self) -> Optional["Element"]:
- return self._document_element
-
- def getElementsByTagName(self, tagname: str) -> NodeList:
- result = []
- self._collect_elements_by_tag(self._document_element, tagname, result)
- return NodeList(result)
-
- def _collect_elements_by_tag(self, node: Node, tagname: str, result: List):
- if node is None:
- return
- if isinstance(node, Element) and (tagname == "*" or node.getTagName() == tagname):
- result.append(node)
- for child in node._child_nodes:
- self._collect_elements_by_tag(child, tagname, result)
-
- def getElementById(self, element_id: str) -> Optional["Element"]:
- result = []
- self._collect_elements_by_tag(self._document_element, "*", result)
- for el in result:
- if el.getAttribute("id") == element_id:
- return el
- return None
-
- def createElement(self, tag_name: str) -> "Element":
- el = Element(tag_name)
- el._owner_document = self
- return el
-
- def createDocumentFragment(self):
- frag = Node(Node.DOCUMENT_FRAGMENT_NODE, "#document-fragment", None)
- frag._owner_document = self
- return frag
-
- def createTextNode(self, data: str) -> "Text":
- tn = Text(data)
- tn._owner_document = self
- return tn
-
- def createComment(self, data: str) -> "Comment":
- c = Comment(data)
- c._owner_document = self
- return c
-
- def createCDATASection(self, data: str) -> "CDATASection":
- cs = CDATASection(data)
- cs._owner_document = self
- return cs
-
- def createProcessingInstruction(self, target: str, data: str) -> "ProcessingInstruction":
- pi = ProcessingInstruction(target, data)
- pi._owner_document = self
- return pi
-
- def createAttribute(self, name: str) -> "Attr":
- attr = Attr(name)
- attr._owner_document = self
- return attr
-
- def createEntityReference(self, name: str) -> "EntityReference":
- er = EntityReference(name)
- er._owner_document = self
- return er
-
- def importNode(self, imported_node: Node, deep: bool) -> Node:
- return imported_node.cloneNode(deep)
-
- def adoptNode(self, node: Node) -> Node:
- node._owner_document = self
- return node
-
- def createAttributeNS(self, namespace_uri: str, qualified_name: str) -> "Attr":
- attr = Attr(qualified_name)
- attr._namespace_uri = namespace_uri
- attr._owner_document = self
- return attr
-
- def createElementNS(self, namespace_uri: str, qualified_name: str) -> "Element":
- el = Element(qualified_name)
- el._namespace_uri = namespace_uri
- el._owner_document = self
- return el
-
- def getDoctype(self) -> Optional["DocumentType"]:
- return self._doctype
-
- def getImplementation(self) -> "DOMImplementation":
- return self._implementation
-
- def getInputEncoding(self) -> str:
- return self._input_encoding
-
- def getXmlEncoding(self) -> str:
- return self._xml_encoding
-
- def getXmlStandalone(self) -> bool:
- return self._xml_standalone
-
- def setXmlStandalone(self, standalone: bool):
- self._xml_standalone = standalone
-
- def getXmlVersion(self) -> str:
- return self._xml_version
-
- def setXmlVersion(self, version: str):
- self._xml_version = version
-
- def getStrictErrorChecking(self) -> bool:
- return self._strict_error_checking
-
- def setStrictErrorChecking(self, strict: bool):
- self._strict_error_checking = strict
-
- def getDocumentURI(self) -> Optional[str]:
- return self._document_uri
-
- def setDocumentURI(self, uri: str):
- self._document_uri = uri
-
- def getDomConfig(self) -> "DOMConfiguration":
- return self._dom_config
-
- def normalizeDocument(self):
- self.normalize()
-
- def renameNode(self, node: Node, namespace_uri: str, qualified_name: str) -> Node:
- node._node_name = qualified_name
- node._namespace_uri = namespace_uri
- return node
-
- def toString(self) -> str:
- return f"Document@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Element
-# ============================================================
-
-class Element(Node):
- """
- org.w3c.dom.Element
- Represents an element in an XML document.
- """
-
- def __init__(self, tag_name: str):
- super().__init__(Node.ELEMENT_NODE, tag_name, None)
- self._tag_name = tag_name
- self._local_name = tag_name
- self._schema_type = None
-
- def getTagName(self) -> str:
- return self._tag_name
-
- def getAttribute(self, name: str) -> str:
- attr = self._attributes.getNamedItem(name)
- return attr.getNodeValue() if attr else ""
-
- def getAttributeNode(self, name: str) -> Optional["Attr"]:
- return self._attributes.getNamedItem(name)
-
- def getElementsByTagName(self, tagname: str) -> NodeList:
- result = []
- doc = self.getOwnerDocument()
- if doc:
- doc._collect_elements_by_tag(self, tagname, result)
- return NodeList(result)
-
- def getAttributeNS(self, namespace_uri: str, local_name: str) -> str:
- attr = self._attributes.getNamedItemNS(namespace_uri, local_name)
- return attr.getNodeValue() if attr else ""
-
- def setAttribute(self, name: str, value: str):
- attr = Attr(name, value)
- self._attributes.setNamedItem(attr)
-
- def setAttributeNS(self, namespace_uri: str, qualified_name: str, value: str):
- attr = Attr(qualified_name, value)
- attr._namespace_uri = namespace_uri
- self._attributes.setNamedItem(attr)
-
- def removeAttribute(self, name: str):
- self._attributes.removeNamedItem(name)
-
- def removeAttributeNS(self, namespace_uri: str, local_name: str):
- self._attributes.removeNamedItemNS(namespace_uri, local_name)
-
- def getAttributeNodeNS(self, namespace_uri: str, local_name: str) -> Optional["Attr"]:
- return self._attributes.getNamedItemNS(namespace_uri, local_name)
-
- def setAttributeNode(self, new_attr: "Attr") -> Optional["Attr"]:
- return self._attributes.setNamedItem(new_attr)
-
- def setAttributeNodeNS(self, new_attr: "Attr") -> Optional["Attr"]:
- return self._attributes.setNamedItemNS(new_attr)
-
- def removeAttributeNode(self, old_attr: "Attr") -> Optional["Attr"]:
- return self._attributes.removeNamedItem(old_attr.getNodeName())
-
- def getElementsByTagNameNS(self, namespace_uri: str, local_name: str) -> NodeList:
- result = []
- self._collect_elements_by_tag_ns(self, namespace_uri, local_name, result)
- return NodeList(result)
-
- def _collect_elements_by_tag_ns(self, node, ns, name, result):
- if node is None:
- return
- if (isinstance(node, Element) and
- (ns == "*" or node.getNamespaceURI() == ns) and
- (name == "*" or node.getLocalName() == name)):
- result.append(node)
- for child in node._child_nodes:
- self._collect_elements_by_tag_ns(child, ns, name, result)
-
- def hasAttribute(self, name: str) -> bool:
- return self._attributes.getNamedItem(name) is not None
-
- def hasAttributeNS(self, namespace_uri: str, local_name: str) -> bool:
- return self._attributes.getNamedItemNS(namespace_uri, local_name) is not None
-
- def getSchemaTypeInfo(self):
- return self._schema_type
-
- def setIdAttribute(self, name: str, is_id: bool):
- pass
-
- def setIdAttributeNS(self, namespace_uri: str, local_name: str, is_id: bool):
- pass
-
- def setIdAttributeNode(self, id_attr: "Attr", is_id: bool):
- pass
-
- def toString(self) -> str:
- return f"Element[{self._tag_name}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Attr
-# ============================================================
-
-class Attr(Node):
- """
- org.w3c.dom.Attr
- Represents an attribute in a DOM document.
- """
- def __init__(self, name: str, value: str = ""):
- super().__init__(Node.ATTRIBUTE_NODE, name, value)
- self._specified = True
- self._owner_element = None
- self._is_id = False
- self._schema_type = None
- self._local_name = name
-
- def getName(self) -> str:
- return self._node_name
-
- def getValue(self) -> str:
- return self._node_value or ""
-
- def setValue(self, value: str):
- self._node_value = value
- self._specified = True
-
- def getOwnerElement(self) -> Optional[Element]:
- return self._owner_element
-
- def getSpecified(self) -> bool:
- return self._specified
-
- def getSchemaTypeInfo(self):
- return self._schema_type
-
- def isId(self) -> bool:
- return self._is_id
-
- def toString(self) -> str:
- return f'Attr[{self._node_name}="{self._node_value}"]'
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Text
-# ============================================================
-
-class Text(Node):
- """
- org.w3c.dom.Text
- Represents the textual content of an element or attribute.
- """
- def __init__(self, data: str = ""):
- super().__init__(Node.TEXT_NODE, "#text", data)
-
- def splitText(self, offset: int) -> "Text":
- if offset >= len(self._node_value or ""):
- raise DOMException(DOMException.INDEX_SIZE_ERR, "Offset out of bounds")
- first_part = self._node_value[:offset]
- second_part = self._node_value[offset:]
- self._node_value = first_part
- new_text = Text(second_part)
- if self._parent_node:
- self._parent_node.insertBefore(new_text, self._next_sibling)
- return new_text
-
- def isElementContentWhitespace(self) -> bool:
- return (self._node_value or "").strip() == ""
-
- def getWholeText(self) -> str:
- parts = [self._node_value or ""]
- # Collect adjacent text nodes
- sibling = self._previous_sibling
- while sibling and sibling.getNodeType() in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
- parts.insert(0, sibling.getNodeValue() or "")
- sibling = sibling._previous_sibling
- sibling = self._next_sibling
- while sibling and sibling.getNodeType() in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
- parts.append(sibling.getNodeValue() or "")
- sibling = sibling._next_sibling
- return "".join(parts)
-
- def replaceWholeText(self, content: str) -> "Text":
- self._node_value = content
- # Remove adjacent text nodes
- siblings = []
- sib = self._previous_sibling
- while sib and sib.getNodeType() in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
- siblings.append(sib)
- sib = sib._previous_sibling
- for s in siblings:
- if self._parent_node:
- self._parent_node.removeChild(s)
- siblings = []
- sib = self._next_sibling
- while sib and sib.getNodeType() in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
- siblings.append(sib)
- sib = sib._next_sibling
- for s in siblings:
- if self._parent_node:
- self._parent_node.removeChild(s)
- return self
-
- def toString(self) -> str:
- return f"Text[{self._node_value}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Comment
-# ============================================================
-
-class Comment(Node):
- """
- org.w3c.dom.Comment
- Represents the content of an XML comment.
- """
- def __init__(self, data: str = ""):
- super().__init__(Node.COMMENT_NODE, "#comment", data)
-
- def toString(self) -> str:
- return f"Comment[{self._node_value}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# CDATASection
-# ============================================================
-
-class CDATASection(Text):
- """
- org.w3c.dom.CDATASection
- Represents a CDATA section.
- """
- def __init__(self, data: str = ""):
- super().__init__(data)
- self._node_type = Node.CDATA_SECTION_NODE
- self._node_name = "#cdata-section"
-
- def toString(self) -> str:
- return f"CDATASection[{self._node_value}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DocumentType
-# ============================================================
-
-class DocumentType(Node):
- """
- org.w3c.dom.DocumentType
- Represents a document type declaration.
- """
- def __init__(self, name: str = "", public_id: str = "", system_id: str = "",
- internal_subset: str = ""):
- super().__init__(Node.DOCUMENT_TYPE_NODE, name, None)
- self._name = name
- self._entities = NamedNodeMap()
- self._notations = NamedNodeMap()
- self._public_id = public_id
- self._system_id = system_id
- self._internal_subset = internal_subset
-
- def getName(self) -> str:
- return self._name
-
- def getEntities(self) -> NamedNodeMap:
- return self._entities
-
- def getNotations(self) -> NamedNodeMap:
- return self._notations
-
- def getPublicId(self) -> str:
- return self._public_id
-
- def getSystemId(self) -> str:
- return self._system_id
-
- def getInternalSubset(self) -> str:
- return self._internal_subset
-
- def toString(self) -> str:
- return f"DocumentType[{self._name}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Notation
-# ============================================================
-
-class Notation(Node):
- """
- org.w3c.dom.Notation
- Represents a notation in a DTD.
- """
- def __init__(self, name: str = "", public_id: str = "", system_id: str = ""):
- super().__init__(Node.NOTATION_NODE, name, None)
- self._public_id = public_id
- self._system_id = system_id
-
- def getPublicId(self) -> str:
- return self._public_id
-
- def getSystemId(self) -> str:
- return self._system_id
-
- def toString(self) -> str:
- return f"Notation[{self._node_name}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Entity
-# ============================================================
-
-class Entity(Node):
- """
- org.w3c.dom.Entity
- Represents an entity in a DTD.
- """
- def __init__(self, name: str = "", public_id: str = "", system_id: str = "",
- notation_name: str = ""):
- super().__init__(Node.ENTITY_NODE, name, None)
- self._public_id = public_id
- self._system_id = system_id
- self._notation_name = notation_name
- self._input_encoding = "UTF-8"
- self._xml_encoding = "UTF-8"
- self._xml_version = "1.0"
-
- def getPublicId(self) -> str:
- return self._public_id
-
- def getSystemId(self) -> str:
- return self._system_id
-
- def getNotationName(self) -> str:
- return self._notation_name
-
- def getInputEncoding(self) -> str:
- return self._input_encoding
-
- def getXmlEncoding(self) -> str:
- return self._xml_encoding
-
- def getXmlVersion(self) -> str:
- return self._xml_version
-
- def toString(self) -> str:
- return f"Entity[{self._node_name}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-class EntityReference(Node):
- """
- org.w3c.dom.EntityReference
- Represents an entity reference.
- """
- def __init__(self, name: str = ""):
- super().__init__(Node.ENTITY_REFERENCE_NODE, name, None)
-
- def toString(self) -> str:
- return f"EntityReference[{self._node_name}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# ProcessingInstruction
-# ============================================================
-
-class ProcessingInstruction(Node):
- """
- org.w3c.dom.ProcessingInstruction
- Represents a processing instruction.
- """
- def __init__(self, target: str = "", data: str = ""):
- super().__init__(Node.PROCESSING_INSTRUCTION_NODE, target, data)
- self._target = target
- self._data = data
-
- def getTarget(self) -> str:
- return self._target
-
- def getData(self) -> str:
- return self._data
-
- def setData(self, data: str):
- self._data = data
-
- def toString(self) -> str:
- return f"ProcessingInstruction[{self._target}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DOMImplementation
-# ============================================================
-
-class DOMImplementation(Stub):
- """
- org.w3c.dom.DOMImplementation
- Interface for DOM implementation.
- """
- def __init__(self):
- super().__init__()
-
- def hasFeature(self, feature: str, version: str) -> bool:
- return feature in ("XML", "Core", "DOM") and version in ("1.0", "2.0", "3.0", "")
-
- def createDocumentType(self, qualified_name: str, public_id: str,
- system_id: str) -> DocumentType:
- return DocumentType(qualified_name, public_id, system_id)
-
- def createDocument(self, namespace_uri: str, qualified_name: str,
- doctype: DocumentType = None) -> Document:
- doc = Document()
- if qualified_name:
- root = doc.createElementNS(namespace_uri or "", qualified_name)
- doc.appendChild(root)
- doc._document_element = root
- doc._doctype = doctype
- return doc
-
- def getFeature(self, feature: str, version: str):
- return self
-
- def toString(self) -> str:
- return f"DOMImplementation@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DOMConfiguration
-# ============================================================
-
-class DOMConfiguration(Stub):
- """
- org.w3c.dom.DOMConfiguration
- Configuration of a DOM document.
- """
- def __init__(self):
- super().__init__()
- self._params = {}
-
- def setParameter(self, name: str, value: Any):
- self._params[name] = value
-
- def getParameter(self, name: str) -> Any:
- return self._params.get(name)
-
- def canSetParameter(self, name: str, value: Any) -> bool:
- return True
-
- def getParameterNames(self) -> NodeList:
- return NodeList([Node(Node.TEXT_NODE, k, str(v)) for k, v in self._params.items()])
-
- def toString(self) -> str:
- return f"DOMConfiguration@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# UserDataHandler
-# ============================================================
-
-class UserDataHandler(Stub):
- """
- org.w3c.dom.UserDataHandler
- Handler for user data events.
- """
- NODE_ADOPTED: int = 5
- NODE_CLONED: int = 1
- NODE_IMPORTED: int = 2
- NODE_DELETED: int = 3
- NODE_RENAMED: int = 4
-
- def handle(self, operation: int, key: str, data: Any, src: Node, dst: Node):
- """Called when a node is adopted, cloned, imported, deleted, or renamed."""
- pass
-
- def toString(self) -> str:
- return f"UserDataHandler@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DOMError
-# ============================================================
-
-class DOMError(Stub):
- """
- org.w3c.dom.DOMError
- Represents an error in DOM operations.
- """
- SEVERITY_WARNING: int = 1
- SEVERITY_ERROR: int = 2
- SEVERITY_FATAL_ERROR: int = 3
-
- def __init__(self, severity: int = SEVERITY_ERROR, message: str = "",
- error_type: str = "", related_exception: Exception = None,
- related_data: Any = None, location: "DOMLocator" = None):
- super().__init__()
- self._severity = severity
- self._message = message
- self._type = error_type
- self._related_exception = related_exception
- self._related_data = related_data
- self._location = location
-
- def getSeverity(self) -> int:
- return self._severity
-
- def getMessage(self) -> str:
- return self._message
-
- def getType(self) -> str:
- return self._type
-
- def getRelatedException(self) -> Exception:
- return self._related_exception
-
- def getRelatedData(self) -> Any:
- return self._related_data
-
- def getLocation(self) -> "DOMLocator":
- return self._location
-
- def toString(self) -> str:
- return f"DOMError[{self._type}]: {self._message}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DOMLocator
-# ============================================================
-
-class DOMLocator(Stub):
- """
- org.w3c.dom.DOMLocator
- Location information for DOM errors.
- """
- def __init__(self, line: int = 0, column: int = 0, byte_offset: int = -1,
- utf16_offset: int = -1, related_node: Node = None, uri: str = ""):
- super().__init__()
- self._line = line
- self._column = column
- self._byte_offset = byte_offset
- self._utf16_offset = utf16_offset
- self._related_node = related_node
- self._uri = uri
-
- def getLineNumber(self) -> int:
- return self._line
-
- def getColumnNumber(self) -> int:
- return self._column
-
- def getByteOffset(self) -> int:
- return self._byte_offset
-
- def getUtf16Offset(self) -> int:
- return self._utf16_offset
-
- def getRelatedNode(self) -> Node:
- return self._related_node
-
- def getUri(self) -> str:
- return self._uri
-
- def toString(self) -> str:
- return f"DOMLocator[line={self._line}, col={self._column}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DOMErrorHandler
-# ============================================================
-
-class DOMErrorHandler(Stub):
- """
- org.w3c.dom.DOMErrorHandler
- Handler for DOM errors.
- """
- def handleError(self, error: DOMError) -> bool:
- """Returns True to continue, False to stop processing."""
- return True
-
- def toString(self) -> str:
- return f"DOMErrorHandler@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# TypeInfo
-# ============================================================
-
-class TypeInfo(Stub):
- """
- org.w3c.dom.TypeInfo
- Represents type information about an element or attribute.
- """
- DERIVATION_RESTRICTION: int = 1
- DERIVATION_EXTENSION: int = 2
- DERIVATION_UNION: int = 4
- DERIVATION_LIST: int = 8
-
- def __init__(self, type_name: str = "", type_namespace: str = ""):
- super().__init__()
- self._type_name = type_name
- self._type_namespace = type_namespace
-
- def getTypeName(self) -> str:
- return self._type_name
-
- def getTypeNamespace(self) -> str:
- return self._type_namespace
-
- def toString(self) -> str:
- return f"TypeInfo[{self._type_name}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/org/xml_pull.py b/android_pyapi/org/xml_pull.py
deleted file mode 100644
index 7e5e04f..0000000
--- a/android_pyapi/org/xml_pull.py
+++ /dev/null
@@ -1,589 +0,0 @@
-"""
-Java org.xmlpull.v1 APIs implemented in Python.
-org.xmlpull.v1 package - XmlPullParser, XmlSerializer, XmlPullParserFactory.
-Wraps Python xml.etree.ElementTree.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-import xml.etree.ElementTree as _ET
-from io import StringIO as _StringIO
-from typing import List, Optional
-
-__all__ = [
- "XmlPullParser", "XmlSerializer", "XmlPullParserFactory", "Factory",
-]
-
-
-# ============================================================
-# XmlPullParser
-# ============================================================
-
-class XmlPullParser(Stub):
- """
- org.xmlpull.v1.XmlPullParser
- An XML pull parser interface.
- """
- # Event types
- START_TAG: int = 2
- END_TAG: int = 3
- TEXT: int = 4
- CDSECT: int = 5
- ENTITY_REF: int = 6
- IGNORABLE_WHITESPACE: int = 7
- PROCESSING_INSTRUCTION: int = 8
- COMMENT: int = 9
- DOCDECL: int = 10
- START_DOCUMENT: int = 0
- END_DOCUMENT: int = 1
- TYPES: List[str] = [
- "START_DOCUMENT", "END_DOCUMENT", "START_TAG", "END_TAG",
- "TEXT", "CDSECT", "ENTITY_REF", "IGNORABLE_WHITESPACE",
- "PROCESSING_INSTRUCTION", "COMMENT", "DOCDECL",
- ]
- NO_TYPES: List[str] = []
- # Features
- FEATURE_PROCESS_NAMESPACES: str = "http://xmlpull.org/v1/doc/features.html#process-ns"
- FEATURE_REPORT_NAMESPACE_ATTRIBUTES: str = "http://xmlpull.org/v1/doc/features.html#report-ns-attributes"
- FEATURE_PROCESS_DOCDECL: str = "http://xmlpull.org/v1/doc/features.html#process-docdecl"
- FEATURE_VALIDATION: str = "http://xmlpull.org/v1/doc/features.html#validation"
-
- class _Event:
- def __init__(self, type_=0, name="", text="", namespace="", prefix="",
- attributes=None, depth=0, line=0, column=0):
- self.type = type_
- self.name = name
- self.text = text
- self.namespace = namespace
- self.prefix = prefix
- self.attributes = attributes or []
- self.depth = depth
- self.line = line
- self.column = column
-
- def __init__(self):
- super().__init__()
- self._events = []
- self._pos = -1
- self._depth = 0
- self._features = {
- self.FEATURE_PROCESS_NAMESPACES: True,
- self.FEATURE_REPORT_NAMESPACE_ATTRIBUTES: False,
- self.FEATURE_PROCESS_DOCDECL: False,
- self.FEATURE_VALIDATION: False,
- }
- self._properties = {}
- self._input_encoding = "UTF-8"
- self._namespace_stack = []
-
- def setInput(self, source: Any, input_encoding: str = None):
- """Set the input source for parsing."""
- if input_encoding:
- self._input_encoding = input_encoding
-
- if isinstance(source, str):
- # Parse directly from XML string
- self._parse_string(source)
- elif hasattr(source, 'read'):
- # File-like object
- data = source.read()
- if isinstance(data, bytes):
- data = data.decode(input_encoding or "UTF-8")
- self._parse_string(data)
- else:
- self._parse_string(str(source))
-
- def _parse_string(self, xml_str: str):
- """Parse XML string into a list of events."""
- self._events = []
- self._pos = -1
-
- try:
- root = _ET.fromstring(xml_str)
- except _ET.ParseError as e:
- # Create minimal events if parsing fails
- self._events.append(XmlPullParser._Event(XmlPullParser.START_DOCUMENT))
- self._events.append(XmlPullParser._Event(XmlPullParser.END_DOCUMENT))
- return
-
- self._events.append(XmlPullParser._Event(XmlPullParser.START_DOCUMENT))
- self._build_events(root, 0)
- self._events.append(XmlPullParser._Event(XmlPullParser.END_DOCUMENT))
-
- def _build_events(self, element: _ET.Element, depth: int):
- """Recursively build events from ElementTree."""
- attrs = []
- for k, v in element.attrib.items():
- ns = ""
- name = k
- prefix = ""
- if "}" in k:
- ns = k[1:k.index("}")]
- name = k[k.index("}") + 1:]
- attrs.append({"namespace": ns, "name": name, "prefix": prefix, "value": v})
-
- # START_TAG
- tag = element.tag
- ns = ""
- prefix = ""
- if "}" in tag:
- ns = tag[1:tag.index("}")]
- tag = tag[tag.index("}") + 1:]
-
- self._events.append(XmlPullParser._Event(
- XmlPullParser.START_TAG, tag, "", ns, prefix, attrs, depth))
-
- # Text content
- if element.text and element.text.strip():
- self._events.append(XmlPullParser._Event(
- XmlPullParser.TEXT, "", element.text, "", "", [], depth + 1))
-
- # Child elements
- for child in element:
- self._build_events(child, depth + 1)
-
- # END_TAG
- self._events.append(XmlPullParser._Event(
- XmlPullParser.END_TAG, tag, "", ns, prefix, [], depth))
-
- # Tail text
- if element.tail and element.tail.strip():
- self._events.append(XmlPullParser._Event(
- XmlPullParser.TEXT, "", element.tail, "", "", [], depth))
-
- # --- Event navigation ---
-
- def getEventType(self) -> int:
- if 0 <= self._pos < len(self._events):
- return self._events[self._pos].type
- return self.END_DOCUMENT
-
- def next(self) -> int:
- """Move to next event."""
- if self._pos < len(self._events) - 1:
- self._pos += 1
- return self.getEventType()
-
- def nextToken(self) -> int:
- """Move to next token (same as next for this impl)."""
- return self.next()
-
- def nextText(self) -> str:
- """Returns the text content of the current element."""
- if self.getEventType() != self.START_TAG:
- return ""
- self.next()
- text = self.getText()
- self.next() # Move to END_TAG
- return text or ""
-
- def nextTag(self) -> int:
- """Move to next tag event."""
- self.next()
- while self.getEventType() not in (self.START_TAG, self.END_TAG, self.END_DOCUMENT):
- self.next()
- return self.getEventType()
-
- def require(self, type_: int, namespace: str, name: str):
- """Check that the current event matches expectations."""
- if self.getEventType() != type_:
- raise AndroidOnlyError(f"Expected event {type_}, got {self.getEventType()}")
- if namespace is not None and self.getNamespace() != namespace:
- raise AndroidOnlyError(f"Expected namespace '{namespace}', got '{self.getNamespace()}'")
- if name is not None and self.getName() != name:
- raise AndroidOnlyError(f"Expected name '{name}', got '{self.getName()}'")
-
- # --- Position info ---
-
- def getDepth(self) -> int:
- if 0 <= self._pos < len(self._events):
- return self._events[self._pos].depth
- return 0
-
- def getLineNumber(self) -> int:
- if 0 <= self._pos < len(self._events):
- return self._events[self._pos].line
- return -1
-
- def getColumnNumber(self) -> int:
- if 0 <= self._pos < len(self._events):
- return self._events[self._pos].column
- return -1
-
- def getInputEncoding(self) -> str:
- return self._input_encoding
-
- # --- Current event data ---
-
- def getName(self) -> str:
- if 0 <= self._pos < len(self._events):
- return self._events[self._pos].name
- return ""
-
- def getNamespace(self) -> str:
- if 0 <= self._pos < len(self._events):
- return self._events[self._pos].namespace
- return ""
-
- def getPrefix(self) -> str:
- if 0 <= self._pos < len(self._events):
- return self._events[self._pos].prefix
- return ""
-
- def getText(self) -> Optional[str]:
- if 0 <= self._pos < len(self._events):
- return self._events[self._pos].text
- return None
-
- def getTextCharacters(self, holder_for_start: List[int]) -> List[str]:
- """Returns text characters and fills start/length in holder."""
- text = self.getText() or ""
- if len(holder_for_start) >= 2:
- holder_for_start[0] = 0
- holder_for_start[1] = len(text)
- return list(text)
-
- # --- Attributes ---
-
- def getAttributeCount(self) -> int:
- if 0 <= self._pos < len(self._events):
- return len(self._events[self._pos].attributes)
- return 0
-
- def getAttributeName(self, index: int) -> str:
- if 0 <= self._pos < len(self._events):
- attrs = self._events[self._pos].attributes
- if 0 <= index < len(attrs):
- return attrs[index]["name"]
- return ""
-
- def getAttributeNamespace(self, index: int) -> str:
- if 0 <= self._pos < len(self._events):
- attrs = self._events[self._pos].attributes
- if 0 <= index < len(attrs):
- return attrs[index]["namespace"]
- return ""
-
- def getAttributePrefix(self, index: int) -> str:
- if 0 <= self._pos < len(self._events):
- attrs = self._events[self._pos].attributes
- if 0 <= index < len(attrs):
- return attrs[index]["prefix"]
- return ""
-
- def getAttributeType(self, index: int) -> str:
- return "CDATA"
-
- def getAttributeValue(self, index_or_name: Any, namespace: str = None) -> str:
- if isinstance(index_or_name, int):
- if 0 <= self._pos < len(self._events):
- attrs = self._events[self._pos].attributes
- if 0 <= index_or_name < len(attrs):
- return attrs[index_or_name]["value"]
- else:
- # Lookup by name
- if 0 <= self._pos < len(self._events):
- attrs = self._events[self._pos].attributes
- for attr in attrs:
- if attr["name"] == index_or_name:
- if namespace is None or attr["namespace"] == namespace:
- return attr["value"]
- return ""
-
- def isAttributeDefault(self, index: int) -> bool:
- return False
-
- # --- Element state ---
-
- def isEmptyElementTag(self) -> bool:
- """Returns True if the current event is an empty element tag."""
- if self.getEventType() == self.START_TAG:
- if self._pos + 1 < len(self._events):
- next_event = self._events[self._pos + 1]
- return next_event.type == self.END_TAG and next_event.name == self.getName()
- return False
-
- def isWhitespace(self) -> bool:
- text = self.getText() or ""
- return text.strip() == ""
-
- # --- Namespace support ---
-
- def getNamespaceCount(self, depth: int) -> int:
- return len(self._namespace_stack)
-
- def getNamespacePrefix(self, index: int) -> str:
- if 0 <= index < len(self._namespace_stack):
- return self._namespace_stack[index][0]
- return ""
-
- def getNamespaceUri(self, prefix: str) -> str:
- for p, uri in self._namespace_stack:
- if p == prefix:
- return uri
- return ""
-
- # --- Features / Properties ---
-
- def getFeature(self, name: str) -> bool:
- return self._features.get(name, False)
-
- def setFeature(self, name: str, value: bool):
- if name in self._features:
- self._features[name] = value
- else:
- raise AndroidOnlyError(f"Unknown feature: {name}")
-
- def getProperty(self, name: str):
- return self._properties.get(name)
-
- def setProperty(self, name: str, value: Any):
- self._properties[name] = value
-
- def toString(self) -> str:
- return f"XmlPullParser@{hex(id(self))}[event={self.getEventType()}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# XmlSerializer
-# ============================================================
-
-class XmlSerializer(Stub):
- """
- org.xmlpull.v1.XmlSerializer
- Interface for serializing XML documents.
- """
-
- def __init__(self):
- super().__init__()
- self._output = []
- self._depth = 0
- self._features = {}
- self._properties = {}
- self._prefixes = {}
- self._output_stream = None
- self._encoding = "UTF-8"
-
- def setOutput(self, output_stream, encoding: str = None):
- """Sets the output writer/stream."""
- self._output_stream = output_stream
- self._encoding = encoding or "UTF-8"
-
- def getFeature(self, name: str) -> bool:
- return self._features.get(name, False)
-
- def setFeature(self, name: str, value: bool):
- self._features[name] = value
-
- def getProperty(self, name: str):
- return self._properties.get(name)
-
- def setProperty(self, name: str, value: Any):
- self._properties[name] = value
-
- def setPrefix(self, prefix: str, namespace_uri: str):
- """Sets the prefix for a namespace."""
- self._prefixes[namespace_uri] = prefix
- if prefix:
- self._write(f' xmlns:{prefix}="{namespace_uri}"')
- else:
- self._write(f' xmlns="{namespace_uri}"')
-
- def startTag(self, namespace: str, name: str) -> "XmlSerializer":
- """Writes a start tag."""
- self._write(f"<{name}")
- self._depth += 1
- return self
-
- def attribute(self, namespace: str, name: str, value: str) -> "XmlSerializer":
- """Writes an attribute."""
- if value is not None:
- escaped = value.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """)
- self._write(f' {name}="{escaped}"')
- return self
-
- def endTag(self, namespace: str, name: str) -> "XmlSerializer":
- """Writes an end tag."""
- self._depth -= 1
- self._write(f"{name}>")
- return self
-
- def text(self, text_or_buf: Any, start: int = None, length: int = None) -> "XmlSerializer":
- """Writes text content."""
- if isinstance(text_or_buf, str):
- escaped = text_or_buf.replace("&", "&").replace("<", "<").replace(">", ">")
- self._write(escaped)
- elif isinstance(text_or_buf, (list, tuple)) and start is not None and length is not None:
- chars = text_or_buf[start:start + length]
- self._write("".join(chars))
- return self
-
- def cdsect(self, text: str) -> "XmlSerializer":
- """Writes a CDATA section."""
- self._write(f"")
- return self
-
- def entityRef(self, name: str) -> "XmlSerializer":
- """Writes an entity reference."""
- self._write(f"&{name};")
- return self
-
- def processingInstruction(self, text: str) -> "XmlSerializer":
- """Writes a processing instruction."""
- self._write(f"{text}?>")
- return self
-
- def comment(self, text: str) -> "XmlSerializer":
- """Writes a comment."""
- self._write(f"")
- return self
-
- def docdecl(self, text: str) -> "XmlSerializer":
- """Writes a document declaration."""
- self._write(f"")
- return self
-
- def startDocument(self, encoding: str = None, standalone: bool = None):
- """Writes the XML declaration."""
- encoding = encoding or self._encoding
- decl = f'"
- self._write(decl)
-
- def endDocument(self):
- """Finishes the document."""
- self.flush()
-
- def flush(self):
- """Flushes the output."""
- content = "".join(self._output)
- if self._output_stream:
- if hasattr(self._output_stream, 'write'):
- self._output_stream.write(content)
- self._output = []
-
- def getDepth(self) -> int:
- return self._depth
-
- def getName(self) -> str:
- return ""
-
- def getNamespace(self) -> str:
- return ""
-
- def getPrefix(self, namespace: str, prefix: bool = False) -> str:
- return self._prefixes.get(namespace, "")
-
- def _write(self, s: str):
- self._output.append(s)
-
- def verbatim(self, text: str) -> "XmlSerializer":
- """Writes raw text without escaping."""
- self._write(text)
- return self
-
- def write(self, text: str) -> "XmlSerializer":
- """Writes text."""
- return self.text(text)
-
- def toString(self) -> str:
- return f"XmlSerializer@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# XmlPullParserFactory
-# ============================================================
-
-class XmlPullParserFactory(Stub):
- """
- org.xmlpull.v1.XmlPullParserFactory
- Factory for creating XmlPullParser and XmlSerializer instances.
- """
-
- def __init__(self):
- super().__init__()
- self._features = {}
- self._properties = {}
-
- @staticmethod
- def newInstance(unused: Any = None, unused_cls: Any = None) -> "XmlPullParserFactory":
- return XmlPullParserFactory()
-
- def setFeature(self, name: str, value: bool):
- self._features[name] = value
-
- def getFeature(self, name: str) -> bool:
- return self._features.get(name, False)
-
- def setProperty(self, name: str, value: Any):
- self._properties[name] = value
-
- def getProperty(self, name: str):
- return self._properties.get(name)
-
- def newPullParser(self) -> XmlPullParser:
- """Creates a new XmlPullParser."""
- return XmlPullParser()
-
- def newSerializer(self) -> XmlSerializer:
- """Creates a new XmlSerializer."""
- return XmlSerializer()
-
- def isNamespaceAware(self) -> bool:
- return self.getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES)
-
- def isValidating(self) -> bool:
- return self.getFeature(XmlPullParser.FEATURE_VALIDATION)
-
- def toString(self) -> str:
- return f"XmlPullParserFactory@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Factory (alias)
-# ============================================================
-
-class Factory(XmlPullParserFactory):
- """
- Factory alias for XmlPullParserFactory.
- """
- def __init__(self):
- super().__init__()
-
- @staticmethod
- def newInstance(unused: Any = None, unused_cls: Any = None) -> "Factory":
- return Factory()
-
- @staticmethod
- def getInstance() -> "Factory":
- return Factory()
-
- def toString(self) -> str:
- return f"Factory@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return isinstance(other, Factory)
-
- def hashCode(self) -> int:
- return hash("Factory") & 0x7FFFFFFF
\ No newline at end of file
diff --git a/android_pyapi/org/xml_sax.py b/android_pyapi/org/xml_sax.py
deleted file mode 100644
index 167b1b6..0000000
--- a/android_pyapi/org/xml_sax.py
+++ /dev/null
@@ -1,890 +0,0 @@
-"""
-Java org.xml.sax APIs implemented in Python.
-org.xml.sax package - XMLReader, ContentHandler, SAXException, etc.
-Wraps Python xml.sax module.
-"""
-
-from __future__ import annotations
-
-from .._core import Stub, AndroidOnlyError
-import xml.sax as _sax
-import xml.sax.handler as _handler
-import xml.sax.xmlreader as _reader
-from typing import List, Optional
-
-__all__ = [
- "XMLReader", "ContentHandler", "DTDHandler", "EntityResolver",
- "ErrorHandler", "InputSource", "SAXException", "SAXParseException",
- "SAXNotRecognizedException", "SAXNotSupportedException",
- "Locator", "Attributes", "AttributeList", "HandlerBase",
- "DocumentHandler", "XMLFilter", "XMLFilterImpl", "DefaultHandler",
- "Helpers",
-]
-
-
-# ============================================================
-# SAXException
-# ============================================================
-
-class SAXException(Exception, Stub):
- """
- org.xml.sax.SAXException
- Encapsulate a general SAX error or warning.
- """
- def __init__(self, message: str = "", exception: Exception = None):
- super().__init__(message)
- self._message = message
- self._exception = exception
-
- def getMessage(self) -> str:
- return self._message
-
- def getException(self) -> Optional[Exception]:
- return self._exception
-
- def toString(self) -> str:
- return f"SAXException: {self._message}"
-
- def equals(self, other) -> bool:
- if isinstance(other, SAXException):
- return self._message == other._message
- return False
-
- def hashCode(self) -> int:
- return hash(self._message) & 0x7FFFFFFF
-
-
-class SAXParseException(SAXException):
- """
- org.xml.sax.SAXParseException
- Encapsulate an XML parse error or warning.
- """
- def __init__(self, message: str = "", public_id: str = "", system_id: str = "",
- line: int = -1, column: int = -1, exception: Exception = None):
- super().__init__(message, exception)
- self._public_id = public_id
- self._system_id = system_id
- self._line = line
- self._column = column
-
- def getPublicId(self) -> str:
- return self._public_id
-
- def getSystemId(self) -> str:
- return self._system_id
-
- def getLineNumber(self) -> int:
- return self._line
-
- def getColumnNumber(self) -> int:
- return self._column
-
- def toString(self) -> str:
- return f"SAXParseException[line={self._line}, col={self._column}]: {self._message}"
-
- def equals(self, other) -> bool:
- if isinstance(other, SAXParseException):
- return (self._line == other._line and
- self._column == other._column and
- self._message == other._message)
- return False
-
- def hashCode(self) -> int:
- return hash((self._line, self._column, self._message)) & 0x7FFFFFFF
-
-
-class SAXNotRecognizedException(SAXException):
- """
- org.xml.sax.SAXNotRecognizedException
- Exception for unrecognized feature or property.
- """
- def __init__(self, message: str = ""):
- super().__init__(message or "Feature or property not recognized")
-
- def toString(self) -> str:
- return f"SAXNotRecognizedException: {self._message}"
-
- def equals(self, other) -> bool:
- return isinstance(other, SAXNotRecognizedException)
-
- def hashCode(self) -> int:
- return hash("SAXNotRecognizedException") & 0x7FFFFFFF
-
-
-class SAXNotSupportedException(SAXException):
- """
- org.xml.sax.SAXNotSupportedException
- Exception for unsupported feature or property.
- """
- def __init__(self, message: str = ""):
- super().__init__(message or "Feature or property not supported")
-
- def toString(self) -> str:
- return f"SAXNotSupportedException: {self._message}"
-
- def equals(self, other) -> bool:
- return isinstance(other, SAXNotSupportedException)
-
- def hashCode(self) -> int:
- return hash("SAXNotSupportedException") & 0x7FFFFFFF
-
-
-# ============================================================
-# Locator
-# ============================================================
-
-class Locator(Stub):
- """
- org.xml.sax.Locator
- Interface for associating a SAX event with a document location.
- """
- def __init__(self, public_id: str = "", system_id: str = "",
- line: int = -1, column: int = -1):
- super().__init__()
- self._public_id = public_id
- self._system_id = system_id
- self._line = line
- self._column = column
-
- def getPublicId(self) -> str:
- return self._public_id
-
- def getSystemId(self) -> str:
- return self._system_id
-
- def getLineNumber(self) -> int:
- return self._line
-
- def getColumnNumber(self) -> int:
- return self._column
-
- def toString(self) -> str:
- return f"Locator[line={self._line}, col={self._column}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# InputSource
-# ============================================================
-
-class InputSource(Stub):
- """
- org.xml.sax.InputSource
- A single input source for a SAX parser.
- """
- def __init__(self, system_id: str = None, byte_stream=None,
- character_stream=None, encoding: str = None):
- super().__init__()
- self._public_id = None
- self._system_id = system_id
- self._byte_stream = byte_stream
- self._character_stream = character_stream
- self._encoding = encoding
-
- def getPublicId(self) -> Optional[str]:
- return self._public_id
-
- def setPublicId(self, public_id: str):
- self._public_id = public_id
-
- def getSystemId(self) -> Optional[str]:
- return self._system_id
-
- def setSystemId(self, system_id: str):
- self._system_id = system_id
-
- def getByteStream(self):
- return self._byte_stream
-
- def setByteStream(self, byte_stream):
- self._byte_stream = byte_stream
-
- def getEncoding(self) -> Optional[str]:
- return self._encoding
-
- def setEncoding(self, encoding: str):
- self._encoding = encoding
-
- def getCharacterStream(self):
- return self._character_stream
-
- def setCharacterStream(self, character_stream):
- self._character_stream = character_stream
-
- def toString(self) -> str:
- return f"InputSource[systemId={self._system_id}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Attributes
-# ============================================================
-
-class Attributes(Stub):
- """
- org.xml.sax.Attributes
- Interface for a list of XML attributes.
- """
- def __init__(self, attrs: List[dict] = None):
- super().__init__()
- self._attrs = attrs or []
-
- def getLength(self) -> int:
- return len(self._attrs)
-
- def getURI(self, index: int) -> str:
- if 0 <= index < len(self._attrs):
- return self._attrs[index].get("uri", "")
- return ""
-
- def getLocalName(self, index: int) -> str:
- if 0 <= index < len(self._attrs):
- return self._attrs[index].get("localName", "")
- return ""
-
- def getQName(self, index: int) -> str:
- if 0 <= index < len(self._attrs):
- return self._attrs[index].get("qname", "")
- return ""
-
- def getType(self, index_or_name: Any) -> str:
- if isinstance(index_or_name, int):
- if 0 <= index_or_name < len(self._attrs):
- return self._attrs[index_or_name].get("type", "CDATA")
- return ""
- for attr in self._attrs:
- if attr.get("qname") == index_or_name:
- return attr.get("type", "CDATA")
- return ""
-
- def getValue(self, index_or_name: Any) -> str:
- if isinstance(index_or_name, int):
- if 0 <= index_or_name < len(self._attrs):
- return self._attrs[index_or_name].get("value", "")
- return ""
- for attr in self._attrs:
- if attr.get("qname") == index_or_name:
- return attr.get("value", "")
- return ""
-
- def getIndex(self, qname_or_uri: str, local_name: str = None) -> int:
- if local_name is None:
- for i, attr in enumerate(self._attrs):
- if attr.get("qname") == qname_or_uri:
- return i
- else:
- for i, attr in enumerate(self._attrs):
- if attr.get("uri") == qname_or_uri and attr.get("localName") == local_name:
- return i
- return -1
-
- def getIndexByQName(self, qname: str) -> int:
- return self.getIndex(qname)
-
- def getIndexByURI(self, uri: str, local_name: str) -> int:
- return self.getIndex(uri, local_name)
-
- def toString(self) -> str:
- return f"Attributes@{hex(id(self))}[length={len(self._attrs)}]"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# AttributeList (deprecated)
-# ============================================================
-
-class AttributeList(Stub):
- """
- org.xml.sax.AttributeList
- Deprecated SAX1 interface for attribute list.
- """
- def __init__(self):
- super().__init__()
- self._attrs = []
-
- def getLength(self) -> int:
- return len(self._attrs)
-
- def getName(self, index: int) -> str:
- if 0 <= index < len(self._attrs):
- return self._attrs[index].get("name", "")
- return ""
-
- def getType(self, index_or_name: Any) -> str:
- if isinstance(index_or_name, int):
- if 0 <= index_or_name < len(self._attrs):
- return self._attrs[index_or_name].get("type", "CDATA")
- return ""
- for attr in self._attrs:
- if attr.get("name") == index_or_name:
- return attr.get("type", "CDATA")
- return ""
-
- def getValue(self, index_or_name: Any) -> str:
- if isinstance(index_or_name, int):
- if 0 <= index_or_name < len(self._attrs):
- return self._attrs[index_or_name].get("value", "")
- return ""
- for attr in self._attrs:
- if attr.get("name") == index_or_name:
- return attr.get("value", "")
- return ""
-
- def toString(self) -> str:
- return f"AttributeList@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# ContentHandler
-# ============================================================
-
-class ContentHandler(Stub):
- """
- org.xml.sax.ContentHandler
- Interface for receiving SAX content events.
- """
- def setDocumentLocator(self, locator: Locator):
- pass
-
- def startDocument(self):
- pass
-
- def endDocument(self):
- pass
-
- def startPrefixMapping(self, prefix: str, uri: str):
- pass
-
- def endPrefixMapping(self, prefix: str):
- pass
-
- def startElement(self, namespace_uri: str, local_name: str, qname: str, atts: Attributes):
- pass
-
- def endElement(self, namespace_uri: str, local_name: str, qname: str):
- pass
-
- def characters(self, ch: str, start: int, length: int):
- pass
-
- def ignorableWhitespace(self, ch: str, start: int, length: int):
- pass
-
- def processingInstruction(self, target: str, data: str):
- pass
-
- def skippedEntity(self, name: str):
- pass
-
- def toString(self) -> str:
- return f"ContentHandler@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DTDHandler
-# ============================================================
-
-class DTDHandler(Stub):
- """
- org.xml.sax.DTDHandler
- Interface for receiving DTD events.
- """
- def notationDecl(self, name: str, public_id: str, system_id: str):
- pass
-
- def unparsedEntityDecl(self, name: str, public_id: str, system_id: str,
- notation_name: str):
- pass
-
- def toString(self) -> str:
- return f"DTDHandler@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# EntityResolver
-# ============================================================
-
-class EntityResolver(Stub):
- """
- org.xml.sax.EntityResolver
- Interface for resolving entities.
- """
- def resolveEntity(self, public_id: str, system_id: str) -> InputSource:
- return InputSource(system_id)
-
- def toString(self) -> str:
- return f"EntityResolver@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# ErrorHandler
-# ============================================================
-
-class ErrorHandler(Stub):
- """
- org.xml.sax.ErrorHandler
- Interface for receiving SAX error events.
- """
- def warning(self, exception: SAXParseException):
- pass
-
- def error(self, exception: SAXParseException):
- pass
-
- def fatalError(self, exception: SAXParseException):
- raise exception
-
- def toString(self) -> str:
- return f"ErrorHandler@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# HandlerBase (deprecated SAX1)
-# ============================================================
-
-class HandlerBase(Stub):
- """
- org.xml.sax.HandlerBase
- Deprecated SAX1 base class for handlers.
- """
- def setDocumentLocator(self, locator: Locator): pass
- def startDocument(self): pass
- def endDocument(self): pass
- def startElement(self, name: str, atts: AttributeList): pass
- def endElement(self, name: str): pass
- def characters(self, ch: str, start: int, length: int): pass
- def ignorableWhitespace(self, ch: str, start: int, length: int): pass
- def processingInstruction(self, target: str, data: str): pass
- def notationDecl(self, name: str, public_id: str, system_id: str): pass
- def unparsedEntityDecl(self, name: str, public_id: str, system_id: str, notation_name: str): pass
- def resolveEntity(self, public_id: str, system_id: str) -> InputSource: return InputSource(system_id)
- def warning(self, exception: SAXParseException): pass
- def error(self, exception: SAXParseException): pass
- def fatalError(self, exception: SAXParseException): raise exception
-
- def toString(self) -> str:
- return f"HandlerBase@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DocumentHandler (deprecated SAX1)
-# ============================================================
-
-class DocumentHandler(Stub):
- """
- org.xml.sax.DocumentHandler
- Deprecated SAX1 interface for document handlers.
- """
- def setDocumentLocator(self, locator: Locator): pass
- def startDocument(self): pass
- def endDocument(self): pass
- def startElement(self, name: str, atts: AttributeList): pass
- def endElement(self, name: str): pass
- def characters(self, ch: str, start: int, length: int): pass
- def ignorableWhitespace(self, ch: str, start: int, length: int): pass
- def processingInstruction(self, target: str, data: str): pass
-
- def toString(self) -> str:
- return f"DocumentHandler@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# XMLReader
-# ============================================================
-
-class XMLReader(Stub):
- """
- org.xml.sax.XMLReader
- Interface for reading an XML document using callbacks.
- Wraps Python xml.sax.
- """
-
- def __init__(self):
- super().__init__()
- self._content_handler = None
- self._dtd_handler = None
- self._error_handler = None
- self._entity_resolver = None
- self._locale = None
- self._features = {}
- self._properties = {}
-
- def parse(self, input_source: Any):
- """
- Parse an XML document from an InputSource or system ID.
- """
- if isinstance(input_source, InputSource):
- sys_id = input_source.getSystemId()
- elif isinstance(input_source, str):
- sys_id = input_source
- else:
- sys_id = str(input_source)
-
- try:
- parser = _sax.make_parser()
- if self._content_handler:
- parser.setContentHandler(self._content_handler)
- if self._error_handler:
- parser.setErrorHandler(self._error_handler)
- if self._dtd_handler:
- parser.setDTDHandler(self._dtd_handler)
- if self._entity_resolver:
- parser.setEntityResolver(self._entity_resolver)
- parser.parse(sys_id)
- except _sax.SAXException as e:
- if self._error_handler:
- self._error_handler.fatalError(
- SAXParseException(str(e), "", sys_id, 0, 0))
- raise SAXException(str(e)) from e
-
- def setContentHandler(self, handler: ContentHandler):
- self._content_handler = handler
-
- def getContentHandler(self) -> Optional[ContentHandler]:
- return self._content_handler
-
- def setDTDHandler(self, handler: DTDHandler):
- self._dtd_handler = handler
-
- def getDTDHandler(self) -> Optional[DTDHandler]:
- return self._dtd_handler
-
- def setErrorHandler(self, handler: ErrorHandler):
- self._error_handler = handler
-
- def getErrorHandler(self) -> Optional[ErrorHandler]:
- return self._error_handler
-
- def setEntityResolver(self, resolver: EntityResolver):
- self._entity_resolver = resolver
-
- def getEntityResolver(self) -> Optional[EntityResolver]:
- return self._entity_resolver
-
- def setLocale(self, locale):
- self._locale = locale
-
- def getFeature(self, name: str) -> bool:
- return self._features.get(name, False)
-
- def setFeature(self, name: str, value: bool):
- if name == "http://xml.org/sax/features/namespaces":
- self._features[name] = value
- elif name == "http://xml.org/sax/features/validation":
- self._features[name] = value
- elif name == "http://xml.org/sax/features/external-general-entities":
- self._features[name] = value
- elif name == "http://xml.org/sax/features/external-parameter-entities":
- self._features[name] = value
- else:
- raise SAXNotRecognizedException(f"Feature not recognized: {name}")
-
- def getProperty(self, name: str) -> Any:
- return self._properties.get(name)
-
- def setProperty(self, name: str, value: Any):
- if name == "http://xml.org/sax/properties/lexical-handler":
- self._properties[name] = value
- else:
- raise SAXNotRecognizedException(f"Property not recognized: {name}")
-
- def toString(self) -> str:
- return f"XMLReader@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# XMLFilter
-# ============================================================
-
-class XMLFilter(XMLReader):
- """
- org.xml.sax.XMLFilter
- Interface for an XML filter.
- """
- def setParent(self, parent: XMLReader):
- self._parent = parent
-
- def getParent(self) -> Optional[XMLReader]:
- return getattr(self, '_parent', None)
-
- def toString(self) -> str:
- return f"XMLFilter@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# XMLFilterImpl
-# ============================================================
-
-class XMLFilterImpl(XMLFilter, ContentHandler, DTDHandler, EntityResolver, ErrorHandler):
- """
- org.xml.sax.helpers.XMLFilterImpl
- Base class for XML filters with default implementation.
- """
-
- def __init__(self):
- super().__init__()
- self._parent = None
-
- def setParent(self, parent: XMLReader):
- self._parent = parent
-
- def getParent(self) -> Optional[XMLReader]:
- return self._parent
-
- def parse(self, input_source: Any):
- if self._parent:
- self._parent.setContentHandler(self)
- self._parent.setDTDHandler(self)
- self._parent.setEntityResolver(self)
- self._parent.setErrorHandler(self)
- self._parent.parse(input_source)
-
- # ContentHandler delegation
- def setContentHandler(self, handler: ContentHandler):
- self._content_handler = handler
-
- def getContentHandler(self) -> Optional[ContentHandler]:
- return getattr(self, '_content_handler', None)
-
- def setDTDHandler(self, handler: DTDHandler):
- self._dtd_handler = handler
-
- def getDTDHandler(self) -> Optional[DTDHandler]:
- return getattr(self, '_dtd_handler', None)
-
- def setEntityResolver(self, resolver: EntityResolver):
- self._entity_resolver = resolver
-
- def getEntityResolver(self) -> Optional[EntityResolver]:
- return getattr(self, '_entity_resolver', None)
-
- def setErrorHandler(self, handler: ErrorHandler):
- self._error_handler = handler
-
- def getErrorHandler(self) -> Optional[ErrorHandler]:
- return getattr(self, '_error_handler', None)
-
- def setLocale(self, locale): pass
-
- def getFeature(self, name: str) -> bool:
- return False
-
- def setFeature(self, name: str, value: bool): pass
-
- def getProperty(self, name: str): return None
-
- def setProperty(self, name: str, value): pass
-
- # Delegated implementations
- def resolveEntity(self, public_id: str, system_id: str) -> InputSource:
- if self._entity_resolver:
- return self._entity_resolver.resolveEntity(public_id, system_id)
- return InputSource(system_id)
-
- def notationDecl(self, name: str, public_id: str, system_id: str):
- if self._dtd_handler:
- self._dtd_handler.notationDecl(name, public_id, system_id)
-
- def unparsedEntityDecl(self, name: str, public_id: str, system_id: str, notation_name: str):
- if self._dtd_handler:
- self._dtd_handler.unparsedEntityDecl(name, public_id, system_id, notation_name)
-
- def setDocumentLocator(self, locator: Locator):
- if self._content_handler:
- self._content_handler.setDocumentLocator(locator)
-
- def startDocument(self):
- if self._content_handler:
- self._content_handler.startDocument()
-
- def endDocument(self):
- if self._content_handler:
- self._content_handler.endDocument()
-
- def startPrefixMapping(self, prefix: str, uri: str):
- if self._content_handler:
- self._content_handler.startPrefixMapping(prefix, uri)
-
- def endPrefixMapping(self, prefix: str):
- if self._content_handler:
- self._content_handler.endPrefixMapping(prefix)
-
- def startElement(self, namespace_uri: str, local_name: str, qname: str, atts: Attributes):
- if self._content_handler:
- self._content_handler.startElement(namespace_uri, local_name, qname, atts)
-
- def endElement(self, namespace_uri: str, local_name: str, qname: str):
- if self._content_handler:
- self._content_handler.endElement(namespace_uri, local_name, qname)
-
- def characters(self, ch: str, start: int, length: int):
- if self._content_handler:
- self._content_handler.characters(ch, start, length)
-
- def ignorableWhitespace(self, ch: str, start: int, length: int):
- if self._content_handler:
- self._content_handler.ignorableWhitespace(ch, start, length)
-
- def processingInstruction(self, target: str, data: str):
- if self._content_handler:
- self._content_handler.processingInstruction(target, data)
-
- def skippedEntity(self, name: str):
- if self._content_handler:
- self._content_handler.skippedEntity(name)
-
- def warning(self, exception: SAXParseException):
- if self._error_handler:
- self._error_handler.warning(exception)
-
- def error(self, exception: SAXParseException):
- if self._error_handler:
- self._error_handler.error(exception)
-
- def fatalError(self, exception: SAXParseException):
- if self._error_handler:
- self._error_handler.fatalError(exception)
- raise exception
-
- def toString(self) -> str:
- return f"XMLFilterImpl@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# DefaultHandler
-# ============================================================
-
-class DefaultHandler(ContentHandler, DTDHandler, EntityResolver, ErrorHandler):
- """
- org.xml.sax.helpers.DefaultHandler
- Default base class for SAX2 event handlers.
- """
- def setDocumentLocator(self, locator: Locator): pass
- def startDocument(self): pass
- def endDocument(self): pass
- def startPrefixMapping(self, prefix: str, uri: str): pass
- def endPrefixMapping(self, prefix: str): pass
- def startElement(self, namespace_uri: str, local_name: str, qname: str, atts: Attributes): pass
- def endElement(self, namespace_uri: str, local_name: str, qname: str): pass
- def characters(self, ch: str, start: int, length: int): pass
- def ignorableWhitespace(self, ch: str, start: int, length: int): pass
- def processingInstruction(self, target: str, data: str): pass
- def skippedEntity(self, name: str): pass
- def notationDecl(self, name: str, public_id: str, system_id: str): pass
- def unparsedEntityDecl(self, name: str, public_id: str, system_id: str, notation_name: str): pass
- def resolveEntity(self, public_id: str, system_id: str) -> InputSource: return InputSource(system_id)
- def warning(self, exception: SAXParseException): pass
- def error(self, exception: SAXParseException): pass
- def fatalError(self, exception: SAXParseException): raise exception
-
- def toString(self) -> str:
- return f"DefaultHandler@{hex(id(self))}"
-
- def equals(self, other) -> bool:
- return self is other
-
- def hashCode(self) -> int:
- return hash(self) & 0x7FFFFFFF
-
-
-# ============================================================
-# Helpers (stub)
-# ============================================================
-
-class Helpers(Stub):
- """
- org.xml.sax.helpers (namespace placeholder)
- """
- @staticmethod
- def makeParser(parser_class: str = None):
- return XMLReader()
-
- @staticmethod
- def parseXML(source: Any, handler: ContentHandler):
- reader = XMLReader()
- reader.setContentHandler(handler)
- reader.parse(source)
-
- def toString(self) -> str:
- return "Helpers"
-
- def equals(self, other) -> bool:
- return isinstance(other, Helpers)
-
- def hashCode(self) -> int:
- return hash("Helpers") & 0x7FFFFFFF
\ No newline at end of file
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 07c3838..0000000
--- a/setup.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from setuptools import setup, find_packages
-from pathlib import Path
-
-long_description = Path("README.md").read_text(encoding="utf-8")
-
-setup(
- name="android-pyapi",
- version="1.0.0",
- description="Android API for Python — 在桌面/Linux 上原生运行 Android API",
- long_description=long_description,
- long_description_content_type="text/markdown",
- license="MIT",
- author="shuiyu1123",
- url="https://gitee.com/shuiyu1123/Android-pyApi",
- packages=find_packages(),
- python_requires=">=3.8",
- install_requires=[
- # 核心依赖(全部可选,缺失时自动降级)
- ],
- extras_require={
- "linux": [
- "psutil",
- "requests",
- "Pillow",
- "opencv-python",
- "numpy",
- ],
- "windows": [
- "psutil",
- "requests",
- "Pillow",
- "opencv-python",
- "numpy",
- "pyautogui",
- "pyperclip",
- "screeninfo",
- "pywin32",
- "wmi",
- "pycaw",
- "comtypes",
- "win10toast",
- ],
- "dev": [
- "pytest",
- "pytest-cov",
- ],
- },
- classifiers=[
- "Development Status :: 4 - Beta",
- "Intended Audience :: Developers",
- "License :: OSI Approved :: MIT License",
- "Operating System :: POSIX :: Linux",
- "Operating System :: MacOS",
- "Operating System :: Microsoft :: Windows",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "Topic :: Software Development :: Libraries :: Python Modules",
- "Topic :: System :: Hardware",
- ],
-)
diff --git a/test_scripts/network_test.js b/test_scripts/network_test.js
deleted file mode 100644
index e69de29..0000000
diff --git a/test_scripts/quick_start.js b/test_scripts/quick_start.js
deleted file mode 100644
index e69de29..0000000
diff --git a/test_scripts/system_tools.js b/test_scripts/system_tools.js
deleted file mode 100644
index e69de29..0000000
diff --git a/test_scripts/test_android_api.py b/test_scripts/test_android_api.py
deleted file mode 100644
index 545bd7c..0000000
--- a/test_scripts/test_android_api.py
+++ /dev/null
@@ -1,141 +0,0 @@
-"""
-Android API 综合测试脚本
-测试 Android-pyApi 的核心 API 功能
-"""
-
-import sys
-import os
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from android_pyapi import (
- Intent, Uri, Bundle, ComponentName,
- ArrayList, HashMap, HashSet, JSONObject, JSONArray,
- String, StringBuilder, Integer, Math, System, Thread,
- File, FileInputStream, FileOutputStream,
- Log, Base64, Scanner,
- Calendar, Date, SimpleDateFormat,
-)
-
-
-def test_intent():
- """测试 Intent"""
- print("\n[Intent 测试]")
- intent = Intent("android.intent.action.VIEW")
- intent.setData(Uri.parse("https://example.com"))
- intent.putExtra("key1", "value1")
- intent.putExtra("key2", 42)
- print(f" Action: {intent.getAction()}")
- print(f" Data: {intent.getData()}")
- print(f" Extra String: {intent.getStringExtra('key1')}")
- print(f" Extra Int: {intent.getIntExtra('key2', 0)}")
-
-
-def test_collections():
- """测试集合类"""
- print("\n[集合类测试]")
- lst = ArrayList()
- lst.add("Apple")
- lst.add("Banana")
- lst.add("Cherry")
- print(f" ArrayList size: {lst.size()}")
- print(f" First: {lst.get(0)}")
-
- m = HashMap()
- m.put("name", "Android-pyApi")
- m.put("version", "1.0.0")
- print(f" HashMap get: {m.get('name')}")
-
- json = JSONObject()
- json.put("platform", "Windows")
- json.put("ok", True)
- print(f" JSONObject: {json.toString()}")
-
-
-def test_string():
- """测试字符串类"""
- print("\n[字符串测试]")
- s = String("Hello, Android-pyApi!")
- print(f" Length: {s.length()}")
- print(f" Upper: {s.toUpperCase()}")
- print(f" Contains 'Android': {s.contains('Android')}")
-
- sb = StringBuilder()
- sb.append("Hello")
- sb.append(", World!")
- print(f" StringBuilder: {sb.toString()}")
-
-
-def test_file():
- """测试文件类"""
- print("\n[文件测试]")
- import tempfile
- temp_file = os.path.join(tempfile.gettempdir(), "android_pyapi_test.txt")
-
- f = File(temp_file)
- print(f" Path: {f.getAbsolutePath()}")
-
- with open(temp_file, 'w') as file:
- file.write("Android-pyApi test")
-
- print(f" Exists: {f.exists()}")
- print(f" Name: {f.getName()}")
- print(f" Size: {f.length()} bytes")
-
- os.remove(temp_file)
- print(f" After delete: {f.exists()}")
-
-
-def test_base64():
- """测试 Base64"""
- print("\n[Base64 测试]")
- text = "Hello, Android-pyApi!"
- encoded = Base64.encodeToString(text.encode('utf-8'))
- decoded = Base64.decode(encoded).decode('utf-8')
- print(f" Original: {text}")
- print(f" Encoded: {encoded}")
- print(f" Decoded: {decoded}")
- print(f" Match: {text == decoded}")
-
-
-def test_math():
- """测试数学类"""
- print("\n[数学测试]")
- print(f" PI: {Math.PI}")
- print(f" abs(-42): {Math.abs(-42)}")
- print(f" max(10, 20): {Math.max(10, 20)}")
- print(f" sqrt(144): {Math.sqrt(144)}")
- print(f" pow(2, 10): {Math.pow(2, 10)}")
-
-
-def test_calendar():
- """测试日历类"""
- print("\n[日历测试]")
- cal = Calendar.getInstance()
- print(f" Year: {cal.get(Calendar.YEAR)}")
- print(f" Month: {cal.get(Calendar.MONTH) + 1}")
- print(f" Day: {cal.get(Calendar.DAY_OF_MONTH)}")
- print(f" Hour: {cal.get(Calendar.HOUR_OF_DAY)}")
- print(f" Minute: {cal.get(Calendar.MINUTE)}")
-
-
-def main():
- """主测试函数"""
- print("=" * 60)
- print("Android-pyApi 综合测试")
- print("=" * 60)
-
- test_intent()
- test_collections()
- test_string()
- test_file()
- test_base64()
- test_math()
- test_calendar()
-
- print("\n" + "=" * 60)
- print("所有测试完成!")
- print("=" * 60)
-
-
-if __name__ == "__main__":
- main()
diff --git a/test_scripts/test_extended_api.py b/test_scripts/test_extended_api.py
deleted file mode 100644
index 5f09fd8..0000000
--- a/test_scripts/test_extended_api.py
+++ /dev/null
@@ -1,400 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-扩展 Android API 测试脚本
-测试 android.os, android.content, android.app, android.widget, android.graphics 等模块
-"""
-
-import sys
-import os
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-def test_os_module():
- """测试 android.os 模块"""
- print("\n" + "=" * 60)
- print("android.os 模块测试")
- print("=" * 60)
-
- from android_pyapi.android.os import (
- Build, SystemClock, Environment, Process,
- Bundle, Handler, Looper, Message,
- BatteryManager, PowerManager, Vibrator,
- AsyncTask, CountDownTimer, Messenger,
- FileObserver, FileUtils, PatternMatcher,
- )
-
- # Build 测试
- print("\n[Build 设备信息]")
- print(f" MODEL: {Build.MODEL}")
- print(f" MANUFACTURER: {Build.MANUFACTURER}")
- print(f" BRAND: {Build.BRAND}")
- print(f" DEVICE: {Build.DEVICE}")
- print(f" FINGERPRINT: {Build.FINGERPRINT}")
- print(f" SDK_INT: {Build.VERSION.SDK_INT}")
- print(f" RELEASE: {Build.VERSION.RELEASE}")
-
- # SystemClock 测试
- print("\n[SystemClock 系统时钟]")
- print(f" 启动时间: {SystemClock.elapsedRealtime()} ms")
- print(f" 运行时间: {SystemClock.uptimeMillis()} ms")
-
- # Environment 测试
- print("\n[Environment 环境目录]")
- print(f" 外部存储: {Environment.getExternalStorageDirectory()}")
- print(f" 下载目录: {Environment.getExternalStoragePublicDirectory('Download')}")
- print(f" 数据目录: {Environment.getDataDirectory()}")
- print(f" 根目录: {Environment.getRootDirectory()}")
-
- # Process 测试
- print("\n[Process 进程信息]")
- print(f" PID: {Process.myPid()}")
- print(f" TID: {Process.myTid()}")
-
- # Bundle 测试
- print("\n[Bundle 数据容器]")
- bundle = Bundle()
- bundle.putString("name", "Android-pyApi")
- bundle.putInt("version", 100)
- bundle.putBoolean("windows", True)
- print(f" name: {bundle.getString('name')}")
- print(f" version: {bundle.getInt('version')}")
- print(f" windows: {bundle.getBoolean('windows')}")
- print(f" size: {bundle.size()}")
-
- # BatteryManager 测试
- print("\n[BatteryManager 电池管理]")
- bm = BatteryManager()
- print(f" 电量: {bm.getLevel()}%")
- print(f" 充电: {bm.isCharging()}")
- print(f" 存在: {bm.isPresent()}")
- print(f" 技术: {bm.getTechnology()}")
-
- # PowerManager 测试
- print("\n[PowerManager 电源管理]")
- pm = PowerManager()
- print(f" 交互: {pm.isInteractive()}")
- print(f" 屏幕: {pm.isScreenOn()}")
-
- # Vibrator 测试
- print("\n[Vibrator 振动器]")
- vib = Vibrator()
- print(f" 有振动器: {vib.hasVibrator()}")
-
- # PatternMatcher 测试
- print("\n[PatternMatcher 模式匹配]")
- pm_literal = PatternMatcher("/sdcard/test.txt", PatternMatcher.PATTERN_LITERAL)
- pm_prefix = PatternMatcher("/sdcard/", PatternMatcher.PATTERN_PREFIX)
- print(f" literal match: {pm_literal.match('/sdcard/test.txt')}")
- print(f" prefix match: {pm_prefix.match('/sdcard/test.txt')}")
-
- # FileUtils 测试
- print("\n[FileUtils 文件工具]")
- test_file = os.path.join(os.environ.get('TEMP', '/tmp'), 'android_pyapi_test.txt')
- FileUtils.stringToFile(test_file, "Hello, Android-pyApi!")
- content = FileUtils.readFileToString(test_file)
- print(f" 写入读取: {content}")
- os.remove(test_file)
-
-
-def test_content_module():
- """测试 android.content 模块"""
- print("\n" + "=" * 60)
- print("android.content 模块测试")
- print("=" * 60)
-
- from android_pyapi.android.content import (
- Uri, ContentValues, ContentResolver, Context,
- SharedPreferences, IntentFilter, BroadcastReceiver,
- ComponentName, ClipData, ClipDescription,
- ContentProvider, ContentProviderClient,
- ClipboardManager,
- )
-
- # Uri 测试
- print("\n[Uri 统一资源标识符]")
- uri = Uri.parse("https://example.com/path?query=1&foo=bar#fragment")
- print(f" scheme: {uri.getScheme()}")
- print(f" host: {uri.getHost()}")
- print(f" path: {uri.getPath()}")
- print(f" query: {uri.getQuery()}")
- print(f" fragment: {uri.getFragment()}")
- print(f" toString: {uri.toString()}")
-
- # ContentValues 测试
- print("\n[ContentValues 内容值]")
- cv = ContentValues()
- cv.put("title", "Test")
- cv.put("value", 42)
- cv.put("flag", True)
- print(f" title: {cv.getAsString('title')}")
- print(f" value: {cv.getAsInteger('value')}")
- print(f" flag: {cv.getAsBoolean('flag')}")
- print(f" size: {cv.size()}")
-
- # Context 测试
- print("\n[Context 应用上下文]")
- ctx = Context()
- print(f" packageName: {ctx.getPackageName()}")
- print(f" filesDir: {ctx.getFilesDir()}")
- print(f" cacheDir: {ctx.getCacheDir()}")
- print(f" dataDir: {ctx.getDataDir()}")
-
- # SharedPreferences 测试
- print("\n[SharedPreferences 持久化存储]")
- sp = ctx.getSharedPreferences("test_prefs")
- editor = sp.edit()
- editor.putString("username", "test_user")
- editor.putInt("login_count", 5)
- editor.putBoolean("remember", True)
- editor.commit()
- print(f" username: {sp.getString('username')}")
- print(f" login_count: {sp.getInt('login_count')}")
- print(f" remember: {sp.getBoolean('remember')}")
-
- # ComponentName 测试
- print("\n[ComponentName 组件名]")
- cn = ComponentName("com.example.app", "com.example.app.MainActivity")
- print(f" package: {cn.getPackageName()}")
- print(f" class: {cn.getClassName()}")
- print(f" short: {cn.getShortClassName()}")
- print(f" flatten: {cn.flattenToString()}")
-
- # ClipData 测试
- print("\n[ClipData 剪贴板数据]")
- clip = ClipData.newPlainText("label", "Hello, Clipboard!")
- item = clip.getItemAt(0)
- print(f" text: {item.getText()}")
- print(f" itemCount: {clip.getItemCount()}")
-
- # ClipboardManager 测试
- print("\n[ClipboardManager 剪贴板管理]")
- cm = ClipboardManager()
- cm.setText("Test Clipboard")
- print(f" getText: {cm.getText()}")
- print(f" hasText: {cm.hasText()}")
-
-
-def test_app_module():
- """测试 android.app 模块"""
- print("\n" + "=" * 60)
- print("android.app 模块测试")
- print("=" * 60)
-
- from android_pyapi.android.app import (
- Intent, Activity, Service,
- Notification, NotificationManager,
- AlarmManager, ActivityManager,
- )
-
- # Intent 测试
- print("\n[Intent 意图]")
- intent = Intent(Intent.ACTION_VIEW)
- intent.setData("https://example.com")
- intent.putExtra("title", "Test")
- intent.putExtra("count", 42)
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- print(f" action: {intent.getAction()}")
- print(f" data: {intent.getData()}")
- print(f" title: {intent.getStringExtra('title')}")
- print(f" count: {intent.getIntExtra('count')}")
- print(f" flags: {hex(intent.getFlags())}")
-
- # Notification 测试
- print("\n[Notification 通知]")
- notif = Notification()
- notif.title = "Test Notification"
- notif.text = "This is a test"
- print(f" title: {notif.title}")
- print(f" text: {notif.text}")
-
- # NotificationManager 测试
- print("\n[NotificationManager 通知管理]")
- nm = NotificationManager()
- print(f" 类型: {type(nm).__name__}")
-
- # AlarmManager 测试
- print("\n[AlarmManager 闹钟管理]")
- am = AlarmManager()
- print(f" 类型: {type(am).__name__}")
-
-
-def test_widget_module():
- """测试 android.widget 模块"""
- print("\n" + "=" * 60)
- print("android.widget 模块测试")
- print("=" * 60)
-
- try:
- from android_pyapi.android.widget import (
- Toast, AlertDialog, Button, TextView,
- EditText, ListView, RecyclerView,
- )
-
- # Toast 测试
- print("\n[Toast 提示]")
- toast = Toast.makeText(None, "Hello, Toast!", Toast.LENGTH_SHORT)
- print(f" text: {toast._text}")
- print(f" duration: {toast._duration}")
-
- # AlertDialog 测试
- print("\n[AlertDialog 对话框]")
- dialog = AlertDialog(None)
- print(f" 类型: {type(dialog).__name__}")
-
- except ImportError as e:
- print(f" widget 模块导入失败: {e}")
-
-
-def test_graphics_module():
- """测试 android.graphics 模块"""
- print("\n" + "=" * 60)
- print("android.graphics 模块测试")
- print("=" * 60)
-
- try:
- from android_pyapi.android.graphics import (
- Bitmap, Canvas, Paint, Color,
- Rect, RectF, Path, Matrix,
- )
-
- # Color 测试
- print("\n[Color 颜色]")
- print(f" RED: {hex(Color.RED)}")
- print(f" GREEN: {hex(Color.GREEN)}")
- print(f" BLUE: {hex(Color.BLUE)}")
- print(f" WHITE: {hex(Color.WHITE)}")
- print(f" BLACK: {hex(Color.BLACK)}")
- print(f" argb(255,128,64,32): {hex(Color.argb(255, 128, 64, 32))}")
-
- # Bitmap 测试
- print("\n[Bitmap 位图]")
- bm = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
- print(f" width: {bm.getWidth()}")
- print(f" height: {bm.getHeight()}")
- print(f" config: {bm.getConfig()}")
-
- # Paint 测试
- print("\n[Paint 画笔]")
- paint = Paint()
- paint.setColor(Color.RED)
- paint.setTextSize(24.0)
- print(f" color: {hex(paint.getColor())}")
- print(f" textSize: {paint.getTextSize()}")
-
- # Rect 测试
- print("\n[Rect 矩形]")
- rect = Rect(10, 20, 100, 200)
- print(f" left: {rect.left}")
- print(f" top: {rect.top}")
- print(f" right: {rect.right}")
- print(f" bottom: {rect.bottom}")
- print(f" width: {rect.width()}")
- print(f" height: {rect.height()}")
-
- except ImportError as e:
- print(f" graphics 模块导入失败: {e}")
-
-
-def test_java_module():
- """测试 java 模块"""
- print("\n" + "=" * 60)
- print("java 模块测试")
- print("=" * 60)
-
- from android_pyapi.java.lang import (
- String, StringBuilder, Integer, Math, System, Thread,
- )
- from android_pyapi.java.io import (
- File, FileInputStream, FileOutputStream,
- )
- from android_pyapi.java.util import (
- ArrayList, HashMap, HashSet,
- )
- from android_pyapi.org.json import JSONObject, JSONArray
-
- # String 测试
- print("\n[String 字符串]")
- s = String("Hello, Android-pyApi!")
- print(f" length: {s.length()}")
- print(f" upper: {s.toUpperCase()}")
- print(f" contains('Android'): {s.contains('Android')}")
- print(f" substring(7): {s.substring(7)}")
-
- # StringBuilder 测试
- print("\n[StringBuilder 字符串构建器]")
- sb = StringBuilder()
- sb.append("Hello")
- sb.append(", ")
- sb.append("World!")
- print(f" result: {sb.toString()}")
- print(f" length: {sb.length()}")
-
- # Integer 测试
- print("\n[Integer 整数]")
- print(f" parseInt('42'): {Integer.parseInt('42')}")
- print(f" MAX_VALUE: {Integer.MAX_VALUE}")
- print(f" MIN_VALUE: {Integer.MIN_VALUE}")
-
- # Math 测试
- print("\n[Math 数学]")
- print(f" PI: {Math.PI}")
- print(f" abs(-42): {Math.abs(-42)}")
- print(f" max(10, 20): {Math.max(10, 20)}")
- print(f" sqrt(144): {Math.sqrt(144)}")
- print(f" pow(2, 10): {Math.pow(2, 10)}")
-
- # ArrayList 测试
- print("\n[ArrayList 列表]")
- lst = ArrayList()
- lst.add("Apple")
- lst.add("Banana")
- lst.add("Cherry")
- print(f" size: {lst.size()}")
- print(f" first: {lst.get(0)}")
- print(f" contains('Banana'): {lst.contains('Banana')}")
-
- # HashMap 测试
- print("\n[HashMap 哈希表]")
- m = HashMap()
- m.put("name", "Android-pyApi")
- m.put("version", "1.0.0")
- print(f" name: {m.get('name')}")
- print(f" size: {m.size()}")
- print(f" containsKey('name'): {m.containsKey('name')}")
-
- # JSONObject 测试
- print("\n[JSONObject JSON 对象]")
- json = JSONObject()
- json.put("platform", "Windows")
- json.put("python", True)
- json.put("version", 3.12)
- print(f" toString: {json.toString()}")
- print(f" platform: {json.getString('platform')}")
-
- # File 测试
- print("\n[File 文件]")
- f = File(os.environ.get('TEMP', '/tmp'), "test_file.txt")
- print(f" path: {f.getAbsolutePath()}")
- print(f" name: {f.getName()}")
- print(f" parent: {f.getParent()}")
-
-
-def main():
- """主测试函数"""
- print("=" * 60)
- print("Android-pyApi 扩展 API 测试")
- print("=" * 60)
-
- test_os_module()
- test_content_module()
- test_app_module()
- test_widget_module()
- test_graphics_module()
- test_java_module()
-
- print("\n" + "=" * 60)
- print("所有测试完成!")
- print("=" * 60)
-
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/test_scripts/test_network.py b/test_scripts/test_network.py
deleted file mode 100644
index 66ab82c..0000000
--- a/test_scripts/test_network.py
+++ /dev/null
@@ -1,73 +0,0 @@
-"""
-网络测试脚本 - 基于 Android-pyApi
-模拟 Operit 的 network_test.js 功能
-"""
-
-import sys
-import os
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from android_pyapi import (
- ConnectivityManager, NetworkInfo, Intent, Uri
-)
-from android_pyapi._windows_impl import WindowsNetwork
-
-
-def test_network():
- """测试网络功能"""
- print("=" * 60)
- print("Android-pyApi 网络测试")
- print("=" * 60)
-
- # 1. 获取 IP 地址
- print("\n[1] IP 地址:")
- ip = WindowsNetwork.get_ip_address()
- print(f" 本机 IP: {ip}")
-
- # 2. 网络连通性
- print("\n[2] 网络连通性:")
- connected = WindowsNetwork.get_connectivity()
- print(f" 连接状态: {'已连接' if connected else '未连接'}")
-
- # 3. WiFi 信息
- print("\n[3] WiFi 信息:")
- wifi = WindowsNetwork.get_wifi_info()
- print(f" SSID: {wifi.get('ssid', 'N/A') or 'N/A'}")
- print(f" 信号: {wifi.get('signal', 0)}%")
- print(f" 状态: {wifi.get('status', 'unknown')}")
-
- # 4. DNS 服务器
- print("\n[4] DNS 服务器:")
- dns = WindowsNetwork.get_dns_servers()
- for d in dns[:3]:
- print(f" - {d}")
-
- # 5. 默认网关
- print("\n[5] 默认网关:")
- gw = WindowsNetwork.get_gateway()
- print(f" 网关: {gw}")
-
- # 6. MAC 地址
- print("\n[6] MAC 地址:")
- mac = WindowsNetwork.get_mac_address()
- print(f" MAC: {mac}")
-
- # 7. 网络接口
- print("\n[7] 网络接口:")
- interfaces = WindowsNetwork.get_interfaces()
- for iface in interfaces[:5]:
- print(f" - {iface.get('ifname', 'N/A')}: {iface.get('operstate', 'N/A')}")
-
- # 8. 流量统计
- print("\n[8] 流量统计:")
- traffic = WindowsNetwork.get_rx_tx_bytes()
- print(f" 接收: {traffic.get('rx_bytes', 0) / 1024 / 1024:.2f} MB")
- print(f" 发送: {traffic.get('tx_bytes', 0) / 1024 / 1024:.2f} MB")
-
- print("\n" + "=" * 60)
- print("测试完成!")
- print("=" * 60)
-
-
-if __name__ == "__main__":
- test_network()
diff --git a/test_scripts/test_system.py b/test_scripts/test_system.py
deleted file mode 100644
index 4cebd5b..0000000
--- a/test_scripts/test_system.py
+++ /dev/null
@@ -1,97 +0,0 @@
-"""
-系统工具测试脚本 - 基于 Android-pyApi
-模拟 Operit 的 system_tools.js 功能
-"""
-
-import sys
-import os
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from android_pyapi import (
- Build, PowerManager, BatteryManager, ActivityManager,
- Environment, Log
-)
-from android_pyapi._windows_impl import (
- WindowsPower, WindowsProcess, WindowsDisplay, WindowsShell
-)
-
-
-def test_system():
- """测试系统工具功能"""
- print("=" * 60)
- print("Android-pyApi 系统工具测试")
- print("=" * 60)
-
- # 1. 设备信息 (Build)
- print("\n[1] 设备信息 (Build):")
- print(f" MODEL: {Build.MODEL}")
- print(f" MANUFACTURER: {Build.MANUFACTURER}")
- print(f" BRAND: {Build.BRAND}")
- print(f" DEVICE: {Build.DEVICE}")
- print(f" PRODUCT: {Build.PRODUCT}")
- print(f" FINGERPRINT: {Build.FINGERPRINT}")
-
- # 2. 系统信息
- print("\n[2] 系统信息:")
- sys_info = WindowsProcess.get_system_info()
- print(f" 主机名: {sys_info.get('hostname', 'N/A')}")
- print(f" 平台: {sys_info.get('platform', 'N/A')}")
- print(f" 版本: {sys_info.get('windows_version', 'N/A')}")
- print(f" 架构: {sys_info.get('arch', 'N/A')}")
- print(f" Python: {sys_info.get('python', 'N/A')}")
- if 'cpu_count' in sys_info:
- print(f" CPU 核心: {sys_info['cpu_count']}")
- if 'memory_total' in sys_info:
- print(f" 内存总量: {sys_info['memory_total'] / 1024 / 1024 / 1024:.2f} GB")
-
- # 3. 电源信息
- print("\n[3] 电源信息:")
- battery = WindowsPower.get_battery_info()
- print(f" 电池存在: {battery['present']}")
- print(f" 电量: {battery['level']}%")
- print(f" 状态: {battery['status']}")
-
- power = WindowsPower.get_power_status()
- print(f" 充电中: {power['is_charging']}")
-
- # 4. CPU 和内存
- print("\n[4] CPU 和内存:")
- cpu = WindowsPower.get_cpu_usage()
- print(f" CPU 使用率: {cpu}%")
-
- mem = WindowsPower.get_memory_info()
- print(f" 内存使用率: {mem['percent']}%")
- print(f" 可用内存: {mem['available'] / 1024 / 1024 / 1024:.2f} GB")
-
- # 5. 显示信息
- print("\n[5] 显示信息:")
- w, h = WindowsDisplay.get_screen_size()
- print(f" 屏幕尺寸: {w}x{h}")
-
- x, y = WindowsDisplay.get_mouse_position()
- print(f" 鼠标位置: ({x}, {y})")
-
- # 6. 进程列表
- print("\n[6] 进程列表 (前10个):")
- procs = WindowsProcess.list_processes()
- for p in procs[:10]:
- print(f" - {p.get('name', 'N/A')} (PID: {p.get('pid', 'N/A')})")
-
- # 7. 运行中的应用
- print("\n[7] 运行中的应用 (前5个):")
- apps = WindowsProcess.get_running_apps()
- for app in apps[:5]:
- print(f" - {app.get('name', 'N/A')}")
-
- # 8. Shell 命令测试
- print("\n[8] Shell 命令测试:")
- result = WindowsShell.exec("echo Hello from Android-pyApi!")
- print(f" 输出: {result.get('stdout', 'N/A')}")
-
- print("\n" + "=" * 60)
- print("测试完成!")
- print("=" * 60)
-
-
-if __name__ == "__main__":
- test_system()
diff --git a/test_scripts/time.js b/test_scripts/time.js
deleted file mode 100644
index e69de29..0000000
diff --git a/test_windows.py b/test_windows.py
deleted file mode 100644
index ae038ff..0000000
--- a/test_windows.py
+++ /dev/null
@@ -1,145 +0,0 @@
-"""
-Windows 实现层测试脚本
-"""
-
-import sys
-import platform
-
-print("=" * 60)
-print(f"平台: {platform.system()} {platform.release()}")
-print(f"Python: {platform.python_version()}")
-print("=" * 60)
-
-# 测试基本导入
-print("\n[1] 测试基本导入...")
-try:
- from android_pyapi import Intent, Uri, Bundle, JSONObject, ArrayList
- print(" ✓ 基本 Android API 导入成功")
-except Exception as e:
- print(f" ✗ 基本导入失败: {e}")
-
-# 测试 Intent
-print("\n[2] 测试 Intent...")
-try:
- intent = Intent("android.intent.action.VIEW")
- intent.setData(Uri.parse("https://example.com"))
- intent.putExtra("key", "value")
- print(f" ✓ Action: {intent.getAction()}")
- print(f" ✓ Data: {intent.getData()}")
- print(f" ✓ Extra: {intent.getStringExtra('key')}")
-except Exception as e:
- print(f" ✗ Intent 测试失败: {e}")
-
-# 测试集合类
-print("\n[3] 测试集合类...")
-try:
- lst = ArrayList()
- lst.add("hello")
- lst.add("world")
- print(f" ✓ ArrayList size: {lst.size()}")
- print(f" ✓ ArrayList[0]: {lst.get(0)}")
-
- json = JSONObject()
- json.put("name", "test")
- json.put("version", 42)
- print(f" ✓ JSONObject: {json.toString()}")
-except Exception as e:
- print(f" ✗ 集合类测试失败: {e}")
-
-# 测试 Windows 实现层
-print("\n[4] 测试 Windows 实现层...")
-try:
- from android_pyapi._windows_impl import (
- IS_WINDOWS, get_windows_capabilities,
- WindowsNetwork, WindowsPower, WindowsDisplay,
- WindowsClipboard, WindowsProcess, WindowsLocation
- )
- print(f" ✓ IS_WINDOWS: {IS_WINDOWS}")
-
- caps = get_windows_capabilities()
- print(f" ✓ 能力检测: {sum(caps.values())}/{len(caps)} 项可用")
-except Exception as e:
- print(f" ✗ Windows 实现层导入失败: {e}")
- import traceback
- traceback.print_exc()
-
-# 测试网络功能
-print("\n[5] 测试网络功能...")
-try:
- ip = WindowsNetwork.get_ip_address()
- print(f" ✓ IP 地址: {ip}")
-
- connected = WindowsNetwork.get_connectivity()
- print(f" ✓ 网络连通: {connected}")
-
- wifi = WindowsNetwork.get_wifi_info()
- print(f" ✓ WiFi SSID: {wifi.get('ssid', 'N/A')}")
-except Exception as e:
- print(f" ✗ 网络测试失败: {e}")
-
-# 测试电源信息
-print("\n[6] 测试电源信息...")
-try:
- battery = WindowsPower.get_battery_info()
- print(f" ✓ 电池存在: {battery['present']}")
- print(f" ✓ 电池电量: {battery['level']}%")
- print(f" ✓ 电池状态: {battery['status']}")
-
- cpu = WindowsPower.get_cpu_usage()
- print(f" ✓ CPU 使用率: {cpu}%")
-
- mem = WindowsPower.get_memory_info()
- print(f" ✓ 内存使用: {mem['percent']}%")
-except Exception as e:
- print(f" ✗ 电源测试失败: {e}")
-
-# 测试显示信息
-print("\n[7] 测试显示信息...")
-try:
- w, h = WindowsDisplay.get_screen_size()
- print(f" ✓ 屏幕尺寸: {w}x{h}")
-
- x, y = WindowsDisplay.get_mouse_position()
- print(f" ✓ 鼠标位置: ({x}, {y})")
-except Exception as e:
- print(f" ✗ 显示测试失败: {e}")
-
-# 测试剪贴板
-print("\n[8] 测试剪贴板...")
-try:
- test_text = "Android-pyApi 测试文本"
- WindowsClipboard.write(test_text)
- read_text = WindowsClipboard.read()
- if read_text == test_text:
- print(f" ✓ 剪贴板读写成功")
- else:
- print(f" ⚠ 剪贴板内容不匹配: '{read_text}'")
-except Exception as e:
- print(f" ✗ 剪贴板测试失败: {e}")
-
-# 测试进程管理
-print("\n[9] 测试进程管理...")
-try:
- procs = WindowsProcess.list_processes()
- print(f" ✓ 进程数量: {len(procs)}")
-
- sys_info = WindowsProcess.get_system_info()
- print(f" ✓ 主机名: {sys_info['hostname']}")
- print(f" ✓ 系统: {sys_info['platform']} {sys_info['windows_version']}")
-except Exception as e:
- print(f" ✗ 进程管理测试失败: {e}")
-
-# 测试位置信息
-print("\n[10] 测试位置信息...")
-try:
- loc = WindowsLocation.get_location()
- print(f" ✓ 来源: {loc['source']}")
- print(f" ✓ 经纬度: {loc['latitude']}, {loc['longitude']}")
- if loc.get('city'):
- print(f" ✓ 城市: {loc['city']}")
-except Exception as e:
- print(f" ✗ 位置测试失败: {e}")
-
-print("\n" + "=" * 60)
-print("测试完成!")
-print("=" * 60)