- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
381 lines
13 KiB
Python
381 lines
13 KiB
Python
"""
|
|
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})" |