chendeben 1 год назад
Родитель
Сommit
1e583bd039

+ 1 - 2
entry/src/main/ets/common/constants/CommonConstants.ets

@@ -13,7 +13,6 @@
  * limitations under the License.
  */
 
-import { SettingPage } from '../../pages/SettingPage';
 import { VideoSpeed } from '../../viewmodel/VideoSpeed';
 
 /**
@@ -21,7 +20,7 @@ import { VideoSpeed } from '../../viewmodel/VideoSpeed';
  */
 export class CommonConstants {
 
-  static readonly DEFAULT_THEME_COLOR: string = SettingPage.THEME_COLOR_LIST[0].color
+  static readonly DEFAULT_THEME_COLOR: string = '#FF4081' // 玫瑰粉,避免循环依赖
 
   static readonly OPEN_DATE: string = '2025-06-10';
 

+ 0 - 1
entry/src/main/ets/common/service/PlayerManager.ets

@@ -9,7 +9,6 @@ import {
 } from '@ohos/ijkplayer';
 import { common } from '@kit.AbilityKit';
 import { PreferencesUtil } from '@pura/harmony-utils';
-import { SettingPage } from '../../pages/SettingPage';
 
 /**
  * 播放器状态回调接口

+ 292 - 2
entry/src/main/ets/common/service/UnifiedPlayerService.ets

@@ -10,6 +10,8 @@ import { DataPersistenceService, PlaylistSyncService, PlaylistSyncListener, IDat
 import { StateSyncService, IStateSyncService, StateChangeCallback, WidgetControlCallback } from './StateSyncService';
 import { ErrorRecoveryStrategy, IErrorRecoveryStrategy, ErrorContext, ErrorRecoveryAction } from './ErrorRecoveryStrategy';
 import { EnhancedFormUpdateService, UpdateStats } from '../widget/EnhancedFormUpdateService';
+import { AvSessionController } from '../../controller/AvSessionController';
+import { avSession } from '@kit.AVSessionKit';
 import json from '@ohos.util.json';
 
 /**
@@ -75,11 +77,13 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
   private stateSync: IStateSyncService;
   private errorRecovery: IErrorRecoveryStrategy;
   private widgetUpdateService: EnhancedFormUpdateService;
+  private avSessionController: AvSessionController | null = null; // 新增:AVSession控制器
   private context: common.UIAbilityContext | null = null;
   private progressTimer: number = -1;
   private isInitialized: boolean = false;
   private isDataRestored: boolean = false; // 新增:数据恢复完成标识
   private currentRetryCount: number = 0;
+  private lastAvSessionUpdate: number = 0; // 新增:上次AVSession更新时间
 
   private constructor() {
     this.playerManager = PlayerManager.getInstance();
@@ -126,6 +130,9 @@ async initialize(context: common.UIAbilityContext): Promise<void> {
       this.widgetUpdateService.setAppContext(context);
       LogUtils.getInstance().LOGI('UnifiedPlayerService: Widget update service initialized');
       
+      // 初始化AVSession控制器
+      this.initializeAvSession();
+      
       // 设置同步监听器
       this.playlistSync.addSyncListener(this);
       this.stateSync.subscribeToStateChanges(this);
@@ -145,11 +152,15 @@ async initialize(context: common.UIAbilityContext): Promise<void> {
         
         onStateChanged(state: PlayerState): void {
           this.stateSync.broadcastState(state);
+          // 状态变化时更新AVSession
+          this.unifiedService.updateSessionPlayState(state.isPlaying);
           // 状态变化时更新卡片
           this.unifiedService.updateWidgetsForStateChange(state);
         }
         onSongChanged(song: VideoItem): void {
           this.stateSync.broadcastSongChange(song);
+          // 歌曲变化时更新AVSession元数据
+          this.unifiedService.updateAvSessionMetadata(song);
           // 歌曲变化时更新卡片
           this.unifiedService.updateWidgetsForSongChange(song);
         }
@@ -270,6 +281,9 @@ async initialize(context: common.UIAbilityContext): Promise<void> {
         // 注意:实际播放和状态更新会在 onPrepared 回调中开始
       }
       
+      // 更新AVSession元数据
+      await this.updateAvSessionMetadata(currentSong);
+      
       // 恢复播放位置(如果有记忆播放功能)
       this.restorePlaybackPosition(currentSong);
       
@@ -343,8 +357,8 @@ async initialize(context: common.UIAbilityContext): Promise<void> {
       // 保存播放状态变化
       this.saveCurrentState();
       
-      // 更新卡片显示暂停状态
-      await this.updateWidgetsForPlayStateChange(false);
+      // 更新AVSession播放状态
+      this.updateSessionPlayState(false);
       
       LogUtils.getInstance().LOGI('UnifiedPlayerService: Playback paused');
     } catch (error) {
@@ -664,6 +678,12 @@ async initialize(context: common.UIAbilityContext): Promise<void> {
       // 保存当前状态
       this.saveCurrentState();
       
+      // 清理AVSession
+      if (this.avSessionController) {
+        this.avSessionController.unregisterSessionListener();
+        this.avSessionController = null;
+      }
+      
       // 清理同步监听器
       this.playlistSync.removeSyncListener(this);
       this.playlistSync.release();
@@ -681,6 +701,257 @@ async initialize(context: common.UIAbilityContext): Promise<void> {
     }
   }
 
+  // ==================== AVSession 控制方法 ====================
+  
+  /**
+   * 初始化AVSession
+   * 按照官方文档的要求:创建 -> 注册控制命令 -> 设置元数据 -> 激活
+   */
+  private initializeAvSession(): void {
+    try {
+      // 1. 创建AVSession控制器(音频模式)
+      this.avSessionController = AvSessionController.getInstance(false);
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession controller created');
+      
+      // 2. 延迟设置监听器,等待AVSession创建完成
+      setTimeout(() => {
+        this.setAvSessionListener();
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession listeners configured');
+      }, 500);
+      
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to initialize AVSession: ${error}`);
+    }
+  }
+  
+
+  
+  /**
+   * 设置AVSession监听器
+   * 注意:控制命令已在AvSessionController中注册,这里设置实际的处理逻辑
+   */
+  private setAvSessionListener(): void {
+    if (!this.avSessionController) {
+      return;
+    }
+    
+    const avSession = this.avSessionController.getAvSession();
+    if (!avSession) {
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession not available for listener setup');
+      return;
+    }
+    
+    try {
+      // 重新注册监听器,覆盖AvSessionController中的空实现
+      // 播放事件监听
+      avSession.on('play', () => {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession play command received');
+        this.startPlayOrResumePlay().catch((error: Error) => {
+          LogUtils.getInstance().LOGI(`AVSession play command failed: ${error}`);
+        });
+      });
+      
+      // 暂停事件监听
+      avSession.on('pause', () => {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession pause command received');
+        this.pause().catch((error: Error) => {
+          LogUtils.getInstance().LOGI(`AVSession pause command failed: ${error}`);
+        });
+      });
+      
+      // 停止事件监听
+      avSession.on('stop', () => {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession stop command received');
+        this.stop().catch((error: Error) => {
+          LogUtils.getInstance().LOGI(`AVSession stop command failed: ${error}`);
+        });
+      });
+      
+      // 下一首事件监听
+      avSession.on('playNext', () => {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession playNext command received');
+        this.playNext().catch((error: Error) => {
+          LogUtils.getInstance().LOGI(`AVSession playNext command failed: ${error}`);
+        });
+      });
+      
+      // 上一首事件监听
+      avSession.on('playPrevious', () => {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession playPrevious command received');
+        this.playPrevious().catch((error: Error) => {
+          LogUtils.getInstance().LOGI(`AVSession playPrevious command failed: ${error}`);
+        });
+      });
+      
+      // 拖拽进度事件监听
+      avSession.on('seek', (time: number) => {
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService: AVSession seek command received: ${time}ms`);
+        this.seekTo(time.toString()).catch((error: Error) => {
+          LogUtils.getInstance().LOGI(`AVSession seek command failed: ${error}`);
+        });
+      });
+      
+      // 循环模式设置监听
+      avSession.on('setLoopMode', (mode: avSession.LoopMode) => {
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService: AVSession setLoopMode command received: ${mode}`);
+        // 转换AVSession循环模式到应用内部播放模式
+        const playMode = this.convertLoopModeToPlayMode(mode);
+        this.setPlayMode(playMode);
+      });
+      
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession listeners set up successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to set AVSession listeners: ${error}`);
+    }
+  }
+  
+  /**
+   * 更新AVSession播放状态
+   * 按照官方文档要求设置完整的播放状态信息
+   */
+  private updateSessionPlayState(isPlaying: boolean): void {
+    if (!this.avSessionController) {
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession controller is null');
+      return;
+    }
+    
+    try {
+      // 检查AVSession状态
+      this.avSessionController.checkAvSessionStatus();
+      
+      const currentSong = this.playlistModel.getCurrentSong();
+      const currentPosition = this.getCurrentPosition();
+      const duration = currentSong?.duration ? Number(currentSong.duration) : 0;
+      const currentState = this.stateModel.getState();
+      
+      // 按照官方文档要求设置完整的播放状态
+      const playbackState: avSession.AVPlaybackState = {
+        // 播放状态
+        state: isPlaying ? avSession.PlaybackState.PLAYBACK_STATE_PLAY : avSession.PlaybackState.PLAYBACK_STATE_PAUSE,
+        
+        // 播放位置信息 - 用于进度条显示
+        position: {
+          elapsedTime: currentPosition, // 已播放时间(毫秒)
+          updateTime: Date.now() // 更新时间戳
+        },
+        
+        // 播放速度
+        speed: currentState.speed || 1.0,
+        
+        // 缓冲时间
+        bufferedTime: Math.max(currentPosition, 0),
+        
+        // 循环模式
+        loopMode: this.convertPlayModeToLoopMode(currentState.playMode),
+        
+        // 收藏状态
+        isFavorite: false // 可以根据实际收藏状态设置
+      };
+      
+      this.avSessionController.setAvSessionPlayState(playbackState);
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: AVSession play state updated: ${isPlaying ? 'PLAYING' : 'PAUSED'}, position: ${currentPosition}ms/${duration}ms, speed: ${playbackState.speed}x, loopMode: ${playbackState.loopMode}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to update AVSession play state: ${error}`);
+    }
+  }
+  
+  /**
+   * 设置当前播放模式到AVSession
+   */
+  private setCurrentPlayMode(): void {
+    if (!this.avSessionController) {
+      return;
+    }
+    
+    try {
+      const playMode = this.stateModel.getState().playMode;
+      const isPlaying = this.stateModel.getState().isPlaying;
+      const currentPosition = this.getCurrentPosition();
+      
+      const playbackState: avSession.AVPlaybackState = {
+        state: isPlaying ? avSession.PlaybackState.PLAYBACK_STATE_PLAY : avSession.PlaybackState.PLAYBACK_STATE_PAUSE,
+        position: {
+          elapsedTime: currentPosition,
+          updateTime: Date.now()
+        },
+        bufferedTime: currentPosition,
+        loopMode: this.convertPlayModeToLoopMode(playMode),
+        isFavorite: false
+      };
+      
+      this.avSessionController.setAvSessionPlayState(playbackState);
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: AVSession play mode updated: ${playMode}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to set AVSession play mode: ${error}`);
+    }
+  }
+  
+  /**
+   * 转换播放模式为AVSession循环模式
+   */
+  private convertPlayModeToLoopMode(playMode: PlayMode): avSession.LoopMode {
+    switch (playMode) {
+      case PlayMode.SINGLE_REPEAT:
+        return avSession.LoopMode.LOOP_MODE_SINGLE;
+      case PlayMode.NORMAL:
+        return avSession.LoopMode.LOOP_MODE_LIST;
+      case PlayMode.RANDOM:
+        return avSession.LoopMode.LOOP_MODE_SHUFFLE;
+      case PlayMode.SEQUENCE:
+      default:
+        return avSession.LoopMode.LOOP_MODE_SEQUENCE;
+    }
+  }
+  
+  /**
+   * 转换AVSession循环模式为播放模式
+   */
+  private convertLoopModeToPlayMode(loopMode: avSession.LoopMode): number {
+    switch (loopMode) {
+      case avSession.LoopMode.LOOP_MODE_SINGLE:
+        return PlayMode.SINGLE_REPEAT;
+      case avSession.LoopMode.LOOP_MODE_LIST:
+        return PlayMode.NORMAL;
+      case avSession.LoopMode.LOOP_MODE_SHUFFLE:
+        return PlayMode.RANDOM;
+      case avSession.LoopMode.LOOP_MODE_SEQUENCE:
+      default:
+        return PlayMode.SEQUENCE;
+    }
+  }
+  
+  /**
+   * 更新AVSession元数据
+   * 按照官方文档要求:设置必要的元数据(标题、副标题/歌手、封面图)
+   */
+  private async updateAvSessionMetadata(song: VideoItem): Promise<void> {
+    if (!this.avSessionController || !song) {
+      return;
+    }
+    
+    try {
+      const duration = song.duration ? Number(song.duration) : 0;
+      // 获取歌词内容(如果有的话)
+      const lyricContent = ''; // 这里可以根据需要获取歌词内容
+      
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Setting AVSession metadata for "${song.name}" by "${song.artist || '未知艺术家'}"`);
+      
+      // 调用AvSessionController设置元数据,它会处理激活逻辑
+      await this.avSessionController.setAVMetadataMusic(song, duration, lyricContent);
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: AVSession metadata and activation completed for ${song.name}`);
+      
+      // 元数据设置完成后,同步当前播放状态
+      setTimeout(() => {
+        const currentState = this.stateModel.getState();
+        this.updateSessionPlayState(currentState.isPlaying);
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService: AVSession state synced - playing: ${currentState.isPlaying}`);
+      }, 300); // 延迟300ms确保AVSession完全激活
+      
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to update AVSession metadata: ${error}`);
+    }
+  }
+  
   // ==================== 错误处理和恢复方法 ====================
   
   /**
@@ -932,6 +1203,14 @@ async initialize(context: common.UIAbilityContext): Promise<void> {
       const duration = ijkPlayer.getDuration();
       
       this.stateModel.updateProgress(currentPosition, duration);
+      
+      // 定期更新AVSession播放状态,确保系统媒体控制界面显示正确的进度
+      // 但不要太频繁,避免性能问题
+      const now = Date.now();
+      if (!this.lastAvSessionUpdate || now - this.lastAvSessionUpdate > 5000) { // 每5秒更新一次
+        this.lastAvSessionUpdate = now;
+        this.updateSessionPlayState(true);
+      }
     } catch (error) {
       LogUtils.getInstance().LOGI(`UnifiedPlayerService updateProgress error: ${error}`);
     }
@@ -1359,8 +1638,16 @@ async initialize(context: common.UIAbilityContext): Promise<void> {
     // 保存播放状态变化
     this.saveCurrentState();
     
+    // 立即更新AVSession播放状态
+    this.updateSessionPlayState(true);
+    
+    // 设置当前播放模式
+    this.setCurrentPlayMode();
+    
     // 播放开始时更新卡片显示播放状态
     this.updateWidgetsForPlayStateChange(true);
+    
+    LogUtils.getInstance().LOGI('UnifiedPlayerService: Playback started - AVSession state updated to PLAYING');
   }
 
   onPlaybackCompleted(): void {
@@ -1371,6 +1658,9 @@ async initialize(context: common.UIAbilityContext): Promise<void> {
     // 保存播放状态变化
     this.saveCurrentState();
     
+    // 更新AVSession播放状态
+    this.updateSessionPlayState(false);
+    
     // 更新卡片显示播放完成状态
     this.updateWidgetsForPlayStateChange(false);
     

+ 123 - 6
entry/src/main/ets/common/widget/PlayerControlService.ets

@@ -384,7 +384,59 @@ export class PlayerControlService {
    */
   async getCurrentPlayState(): Promise<WidgetData> {
     try {
-      // 优先从AvSession获取当前状态
+      // 优先从UnifiedPlayerService获取实时状态
+      if (this.unifiedPlayerService) {
+        const currentState = this.unifiedPlayerService.getCurrentState();
+        const currentSong = this.unifiedPlayerService.getCurrentSong();
+        const playlist = this.unifiedPlayerService.getPlaylist();
+        const currentIndex = this.unifiedPlayerService.getCurrentIndex();
+        
+        if (currentSong) {
+          const widgetData: WidgetData = {
+            playState: {
+              isPlaying: currentState.isPlaying || false,
+              isPaused: currentState.isPaused || true,
+              isLoading: currentState.isLoading || false
+            },
+            currentSong: {
+              id: currentSong.id || '',
+              title: currentSong.name || '暂无播放',
+              artist: currentSong.artist || '未知艺术家',
+              album: currentSong.album || '未知专辑',
+              coverImagePath: currentSong.pixelMapPath || '',
+              duration: currentSong.duration ? Number(currentSong.duration) : 0
+            },
+            progress: {
+              currentPosition: currentState.currentPosition || 0,
+              duration: currentState.duration || 0,
+              percentage: this.calculatePercentage(currentState.currentPosition || 0, currentState.duration || 0),
+              currentTimeText: this.formatTime(Math.floor((currentState.currentPosition || 0) / 1000)),
+              totalTimeText: this.formatTime(Math.floor((currentState.duration || 0) / 1000))
+            },
+            playlist: {
+              hasNext: currentState.hasNext || false,
+              hasPrevious: currentState.hasPrevious || false,
+              currentIndex: currentIndex,
+              totalCount: playlist.length
+            },
+            config: {
+              size: 'medium',
+              theme: 'auto',
+              showProgress: true,
+              showCover: true
+            }
+          };
+          
+          hilog.info(0x0000, TAG, `Got current state from UnifiedPlayerService: isPlaying=${widgetData.playState.isPlaying}, title=${widgetData.currentSong.title}`);
+          
+          // 更新AvSession监听器的缓存
+          this.avSessionListener.updateWidgetData(widgetData);
+          
+          return widgetData;
+        }
+      }
+      
+      // 备用方案:从AvSession获取当前状态
       const avSessionData = this.avSessionListener.getCurrentWidgetData();
       
       // 同时请求CommonEvent状态作为备用
@@ -434,16 +486,81 @@ export class PlayerControlService {
       return;
     }
     
-    // 延迟获取当前状态,给主应用时间来广播真实状态
-    setTimeout(() => {
+    // 立即尝试从UnifiedPlayerService获取当前状态
+    setTimeout(async () => {
       try {
+        // 优先从UnifiedPlayerService获取实时状态
+        if (this.unifiedPlayerService) {
+          const currentState = this.unifiedPlayerService.getCurrentState();
+          const currentSong = this.unifiedPlayerService.getCurrentSong();
+          const playlist = this.unifiedPlayerService.getPlaylist();
+          const currentIndex = this.unifiedPlayerService.getCurrentIndex();
+          
+          if (currentSong) {
+            // 构建完整的WidgetData
+            const widgetData: WidgetData = {
+              playState: {
+                isPlaying: currentState.isPlaying || false,
+                isPaused: currentState.isPaused || true,
+                isLoading: currentState.isLoading || false
+              },
+              currentSong: {
+                id: currentSong.id || '',
+                title: currentSong.name || '暂无播放',
+                artist: currentSong.artist || '未知艺术家',
+                album: currentSong.album || '未知专辑',
+                coverImagePath: currentSong.pixelMapPath || '',
+                duration: currentSong.duration ? Number(currentSong.duration) : 0
+              },
+              progress: {
+                currentPosition: currentState.currentPosition || 0,
+                duration: currentState.duration || 0,
+                percentage: this.calculatePercentage(currentState.currentPosition || 0, currentState.duration || 0),
+                currentTimeText: this.formatTime(Math.floor((currentState.currentPosition || 0) / 1000)),
+                totalTimeText: this.formatTime(Math.floor((currentState.duration || 0) / 1000))
+              },
+              playlist: {
+                hasNext: currentState.hasNext || false,
+                hasPrevious: currentState.hasPrevious || false,
+                currentIndex: currentIndex,
+                totalCount: playlist.length
+              },
+              config: {
+                size: 'medium',
+                theme: 'auto',
+                showProgress: true,
+                showCover: true
+              }
+            };
+            
+            hilog.info(0x0000, TAG, `Sending UnifiedPlayerService data to listener: isPlaying=${widgetData.playState.isPlaying}, title=${widgetData.currentSong.title}, hasNext=${widgetData.playlist.hasNext}, hasPrevious=${widgetData.playlist.hasPrevious}`);
+            
+            // 更新AvSession监听器的缓存数据
+            this.avSessionListener.updateWidgetData(widgetData);
+            
+            // 立即回调给监听器
+            callback(widgetData);
+            return;
+          }
+        }
+        
+        // 备用方案:从AvSession监听器获取缓存数据
         const currentData = this.avSessionListener.getCurrentWidgetData();
-        hilog.info(0x0000, TAG, `Sending current data to listener: hasNext=${currentData.playlist.hasNext}, hasPrevious=${currentData.playlist.hasPrevious}`);
+        hilog.info(0x0000, TAG, `Sending cached AvSession data to listener: hasNext=${currentData.playlist.hasNext}, hasPrevious=${currentData.playlist.hasPrevious}`);
         callback(currentData);
+        
       } catch (error) {
-        hilog.error(0x0000, TAG, `Error getting current AvSession data: ${error}`);
+        hilog.error(0x0000, TAG, `Error getting current state for new listener: ${error}`);
+        // 发送默认数据作为最后的备用方案
+        const defaultData = this.getDefaultWidgetData();
+        callback(defaultData);
       }
-    }, 1500); // 延迟1.5秒,确保主应用已经广播了状态
+    }, 500); // 减少延迟到500ms,提高响应速度
+    
+    // 额外的状态请求,确保能获取到最新状态
+    setTimeout(async () => {
+      await this.requestCurrentState();
+    }, 1000);
   }
 
   /**

+ 20 - 11
entry/src/main/ets/common/widget/WidgetDataManager.ets

@@ -2,7 +2,7 @@ import formProvider from '@ohos.app.form.formProvider';
 import formBindingData from '@ohos.app.form.formBindingData';
 import preferences from '@ohos.data.preferences';
 import { hilog } from '@kit.PerformanceAnalysisKit';
-import { WidgetData, WidgetSize, WidgetTheme, FormattedWidgetData, PreferencesData, CacheStats } from './WidgetTypes';
+import { WidgetData, WidgetSize, WidgetTheme, FormattedWidgetData, PreferencesData, CacheStats, PlayState, SongInfo, PlayProgress, PlaylistState, WidgetConfig } from './WidgetTypes';
 
 const TAG = 'WidgetDataManager';
 const WIDGET_PREFERENCES_NAME = 'widget_data_prefs';
@@ -54,12 +54,21 @@ export class WidgetDataManager {
    * 获取初始卡片数据
    */
   getInitialWidgetData(): WidgetData {
+    // 尝试从UnifiedPlayerService获取当前状态作为初始数据
+    try {
+      // 这里需要导入UnifiedPlayerService,但为了避免循环依赖,我们使用默认数据
+      // 实际的状态同步会通过PlayerControlService处理
+      hilog.info(0x0000, TAG, 'Getting initial widget data - using default values, real state will sync via PlayerControlService');
+    } catch (error) {
+      hilog.warn(0x0000, TAG, `Could not get real initial state: ${error}`);
+    }
+    
     const initialData: WidgetData = {
       playState: {
         isPlaying: false,
         isPaused: true,
         isLoading: false
-      },
+      } as PlayState,
       currentSong: {
         id: '',
         title: '暂无播放',
@@ -67,26 +76,26 @@ export class WidgetDataManager {
         album: '未知专辑',
         coverImagePath: '',
         duration: 0
-      },
+      } as SongInfo,
       progress: {
         currentPosition: 0,
         duration: 0,
         percentage: 0,
         currentTimeText: '00:00',
         totalTimeText: '00:00'
-      },
+      } as PlayProgress,
       playlist: {
         hasNext: false,
         hasPrevious: false,
         currentIndex: 0,
         totalCount: 0
-      },
+      } as PlaylistState,
       config: {
         size: WidgetSize.MEDIUM,
         theme: WidgetTheme.AUTO,
         showProgress: true,
         showCover: true
-      }
+      } as WidgetConfig
     };
     return initialData;
   }
@@ -467,7 +476,7 @@ export class WidgetDataManager {
         isPlaying: formattedData.isPlaying,
         isPaused: formattedData.isPaused,
         isLoading: formattedData.isLoading
-      },
+      } as PlayState,
       currentSong: {
         id: '', // FormattedWidgetData中没有id,使用空字符串
         title: formattedData.songTitle,
@@ -475,26 +484,26 @@ export class WidgetDataManager {
         album: formattedData.songAlbum,
         coverImagePath: formattedData.coverImage,
         duration: 0 // FormattedWidgetData中没有duration,使用0
-      },
+      } as SongInfo,
       progress: {
         currentPosition: 0, // 需要从时间文本反推,这里简化处理
         duration: 0,
         percentage: formattedData.progressPercentage,
         currentTimeText: formattedData.currentTime,
         totalTimeText: formattedData.totalTime
-      },
+      } as PlayProgress,
       playlist: {
         hasNext: formattedData.hasNext,
         hasPrevious: formattedData.hasPrevious,
         currentIndex: 0,
         totalCount: 0
-      },
+      } as PlaylistState,
       config: {
         size: this.parseWidgetSize(formattedData.widgetSize),
         theme: WidgetTheme.AUTO,
         showProgress: formattedData.showProgress,
         showCover: formattedData.showCover
-      }
+      } as WidgetConfig
     };
     return widgetData;
   }

+ 128 - 25
entry/src/main/ets/controller/AvSessionController.ets

@@ -21,7 +21,6 @@ import { BackgroundTaskManager } from '../common/util/BackgroundTaskManager';
 import { VideoItem } from '../viewmodel/VideoItem';
 import { ImageUtil, PreferencesUtil } from '@pura/harmony-utils';
 import { image } from '@kit.ImageKit';
-import { SettingPage } from '../pages/SettingPage';
 import { Utility } from '../common/util/Utility';
 import LyricUtil from '../common/util/LyricUtil';
 import ImageUtils from '../common/util/ImageUtils';
@@ -47,7 +46,7 @@ export class AvSessionController {
 
   public initAvSession(isVideo:boolean) {
     if(isVideo){
-      let isBgPlayOpen = PreferencesUtil.getBooleanSync(SettingPage.IS_BGPLAY_OPEN,true)
+      let isBgPlayOpen = PreferencesUtil.getBooleanSync('isBgPlayOpen',true)
       if(!isBgPlayOpen)
         return
     }
@@ -58,17 +57,25 @@ export class AvSessionController {
       return;
     }
     let type: avSession.AVSessionType = isVideo ? 'video' : 'audio';
-    avSession.createAVSession(this.context, 'sessionName', type).then(async (avSession) => {
+    avSession.createAVSession(this.context, 'TTMusic_Session', type).then(async (avSession) => {
       this.avSession = avSession;
       hilog.info(0x0000, TAG, `session create successed : sessionId : ${this.avSession.sessionId}`);
       BackgroundTaskManager.startContinuousTask(this.context);
       this.setLaunchAbility();
-      this.avSession.activate();
+      
+      // 设置扩展信息
       this.avSession.setExtras({
         requireAbilityList: ['url-cast']
       });
+      
+      // 注册控制命令监听器 - 必须在激活前注册
+      this.registerControlCommands();
+      
+      hilog.info(0x0000, TAG, 'Control commands registered, AVSession ready for metadata and activation');
+      
     }).catch((error:Error) => {
       console.error('Failed to create AVSession:', error);
+      hilog.error(0x0000, TAG, `Failed to create AVSession: ${error}`);
     });
   }
 
@@ -128,48 +135,69 @@ export class AvSessionController {
     }
   }
 
-  public async setAVMetadataMusic(curSource: VideoItem, duration: number,lyricContent?:string) {
+  public async setAVMetadataMusic(curSource: VideoItem, duration: number, lyricContent?: string) {
     if (curSource === undefined) {
       hilog.error(0x0000, TAG, 'SetAVMetadata Error, curSource is null');
       return;
     }
     try {
       BackgroundTaskManager.startContinuousTask(this.context);
-      let pixelMapPath:string|undefined = curSource.pixelMapPath
+      let pixelMapPath: string | undefined = curSource.pixelMapPath
 
-      let imagePixMap: PixelMap|string ;
-      if(pixelMapPath){
+      let imagePixMap: PixelMap | string;
+      if (pixelMapPath) {
         imagePixMap = await ImageUtils.imagePathToPixelMap(pixelMapPath)
-      }else{
+      } else {
         imagePixMap = await ImageUtil.getPixelMapFromMedia($r('app.media.ic_avatar2'));
       }
       let lyric = ''
-      if(lyricContent)
+      if (lyricContent)
         lyric = LyricUtil.convertLyricToSimpleLrc(lyricContent)
 
-      hilog.info(0x0000, TAG, 'onecold SetAVMetadata successfully curSource.pixelMapPath '+curSource.pixelMapPath);
+      hilog.info(0x0000, TAG, 'Setting AVMetadata with required fields');
+      
+      // 按照官方文档要求,设置必要的元数据:标题、副标题/歌手、封面图
       let metadata: avSession.AVMetadata = {
         assetId: `${curSource.filePath}`,
-        title: curSource.name,
-        filter: avSession.ProtocolType.TYPE_CAST_PLUS_STREAM|avSession.ProtocolType.TYPE_DLNA,
-        artist: curSource.artist,
-        mediaImage: imagePixMap,
+        title: curSource.name || '未知标题', // 必需:标题
+        artist: curSource.artist || '未知艺术家', // 必需:副标题/歌手
+        mediaImage: imagePixMap, // 必需:封面图
+        album: curSource.album || '未知专辑',
         duration: duration,
-        lyric:lyric,
+        lyric: lyric,
+        filter: avSession.ProtocolType.TYPE_CAST_PLUS_STREAM | avSession.ProtocolType.TYPE_DLNA,
       };
 
       if (this.avSession) {
-        this.avSession.setAVMetadata(metadata).then(() => {
-          this.avSessionMetadata = metadata;
-          hilog.info(0x0000, TAG, 'SetAVMetadata successfully');
-        }).catch((err: BusinessError) => {
-          hilog.error(0x0000, TAG, `SetAVMetadata BusinessError: code: ${err.code}, message: ${err.message}`);
-        });
+        // 设置元数据
+        await this.avSession.setAVMetadata(metadata);
+        this.avSessionMetadata = metadata;
+        hilog.info(0x0000, TAG, 'AVMetadata set successfully');
+        
+        // 按照官方文档:激活接口要在元数据、控制命令注册完成之后再执行
+        // 直接激活AVSession
+        await this.avSession.activate();
+        hilog.info(0x0000, TAG, 'AVSession activated successfully - should now be visible in system media controls');
+        
+        // 设置初始播放状态 - 根据文档,这是必需的
+        const initialPlaybackState: avSession.AVPlaybackState = {
+          state: avSession.PlaybackState.PLAYBACK_STATE_PAUSE,
+          position: {
+            elapsedTime: 0,
+            updateTime: Date.now()
+          },
+          bufferedTime: 0,
+          loopMode: avSession.LoopMode.LOOP_MODE_SEQUENCE,
+          isFavorite: false
+        };
+        
+        this.setAvSessionPlayState(initialPlaybackState);
+        hilog.info(0x0000, TAG, 'Initial playback state set - AVSession should now be visible in system controls');
       }
     } catch (error) {
-      console.warn(' setAVMetadataMusic:', error.message);
+      console.warn('setAVMetadataMusic error:', error.message);
+      hilog.error(0x0000, TAG, `SetAVMetadata error: ${error}`);
     }
-
   }
 
   public setAvSessionPlayState(playbackState: avSession.AVPlaybackState) {
@@ -179,9 +207,84 @@ export class AvSessionController {
         if (err) {
           hilog.error(0x0000, TAG, `SetAVPlaybackState BusinessError: code: ${err.code}, message: ${err.message}`);
         } else {
-          hilog.info(0x0000, TAG, 'SetAVPlaybackState successfully');
+          hilog.info(0x0000, TAG, `SetAVPlaybackState successfully - State: ${playbackState.state}, Position: ${playbackState.position?.elapsedTime}ms`);
         }
       });
+    } else {
+      hilog.error(0x0000, TAG, 'Cannot set playback state: AVSession is null');
+    }
+  }
+
+  /**
+   * 注册控制命令监听器
+   * 根据官方文档,必须在激活前注册所有需要的控制命令
+   */
+  private registerControlCommands(): void {
+    if (!this.avSession) {
+      hilog.error(0x0000, TAG, 'Cannot register commands: AVSession is null');
+      return;
+    }
+
+    try {
+      // 注册播放命令
+      this.avSession.on('play', () => {
+        hilog.info(0x0000, TAG, 'AVSession: Received play command');
+        // 这里会通过UnifiedPlayerService的监听器处理
+      });
+
+      // 注册暂停命令
+      this.avSession.on('pause', () => {
+        hilog.info(0x0000, TAG, 'AVSession: Received pause command');
+        // 这里会通过UnifiedPlayerService的监听器处理
+      });
+
+      // 注册停止命令
+      this.avSession.on('stop', () => {
+        hilog.info(0x0000, TAG, 'AVSession: Received stop command');
+        // 这里会通过UnifiedPlayerService的监听器处理
+      });
+
+      // 注册下一首命令
+      this.avSession.on('playNext', () => {
+        hilog.info(0x0000, TAG, 'AVSession: Received playNext command');
+        // 这里会通过UnifiedPlayerService的监听器处理
+      });
+
+      // 注册上一首命令
+      this.avSession.on('playPrevious', () => {
+        hilog.info(0x0000, TAG, 'AVSession: Received playPrevious command');
+        // 这里会通过UnifiedPlayerService的监听器处理
+      });
+
+      // 注册进度控制命令
+      this.avSession.on('seek', (time: number) => {
+        hilog.info(0x0000, TAG, `AVSession: Received seek command to ${time}ms`);
+        // 这里会通过UnifiedPlayerService的监听器处理
+      });
+
+      // 注册循环模式命令
+      this.avSession.on('setLoopMode', (mode: avSession.LoopMode) => {
+        hilog.info(0x0000, TAG, `AVSession: Received setLoopMode command: ${mode}`);
+        // 这里会通过UnifiedPlayerService的监听器处理
+      });
+
+      hilog.info(0x0000, TAG, 'All control commands registered successfully');
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to register control commands: ${error}`);
+    }
+  }
+
+  /**
+   * 检查AVSession状态
+   */
+  public checkAvSessionStatus(): void {
+    if (this.avSession) {
+      hilog.info(0x0000, TAG, `AVSession status - ID: ${this.avSession.sessionId}`);
+      if (this.avSessionMetadata) {
+        hilog.info(0x0000, TAG, `AVSession metadata - Title: ${this.avSessionMetadata.title}, Artist: ${this.avSessionMetadata.artist}`);
+      }
+    } else {
+      hilog.warn(0x0000, TAG, 'AVSession is null');
     }
   }
 

+ 132 - 2
entry/src/main/ets/entryability/EntryAbility.ets

@@ -14,17 +14,63 @@ import { AbilityConstant, Want } from '@kit.AbilityKit';
 import { BusinessError, emitter } from '@kit.BasicServicesKit';
 import { AppUtil, ArrayUtil, GlobalContext, LogUtil, StrUtil } from '@pura/harmony-utils';
 import { rpc } from '@kit.IPCKit';
-
 import { Utility } from '../common/util/Utility';
 import { WXApi, WXEventHandler } from '../common/util/WXApiWrap';
 import { UnifiedPlayerService } from '../common/service/UnifiedPlayerService';
 import { WidgetRegistrationFix } from '../common/widget/WidgetRegistrationFix';
-
 import { systemShare } from '@kit.ShareKit';
 import { SpiderMan } from '@simplepeng/spider-man';
 import { smartMobilityCommon } from '@kit.CarKit';
 
 
+
+/**
+ * 播放状态广播数据接口
+ */
+interface PlayStateBroadcast {
+  isPlaying: boolean;
+  isPaused: boolean;
+  isLoading: boolean;
+}
+
+interface SongBroadcast {
+  id: string;
+  title: string;
+  artist: string;
+  album: string;
+  coverImagePath: string;
+  duration: number;
+}
+
+interface ProgressBroadcast {
+  currentPosition: number;
+  duration: number;
+  percentage: number;
+  currentTimeText: string;
+  totalTimeText: string;
+}
+
+interface PlaylistBroadcast {
+  hasNext: boolean;
+  hasPrevious: boolean;
+  currentIndex: number;
+  totalCount: number;
+}
+
+interface BroadcastData {
+  playState: PlayStateBroadcast;
+  currentSong: SongBroadcast;
+  progress: ProgressBroadcast;
+  playlist: PlaylistBroadcast;
+}
+
+interface PublishInfo {
+  data: string;
+}
+
+interface EventDataWrapper {
+  data: BroadcastData;
+}
 /**
  * RPC通信返回类型的实现,用于RPC通信数据序列化和反序列化
  */
@@ -115,6 +161,11 @@ export default class EntryAbility extends UIAbility {
         try {
             await UnifiedPlayerService.getInstance().initialize(this.context);
             hilog.info(0x0000, 'Heanup2', '✅ UnifiedPlayerService initialized successfully');
+            
+            // 延迟广播当前状态,确保卡片能接收到初始状态
+            setTimeout(() => {
+                this.broadcastCurrentPlayerState();
+            }, 2000);
         } catch (error) {
             hilog.error(0x0000, 'Heanup2', `❌ Failed to initialize UnifiedPlayerService: ${error}`);
         }
@@ -498,4 +549,83 @@ export default class EntryAbility extends UIAbility {
             }
         }, 3000);
     }
+
+    /**
+     * 广播当前播放器状态给卡片
+     */
+    private broadcastCurrentPlayerState(): void {
+        try {
+            const unifiedService = UnifiedPlayerService.getInstance();
+            const currentState = unifiedService.getCurrentState();
+            const currentSong = unifiedService.getCurrentSong();
+            const playlist = unifiedService.getPlaylist();
+            const currentIndex = unifiedService.getCurrentIndex();
+            
+            if (currentSong) {
+                // 构建播放器状态广播数据
+                const broadcastData: BroadcastData = {
+                    playState: {
+                        isPlaying: currentState.isPlaying || false,
+                        isPaused: currentState.isPaused || true,
+                        isLoading: currentState.isLoading || false
+                    } as PlayStateBroadcast,
+                    currentSong: {
+                        id: currentSong.id || '',
+                        title: currentSong.name || '暂无播放',
+                        artist: currentSong.artist || '未知艺术家',
+                        album: currentSong.album || '未知专辑',
+                        coverImagePath: currentSong.pixelMapPath || '',
+                        duration: currentSong.duration ? Number(currentSong.duration) : 0
+                    } as SongBroadcast,
+                    progress: {
+                        currentPosition: currentState.currentPosition || 0,
+                        duration: currentState.duration || 0,
+                        percentage: this.calculatePercentage(currentState.currentPosition || 0, currentState.duration || 0),
+                        currentTimeText: this.formatTime(Math.floor((currentState.currentPosition || 0) / 1000)),
+                        totalTimeText: this.formatTime(Math.floor((currentState.duration || 0) / 1000))
+                    } as ProgressBroadcast,
+                    playlist: {
+                        hasNext: currentState.hasNext || false,
+                        hasPrevious: currentState.hasPrevious || false,
+                        currentIndex: currentIndex,
+                        totalCount: playlist.length
+                    } as PlaylistBroadcast
+                };
+                
+                // 发送状态变化事件
+                const publishInfo: PublishInfo = {
+                    data: JSON.stringify(broadcastData)
+                };
+                
+                // 使用emitter发送事件
+                const eventData: EventDataWrapper = {
+                    data: broadcastData
+                };
+                emitter.emit({ eventId: 1001 }, eventData); // 使用特定的事件ID
+                
+                hilog.info(0x0000, 'Heanup2', `📡 Broadcasted current player state: ${currentSong.name}, isPlaying=${currentState.isPlaying}`);
+            } else {
+                hilog.info(0x0000, 'Heanup2', '📡 No current song to broadcast');
+            }
+        } catch (error) {
+            hilog.error(0x0000, 'Heanup2', `❌ Failed to broadcast current player state: ${error}`);
+        }
+    }
+
+    /**
+     * 计算播放进度百分比
+     */
+    private calculatePercentage(current: number, total: number): number {
+        if (total <= 0) return 0;
+        return Math.min(100, Math.max(0, (current / total) * 100));
+    }
+
+    /**
+     * 格式化时间显示
+     */
+    private formatTime(seconds: number): string {
+        const mins = Math.floor(seconds / 60);
+        const secs = Math.floor(seconds % 60);
+        return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
+    }
 }