Bläddra i källkod

卡片交互由message改为call

chendeben 1 år sedan
förälder
incheckning
de3ccac96f

+ 389 - 0
entry/src/main/ets/entryability/EntryAbility.ets

@@ -14,9 +14,12 @@ import { AbilityConstant, Want } from '@kit.AbilityKit';
 import { BusinessError, emitter } from '@kit.BasicServicesKit';
 import { AppUtil, ArrayUtil, GlobalContext, LogUtil, StrUtil } from '@pura/harmony-utils';
 import { DemoConstants } from './DemoConstants';
+import { rpc } from '@kit.IPCKit';
 
 import { Utility } from '../common/util/Utility';
 import { WXApi, WXEventHandler } from '../common/util/WXApiWrap';
+import { WidgetPlayerControlService } from '../common/service/WidgetPlayerControlService';
+import { IndependentPlayerService } from '../common/service/IndependentPlayerService';
 
 import { systemShare } from '@kit.ShareKit';
 import Logger from '../common/util/Logger';
@@ -25,6 +28,10 @@ import StatusBarViewExtensionAbility from '@hms.pcService.StatusBarViewExtension
 import { SpiderMan } from '@simplepeng/spider-man';
 import { smartMobilityCommon } from '@kit.CarKit';
 import { url } from '@kit.ArkTS';
+import commonEventManager from '@ohos.commonEventManager';
+import { WIDGET_CONTROL_EVENT } from '../common/widget/WidgetEventConstants';
+import { EventData, WidgetControlParams } from '../common/widget/WidgetTypes';
+import { VideoItem } from '../viewmodel/VideoItem';
 
 /**
  * 卡片配置页面参数接口
@@ -44,6 +51,28 @@ interface WidgetDeleteParams extends Record<string, Object> {
   action: string;
 }
 
+/**
+ * RPC通信返回类型的实现,用于RPC通信数据序列化和反序列化
+ */
+class MyParcelable implements rpc.Parcelable {
+  num: number;
+  str: string;
+  constructor(num: number, str: string) {
+    this.num = num;
+    this.str = str;
+  }
+  marshalling(messageSequence: rpc.MessageSequence): boolean {
+    messageSequence.writeInt(this.num);
+    messageSequence.writeString(this.str);
+    return true;
+  }
+  unmarshalling(messageSequence: rpc.MessageSequence): boolean {
+    this.num = messageSequence.readInt();
+    this.str = messageSequence.readString();
+    return true;
+  }
+}
+
 /**
  * 主Ability类,继承自UIAbility
  * 负责:
@@ -103,6 +132,24 @@ export default class EntryAbility extends UIAbility {
     async onCreate(want:Want, launchParam:AbilityConstant.LaunchParam) {
         AppStorage.setOrCreate('context', this.context);
         hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
+        
+        // 注册卡片call事件监听器
+        this.registerWidgetCallListeners();
+        
+        // 初始化独立播放器服务(优先级最高)
+        try {
+            await IndependentPlayerService.getInstance().initialize(this.context);
+            hilog.info(0x0000, 'testTag', '✅ IndependentPlayerService initialized successfully');
+        } catch (error) {
+            hilog.error(0x0000, 'testTag', `❌ Failed to initialize IndependentPlayerService: ${error}`);
+        }
+        
+        // 初始化卡片播放器控制服务(作为备用)
+        WidgetPlayerControlService.getInstance().initialize();
+        
+        // 设置备用的CommonEvent监听器
+        this.setupBackupCommonEventListener();
+        
         setTimeout(async ()=>{
             this.loadDoWant(want)
             await this.handleParam(want)
@@ -181,6 +228,13 @@ export default class EntryAbility extends UIAbility {
 
     onDestroy() {
         hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
+        
+        // 注销卡片call事件监听器
+        this.unregisterWidgetCallListeners();
+        
+        // 销毁卡片播放器控制服务
+        WidgetPlayerControlService.getInstance().destroy();
+        
         let types: smartMobilityCommon.SmartMobilityType[] = [smartMobilityCommon.SmartMobilityType.CAR_HOP];
         // 出行连接状态回调函数
         const callBack = (info: smartMobilityCommon.SmartMobilityInfo) => {
@@ -418,4 +472,339 @@ export default class EntryAbility extends UIAbility {
         }
     }
 
+    /**
+     * 注册卡片call事件监听器
+     */
+    private registerWidgetCallListeners(): void {
+        try {
+            // 监听播放/暂停事件
+            this.callee.on('playPause', (data: rpc.MessageSequence) => {
+                hilog.info(0x0000, 'testTag', `Widget call: playPause received`);
+                const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
+                hilog.info(0x0000, 'testTag', `Widget playPause params: ${JSON.stringify(params)}`);
+                
+                // 发送播放/暂停事件到主应用
+                this.sendWidgetControlEvent('PLAY_PAUSE', params);
+                
+                return new MyParcelable(1, 'playPause_success');
+            });
+
+            // 监听下一首事件
+            this.callee.on('nextSong', (data: rpc.MessageSequence) => {
+                hilog.info(0x0000, 'testTag', `Widget call: nextSong received`);
+                const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
+                hilog.info(0x0000, 'testTag', `Widget nextSong params: ${JSON.stringify(params)}`);
+                
+                // 发送下一首事件到主应用
+                this.sendWidgetControlEvent('NEXT_SONG', params);
+                
+                return new MyParcelable(2, 'nextSong_success');
+            });
+
+            // 监听上一首事件
+            this.callee.on('prevSong', (data: rpc.MessageSequence) => {
+                hilog.info(0x0000, 'testTag', `Widget call: prevSong received`);
+                const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
+                hilog.info(0x0000, 'testTag', `Widget prevSong params: ${JSON.stringify(params)}`);
+                
+                // 发送上一首事件到主应用
+                this.sendWidgetControlEvent('PREV_SONG', params);
+                
+                return new MyParcelable(3, 'prevSong_success');
+            });
+
+            // 监听打开应用事件
+            this.callee.on('openApp', (data: rpc.MessageSequence) => {
+                hilog.info(0x0000, 'testTag', `Widget call: openApp received`);
+                const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
+                hilog.info(0x0000, 'testTag', `Widget openApp params: ${JSON.stringify(params)}`);
+                
+                // 发送打开应用事件到主应用
+                this.sendWidgetControlEvent('OPEN_APP', params);
+                
+                return new MyParcelable(4, 'openApp_success');
+            });
+
+            // 监听播放控制事件(新增,符合文档标准)
+            this.callee.on('playByAction', (data: rpc.MessageSequence) => {
+                hilog.info(0x0000, 'testTag', `Widget call: playByAction received`);
+                const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
+                const playActionType = params['playActionType'] as string;
+                hilog.info(0x0000, 'testTag', `Widget playByAction type: ${playActionType}`);
+                
+                // 发送播放控制事件
+                this.sendWidgetControlEvent(playActionType, params);
+                
+                return new MyParcelable(5, 'playByAction_success');
+            });
+
+            // 监听收藏事件(新增,符合文档标准)
+            this.callee.on('collectAction', (data: rpc.MessageSequence) => {
+                hilog.info(0x0000, 'testTag', `Widget call: collectAction received`);
+                const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
+                const collectActionType = params['collectActionType'] as string;
+                const songId = params['songId'] as string;
+                hilog.info(0x0000, 'testTag', `Widget collectAction type: ${collectActionType}, songId: ${songId}`);
+                
+                return new MyParcelable(6, 'collectAction_success');
+            });
+
+            // 监听卡片更新请求事件(新增,符合文档标准)
+            this.callee.on('requestUpdatePlayCard', (data: rpc.MessageSequence) => {
+                hilog.info(0x0000, 'testTag', `Widget call: requestUpdatePlayCard received`);
+                const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
+                const formId = params['formId'] as string;
+                hilog.info(0x0000, 'testTag', `Widget requestUpdate formId: ${formId}`);
+                
+                // 更新卡片数据
+                this.updatePlayCard(formId);
+                
+                return new MyParcelable(7, 'requestUpdatePlayCard_success');
+            });
+
+            hilog.info(0x0000, 'testTag', 'Widget call listeners registered successfully');
+        } catch (err) {
+            hilog.error(0x0000, 'testTag', `Failed to register widget call listeners: ${JSON.stringify(err as BusinessError)}`);
+        }
+    }
+
+    /**
+     * 注销卡片call事件监听器
+     */
+    private unregisterWidgetCallListeners(): void {
+        try {
+            this.callee.off('playPause');
+            this.callee.off('nextSong');
+            this.callee.off('prevSong');
+            this.callee.off('openApp');
+            this.callee.off('playByAction');
+            this.callee.off('collectAction');
+            this.callee.off('requestUpdatePlayCard');
+            hilog.info(0x0000, 'testTag', 'Widget call listeners unregistered successfully');
+        } catch (err) {
+            hilog.error(0x0000, 'testTag', `Failed to unregister widget call listeners: ${JSON.stringify(err as BusinessError)}`);
+        }
+    }
+
+    /**
+     * 更新播放卡片
+     */
+    private async updatePlayCard(formId: string): Promise<void> {
+        try {
+            hilog.info(0x0000, 'testTag', `Updating play card: ${formId}`);
+            
+            // 获取当前播放状态
+            const isPlay = AppStorage.get<boolean>('isPlay') || false;
+            const currentSong = AppStorage.get<VideoItem>('currentSong');
+            
+            if (currentSong) {
+                // 使用FormUtils更新卡片
+                import('../common/widget/FormUtils').then((module) => {
+                    const formUtils = module.FormUtils.getInstance();
+                    formUtils.updateMusicControlCards(this.context, currentSong, isPlay);
+                });
+            }
+            
+            hilog.info(0x0000, 'testTag', `Play card update completed: ${formId}`);
+        } catch (error) {
+            hilog.error(0x0000, 'testTag', `Failed to update play card: ${error}`);
+        }
+    }
+
+    /**
+     * 发送卡片控制事件到主应用
+     */
+    private async sendWidgetControlEvent(command: string, params: Record<string, Object>): Promise<void> {
+        try {
+            hilog.info(0x0000, 'testTag', `🎵 Processing widget control command: ${command}`);
+            
+            // 确保IndependentPlayerService已初始化
+            const independentService = IndependentPlayerService.getInstance();
+            if (!independentService.getCurrentState().currentSong && !independentService.getCurrentState().playlist.length) {
+                hilog.info(0x0000, 'testTag', '🔄 IndependentPlayerService not ready, reinitializing...');
+                try {
+                    await independentService.initialize(this.context);
+                } catch (error) {
+                    hilog.error(0x0000, 'testTag', `❌ Failed to reinitialize IndependentPlayerService: ${error}`);
+                }
+            }
+            
+            // 优先通过IndependentPlayerService直接处理
+            const eventData: emitter.EventData = {
+                data: {
+                    command: command,
+                    params: params,
+                    source: 'widget_call',
+                    timestamp: Date.now()
+                }
+            };
+            
+            // 发送到IndependentPlayerService(事件ID: 9001)
+            emitter.emit({ eventId: 9001 }, eventData);
+            hilog.info(0x0000, 'testTag', `✅ Widget control event sent to IndependentPlayerService: ${command}`);
+            
+            // 同时发送CommonEvent作为备用,确保LocalMusic也能接收到(如果已经初始化)
+            // this.sendCommonEventToLocalMusic(command, params);
+        } catch (error) {
+            hilog.error(0x0000, 'testTag', `❌ Failed to send widget control event: ${error}`);
+        }
+    }
+
+    /**
+     * 发送CommonEvent到LocalMusic
+     */
+    private async sendCommonEventToLocalMusic(command: string, params: Record<string, Object>): Promise<void> {
+        try {
+            // 构造事件数据
+            interface EventData {
+                command: string;
+                params: Record<string, Object>;
+                timestamp: number;
+                source: string;
+            }
+            
+            const eventData: EventData = {
+                command: this.mapCommandToWidgetCommand(command),
+                params: params,
+                timestamp: Date.now(),
+                source: 'widget_call'
+            };
+
+            // 发送CommonEvent
+            const publishInfo: commonEventManager.CommonEventPublishData = {
+                data: JSON.stringify(eventData)
+            };
+            
+            hilog.info(0x0000, 'testTag', `📤 Publishing CommonEvent: ${WIDGET_CONTROL_EVENT}`);
+            
+            commonEventManager.publish(WIDGET_CONTROL_EVENT, publishInfo, (err: Error) => {
+                if (err) {
+                    hilog.error(0x0000, 'testTag', `❌ Failed to publish CommonEvent: ${err}`);
+                } else {
+                    hilog.info(0x0000, 'testTag', `✅ CommonEvent published successfully: ${command}`);
+                }
+            });
+            
+            // 延迟重试机制,确保LocalMusic有时间初始化
+            // const retryDelays = [2000, 5000, 8000]; // 2秒、5秒、8秒后重试
+            // retryDelays.forEach((delay, index) => {
+            //     setTimeout(() => {
+            //         hilog.info(0x0000, 'testTag', `🔄 Retry ${index + 1}: Publishing CommonEvent after ${delay}ms`);
+            //         commonEventManager.publish(WIDGET_CONTROL_EVENT, publishInfo, (err: Error) => {
+            //             if (err) {
+            //                 hilog.error(0x0000, 'testTag', `❌ Retry ${index + 1} failed: ${err}`);
+            //             } else {
+            //                 hilog.info(0x0000, 'testTag', `✅ Retry ${index + 1} succeeded: ${command}`);
+            //             }
+            //         });
+            //     }, delay);
+            // });
+            
+        } catch (error) {
+            hilog.error(0x0000, 'testTag', `❌ Failed to send CommonEvent: ${error}`);
+        }
+    }
+
+    /**
+     * 映射命令字符串到WidgetCommand
+     */
+    private mapCommandToWidgetCommand(command: string): string {
+        switch (command) {
+            case 'PLAY_PAUSE':
+                return 'PLAY_PAUSE';
+            case 'NEXT_SONG':
+                return 'NEXT_SONG';
+            case 'PREV_SONG':
+                return 'PREV_SONG';
+            default:
+                return command;
+        }
+    }
+
+    /**
+     * 设置备用的CommonEvent监听器
+     * 当主应用页面还没加载时,EntryAbility作为备用接收器
+     */
+    private async setupBackupCommonEventListener(): Promise<void> {
+        try {
+            hilog.info(0x0000, 'testTag', '🔧 Setting up backup CommonEvent listener...');
+            
+            // 订阅WIDGET_CONTROL_EVENT,作为LocalMusic的备用处理器
+            const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
+                events: [WIDGET_CONTROL_EVENT]
+            };
+            
+            const subscriber = await commonEventManager.createSubscriber(subscribeInfo);
+            
+            await commonEventManager.subscribe(subscriber, (err, data: commonEventManager.CommonEventData) => {
+                if (!err && data.event === WIDGET_CONTROL_EVENT) {
+                    hilog.info(0x0000, 'testTag', `🎵 EntryAbility received widget control event: ${data.data}`);
+                    this.handleBackupWidgetControl(data.data || '{}');
+                } else if (err) {
+                    hilog.error(0x0000, 'testTag', `❌ Backup CommonEvent error: ${JSON.stringify(err)}`);
+                }
+            });
+            
+            hilog.info(0x0000, 'testTag', '✅ Backup CommonEvent listener setup completed');
+        } catch (error) {
+            hilog.error(0x0000, 'testTag', `❌ Failed to setup backup CommonEvent listener: ${error}`);
+        }
+    }
+
+    /**
+     * 备用的卡片控制处理器
+     * 当LocalMusic还没有准备好时,EntryAbility临时处理卡片事件
+     */
+    private handleBackupWidgetControl(dataStr: string): void {
+        try {
+            const eventData = JSON.parse(dataStr) as EventData;
+            hilog.info(0x0000, 'testTag', `🎵 EntryAbility processing backup widget command: ${eventData.command}`);
+            
+            // 通过emitter发送事件到主应用,确保LocalMusic能接收到
+            const emitterEventData: emitter.EventData = {
+                data: {
+                    command: eventData.command,
+                    params: eventData.params || {},
+                    source: 'widget_backup_handler',
+                    timestamp: Date.now()
+                }
+            };
+            
+            // 使用特定的事件ID发送卡片控制事件
+            emitter.emit({ eventId: 9001 }, emitterEventData);
+            hilog.info(0x0000, 'testTag', `🎵 EntryAbility forwarded widget command via emitter: ${eventData.command}`);
+            
+            // 同时延迟重发CommonEvent,给LocalMusic更多时间初始化
+            setTimeout(() => {
+                this.retryCommonEventForLocalMusic(eventData);
+            }, 3000);
+            
+        } catch (error) {
+            hilog.error(0x0000, 'testTag', `❌ Failed to handle backup widget control: ${error}`);
+        }
+    }
+
+    /**
+     * 延迟重发CommonEvent给LocalMusic
+     */
+    private async retryCommonEventForLocalMusic(eventData: EventData): Promise<void> {
+        try {
+            const publishInfo: commonEventManager.CommonEventPublishData = {
+                data: JSON.stringify(eventData)
+            };
+            
+            hilog.info(0x0000, 'testTag', `🔄 EntryAbility retrying CommonEvent for LocalMusic: ${eventData.command}`);
+            
+            commonEventManager.publish(WIDGET_CONTROL_EVENT, publishInfo, (err: Error) => {
+                if (err) {
+                    hilog.error(0x0000, 'testTag', `❌ Retry CommonEvent failed: ${err}`);
+                } else {
+                    hilog.info(0x0000, 'testTag', `✅ Retry CommonEvent succeeded: ${eventData.command}`);
+                }
+            });
+        } catch (error) {
+            hilog.error(0x0000, 'testTag', `❌ Failed to retry CommonEvent: ${error}`);
+        }
+    }
+
 }

+ 31 - 260
entry/src/main/ets/entryformability/EntryFormAbility.ets

@@ -7,43 +7,15 @@ import { http } from '@kit.NetworkKit';
 import { WidgetDataManager } from '../common/widget/WidgetDataManager';
 import { PlayerControlService } from '../common/widget/PlayerControlService';
 import { AvSessionWidgetListener } from '../common/widget/AvSessionWidgetListener';
-import { WidgetCommand, WidgetControlParams, WidgetData, WidgetSize, FormattedWidgetData } from '../common/widget/WidgetTypes';
+import { WidgetData, WidgetSize, FormattedWidgetData } from '../common/widget/WidgetTypes';
 import { FormLayoutManager } from '../common/widget/FormLayoutManager';
 import { GlobalWidgetManager } from '../common/widget/GlobalWidgetManager';
 import { WidgetSizeAdapter, SizeChangeListener } from '../common/widget/WidgetSizeAdapter';
 import { PreferencesUtil } from '../common/utils/PreferencesUtil';
-import {
-  PLAY_PAUSE_EVENT,
-  NEXT_SONG_EVENT,
-  PREV_SONG_EVENT,
-  SEEK_TO_EVENT,
-  OPEN_APP_EVENT,
-  OPEN_PLAYER_EVENT,
-  LONG_PRESS_MENU_EVENT,
-  WIDGET_SETTINGS_EVENT,
-  WIDGET_DELETE_EVENT,
-  WIDGET_CONFIG_PAGE_EVENT,
-  PAGE_MAIN,
-  PAGE_PLAYER
-} from '../common/widget/WidgetEventConstants';
 
 const TAG = 'Heanup';
 
-/**
- * 卡片设置参数接口
- */
-interface WidgetSettingsParams extends Record<string, Object> {
-  formId: string;
-  currentSize: string;
-}
 
-/**
- * 卡片配置参数接口
- */
-interface WidgetConfigParams extends Record<string, Object> {
-  formId: string;
-  configType: string;
-}
 
 /**
  * 扩展的卡片数据接口,支持图片传递
@@ -477,9 +449,10 @@ implements SizeChangeListener {
 
     const formId = want.parameters?.['ohos.extra.param.key.form_identity'] as string;
     const formName = want.parameters?.['ohos.extra.param.key.form_name'] as string;
+    const formDimension = want.parameters?.['ohos.extra.param.key.form_dimension'] as string;
     const tempFlag = want.parameters?.['ohos.extra.param.key.form_temporary'] as boolean;
 
-    hilog.info(0x0000, TAG, `Form added: ${formId}, name: ${formName}, temp: ${tempFlag}`);
+    hilog.info(0x0000, TAG, `Form added: ${formId}, name: ${formName}, dimension: ${formDimension}, temp: ${tempFlag}`);
 
     // 持久化保存 Form ID(异步执行,不阻塞返回)
     this.saveFormIdToPersistence(formId).then(() => {
@@ -495,6 +468,21 @@ implements SizeChangeListener {
       hilog.error(0x0000, TAG, `Failed to register widget: ${error}`);
     }
 
+    // 注册到FormUtils活跃卡片列表
+    try {
+      import('../common/widget/FormUtils').then((module) => {
+        const formUtils = module.FormUtils.getInstance();
+        formUtils.registerActiveForm(formId);
+        
+        // 如果是音乐播控卡片,初始化数据
+        if (formName && formName.includes('PlayControlCard')) {
+          formUtils.updateMusicControlCard(formId, true);
+        }
+      });
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to register form to FormUtils: ${error}`);
+    }
+
     hilog.info(0x0000, TAG, `Detected widget size: ${widgetSize} for form: ${formId}`);
 
     // 注册各种监听器
@@ -516,11 +504,6 @@ implements SizeChangeListener {
       }
     }, 2000);
 
-    // 添加数据流测试 - 仅在开发环境中
-    setTimeout(() => {
-      this.testWidgetDataFlow(formId);
-    }, 3000);
-
     // 获取当前播放状态而不是初始数据
     this.playerControlService.getCurrentPlayState().then((currentState: WidgetData) => {
       const adaptedData = this.layoutManager.adaptDataForSize(currentState, widgetSize);
@@ -610,6 +593,16 @@ implements SizeChangeListener {
       hilog.info(0x0000, TAG, `🗑️ Form ID removal completed for: ${formId}`);
     });
 
+    // 从FormUtils活跃卡片列表中移除
+    try {
+      import('../common/widget/FormUtils').then((module) => {
+        const formUtils = module.FormUtils.getInstance();
+        formUtils.unregisterActiveForm(formId);
+      });
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to unregister form from FormUtils: ${error}`);
+    }
+
     // 注销各种监听器
     this.sizeAdapter.unregisterSizeChangeListener(formId);
 
@@ -641,41 +634,11 @@ implements SizeChangeListener {
 
   /**
    * 处理卡片事件(用户交互)
+   * 注意:由于改用call方式,此方法不再被调用,保留用于兼容性
    */
   onFormEvent(formId: string, message: string): void {
-    const processId = `${Date.now()}_${Math.random().toString(36).substr(2, 5)}`;
-    hilog.info(0x0000, TAG, `Heanup EntryFormAbility [${processId}] onFormEvent called: ${formId}, message: ${message}`);
-
-    // 确保服务已初始化
-    if (!this.globalListenerSetup) {
-      hilog.info(0x0000, TAG, `Heanup EntryFormAbility [${processId}] services not initialized in onFormEvent, initializing now...`);
-      this.initializeServices();
-      
-      // 强制请求当前状态,确保新进程能获取到最新数据
-      setTimeout(() => {
-        this.playerControlService.getCurrentPlayState().then((currentState) => {
-          hilog.info(0x0000, TAG, `Heanup EntryFormAbility [${processId}] got current state: isPlaying=${currentState.playState.isPlaying}, title=${currentState.currentSong.title}`);
-          // 手动触发一次状态更新,确保widget显示正确
-          this.updateAllWidgetsWithData(currentState);
-        }).catch(() => {
-          hilog.error(0x0000, TAG, `Heanup EntryFormAbility [${processId}] failed to get current state: `);
-        });
-      }, 1000);
-    }
-
-    // 确保widget已注册到GlobalWidgetManager
-    if (!this.globalWidgetManager.hasWidget(formId)) {
-      hilog.info(0x0000, TAG, `Heanup EntryFormAbility [${processId}] widget ${formId} not registered, registering as MEDIUM size`);
-      // 默认注册为MEDIUM尺寸,这样2*4卡片就能正确使用medium适配
-      this.globalWidgetManager.registerWidget(formId, 'medium' as WidgetSize);
-    }
-
-    try {
-      const eventData = JSON.parse(message) as Object;
-      this.handleWidgetEvent(formId, eventData);
-    } catch (error) {
-      hilog.error(0x0000, TAG, `Heanup EntryFormAbility [${processId}] failed to parse form event: ${error}`);
-    }
+    hilog.info(0x0000, TAG, `onFormEvent called but ignored (using call method): ${formId}`);
+    // 由于改用call方式,此方法不再处理事件
   }
 
   /**
@@ -776,106 +739,6 @@ implements SizeChangeListener {
 
 
 
-  /**
-   * 处理卡片事件
-   */
-  private async handleWidgetEvent(formId: string, eventData: Object): Promise<void> {
-    try {
-      // 解析事件数据
-      const actionData: Record<string, Object> = eventData as Record<string, Object>;
-      const action: string = (actionData['action'] as string) || 'message';
-      
-      hilog.info(0x0000, TAG, `Handling widget event,action ${action}`);
-      hilog.info(0x0000, TAG, `Handling widget event,actionData ${JSON.stringify(actionData)}`);
-
-      // 获取事件类型,优先从顶层的func字段获取,如果没有则从params中获取
-      let eventType: string = (actionData['func'] as string) || '';
-      let eventParams: Record<string, Object> = {};
-
-      if (!eventType) {
-        // 如果顶层没有func,尝试从params中获取
-        const params: Record<string, Object> = (actionData['params'] as Record<string, Object>) || {};
-        eventType = (params['func'] as string) || '';
-        eventParams = params;
-      } else {
-        // 如果顶层有func,则整个actionData就是参数
-        eventParams = actionData;
-      }
-
-      if (!eventType) {
-        hilog.warn(0x0000, TAG, `No event type found in widget event data`);
-        return;
-      }
-
-      hilog.info(0x0000, TAG, `Processing widget event type: ${eventType}`);
-
-      switch (eventType) {
-        case PLAY_PAUSE_EVENT:
-          await this.playerControlService.sendControlCommand(WidgetCommand.PLAY_PAUSE);
-          break;
-
-        case NEXT_SONG_EVENT:
-          await this.playerControlService.sendControlCommand(WidgetCommand.NEXT_SONG);
-          break;
-
-        case PREV_SONG_EVENT:
-          await this.playerControlService.sendControlCommand(WidgetCommand.PREV_SONG);
-          break;
-
-        case SEEK_TO_EVENT:
-          const percentage = (eventParams['percentage'] as number) || 0;
-          const controlParams: WidgetControlParams = {
-            percentage: percentage,
-            position: 0
-          };
-          hilog.info(0x0000, TAG, `Seeking to percentage: ${percentage}`);
-          await this.playerControlService.sendControlCommand(WidgetCommand.SEEK_TO, controlParams);
-          break;
-
-        case OPEN_APP_EVENT:
-          // 启动主应用到首页
-          await this.playerControlService.launchMainApp(PAGE_MAIN);
-          break;
-
-        case OPEN_PLAYER_EVENT:
-          // 启动主应用到播放器页面
-          await this.playerControlService.launchMainApp(PAGE_PLAYER);
-          break;
-
-        case LONG_PRESS_MENU_EVENT:
-          // 处理长按菜单显示(由系统处理,这里记录日志)
-          hilog.info(0x0000, TAG, 'Long press menu event triggered');
-          break;
-
-        case WIDGET_SETTINGS_EVENT:
-          // 打开卡片设置页面
-          await this.handleWidgetSettings(formId);
-          break;
-
-        case WIDGET_DELETE_EVENT:
-          // 处理卡片删除
-          await this.handleWidgetDelete(formId);
-          break;
-
-        case WIDGET_CONFIG_PAGE_EVENT:
-          // 跳转到卡片配置界面
-          await this.handleWidgetConfigPage(formId);
-          break;
-
-        default:
-          hilog.warn(0x0000, TAG, `Unknown widget event type: ${eventType}`);
-          return;
-      }
-
-      // 不要立即更新卡片,等待真实状态通过CommonEvent到达
-      // 真实状态会通过全局监听器自动更新所有卡片
-      hilog.info(0x0000, TAG, `Widget event processed, waiting for real state update via CommonEvent`);
-
-    } catch (error) {
-      hilog.error(0x0000, TAG, `Failed to handle widget event: ${error}`);
-    }
-  }
-
   /**
    * 处理表单尺寸变化
    */
@@ -899,99 +762,7 @@ implements SizeChangeListener {
   }
 
 
-  /**
-   * 处理卡片设置
-   */
-  private async handleWidgetSettings(formId: string): Promise<void> {
-    try {
-      hilog.info(0x0000, TAG, `Opening widget settings for form: ${formId}`);
 
-      // 获取当前卡片配置
-      const currentSize = this.globalWidgetManager.getWidgetSize(formId) || WidgetSize.MEDIUM;
-
-      // 启动主应用到卡片设置页面,传递卡片ID和当前配置
-      const settingsParams: WidgetSettingsParams = {
-        formId: formId,
-        currentSize: currentSize
-      };
-
-      await this.playerControlService.launchMainApp('widget_settings', settingsParams);
-
-      hilog.info(0x0000, TAG, `Widget settings opened for form: ${formId}`);
-    } catch (error) {
-      hilog.error(0x0000, TAG, `Failed to open widget settings: ${error}`);
-    }
-  }
-
-  /**
-   * 处理卡片删除
-   */
-  private async handleWidgetDelete(formId: string): Promise<void> {
-    try {
-      hilog.info(0x0000, TAG, `Processing widget delete for form: ${formId}`);
-
-      // 显示删除确认对话框(通过主应用)
-      const deleteParams: WidgetConfigParams = {
-        formId: formId,
-        configType: 'delete'
-      };
-
-      await this.playerControlService.launchMainApp('widget_delete_confirm', deleteParams);
-
-      hilog.info(0x0000, TAG, `Widget delete confirmation shown for form: ${formId}`);
-    } catch (error) {
-      hilog.error(0x0000, TAG, `Failed to process widget delete: ${error}`);
-    }
-  }
-
-  /**
-   * 处理卡片配置界面跳转
-   */
-  private async handleWidgetConfigPage(formId: string): Promise<void> {
-    try {
-      hilog.info(0x0000, TAG, `Opening widget config page for form: ${formId}`);
-
-      // 启动主应用到卡片配置页面
-      const configParams: WidgetConfigParams = {
-        formId: formId,
-        configType: 'full_config'
-      };
-
-      await this.playerControlService.launchMainApp('widget_config', configParams);
-
-      hilog.info(0x0000, TAG, `Widget config page opened for form: ${formId}`);
-    } catch (error) {
-      hilog.error(0x0000, TAG, `Failed to open widget config page: ${error}`);
-    }
-  }
-
-  /**
-   * 测试卡片数据流(开发调试用)
-   */
-  private testWidgetDataFlow(formId: string): void {
-    hilog.info(0x0000, TAG, `🔍 Testing widget data flow for form: ${formId}`);
-
-    // 测试1: 检查监听器状态
-    hilog.info(0x0000, TAG, `📊 Current listener count: PlayerControlService has listeners registered`);
-
-    // 测试2: 手动触发一次数据更新
-    setTimeout(() => {
-      hilog.info(0x0000, TAG, `🔄 Manually triggering data update for form: ${formId}`);
-      this.updateWidgetData(formId);
-    }, 1000);
-
-    // 测试3: 获取AvSession当前数据
-    setTimeout(() => {
-      try {
-        const currentData = this.playerControlService.getCurrentPlayState();
-        currentData.then((data) => {
-          hilog.info(0x0000, TAG, `📊 AvSession current data: isPlaying=${data.playState.isPlaying}, hasNext=${data.playlist.hasNext}, hasPrevious=${data.playlist.hasPrevious}, title=${data.currentSong.title}`);
-        });
-      } catch (error) {
-        hilog.error(0x0000, TAG, `❌ Failed to get current data: ${error}`);
-      }
-    }, 2000);
-  }
 
   /**
    * 保存 Form ID 到持久化存储

+ 95 - 6
entry/src/main/ets/view/LocalMusic.ets

@@ -492,6 +492,23 @@ export struct LocalMusic {
 
     });
 
+    // 监听卡片控制事件(来自EntryAbility的转发)
+    let eventWidgetControl: emitter.InnerEvent = { eventId: 9001 }
+    emitter.on(eventWidgetControl, (eventData: emitter.EventData) => {
+      LogUtils.getInstance().LOGI(`🎵 LocalMusic received widget control via emitter: ${JSON.stringify(eventData.data)}`);
+      if (eventData.data && (eventData.data as Record<string, Object>)['command']) {
+        // 将data转换为EventData类型
+        const widgetEventData = eventData.data as Record<string, Object>;
+        const typedEventData: EventData = {
+          command: widgetEventData['command'] as WidgetCommand,
+          params: (widgetEventData['params'] as WidgetControlParams) || {},
+          timestamp: (widgetEventData['timestamp'] as number) || Date.now(),
+          source: (widgetEventData['source'] as string) || 'unknown'
+        };
+        this.handleWidgetControlFromEmitter(typedEventData);
+      }
+    });
+
     let event: Callback<InterruptEvent> = (event) => {
       LogUtils.getInstance().LOGI(`onecold 与其他应用音频冲突 被截断点event: ${JSON.stringify(event)}`);
       this.savePlaybackPosition()
@@ -815,6 +832,11 @@ export struct LocalMusic {
       } else {
         this.curIndex = Utility.getIndexFromList(this.songList, this.currentSong.filePath)
       }
+      
+      // 同步播放列表和当前索引到AppStorage,确保IndependentPlayerService能访问
+      AppStorage.setOrCreate('songList', this.songList);
+      AppStorage.setOrCreate('currIndex', this.curIndex);
+      
       if (ArrayUtil.isNotEmpty(this.songList)) {
         this.isFirstStartPlay = true
         this.sonDataSource.pushArrayData(this.songList)
@@ -10408,19 +10430,28 @@ export struct LocalMusic {
 
       // 如果播放位置接近视频末尾,则保存 position 为 0
       const playbackPosition = (duration - position < threshold) ? 0 : position;
+      
+      // 同时保存到PreferencesUtil和AppStorage,确保IndependentPlayerService也能访问
       PreferencesUtil.putSync(this.videoUrl, playbackPosition);
+      AppStorage.setOrCreate(`playback_${this.videoUrl}`, playbackPosition);
 
+      LogUtils.getInstance().LOGI(`Saved playback position: ${playbackPosition}ms for ${this.name}`);
     }
   }
 
   //获取记忆播放功能
   private restorePlaybackPosition() {
-    const position: number = PreferencesUtil.getNumberSync(this.videoUrl, 0);
+    // 优先从AppStorage获取,如果没有则从PreferencesUtil获取
+    let position: number = AppStorage.get<number>(`playback_${this.videoUrl}`) || 0;
+    if (position === 0) {
+      position = PreferencesUtil.getNumberSync(this.videoUrl, 0);
+    }
+    
     // ToastUtil.showToast('position = ' + position)
     if (this.mIjkMediaPlayer != null && position > 0) {
       // ToastUtil.showToast('seekTo = ' + position)
       this.seekTo(position + "");
-
+      LogUtils.getInstance().LOGI(`Restored playback position: ${position}ms for ${this.name}`);
     }
   }
 
@@ -10480,6 +10511,11 @@ export struct LocalMusic {
       } else {
         this.curIndex++;
       }
+      
+      // 同步到AppStorage,确保IndependentPlayerService能获取到最新状态
+      AppStorage.setOrCreate('songList', this.songList);
+      AppStorage.setOrCreate('currIndex', this.curIndex);
+      
       this.CONTROL_PlayStatus = PlayStatus.INIT;
       this.stop();
       this.currentSong = this.songList[this.curIndex]
@@ -10622,6 +10658,10 @@ export struct LocalMusic {
       this.curIndex--;
     }
 
+    // 同步到AppStorage,确保IndependentPlayerService能获取到最新状态
+    AppStorage.setOrCreate('songList', this.songList);
+    AppStorage.setOrCreate('currIndex', this.curIndex);
+
     this.CONTROL_PlayStatus = PlayStatus.INIT;
     this.stop();
     this.currentSong = this.songList[this.curIndex]
@@ -11099,9 +11139,9 @@ export struct LocalMusic {
       // 初始化AvSession卡片监听器
       this.initAvSessionWidgetListener();
 
-      LogUtils.getInstance().LOGI('Widget event listener initialized successfully');
+      LogUtils.getInstance().LOGI('🎵 Widget event listener initialized successfully - LocalMusic is ready to receive CommonEvents!');
     } catch (error) {
-      LogUtils.getInstance().error(`Failed to initialize widget event listener: ${error}`);
+      LogUtils.getInstance().error(`Failed to initialize widget event listener: ${error}`);
     }
   }
 
@@ -11191,8 +11231,57 @@ export struct LocalMusic {
   private handleWidgetControlCommand(dataStr: string): void {
     try {
       const eventData = JSON.parse(dataStr) as EventData;
-      LogUtils.getInstance().LOGI(`Processing widget command: ${eventData.command}`);
+      LogUtils.getInstance().LOGI(`🎵 LocalMusic processing widget command: ${eventData.command}`);
+      this.executeWidgetCommand(eventData);
+    } catch (error) {
+      LogUtils.getInstance().error(`Failed to handle widget control command: ${error}`);
+    }
+  }
 
+  /**
+   * 处理来自emitter的卡片控制命令
+   */
+  private handleWidgetControlFromEmitter(eventData: EventData): void {
+    try {
+      LogUtils.getInstance().LOGI(`🎵 LocalMusic processing widget command from emitter: ${eventData.command}`);
+      this.executeWidgetCommand(eventData);
+    } catch (error) {
+      LogUtils.getInstance().error(`Failed to handle widget control command from emitter: ${error}`);
+    }
+  }
+
+  /**
+   * 执行卡片控制命令的通用方法
+   */
+  private executeWidgetCommand(eventData: EventData): void {
+    try {
+      // 检查事件来源,避免与IndependentPlayerService冲突
+      if (eventData.source === 'widget_call' || eventData.source === 'widget_backup_handler') {
+        // 如果是来自卡片的直接调用,检查IndependentPlayerService是否已经处理
+        const timeSinceEvent = Date.now() - eventData.timestamp;
+        if (timeSinceEvent < 1000) {
+          // 事件很新,可能IndependentPlayerService正在处理,延迟处理避免冲突
+          LogUtils.getInstance().LOGI(`🔄 Delaying widget command execution to avoid conflict: ${eventData.command}, age: ${timeSinceEvent}ms`);
+          setTimeout(() => {
+            this.executeWidgetCommandInternal(eventData);
+          }, 800);
+          return;
+        }
+      }
+      
+      this.executeWidgetCommandInternal(eventData);
+    } catch (error) {
+      LogUtils.getInstance().error(`Failed to execute widget command: ${error}`);
+    }
+  }
+
+  /**
+   * 内部执行卡片控制命令
+   */
+  private executeWidgetCommandInternal(eventData: EventData): void {
+    try {
+      LogUtils.getInstance().LOGI(`🎵 LocalMusic executing widget command: ${eventData.command} from ${eventData.source}`);
+      
       switch (eventData.command) {
         case WidgetCommand.PLAY_PAUSE:
           this.playOrPause();
@@ -11226,7 +11315,7 @@ export struct LocalMusic {
         this.broadcastPlayerState();
       }, 100);
     } catch (error) {
-      LogUtils.getInstance().error(`Failed to handle widget control command: ${error}`);
+      LogUtils.getInstance().error(`Failed to execute widget command internally: ${error}`);
     }
   }
 

+ 13 - 6
entry/src/main/ets/widget/pages/PlayerWidgetMedium.ets

@@ -32,6 +32,7 @@ let storageUpdateCall = new LocalStorage();
 @Component
 struct PlayerWidgetMedium {
   // 卡片数据属性 - 使用LocalStorageProp与FormExtensionAbility通信
+  @LocalStorageProp('formId') formId: string = '12400633174999288';
   @LocalStorageProp('isPlaying') isPlaying: boolean = false;
   @LocalStorageProp('songTitle') songTitle: string = 'Dream It Possible';
   @LocalStorageProp('songArtist') songArtist: string = 'Delacey';
@@ -216,9 +217,11 @@ struct PlayerWidgetMedium {
           console.info(`Heanup PlayerWidgetMedium: Previous button clicked`);
           if (!this.isLoading && this.hasPrevious) {
             postCardAction(this, {
-              'action': 'message',
+              'action': 'call',
+              'abilityName': 'EntryAbility',
               'params': {
-                "func":"prev_song"
+                'formId': this.formId,
+                'method': 'prevSong'
               }
             });
           }
@@ -240,9 +243,11 @@ struct PlayerWidgetMedium {
           console.info('Heanup PlayerWidgetMedium: Play/Pause button clicked');
           if (!this.isLoading) {
             postCardAction(this, {
-              'action': 'message',
+              'action': 'call',
+              'abilityName': 'EntryAbility',
               'params': {
-                "func":"play_pause"
+                'formId': this.formId,
+                'method': 'playPause'
               }
             });
           }
@@ -264,9 +269,11 @@ struct PlayerWidgetMedium {
           console.info(`Heanup PlayerWidgetMedium: Next button clicked`);
           if (!this.isLoading && this.hasNext) {
             postCardAction(this, {
-              'action': 'message',
+              'action': 'call',
+              'abilityName': 'EntryAbility',
               'params': {
-                "func":"next_song"
+                'formId': this.formId,
+                'method': 'nextSong'
               }
             });
           }

+ 13 - 6
entry/src/main/ets/widget/pages/PlayerWidgetSmall.ets

@@ -8,6 +8,7 @@
 @Component
 struct PlayerWidgetSmall {
   // 卡片数据属性 - 使用LocalStorageProp与FormExtensionAbility通信
+  @LocalStorageProp('formId') formId: string = '12400633174999288';
   @LocalStorageProp('isPlaying') isPlaying: boolean = false;
   @LocalStorageProp('hasNext') hasNext: boolean = false;
   @LocalStorageProp('hasPrevious') hasPrevious: boolean = false;
@@ -32,9 +33,11 @@ struct PlayerWidgetSmall {
         console.info(`Heanup PlayerWidgetSmall: Previous button clicked`);
         if (!this.isLoading && this.hasPrevious) {
           postCardAction(this, {
-            'action': 'message',
+            'action': 'call',
+            'abilityName': 'EntryAbility',
             'params': {
-              "func":"prev_song"
+              'formId': this.formId,
+              'method': 'prevSong'
             }
           });
         }
@@ -56,9 +59,11 @@ struct PlayerWidgetSmall {
         console.info('Heanup PlayerWidgetSmall: Play/Pause button clicked');
         if (!this.isLoading) {
           postCardAction(this, {
-            'action': 'message',
+            'action': 'call',
+            'abilityName': 'EntryAbility',
             'params': {
-              "func":"play_pause"
+              'formId': this.formId,
+              'method': 'playPause'
             }
           });
         }
@@ -80,9 +85,11 @@ struct PlayerWidgetSmall {
         console.info(`Heanup PlayerWidgetSmall: Next button clicked`);
         if (!this.isLoading && this.hasNext) {
           postCardAction(this, {
-            'action': 'message',
+            'action': 'call',
+            'abilityName': 'EntryAbility',
             'params': {
-              "func":"next_song"
+              'formId': this.formId,
+              'method': 'nextSong'
             }
           });
         }

+ 5 - 2
entry/src/main/ets/widget/pages/PlayerWidgetSquare.ets

@@ -25,6 +25,7 @@ const PlayAlignRules: Record<string, Record<string, string | VerticalAlign | Hor
 @Component
 struct PlayerWidgetSquare {
   // 卡片数据属性 - 使用LocalStorageProp与FormExtensionAbility通信
+  @LocalStorageProp('formId') formId: string = '12400633174999288';
   @LocalStorageProp('isPlaying') isPlaying: boolean = false;
   @LocalStorageProp('songTitle') songTitle: string = 'Dream It Possible';
   @LocalStorageProp('songArtist') songArtist: string = 'Delacey';
@@ -140,9 +141,11 @@ struct PlayerWidgetSquare {
           console.info('Heanup PlayerWidgetSquare: Play/Pause button clicked');
           if (!this.isLoading) {
             postCardAction(this, {
-              'action': 'message',
+              'action': 'call',
+              'abilityName': 'EntryAbility',
               'params': {
-                "func":"play_pause"
+                'formId': this.formId,
+                'method': 'playPause'
               }
             });
           }