/** * 摇一摇能力(契约 §8.5/§9,T-M3-08)。@kit.SensorServiceKit 加速度计。 * - startshake:开始监听;检测到摇动后约 1 秒出站 shakeEnd(空串)。 * - SwitchShake:data="1" 开声音/震动反馈 / 其他关。 * - stopshake:停止监听。 * 需 module.json5 声明 ohos.permission.ACCELEROMETER。 */ import { sensor } from '@kit.SensorServiceKit'; import { vibrator } from '@kit.SensorServiceKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { BridgeController } from 'feature_bridge'; import { InboundHandlers, OutboundHandlers } from 'contracts'; import { Logger } from 'common'; import { CapabilityContext, CapabilityProvider } from '../core/CapabilityProvider'; /** 摇动阈值(合加速度 m/s²;静止约 9.8,摇动易超 20)。 */ const SHAKE_THRESHOLD: number = 20; /** 上报周期 100ms。 */ const INTERVAL_NS: number = 100000000; /** shakeEnd 延迟(约 1 秒)。 */ const SHAKE_END_DELAY: number = 1000; export class ShakeProvider implements CapabilityProvider { readonly name: string = 'shake'; private readonly log: Logger = Logger.tag('ShakeProvider'); private bridge: BridgeController | undefined = undefined; private listening: boolean = false; private feedbackOn: boolean = false; private pending: boolean = false; private endTimer: number = -1; private wantShake: boolean = false; private readonly onAccel: (data: sensor.AccelerometerResponse) => void; constructor() { this.onAccel = (data: sensor.AccelerometerResponse) => this.handleAccel(data); } register(bridge: BridgeController, _ctx: CapabilityContext): void { this.bridge = bridge; bridge.registerHandler(InboundHandlers.StartShake, (_d: string, _cb: (resp: string) => void) => { this.wantShake = true; this.start(); }); bridge.registerHandler(InboundHandlers.SwitchShake, (data: string, _cb: (resp: string) => void) => { this.feedbackOn = data === '1'; }); bridge.registerHandler(InboundHandlers.StopShake, (_d: string, _cb: (resp: string) => void) => { this.wantShake = false; this.stop(); }); } /** 槽激活:若 H5 仍要摇一摇则恢复监听(M5 §7.5)。 */ onForeground(): void { if (this.wantShake) { this.start(); } } /** 槽去激活:停传感器监听(保留 H5 意图,激活时恢复)。 */ onBackground(): void { this.stop(); } onDestroy(): void { this.wantShake = false; this.stop(); } private start(): void { if (this.listening) { return; } try { sensor.on(sensor.SensorId.ACCELEROMETER, this.onAccel, { interval: INTERVAL_NS }); this.listening = true; } catch (e) { this.log.w(`sensor.on failed: ${(e as BusinessError).message}`); } } private stop(): void { if (!this.listening) { return; } try { sensor.off(sensor.SensorId.ACCELEROMETER, this.onAccel); } catch (e) { this.log.w(`sensor.off failed: ${(e as BusinessError).message}`); } this.listening = false; // 取消未决的 shakeEnd 计时并复位节流,避免停止后仍触发出站 / 重启后首次摇动被吞 if (this.endTimer !== -1) { clearTimeout(this.endTimer); this.endTimer = -1; } this.pending = false; } private handleAccel(data: sensor.AccelerometerResponse): void { if (this.pending) { return; } const magnitude: number = Math.sqrt(data.x * data.x + data.y * data.y + data.z * data.z); if (magnitude < SHAKE_THRESHOLD) { return; } // 摇动触发:节流;可选反馈震动;约 1 秒后出站 shakeEnd this.pending = true; if (this.feedbackOn) { vibrator.startVibration({ type: 'time', duration: 200 }, { usage: 'notification' }) .catch((e: BusinessError) => this.log.w(`shake vibrate failed: ${e.message}`)); } this.endTimer = setTimeout(() => { this.endTimer = -1; this.bridge?.callHandler(OutboundHandlers.ShakeEnd, ''); this.pending = false; }, SHAKE_END_DELAY); } }