Explorar o código

抽取ijkplayer播放服务

chendeben hai 1 ano
pai
achega
98d17ebbb4

+ 835 - 0
entry/src/main/ets/common/service/DataPersistenceService.ets

@@ -0,0 +1,835 @@
+import { VideoItem } from '../../viewmodel/VideoItem';
+import { PlayerState, PlayMode } from './PlayerStateModel';
+import { PreferencesUtil } from '@pura/harmony-utils';
+import { LogUtils } from '@ohos/ijkplayer';
+import { common } from '@kit.AbilityKit';
+
+/**
+ * 存储键名接口
+ */
+interface StorageKeys {
+  PLAYLIST: string;
+  PLAYER_STATE: string;
+  PROGRESS_PREFIX: string;
+  COMPLETED_SONGS: string;
+}
+
+/**
+ * 播放进度数据接口
+ */
+export interface PlaybackProgress {
+  songId: string;
+  filePath: string;
+  position: number;
+  duration: number;
+  timestamp: number;
+  completed: boolean;
+}
+
+/**
+ * 播放列表数据接口
+ */
+export interface PlaylistData {
+  songs: VideoItem[];
+  currentIndex: number;
+  playMode: PlayMode;
+  timestamp: number;
+}
+
+/**
+ * 播放状态数据接口
+ */
+export interface PlayerStateData {
+  isPlaying: boolean;
+  isPaused: boolean;
+  currentIndex: number;
+  playMode: PlayMode;
+  volume: number;
+  speed: number;
+  timestamp: number;
+}
+
+/**
+ * 数据统计信息接口
+ */
+export interface DataStats {
+  playlistSize: number;
+  progressRecords: number;
+  completedSongs: number;
+  lastUpdate: number;
+}
+
+/**
+ * 同步状态接口
+ */
+export interface SyncStatus {
+  autoSyncEnabled: boolean;
+  lastSyncTimestamp: number;
+  syncInterval: number;
+}
+
+/**
+ * 数据持久化服务接口
+ */
+export interface IDataPersistenceService {
+  // 播放进度相关
+  savePlaybackProgress(songId: string, filePath: string, position: number, duration: number): Promise<void>;
+  loadPlaybackProgress(songId: string): Promise<PlaybackProgress | null>;
+  clearPlaybackProgress(songId: string): Promise<void>;
+  clearCompletedProgress(): Promise<void>;
+  
+  // 播放列表相关
+  savePlaylist(playlist: VideoItem[], currentIndex: number, playMode: PlayMode): Promise<void>;
+  loadPlaylist(): Promise<PlaylistData | null>;
+  
+  // 播放状态相关
+  savePlayerState(state: PlayerState): Promise<void>;
+  loadPlayerState(): Promise<PlayerStateData | null>;
+  
+  // 初始化和清理
+  initialize(context: common.UIAbilityContext): Promise<void>;
+  clearAllData(): Promise<void>;
+}
+
+/**
+ * 数据持久化服务实现
+ * 处理播放列表、播放状态和播放进度的持久化存储
+ */
+export class DataPersistenceService implements IDataPersistenceService {
+  private static instance: DataPersistenceService | null = null;
+  private context: common.UIAbilityContext | null = null;
+  private isInitialized: boolean = false;
+  
+  // 存储键名常量
+  private static readonly KEYS: StorageKeys = {
+    PLAYLIST: 'player_playlist',
+    PLAYER_STATE: 'player_state',
+    PROGRESS_PREFIX: 'playback_progress_',
+    COMPLETED_SONGS: 'completed_songs'
+  };
+  
+  // 播放完成阈值(5秒)
+  private static readonly COMPLETION_THRESHOLD = 5000;
+  
+  private constructor() {
+    LogUtils.getInstance().LOGI('DataPersistenceService: Instance created');
+  }
+  
+  public static getInstance(): DataPersistenceService {
+    if (!DataPersistenceService.instance) {
+      DataPersistenceService.instance = new DataPersistenceService();
+    }
+    return DataPersistenceService.instance;
+  }
+  
+  async initialize(context: common.UIAbilityContext): Promise<void> {
+    if (this.isInitialized) {
+      LogUtils.getInstance().LOGI('DataPersistenceService: Already initialized');
+      return;
+    }
+    
+    try {
+      this.context = context;
+      this.isInitialized = true;
+      
+      LogUtils.getInstance().LOGI('DataPersistenceService: Initialized successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService initialization error: ${error}`);
+      throw new Error;
+    }
+  }  
+  
+  // ==================== 播放进度记忆功能实现 ====================
+  
+  /**
+   * 保存播放进度
+   * 实现播放位置的自动保存机制
+   */
+  async savePlaybackProgress(songId: string, filePath: string, position: number, duration: number): Promise<void> {
+    try {
+      if (!this.isInitialized) {
+        throw new Error('DataPersistenceService not initialized');
+      }
+      
+      // 检查是否接近播放完成
+      const isCompleted = duration > 0 && (duration - position) < DataPersistenceService.COMPLETION_THRESHOLD;
+      
+      const progressData: PlaybackProgress = {
+        songId,
+        filePath,
+        position: isCompleted ? 0 : position, // 播放完成时保存为0
+        duration,
+        timestamp: Date.now(),
+        completed: isCompleted
+      };
+      
+      const key = DataPersistenceService.KEYS.PROGRESS_PREFIX + songId;
+      
+      // 保存到PreferencesUtil
+      await PreferencesUtil.put(key, JSON.stringify(progressData));
+      
+      // 同时保存到AppStorage以便快速访问
+      AppStorage.setOrCreate(key, progressData);
+      
+      // 如果播放完成,添加到已完成列表
+      if (isCompleted) {
+        await this.addToCompletedSongs(songId);
+      }
+      
+      LogUtils.getInstance().LOGI(`DataPersistenceService: Saved progress for ${songId}: ${position}ms (completed: ${isCompleted})`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService savePlaybackProgress error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 加载播放进度
+   * 实现应用重启后的播放位置恢复
+   */
+  async loadPlaybackProgress(songId: string): Promise<PlaybackProgress | null> {
+    try {
+      if (!this.isInitialized) {
+        throw new Error('DataPersistenceService not initialized');
+      }
+      
+      const key = DataPersistenceService.KEYS.PROGRESS_PREFIX + songId;
+      
+      // 优先从AppStorage获取(内存中的数据)
+      let progressData = AppStorage.get<PlaybackProgress>(key);
+      
+      if (!progressData) {
+        // 从PreferencesUtil获取持久化数据
+        const progressStr = await PreferencesUtil.getString(key, '');
+        if (progressStr) {
+          try {
+            progressData = JSON.parse(progressStr) as PlaybackProgress;
+            // 同步到AppStorage
+            AppStorage.setOrCreate(key, progressData);
+          } catch (parseError) {
+            LogUtils.getInstance().LOGI(`DataPersistenceService: Failed to parse progress data for ${songId}: ${parseError}`);
+            return null;
+          }
+        }
+      }
+      
+      if (progressData) {
+        LogUtils.getInstance().LOGI(`DataPersistenceService: Loaded progress for ${songId}: ${progressData.position}ms`);
+        return progressData;
+      }
+      
+      return null;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService loadPlaybackProgress error: ${error}`);
+      return null;
+    }
+  }
+  
+  /**
+   * 清除播放进度
+   * 添加播放完成时的进度清理逻辑
+   */
+  async clearPlaybackProgress(songId: string): Promise<void> {
+    try {
+      if (!this.isInitialized) {
+        throw new Error('DataPersistenceService not initialized');
+      }
+      
+      const key = DataPersistenceService.KEYS.PROGRESS_PREFIX + songId;
+      
+      // 从PreferencesUtil删除
+      await PreferencesUtil.delete(key);
+      
+      // 从AppStorage删除
+      AppStorage.delete(key);
+      
+      LogUtils.getInstance().LOGI(`DataPersistenceService: Cleared progress for ${songId}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService clearPlaybackProgress error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 清理已完成播放的进度记录
+   */
+  async clearCompletedProgress(): Promise<void> {
+    try {
+      if (!this.isInitialized) {
+        throw new Error('DataPersistenceService not initialized');
+      }
+      
+      // 获取已完成的歌曲列表
+      const completedSongs = await this.getCompletedSongs();
+      
+      // 清理每个已完成歌曲的进度记录
+      for (const songId of completedSongs) {
+        await this.clearPlaybackProgress(songId);
+      }
+      
+      // 清空已完成列表
+      await PreferencesUtil.delete(DataPersistenceService.KEYS.COMPLETED_SONGS);
+      AppStorage.delete(DataPersistenceService.KEYS.COMPLETED_SONGS);
+      
+      LogUtils.getInstance().LOGI(`DataPersistenceService: Cleared ${completedSongs.length} completed progress records`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService clearCompletedProgress error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 添加歌曲到已完成列表
+   */
+  private async addToCompletedSongs(songId: string): Promise<void> {
+    try {
+      const completedSongs = await this.getCompletedSongs();
+      if (!completedSongs.includes(songId)) {
+        completedSongs.push(songId);
+        await PreferencesUtil.put(DataPersistenceService.KEYS.COMPLETED_SONGS, JSON.stringify(completedSongs));
+        AppStorage.setOrCreate(DataPersistenceService.KEYS.COMPLETED_SONGS, completedSongs);
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService addToCompletedSongs error: ${error}`);
+    }
+  }
+  
+  /**
+   * 获取已完成播放的歌曲列表
+   */
+  private async getCompletedSongs(): Promise<string[]> {
+    try {
+      // 优先从AppStorage获取
+      let completedSongs = AppStorage.get<string[]>(DataPersistenceService.KEYS.COMPLETED_SONGS);
+      
+      if (!completedSongs) {
+        // 从PreferencesUtil获取
+        const completedStr = await PreferencesUtil.getString(DataPersistenceService.KEYS.COMPLETED_SONGS, '[]');
+        try {
+          completedSongs = JSON.parse(completedStr) as string[];
+          AppStorage.setOrCreate(DataPersistenceService.KEYS.COMPLETED_SONGS, completedSongs);
+        } catch (parseError) {
+          LogUtils.getInstance().LOGI(`DataPersistenceService: Failed to parse completed songs: ${parseError}`);
+          completedSongs = [];
+        }
+      }
+      
+      return completedSongs || [];
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService getCompletedSongs error: ${error}`);
+      return [];
+    }
+  }  
+  // ==================== 播放列表持久化功能实现 ====================
+  
+  /**
+   * 保存播放列表
+   */
+  async savePlaylist(playlist: VideoItem[], currentIndex: number, playMode: PlayMode): Promise<void> {
+    try {
+      if (!this.isInitialized) {
+        throw new Error('DataPersistenceService not initialized');
+      }
+      
+      const playlistData: PlaylistData = {
+        songs: playlist,
+        currentIndex,
+        playMode,
+        timestamp: Date.now()
+      };
+      
+      // 保存到PreferencesUtil
+      await PreferencesUtil.put(DataPersistenceService.KEYS.PLAYLIST, JSON.stringify(playlistData));
+      
+      // 同时保存到AppStorage
+      AppStorage.setOrCreate(DataPersistenceService.KEYS.PLAYLIST, playlistData);
+      
+      LogUtils.getInstance().LOGI(`DataPersistenceService: Saved playlist with ${playlist.length} songs, index ${currentIndex}, mode ${playMode}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService savePlaylist error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 加载播放列表
+   */
+  async loadPlaylist(): Promise<PlaylistData | null> {
+    try {
+      if (!this.isInitialized) {
+        throw new Error('DataPersistenceService not initialized');
+      }
+      
+      // 优先从AppStorage获取
+      let playlistData = AppStorage.get<PlaylistData>(DataPersistenceService.KEYS.PLAYLIST);
+      
+      if (!playlistData) {
+        // 从PreferencesUtil获取
+        const playlistStr = await PreferencesUtil.getString(DataPersistenceService.KEYS.PLAYLIST, '');
+        if (playlistStr) {
+          try {
+            playlistData = JSON.parse(playlistStr) as PlaylistData;
+            // 同步到AppStorage
+            AppStorage.setOrCreate(DataPersistenceService.KEYS.PLAYLIST, playlistData);
+          } catch (parseError) {
+            LogUtils.getInstance().LOGI(`DataPersistenceService: Failed to parse playlist data: ${parseError}`);
+            return null;
+          }
+        }
+      }
+      
+      if (playlistData) {
+        LogUtils.getInstance().LOGI(`DataPersistenceService: Loaded playlist with ${playlistData.songs.length} songs`);
+        return playlistData;
+      }
+      
+      return null;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService loadPlaylist error: ${error}`);
+      return null;
+    }
+  }
+  
+  // ==================== 播放状态持久化功能实现 ====================
+  
+  /**
+   * 保存播放状态
+   */
+  async savePlayerState(state: PlayerState): Promise<void> {
+    try {
+      if (!this.isInitialized) {
+        throw new Error('DataPersistenceService not initialized');
+      }
+      
+      const stateData: PlayerStateData = {
+        isPlaying: state.isPlaying,
+        isPaused: state.isPaused,
+        currentIndex: state.currentIndex,
+        playMode: state.playMode,
+        volume: state.volume,
+        speed: state.speed,
+        timestamp: Date.now()
+      };
+      
+      // 保存到PreferencesUtil
+      await PreferencesUtil.put(DataPersistenceService.KEYS.PLAYER_STATE, JSON.stringify(stateData));
+      
+      // 同时保存到AppStorage
+      AppStorage.setOrCreate(DataPersistenceService.KEYS.PLAYER_STATE, stateData);
+      
+      LogUtils.getInstance().LOGI(`DataPersistenceService: Saved player state - playing: ${state.isPlaying}, index: ${state.currentIndex}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService savePlayerState error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 加载播放状态
+   */
+  async loadPlayerState(): Promise<PlayerStateData | null> {
+    try {
+      if (!this.isInitialized) {
+        throw new Error('DataPersistenceService not initialized');
+      }
+      
+      // 优先从AppStorage获取
+      let stateData = AppStorage.get<PlayerStateData>(DataPersistenceService.KEYS.PLAYER_STATE);
+      
+      if (!stateData) {
+        // 从PreferencesUtil获取
+        const stateStr = await PreferencesUtil.getString(DataPersistenceService.KEYS.PLAYER_STATE, '');
+        if (stateStr) {
+          try {
+            stateData = JSON.parse(stateStr) as PlayerStateData;
+            // 同步到AppStorage
+            AppStorage.setOrCreate(DataPersistenceService.KEYS.PLAYER_STATE, stateData);
+          } catch (parseError) {
+            LogUtils.getInstance().LOGI(`DataPersistenceService: Failed to parse state data: ${parseError}`);
+            return null;
+          }
+        }
+      }
+      
+      if (stateData) {
+        LogUtils.getInstance().LOGI(`DataPersistenceService: Loaded player state - playing: ${stateData.isPlaying}, index: ${stateData.currentIndex}`);
+        return stateData;
+      }
+      
+      return null;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService loadPlayerState error: ${error}`);
+      return null;
+    }
+  }
+  
+  // ==================== 数据清理和维护功能 ====================
+  
+  /**
+   * 清除所有持久化数据
+   */
+  async clearAllData(): Promise<void> {
+    try {
+      if (!this.isInitialized) {
+        throw new Error('DataPersistenceService not initialized');
+      }
+      
+      // 清除播放列表
+      await PreferencesUtil.delete(DataPersistenceService.KEYS.PLAYLIST);
+      AppStorage.delete(DataPersistenceService.KEYS.PLAYLIST);
+      
+      // 清除播放状态
+      await PreferencesUtil.delete(DataPersistenceService.KEYS.PLAYER_STATE);
+      AppStorage.delete(DataPersistenceService.KEYS.PLAYER_STATE);
+      
+      // 清除所有播放进度
+      await this.clearCompletedProgress();
+      
+      LogUtils.getInstance().LOGI('DataPersistenceService: All data cleared');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService clearAllData error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 数据同步检查
+   * 确保AppStorage和PreferencesUtil数据一致性
+   */
+  async syncData(): Promise<void> {
+    try {
+      if (!this.isInitialized) {
+        return;
+      }
+      
+      // 同步播放列表数据
+      const playlistData = await this.loadPlaylist();
+      if (playlistData) {
+        AppStorage.setOrCreate(DataPersistenceService.KEYS.PLAYLIST, playlistData);
+      }
+      
+      // 同步播放状态数据
+      const stateData = await this.loadPlayerState();
+      if (stateData) {
+        AppStorage.setOrCreate(DataPersistenceService.KEYS.PLAYER_STATE, stateData);
+      }
+      
+      LogUtils.getInstance().LOGI('DataPersistenceService: Data synchronized');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService syncData error: ${error}`);
+    }
+  }
+  
+  /**
+   * 获取数据统计信息
+   */
+  async getDataStats(): Promise<DataStats> {
+    try {
+      const playlistData = await this.loadPlaylist();
+      const completedSongs = await this.getCompletedSongs();
+      
+      const stats: DataStats = {
+        playlistSize: playlistData?.songs.length || 0,
+        progressRecords: 0, // 这里可以扩展统计所有进度记录
+        completedSongs: completedSongs.length,
+        lastUpdate: Math.max(
+          playlistData?.timestamp || 0,
+          (await this.loadPlayerState())?.timestamp || 0
+        )
+      };
+      return stats;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`DataPersistenceService getDataStats error: ${error}`);
+      const errorStats: DataStats = {
+        playlistSize: 0,
+        progressRecords: 0,
+        completedSongs: 0,
+        lastUpdate: 0
+      };
+      return errorStats;
+    }
+  }
+}
+/**
+
+ * 播放列表同步服务
+ * 实现与PreferencesUtil的数据同步和数据变化监听
+ */
+export class PlaylistSyncService {
+  private static instance: PlaylistSyncService | null = null;
+  private dataPersistence: DataPersistenceService;
+  private syncListeners: Set<PlaylistSyncListener> = new Set();
+  private autoSyncEnabled: boolean = true;
+  private syncTimer: number = -1;
+  private lastSyncTimestamp: number = 0;
+  
+  // 同步间隔(毫秒)
+  private static readonly SYNC_INTERVAL = 5000; // 5秒
+  
+  private constructor() {
+    this.dataPersistence = DataPersistenceService.getInstance();
+    LogUtils.getInstance().LOGI('PlaylistSyncService: Instance created');
+  }
+  
+  public static getInstance(): PlaylistSyncService {
+    if (!PlaylistSyncService.instance) {
+      PlaylistSyncService.instance = new PlaylistSyncService();
+    }
+    return PlaylistSyncService.instance;
+  }
+  
+  /**
+   * 初始化同步服务
+   */
+  async initialize(context: common.UIAbilityContext): Promise<void> {
+    try {
+      await this.dataPersistence.initialize(context);
+      
+      if (this.autoSyncEnabled) {
+        this.startAutoSync();
+      }
+      
+      LogUtils.getInstance().LOGI('PlaylistSyncService: Initialized successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlaylistSyncService initialization error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 同步播放列表到持久化存储
+   * 确保与LocalMusic的播放列表数据一致性
+   */
+  async syncPlaylistToStorage(playlist: VideoItem[], currentIndex: number, playMode: PlayMode): Promise<void> {
+    try {
+      // 保存到持久化存储
+      await this.dataPersistence.savePlaylist(playlist, currentIndex, playMode);
+      
+      // 更新同步时间戳
+      this.lastSyncTimestamp = Date.now();
+      
+      // 通知监听器
+      this.notifyPlaylistSynced(playlist, currentIndex, playMode);
+      
+      LogUtils.getInstance().LOGI(`PlaylistSyncService: Synced playlist with ${playlist.length} songs to storage`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlaylistSyncService syncPlaylistToStorage error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 从持久化存储同步播放列表
+   */
+  async syncPlaylistFromStorage(): Promise<PlaylistData | null> {
+    try {
+      const playlistData = await this.dataPersistence.loadPlaylist();
+      
+      if (playlistData) {
+        // 通知监听器
+        this.notifyPlaylistLoaded(playlistData);
+        LogUtils.getInstance().LOGI(`PlaylistSyncService: Synced playlist with ${playlistData.songs.length} songs from storage`);
+      }
+      
+      return playlistData;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlaylistSyncService syncPlaylistFromStorage error: ${error}`);
+      return null;
+    }
+  }
+  
+  /**
+   * 双向同步播放列表
+   * 比较本地和存储中的数据,选择最新的版本
+   */
+  async bidirectionalSync(localPlaylist: VideoItem[], localIndex: number, localPlayMode: PlayMode): Promise<PlaylistData> {
+    try {
+      const storedData = await this.dataPersistence.loadPlaylist();
+      
+      // 如果没有存储的数据,使用本地数据
+      if (!storedData) {
+        await this.syncPlaylistToStorage(localPlaylist, localIndex, localPlayMode);
+        return {
+          songs: localPlaylist,
+          currentIndex: localIndex,
+          playMode: localPlayMode,
+          timestamp: Date.now()
+        };
+      }
+      
+      // 比较时间戳,使用更新的数据
+      const localTimestamp = this.lastSyncTimestamp || Date.now();
+      
+      if (storedData.timestamp > localTimestamp) {
+        // 存储的数据更新,使用存储的数据
+        LogUtils.getInstance().LOGI('PlaylistSyncService: Using stored playlist (newer)');
+        return storedData;
+      } else {
+        // 本地数据更新,同步到存储
+        await this.syncPlaylistToStorage(localPlaylist, localIndex, localPlayMode);
+        LogUtils.getInstance().LOGI('PlaylistSyncService: Using local playlist (newer)');
+        return {
+          songs: localPlaylist,
+          currentIndex: localIndex,
+          playMode: localPlayMode,
+          timestamp: Date.now()
+        };
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlaylistSyncService bidirectionalSync error: ${error}`);
+      // 出错时返回本地数据
+      return {
+        songs: localPlaylist,
+        currentIndex: localIndex,
+        playMode: localPlayMode,
+        timestamp: Date.now()
+      };
+    }
+  }
+  
+  /**
+   * 启动自动同步
+   */
+  startAutoSync(): void {
+    if (this.syncTimer !== -1) {
+      return; // 已经启动
+    }
+    
+    this.syncTimer = setInterval(async () => {
+      try {
+        await this.performAutoSync();
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`PlaylistSyncService auto sync error: ${error}`);
+      }
+    }, PlaylistSyncService.SYNC_INTERVAL);
+    
+    LogUtils.getInstance().LOGI('PlaylistSyncService: Auto sync started');
+  }
+  
+  /**
+   * 停止自动同步
+   */
+  stopAutoSync(): void {
+    if (this.syncTimer !== -1) {
+      clearInterval(this.syncTimer);
+      this.syncTimer = -1;
+      LogUtils.getInstance().LOGI('PlaylistSyncService: Auto sync stopped');
+    }
+  }
+  
+  /**
+   * 执行自动同步
+   */
+  private async performAutoSync(): Promise<void> {
+    try {
+      // 检查数据一致性
+      await this.dataPersistence.syncData();
+      
+      // 通知监听器执行同步检查
+      this.notifyAutoSyncPerformed();
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlaylistSyncService performAutoSync error: ${error}`);
+    }
+  }
+  
+  /**
+   * 设置自动同步开关
+   */
+  setAutoSyncEnabled(enabled: boolean): void {
+    this.autoSyncEnabled = enabled;
+    
+    if (enabled) {
+      this.startAutoSync();
+    } else {
+      this.stopAutoSync();
+    }
+    
+    LogUtils.getInstance().LOGI(`PlaylistSyncService: Auto sync ${enabled ? 'enabled' : 'disabled'}`);
+  }
+  
+  /**
+   * 添加同步监听器
+   */
+  addSyncListener(listener: PlaylistSyncListener): void {
+    this.syncListeners.add(listener);
+    LogUtils.getInstance().LOGI('PlaylistSyncService: Sync listener added');
+  }
+  
+  /**
+   * 移除同步监听器
+   */
+  removeSyncListener(listener: PlaylistSyncListener): void {
+    this.syncListeners.delete(listener);
+    LogUtils.getInstance().LOGI('PlaylistSyncService: Sync listener removed');
+  }
+  
+  /**
+   * 通知播放列表已同步到存储
+   */
+  private notifyPlaylistSynced(playlist: VideoItem[], currentIndex: number, playMode: PlayMode): void {
+    this.syncListeners.forEach(listener => {
+      try {
+        listener.onPlaylistSynced?.(playlist, currentIndex, playMode);
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`PlaylistSyncService: Error notifying playlist synced: ${error}`);
+      }
+    });
+  }
+  
+  /**
+   * 通知播放列表已从存储加载
+   */
+  private notifyPlaylistLoaded(playlistData: PlaylistData): void {
+    this.syncListeners.forEach(listener => {
+      try {
+        listener.onPlaylistLoaded?.(playlistData);
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`PlaylistSyncService: Error notifying playlist loaded: ${error}`);
+      }
+    });
+  }
+  
+  /**
+   * 通知自动同步已执行
+   */
+  private notifyAutoSyncPerformed(): void {
+    this.syncListeners.forEach(listener => {
+      try {
+        listener.onAutoSyncPerformed?.();
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`PlaylistSyncService: Error notifying auto sync: ${error}`);
+      }
+    });
+  }
+  
+  /**
+   * 获取同步状态
+   */
+  getSyncStatus(): SyncStatus {
+    const status: SyncStatus = {
+      autoSyncEnabled: this.autoSyncEnabled,
+      lastSyncTimestamp: this.lastSyncTimestamp,
+      syncInterval: PlaylistSyncService.SYNC_INTERVAL
+    };
+    return status;
+  }
+  
+  /**
+   * 清理资源
+   */
+  release(): void {
+    this.stopAutoSync();
+    this.syncListeners.clear();
+    LogUtils.getInstance().LOGI('PlaylistSyncService: Resources released');
+  }
+}
+
+/**
+ * 播放列表同步监听器接口
+ */
+export interface PlaylistSyncListener {
+  onPlaylistSynced?(playlist: VideoItem[], currentIndex: number, playMode: PlayMode): void;
+  onPlaylistLoaded?(playlistData: PlaylistData): void;
+  onAutoSyncPerformed?(): void;
+  onSyncError?(error: Error): void;
+}

+ 186 - 0
entry/src/main/ets/common/service/DataPersistenceServiceTest.ets

@@ -0,0 +1,186 @@
+import { DataPersistenceService, PlaylistSyncService } from './DataPersistenceService';
+import { VideoItem } from '../../viewmodel/VideoItem';
+import { PlayMode } from './PlayerStateModel';
+import { LogUtils } from '@ohos/ijkplayer';
+
+/**
+ * DataPersistenceService 测试类
+ * 用于验证数据持久化功能的正确性
+ */
+export class DataPersistenceServiceTest {
+  private dataPersistence: DataPersistenceService;
+  private playlistSync: PlaylistSyncService;
+  
+  constructor() {
+    this.dataPersistence = DataPersistenceService.getInstance();
+    this.playlistSync = PlaylistSyncService.getInstance();
+  }
+  
+  /**
+   * 测试播放进度记忆功能
+   */
+  async testPlaybackProgressMemory(): Promise<boolean> {
+    try {
+      const testSongId = 'test_song_001';
+      const testFilePath = '/storage/test/song.mp3';
+      const testPosition = 120000; // 2分钟
+      const testDuration = 300000; // 5分钟
+      
+      // 测试保存播放进度
+      await this.dataPersistence.savePlaybackProgress(testSongId, testFilePath, testPosition, testDuration);
+      LogUtils.getInstance().LOGI('DataPersistenceServiceTest: Progress saved successfully');
+      
+      // 测试加载播放进度
+      const loadedProgress = await this.dataPersistence.loadPlaybackProgress(testSongId);
+      if (!loadedProgress) {
+        LogUtils.getInstance().LOGE('DataPersistenceServiceTest: Failed to load progress');
+        return false;
+      }
+      
+      // 验证数据正确性
+      if (loadedProgress.position !== testPosition || 
+          loadedProgress.duration !== testDuration ||
+          loadedProgress.filePath !== testFilePath) {
+        LogUtils.getInstance().LOGE('DataPersistenceServiceTest: Progress data mismatch');
+        return false;
+      }
+      
+      // 测试清除播放进度
+      await this.dataPersistence.clearPlaybackProgress(testSongId);
+      const clearedProgress = await this.dataPersistence.loadPlaybackProgress(testSongId);
+      if (clearedProgress !== null) {
+        LogUtils.getInstance().LOGE('DataPersistenceServiceTest: Progress not cleared properly');
+        return false;
+      }
+      
+      LogUtils.getInstance().LOGI('DataPersistenceServiceTest: Playback progress memory test passed');
+      return true;
+    } catch (error) {
+      LogUtils.getInstance().LOGE(`DataPersistenceServiceTest: Progress memory test failed: ${error}`);
+      return false;
+    }
+  }
+  
+  /**
+   * 测试播放列表同步功能
+   */
+  async testPlaylistSync(): Promise<boolean> {
+    try {
+      // 创建测试播放列表
+      const testPlaylist: VideoItem[] = [
+        {
+          name: 'Test Song 1',
+          filePath: '/storage/test/song1.mp3',
+          artist: 'Test Artist 1',
+          album: 'Test Album',
+          pixelMapPath: ''
+        } as VideoItem,
+        {
+          name: 'Test Song 2', 
+          filePath: '/storage/test/song2.mp3',
+          artist: 'Test Artist 2',
+          album: 'Test Album',
+          pixelMapPath: ''
+        } as VideoItem
+      ];
+      
+      const testIndex = 1;
+      const testPlayMode = PlayMode.RANDOM;
+      
+      // 测试保存播放列表
+      await this.dataPersistence.savePlaylist(testPlaylist, testIndex, testPlayMode);
+      LogUtils.getInstance().LOGI('DataPersistenceServiceTest: Playlist saved successfully');
+      
+      // 测试加载播放列表
+      const loadedPlaylist = await this.dataPersistence.loadPlaylist();
+      if (!loadedPlaylist) {
+        LogUtils.getInstance().LOGE('DataPersistenceServiceTest: Failed to load playlist');
+        return false;
+      }
+      
+      // 验证数据正确性
+      if (loadedPlaylist.songs.length !== testPlaylist.length ||
+          loadedPlaylist.currentIndex !== testIndex ||
+          loadedPlaylist.playMode !== testPlayMode) {
+        LogUtils.getInstance().LOGE('DataPersistenceServiceTest: Playlist data mismatch');
+        return false;
+      }
+      
+      // 验证歌曲数据
+      for (let i = 0; i < testPlaylist.length; i++) {
+        if (loadedPlaylist.songs[i].name !== testPlaylist[i].name ||
+            loadedPlaylist.songs[i].filePath !== testPlaylist[i].filePath) {
+          LogUtils.getInstance().LOGE(`DataPersistenceServiceTest: Song ${i} data mismatch`);
+          return false;
+        }
+      }
+      
+      LogUtils.getInstance().LOGI('DataPersistenceServiceTest: Playlist sync test passed');
+      return true;
+    } catch (error) {
+      LogUtils.getInstance().LOGE(`DataPersistenceServiceTest: Playlist sync test failed: ${error}`);
+      return false;
+    }
+  }
+  
+  /**
+   * 测试双向同步功能
+   */
+  async testBidirectionalSync(): Promise<boolean> {
+    try {
+      const localPlaylist: VideoItem[] = [
+        {
+          name: 'Local Song',
+          filePath: '/storage/local/song.mp3',
+          artist: 'Local Artist',
+          album: 'Local Album',
+          pixelMapPath: ''
+        } as VideoItem
+      ];
+      
+      const localIndex = 0;
+      const localPlayMode = PlayMode.SEQUENCE;
+      
+      // 测试双向同步
+      const syncedData = await this.playlistSync.bidirectionalSync(localPlaylist, localIndex, localPlayMode);
+      
+      if (!syncedData) {
+        LogUtils.getInstance().LOGE('DataPersistenceServiceTest: Bidirectional sync returned null');
+        return false;
+      }
+      
+      // 验证同步结果
+      if (syncedData.songs.length === 0) {
+        LogUtils.getInstance().LOGE('DataPersistenceServiceTest: Synced playlist is empty');
+        return false;
+      }
+      
+      LogUtils.getInstance().LOGI('DataPersistenceServiceTest: Bidirectional sync test passed');
+      return true;
+    } catch (error) {
+      LogUtils.getInstance().LOGE(`DataPersistenceServiceTest: Bidirectional sync test failed: ${error}`);
+      return false;
+    }
+  }
+  
+  /**
+   * 运行所有测试
+   */
+  async runAllTests(): Promise<boolean> {
+    LogUtils.getInstance().LOGI('DataPersistenceServiceTest: Starting all tests...');
+    
+    const progressTest = await this.testPlaybackProgressMemory();
+    const playlistTest = await this.testPlaylistSync();
+    const syncTest = await this.testBidirectionalSync();
+    
+    const allPassed = progressTest && playlistTest && syncTest;
+    
+    if (allPassed) {
+      LogUtils.getInstance().LOGI('DataPersistenceServiceTest: All tests passed!');
+    } else {
+      LogUtils.getInstance().LOGE('DataPersistenceServiceTest: Some tests failed');
+    }
+    
+    return allPassed;
+  }
+}

+ 397 - 0
entry/src/main/ets/common/service/ErrorRecoveryStrategy.ets

@@ -0,0 +1,397 @@
+import { VideoItem } from '../../viewmodel/VideoItem';
+import { PlayerError, PlayerErrorType } from './PlayerStateModel';
+import { LogUtils } from '@ohos/ijkplayer';
+import { fileIo } from '@kit.CoreFileKit';
+import { connection } from '@kit.NetworkKit';
+
+/**
+ * 错误恢复策略接口
+ */
+export interface IErrorRecoveryStrategy {
+  handleError(error: PlayerError, context: ErrorContext): Promise<ErrorRecoveryAction>;
+  shouldRetry(error: PlayerError): boolean;
+  getRetryDelay(retryCount: number): number;
+  canSkipToNext(): boolean;
+}
+
+/**
+ * 错误上下文信息
+ */
+export interface ErrorContext {
+  currentSong: VideoItem | null;
+  playlist: VideoItem[];
+  currentIndex: number;
+  retryCount: number;
+  isNetworkAvailable: boolean;
+}
+
+/**
+ * 错误恢复动作
+ */
+export enum ErrorRecoveryAction {
+  RETRY = 'retry',           // 重试当前操作
+  SKIP_TO_NEXT = 'skip_next', // 跳到下一首
+  STOP_PLAYBACK = 'stop',    // 停止播放
+  WAIT_AND_RETRY = 'wait_retry', // 等待后重试
+  SHOW_ERROR = 'show_error'  // 显示错误信息
+}
+
+/**
+ * 错误恢复结果
+ */
+export interface ErrorRecoveryResult {
+  action: ErrorRecoveryAction;
+  delay?: number;
+  message?: string;
+  shouldNotifyUser?: boolean;
+}
+
+/**
+ * 网络状态检查器
+ */
+class NetworkChecker {
+  /**
+   * 检查网络连接状态
+   */
+  static async checkNetworkAvailability(): Promise<boolean> {
+    try {
+      const netHandle = await connection.getDefaultNet();
+      const capabilities = await connection.getNetCapabilities(netHandle);
+      return capabilities.bearerTypes.length > 0;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`NetworkChecker: Failed to check network: ${error}`);
+      return false;
+    }
+  }
+
+  /**
+   * 检查是否为网络URL
+   */
+  static isNetworkUrl(url: string): boolean {
+    return url.startsWith('http://') || url.startsWith('https://') || url.startsWith('rtmp://');
+  }
+}
+
+/**
+ * 文件检查器
+ */
+class FileChecker {
+  /**
+   * 检查文件是否存在
+   */
+  static async checkFileExists(filePath: string): Promise<boolean> {
+    try {
+      const stat = await fileIo.stat(filePath);
+      return stat.isFile();
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`FileChecker: File not found: ${filePath}`);
+      return false;
+    }
+  }
+
+  /**
+   * 检查文件是否可读
+   */
+  static async checkFileReadable(filePath: string): Promise<boolean> {
+    try {
+      await fileIo.access(filePath);
+      return true;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`FileChecker: File not readable: ${filePath}`);
+      return false;
+    }
+  }
+
+  /**
+   * 获取文件大小
+   */
+  static async getFileSize(filePath: string): Promise<number> {
+    try {
+      const stat = await fileIo.stat(filePath);
+      return stat.size;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`FileChecker: Failed to get file size: ${filePath}`);
+      return 0;
+    }
+  }
+}
+
+/**
+ * 错误恢复策略实现
+ */
+export class ErrorRecoveryStrategy implements IErrorRecoveryStrategy {
+  private static instance: ErrorRecoveryStrategy | null = null;
+  private readonly maxRetries: number = 3;
+  private readonly baseRetryDelay: number = 1000; // 1秒基础延迟
+  private readonly maxRetryDelay: number = 10000; // 最大10秒延迟
+  private readonly networkRetryDelay: number = 5000; // 网络错误重试延迟5秒
+
+  private constructor() {}
+
+  public static getInstance(): ErrorRecoveryStrategy {
+    if (!ErrorRecoveryStrategy.instance) {
+      ErrorRecoveryStrategy.instance = new ErrorRecoveryStrategy();
+    }
+    return ErrorRecoveryStrategy.instance;
+  }
+
+  /**
+   * 处理播放错误
+   */
+  async handleError(error: PlayerError, context: ErrorContext): Promise<ErrorRecoveryAction> {
+    LogUtils.getInstance().LOGI(`ErrorRecoveryStrategy: Handling error - type: ${error.type}, message: ${error.message}, retryCount: ${error.retryCount}`);
+
+    // 根据错误类型制定恢复策略
+    switch (error.type) {
+      case PlayerErrorType.FILE_NOT_FOUND:
+        return await this.handleFileNotFoundError(error, context);
+      
+      case PlayerErrorType.NETWORK_ERROR:
+        return await this.handleNetworkError(error, context);
+      
+      case PlayerErrorType.PLAYBACK_ERROR:
+        return await this.handlePlaybackError(error, context);
+      
+      case PlayerErrorType.INITIALIZATION_ERROR:
+        return await this.handleInitializationError(error, context);
+      
+      case PlayerErrorType.AUDIO_FOCUS_ERROR:
+        return await this.handleAudioFocusError(error, context);
+      
+      default:
+        return await this.handleGenericError(error, context);
+    }
+  }
+
+  /**
+   * 处理文件不存在错误
+   */
+  private async handleFileNotFoundError(error: PlayerError, context: ErrorContext): Promise<ErrorRecoveryAction> {
+    if (!context.currentSong) {
+      return ErrorRecoveryAction.STOP_PLAYBACK;
+    }
+
+    // 检查文件是否真的不存在
+    const fileExists = await FileChecker.checkFileExists(context.currentSong.filePath);
+    if (!fileExists) {
+      LogUtils.getInstance().LOGI(`ErrorRecoveryStrategy: File not found: ${context.currentSong.filePath}`);
+      
+      // 如果有下一首歌,跳到下一首
+      if (this.canSkipToNextWithContext(context)) {
+        return ErrorRecoveryAction.SKIP_TO_NEXT;
+      } else {
+        return ErrorRecoveryAction.STOP_PLAYBACK;
+      }
+    }
+
+    // 文件存在但无法访问,检查权限
+    const fileReadable = await FileChecker.checkFileReadable(context.currentSong.filePath);
+    if (!fileReadable) {
+      LogUtils.getInstance().LOGI(`ErrorRecoveryStrategy: File not readable: ${context.currentSong.filePath}`);
+      return this.canSkipToNextWithContext(context) ? ErrorRecoveryAction.SKIP_TO_NEXT : ErrorRecoveryAction.STOP_PLAYBACK;
+    }
+
+    // 文件存在且可读,可能是临时问题,尝试重试
+    if (this.shouldRetry(error)) {
+      return ErrorRecoveryAction.RETRY;
+    } else {
+      return this.canSkipToNextWithContext(context) ? ErrorRecoveryAction.SKIP_TO_NEXT : ErrorRecoveryAction.STOP_PLAYBACK;
+    }
+  }
+
+  /**
+   * 处理网络错误
+   */
+  private async handleNetworkError(error: PlayerError, context: ErrorContext): Promise<ErrorRecoveryAction> {
+    if (!context.currentSong) {
+      return ErrorRecoveryAction.STOP_PLAYBACK;
+    }
+
+    // 检查是否为网络资源
+    const isNetworkResource = NetworkChecker.isNetworkUrl(context.currentSong.filePath);
+    if (!isNetworkResource) {
+      // 不是网络资源但报网络错误,可能是其他问题
+      return this.shouldRetry(error) ? ErrorRecoveryAction.RETRY : ErrorRecoveryAction.SKIP_TO_NEXT;
+    }
+
+    // 检查网络连接状态
+    const networkAvailable = await NetworkChecker.checkNetworkAvailability();
+    if (!networkAvailable) {
+      LogUtils.getInstance().LOGI('ErrorRecoveryStrategy: Network not available, waiting for connection');
+      
+      // 网络不可用,等待网络恢复后重试
+      if (error.retryCount < this.maxRetries) {
+        return ErrorRecoveryAction.WAIT_AND_RETRY;
+      } else {
+        // 超过重试次数,跳到下一首(如果下一首是本地文件)
+        return this.canSkipToNextWithContext(context) ? ErrorRecoveryAction.SKIP_TO_NEXT : ErrorRecoveryAction.SHOW_ERROR;
+      }
+    }
+
+    // 网络可用但连接失败,可能是服务器问题
+    if (this.shouldRetry(error)) {
+      return ErrorRecoveryAction.WAIT_AND_RETRY;
+    } else {
+      return this.canSkipToNextWithContext(context) ? ErrorRecoveryAction.SKIP_TO_NEXT : ErrorRecoveryAction.SHOW_ERROR;
+    }
+  }
+
+  /**
+   * 处理播放错误
+   */
+  private async handlePlaybackError(error: PlayerError, context: ErrorContext): Promise<ErrorRecoveryAction> {
+    if (!context.currentSong) {
+      return ErrorRecoveryAction.STOP_PLAYBACK;
+    }
+
+    // 检查文件完整性
+    if (!NetworkChecker.isNetworkUrl(context.currentSong.filePath)) {
+      const fileSize = await FileChecker.getFileSize(context.currentSong.filePath);
+      if (fileSize === 0) {
+        LogUtils.getInstance().LOGI(`ErrorRecoveryStrategy: File is empty or corrupted: ${context.currentSong.filePath}`);
+        return this.canSkipToNextWithContext(context) ? ErrorRecoveryAction.SKIP_TO_NEXT : ErrorRecoveryAction.STOP_PLAYBACK;
+      }
+    }
+
+    // 播放错误可能是临时的,尝试重试
+    if (this.shouldRetry(error)) {
+      return ErrorRecoveryAction.RETRY;
+    } else {
+      return this.canSkipToNextWithContext(context) ? ErrorRecoveryAction.SKIP_TO_NEXT : ErrorRecoveryAction.STOP_PLAYBACK;
+    }
+  }
+
+  /**
+   * 处理初始化错误
+   */
+  private async handleInitializationError(error: PlayerError, context: ErrorContext): Promise<ErrorRecoveryAction> {
+    // 初始化错误通常需要重试
+    if (this.shouldRetry(error)) {
+      return ErrorRecoveryAction.WAIT_AND_RETRY;
+    } else {
+      return ErrorRecoveryAction.SHOW_ERROR;
+    }
+  }
+
+  /**
+   * 处理音频焦点错误
+   */
+  private async handleAudioFocusError(error: PlayerError, context: ErrorContext): Promise<ErrorRecoveryAction> {
+    // 音频焦点错误通常不需要跳歌,等待焦点恢复
+    LogUtils.getInstance().LOGI('ErrorRecoveryStrategy: Audio focus error, pausing playback');
+    return ErrorRecoveryAction.STOP_PLAYBACK;
+  }
+
+  /**
+   * 处理通用错误
+   */
+  private async handleGenericError(error: PlayerError, context: ErrorContext): Promise<ErrorRecoveryAction> {
+    if (this.shouldRetry(error)) {
+      return ErrorRecoveryAction.RETRY;
+    } else {
+      return this.canSkipToNextWithContext(context) ? ErrorRecoveryAction.SKIP_TO_NEXT : ErrorRecoveryAction.SHOW_ERROR;
+    }
+  }
+
+  /**
+   * 判断是否应该重试
+   */
+  shouldRetry(error: PlayerError): boolean {
+    if (!error.recoverable) {
+      return false;
+    }
+    return error.retryCount < this.maxRetries;
+  }
+
+  /**
+   * 获取重试延迟时间
+   */
+  getRetryDelay(retryCount: number): number {
+    // 指数退避算法:基础延迟 * 2^重试次数
+    const delay = Math.min(
+      this.baseRetryDelay * Math.pow(2, retryCount),
+      this.maxRetryDelay
+    );
+    
+    // 网络错误使用固定延迟
+    return delay;
+  }
+
+  /**
+   * 获取网络错误重试延迟
+   */
+  getNetworkRetryDelay(): number {
+    return this.networkRetryDelay;
+  }
+
+  /**
+   * 判断是否可以跳到下一首
+   */
+  canSkipToNext(): boolean {
+    return true; // 基础实现总是允许跳歌
+  }
+
+  /**
+   * 判断是否可以跳到下一首(带上下文)
+   */
+  private canSkipToNextWithContext(context: ErrorContext): boolean {
+    return context.playlist.length > 1 && context.currentIndex < context.playlist.length - 1;
+  }
+
+  /**
+   * 创建错误恢复结果
+   */
+  createRecoveryResult(
+    action: ErrorRecoveryAction,
+    delay?: number,
+    message?: string,
+    shouldNotifyUser: boolean = false
+  ): ErrorRecoveryResult {
+    return {
+      action,
+      delay,
+      message,
+      shouldNotifyUser
+    };
+  }
+
+  /**
+   * 获取错误描述信息
+   */
+  getErrorDescription(error: PlayerError): string {
+    switch (error.type) {
+      case PlayerErrorType.FILE_NOT_FOUND:
+        return '文件不存在或无法访问';
+      case PlayerErrorType.NETWORK_ERROR:
+        return '网络连接错误';
+      case PlayerErrorType.PLAYBACK_ERROR:
+        return '播放出现错误';
+      case PlayerErrorType.INITIALIZATION_ERROR:
+        return '播放器初始化失败';
+      case PlayerErrorType.AUDIO_FOCUS_ERROR:
+        return '音频焦点丢失';
+      default:
+        return '未知错误';
+    }
+  }
+
+  /**
+   * 获取恢复动作描述
+   */
+  getRecoveryActionDescription(action: ErrorRecoveryAction): string {
+    switch (action) {
+      case ErrorRecoveryAction.RETRY:
+        return '正在重试...';
+      case ErrorRecoveryAction.SKIP_TO_NEXT:
+        return '跳到下一首';
+      case ErrorRecoveryAction.STOP_PLAYBACK:
+        return '停止播放';
+      case ErrorRecoveryAction.WAIT_AND_RETRY:
+        return '等待网络恢复后重试...';
+      case ErrorRecoveryAction.SHOW_ERROR:
+        return '显示错误信息';
+      default:
+        return '处理错误中...';
+    }
+  }
+}

+ 244 - 0
entry/src/main/ets/common/service/ErrorRecoveryStrategyTest.ets

@@ -0,0 +1,244 @@
+import { ErrorRecoveryStrategy, ErrorContext, ErrorRecoveryAction } from './ErrorRecoveryStrategy';
+import { PlayerError, PlayerErrorType } from './PlayerStateModel';
+import { VideoItem } from '../../viewmodel/VideoItem';
+import { LogUtils } from '@ohos/ijkplayer';
+
+/**
+ * 错误恢复策略测试类
+ * 用于验证错误恢复机制的正确性
+ */
+export class ErrorRecoveryStrategyTest {
+  private errorRecovery: ErrorRecoveryStrategy;
+
+  constructor() {
+    this.errorRecovery = ErrorRecoveryStrategy.getInstance();
+  }
+
+  /**
+   * 运行所有测试
+   */
+  async runAllTests(): Promise<void> {
+    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Starting all tests');
+
+    try {
+      await this.testFileNotFoundError();
+      await this.testNetworkError();
+      await this.testPlaybackError();
+      await this.testInitializationError();
+      await this.testRetryLogic();
+      await this.testSkipLogic();
+
+      LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: All tests completed successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`ErrorRecoveryStrategyTest: Test failed: ${error}`);
+    }
+  }
+
+  /**
+   * 测试文件不存在错误
+   */
+  private async testFileNotFoundError(): Promise<void> {
+    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing file not found error');
+
+    const error = new PlayerError(PlayerErrorType.FILE_NOT_FOUND, 'Test file not found');
+    const context = this.createTestContext();
+
+    const action = await this.errorRecovery.handleError(error, context);
+    
+    if (action === ErrorRecoveryAction.SKIP_TO_NEXT) {
+      LogUtils.getInstance().LOGI('✅ File not found error test passed');
+    } else {
+      throw new Error(`Expected SKIP_TO_NEXT, got ${action}`);
+    }
+  }
+
+  /**
+   * 测试网络错误
+   */
+  private async testNetworkError(): Promise<void> {
+    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing network error');
+
+    const error = new PlayerError(PlayerErrorType.NETWORK_ERROR, 'Test network error');
+    error.retryCount = 0;
+    
+    const context = this.createTestContext();
+    context.currentSong = this.createNetworkSong();
+
+    const action = await this.errorRecovery.handleError(error, context);
+    
+    if (action === ErrorRecoveryAction.WAIT_AND_RETRY || action === ErrorRecoveryAction.RETRY) {
+      LogUtils.getInstance().LOGI('✅ Network error test passed');
+    } else {
+      throw new Error(`Expected WAIT_AND_RETRY or RETRY, got ${action}`);
+    }
+  }
+
+  /**
+   * 测试播放错误
+   */
+  private async testPlaybackError(): Promise<void> {
+    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing playback error');
+
+    const error = new PlayerError(PlayerErrorType.PLAYBACK_ERROR, 'Test playback error');
+    error.retryCount = 0;
+    
+    const context = this.createTestContext();
+
+    const action = await this.errorRecovery.handleError(error, context);
+    
+    if (action === ErrorRecoveryAction.RETRY) {
+      LogUtils.getInstance().LOGI('✅ Playback error test passed');
+    } else {
+      throw new Error(`Expected RETRY, got ${action}`);
+    }
+  }
+
+  /**
+   * 测试初始化错误
+   */
+  private async testInitializationError(): Promise<void> {
+    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing initialization error');
+
+    const error = new PlayerError(PlayerErrorType.INITIALIZATION_ERROR, 'Test initialization error');
+    error.retryCount = 0;
+    
+    const context = this.createTestContext();
+
+    const action = await this.errorRecovery.handleError(error, context);
+    
+    if (action === ErrorRecoveryAction.WAIT_AND_RETRY) {
+      LogUtils.getInstance().LOGI('✅ Initialization error test passed');
+    } else {
+      throw new Error(`Expected WAIT_AND_RETRY, got ${action}`);
+    }
+  }
+
+  /**
+   * 测试重试逻辑
+   */
+  private async testRetryLogic(): Promise<void> {
+    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing retry logic');
+
+    const error = new PlayerError(PlayerErrorType.PLAYBACK_ERROR, 'Test retry logic');
+    
+    // 测试重试次数限制
+    error.retryCount = 0;
+    if (!this.errorRecovery.shouldRetry(error)) {
+      throw new Error('Should retry when retryCount is 0');
+    }
+    
+    error.retryCount = 3;
+    if (this.errorRecovery.shouldRetry(error)) {
+      throw new Error('Should not retry when retryCount exceeds limit');
+    }
+    
+    // 测试不可恢复错误
+    const nonRecoverableError = new PlayerError(PlayerErrorType.FILE_NOT_FOUND, 'Non-recoverable error');
+    if (this.errorRecovery.shouldRetry(nonRecoverableError)) {
+      throw new Error('Should not retry non-recoverable errors');
+    }
+    
+    // 测试重试延迟
+    const delay1 = this.errorRecovery.getRetryDelay(0);
+    const delay2 = this.errorRecovery.getRetryDelay(1);
+    const delay3 = this.errorRecovery.getRetryDelay(2);
+    
+    if (delay1 >= delay2 || delay2 >= delay3) {
+      throw new Error('Retry delay should increase with retry count');
+    }
+
+    LogUtils.getInstance().LOGI('✅ Retry logic test passed');
+  }
+
+  /**
+   * 测试跳歌逻辑
+   */
+  private async testSkipLogic(): Promise<void> {
+    LogUtils.getInstance().LOGI('ErrorRecoveryStrategyTest: Testing skip logic');
+
+    // 测试有下一首歌的情况
+    const error = new PlayerError(PlayerErrorType.FILE_NOT_FOUND, 'Test skip logic');
+    const context = this.createTestContext();
+    context.currentIndex = 0;
+    context.playlist = [this.createTestSong('song1'), this.createTestSong('song2')];
+
+    const action = await this.errorRecovery.handleError(error, context);
+    
+    if (action !== ErrorRecoveryAction.SKIP_TO_NEXT) {
+      throw new Error(`Expected SKIP_TO_NEXT when next song available, got ${action}`);
+    }
+
+    // 测试没有下一首歌的情况
+    context.currentIndex = 1;
+    context.playlist = [this.createTestSong('song1'), this.createTestSong('song2')];
+
+    const action2 = await this.errorRecovery.handleError(error, context);
+    
+    if (action2 !== ErrorRecoveryAction.STOP_PLAYBACK) {
+      throw new Error(`Expected STOP_PLAYBACK when no next song, got ${action2}`);
+    }
+
+    LogUtils.getInstance().LOGI('✅ Skip logic test passed');
+  }
+
+  /**
+   * 创建测试上下文
+   */
+  private createTestContext(): ErrorContext {
+    return {
+      currentSong: this.createTestSong('test_song'),
+      playlist: [this.createTestSong('song1'), this.createTestSong('song2')],
+      currentIndex: 0,
+      retryCount: 0,
+      isNetworkAvailable: true
+    };
+  }
+
+  /**
+   * 创建测试歌曲
+   */
+  private createTestSong(name: string): VideoItem {
+    return {
+      id: name,
+      name: name,
+      filePath: `/test/path/${name}.mp3`,
+      artist: 'Test Artist',
+      album: 'Test Album',
+      duration: 180000,
+      pixelMapPath: '',
+      size: 0,
+      dateAdded: Date.now(),
+      dateModified: Date.now(),
+      displayName: name,
+      title: name
+    };
+  }
+
+  /**
+   * 创建网络歌曲
+   */
+  private createNetworkSong(): VideoItem {
+    return {
+      id: 'network_song',
+      name: 'Network Song',
+      filePath: 'https://example.com/song.mp3',
+      artist: 'Network Artist',
+      album: 'Network Album',
+      duration: 180000,
+      pixelMapPath: '',
+      size: 0,
+      dateAdded: Date.now(),
+      dateModified: Date.now(),
+      displayName: 'Network Song',
+      title: 'Network Song'
+    };
+  }
+}
+
+/**
+ * 运行错误恢复策略测试
+ */
+export async function runErrorRecoveryTests(): Promise<void> {
+  const test = new ErrorRecoveryStrategyTest();
+  await test.runAllTests();
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 941 - 30
entry/src/main/ets/common/service/IndependentPlayerService.ets


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

@@ -0,0 +1,284 @@
+import { 
+  IjkMediaPlayer, 
+  InterruptEvent, 
+  InterruptHintType, 
+  LogUtils,
+  OnPreparedListener,
+  OnCompletionListener,
+  OnErrorListener
+} from '@ohos/ijkplayer';
+import { common } from '@kit.AbilityKit';
+import { PreferencesUtil } from '@pura/harmony-utils';
+import { SettingPage } from '../../pages/SettingPage';
+
+/**
+ * 播放器状态回调接口
+ */
+export interface PlayerStateCallback {
+  onPrepared(): void;
+  onPlaybackStarted(): void;
+  onPlaybackCompleted(): void;
+  onPlaybackError(what: number, extra: number): void;
+}
+
+/**
+ * 播放器管理器接口
+ * 负责管理ijkPlayer实例和音频会话
+ */
+export interface IPlayerManager {
+  initialize(context: common.UIAbilityContext): Promise<void>;
+  getIjkPlayer(): IjkMediaPlayer | null;
+  setupIjkPlayerOptions(): void;
+  setupPlayerCallbacks(): void;
+  handleAudioInterrupt(event: InterruptEvent): void;
+  
+  // 播放器状态回调
+  setStateCallback(callback: PlayerStateCallback): void;
+  
+  // 基于LocalMusic现有方法
+  startPlayOrResumePlay(): Promise<void>;
+  pausePlayback(): void;
+  stopPlayback(): void;
+  seekToPosition(position: string): void;
+  setPlaybackSpeed(speed: string): void;
+  setVolume(leftVolume: string, rightVolume: string): void;
+  
+  // 清理资源
+  release(): void;
+}
+
+/**
+ * 播放器管理器实现
+ * 从LocalMusic中提取ijkPlayer相关的播放逻辑
+ */
+export class PlayerManager implements IPlayerManager {
+  private static instance: PlayerManager | null = null;
+  private mIjkMediaPlayer: IjkMediaPlayer;
+  private mContext: common.UIAbilityContext | null = null;
+  private audioInterruptCallback: ((event: InterruptEvent) => void) | null = null;
+  private stateCallback: PlayerStateCallback | null = null;
+  
+  private constructor() {
+    this.mIjkMediaPlayer = IjkMediaPlayer.getInstance();
+  }
+  
+  public static getInstance(): PlayerManager {
+    if (!PlayerManager.instance) {
+      PlayerManager.instance = new PlayerManager();
+    }
+    return PlayerManager.instance;
+  }
+
+  async initialize(context: common.UIAbilityContext): Promise<void> {
+    this.mContext = context;
+    
+    // 设置为音频模式 - 关键修复
+    this.mIjkMediaPlayer.setAudioId('unifiedPlayer');
+    LogUtils.getInstance().LOGI('PlayerManager: Set audio mode with ID unifiedPlayer');
+    
+    this.setupIjkPlayerOptions();
+    this.setupPlayerCallbacks();
+    LogUtils.getInstance().LOGI('PlayerManager initialized');
+  }
+
+  getIjkPlayer(): IjkMediaPlayer | null {
+    return this.mIjkMediaPlayer;
+  }  
+  setupIjkPlayerOptions(): void {
+    // 基于LocalMusic中的ijkPlayer配置逻辑
+    this.mIjkMediaPlayer.setDebug(false);
+    
+    // 音频模式初始化 - 在setAudioId之后调用
+    this.mIjkMediaPlayer.native_setup();
+    LogUtils.getInstance().LOGI('PlayerManager: Audio native setup completed');
+    
+    // 设置音量(纯音频播放)
+    this.mIjkMediaPlayer.setVolume('1.0', '1.0');
+    
+    // 使用精确寻帧
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", "1");
+    
+    // 预读数据的缓冲区大小
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", "1048576");
+    
+    // 重连模式
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "reconnect", '1');
+    
+    // 设置缓冲相关选项
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", "100");
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-frames", "1000");
+    
+    // 启动预加载
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", "1");
+    
+    // 设置无缓冲
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", "0");
+    
+    // 跳帧处理
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", "5");
+    
+    // 最大缓冲cache
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", "3000");
+    
+    // 无限制收流
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", "1");
+    this.mIjkMediaPlayer.setOptionLong(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", "1");
+    
+    // 屏幕常亮
+    this.mIjkMediaPlayer.setScreenOnWhilePlaying(true);
+    
+    // 设置超时
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", "10000000");
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "connect_timeout", "10000000");
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "addrinfo_timeout", "10000000");
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_timeout", "10000000");
+    
+    // 变速播放
+    this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", "1");
+    
+    LogUtils.getInstance().LOGI('PlayerManager options configured');
+  }  
+  setStateCallback(callback: PlayerStateCallback): void {
+    this.stateCallback = callback;
+  }
+
+  setupPlayerCallbacks(): void {
+    // 设置音频中断处理回调
+    this.audioInterruptCallback = (event: InterruptEvent) => {
+      this.handleAudioInterrupt(event);
+    };
+    this.mIjkMediaPlayer.on('audioInterrupt', this.audioInterruptCallback);
+    
+    // 设置准备完成回调
+    const onPreparedListener: OnPreparedListener = {
+      onPrepared: () => {
+        LogUtils.getInstance().LOGI('PlayerManager: Player prepared, starting playback');
+        try {
+          this.mIjkMediaPlayer.start();
+          LogUtils.getInstance().LOGI('PlayerManager: Playback started after prepared');
+          this.stateCallback?.onPrepared();
+          this.stateCallback?.onPlaybackStarted();
+        } catch (error) {
+          LogUtils.getInstance().LOGI(`PlayerManager: Failed to start after prepared: ${error}`);
+          this.stateCallback?.onPlaybackError(-1, -1);
+        }
+      }
+    };
+    this.mIjkMediaPlayer.setOnPreparedListener(onPreparedListener);
+    
+    // 设置播放完成回调
+    const onCompletionListener: OnCompletionListener = {
+      onCompletion: () => {
+        LogUtils.getInstance().LOGI('PlayerManager: Playback completed');
+        this.stateCallback?.onPlaybackCompleted();
+      }
+    };
+    this.mIjkMediaPlayer.setOnCompletionListener(onCompletionListener);
+    
+    // 设置错误回调
+    const onErrorListener: OnErrorListener = {
+      onError: (what: number, extra: number) => {
+        LogUtils.getInstance().LOGI(`PlayerManager: Player error - what: ${what}, extra: ${extra}`);
+        this.stateCallback?.onPlaybackError(what, extra);
+        return true; // 表示错误已处理
+      }
+    };
+    this.mIjkMediaPlayer.setOnErrorListener(onErrorListener);
+    
+    LogUtils.getInstance().LOGI('PlayerManager callbacks configured');
+  }
+
+  handleAudioInterrupt(event: InterruptEvent): void {
+    LogUtils.getInstance().LOGI(`PlayerManager audio interrupt: ${JSON.stringify(event)}`);
+    
+    if (event.hintType === InterruptHintType.INTERRUPT_HINT_PAUSE) {
+      this.pausePlayback();
+    } else if (event.hintType === InterruptHintType.INTERRUPT_HINT_RESUME) {
+      this.startPlayOrResumePlay();
+    } else if (event.hintType === InterruptHintType.INTERRUPT_HINT_STOP) {
+      this.stopPlayback();
+    }
+  }
+
+  async startPlayOrResumePlay(): Promise<void> {
+    try {
+      if (this.mIjkMediaPlayer.isPlaying()) {
+        LogUtils.getInstance().LOGI('PlayerManager: Already playing');
+        return;
+      }
+      
+      // 对于暂停后的恢复播放,直接调用start()
+      // 对于新的播放,需要先调用prepareAsync(),在onPrepared回调中自动开始播放
+      this.mIjkMediaPlayer.start();
+      LogUtils.getInstance().LOGI('PlayerManager: Playback started/resumed');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlayerManager startPlayOrResumePlay error: ${error}`);
+      throw new Error(`Failed to start playback: ${error}`);
+    }
+  }
+
+  pausePlayback(): void {
+    try {
+      if (this.mIjkMediaPlayer.isPlaying()) {
+        this.mIjkMediaPlayer.pause();
+        LogUtils.getInstance().LOGI('PlayerManager: Playback paused');
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlayerManager pausePlayback error: ${error}`);
+    }
+  }
+
+  stopPlayback(): void {
+    try {
+      this.mIjkMediaPlayer.stop();
+      this.mIjkMediaPlayer.release();
+      LogUtils.getInstance().LOGI('PlayerManager: Playback stopped');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlayerManager stopPlayback error: ${error}`);
+    }
+  } 
+ seekToPosition(position: string): void {
+    try {
+      this.mIjkMediaPlayer.seekTo(position);
+      LogUtils.getInstance().LOGI(`PlayerManager: Seeked to position ${position}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlayerManager seekToPosition error: ${error}`);
+    }
+  }
+
+  setPlaybackSpeed(speed: string): void {
+    try {
+      this.mIjkMediaPlayer.setSpeed(speed);
+      LogUtils.getInstance().LOGI(`PlayerManager: Speed set to ${speed}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlayerManager setPlaybackSpeed error: ${error}`);
+    }
+  }
+
+  setVolume(leftVolume: string, rightVolume: string): void {
+    try {
+      this.mIjkMediaPlayer.setVolume(leftVolume, rightVolume);
+      LogUtils.getInstance().LOGI(`PlayerManager: Volume set to L:${leftVolume} R:${rightVolume}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlayerManager setVolume error: ${error}`);
+    }
+  }
+
+  release(): void {
+    try {
+      // 移除音频中断监听
+      if (this.audioInterruptCallback) {
+        this.mIjkMediaPlayer.off('audioInterrupt');
+        this.audioInterruptCallback = null;
+      }
+      
+      // 停止播放并释放资源
+      this.mIjkMediaPlayer.setScreenOnWhilePlaying(false);
+      this.stopPlayback();
+      
+      LogUtils.getInstance().LOGI('PlayerManager: Resources released');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`PlayerManager release error: ${error}`);
+    }
+  }
+}

+ 424 - 0
entry/src/main/ets/common/service/PlayerStateModel.ets

@@ -0,0 +1,424 @@
+import { VideoItem } from '../../viewmodel/VideoItem';
+import { WidgetData, PlayProgress, PlayState, SongInfo, PlaylistState, WidgetConfig, WidgetSize, WidgetTheme } from '../widget/WidgetTypes';
+import { LogUtils } from '@ohos/ijkplayer';
+
+/**
+ * 播放模式枚举
+ */
+export enum PlayMode {
+  SEQUENCE = 0,    // 顺序播放
+  SINGLE_REPEAT = 1, // 单曲循环
+  NORMAL = 2,      // 正常播放
+  RANDOM = 3       // 随机播放
+}
+
+/**
+ * 播放状态接口
+ */
+export interface PlayerState {
+  isPlaying: boolean;
+  isPaused: boolean;
+  isLoading: boolean;
+  currentPosition: number;
+  duration: number;
+  currentIndex: number;
+  playMode: PlayMode;
+  volume: number;
+  speed: number;
+  // 播放列表相关状态
+  hasNext?: boolean;
+  hasPrevious?: boolean;
+  totalCount?: number;
+  currentSong?: VideoItem;
+}
+
+/**
+ * 播放状态监听器接口
+ */
+export interface PlayerStateListener {
+  onStateChanged(state: PlayerState): void;
+  onSongChanged(song: VideoItem): void;
+  onProgressChanged(progress: PlayProgress): void;
+  onError(error: PlayerError): void;
+}
+
+/**
+ * 播放器错误类型
+ */
+export enum PlayerErrorType {
+  INITIALIZATION_ERROR = 'initialization_error',
+  PLAYBACK_ERROR = 'playback_error',
+  NETWORK_ERROR = 'network_error',
+  FILE_NOT_FOUND = 'file_not_found',
+  AUDIO_FOCUS_ERROR = 'audio_focus_error',
+  STATE_SYNC_ERROR = 'state_sync_error'
+}
+
+/**
+ * 播放器错误类
+ */
+export class PlayerError extends Error {
+  type: PlayerErrorType;
+  code: number;
+  recoverable: boolean;
+  retryCount: number;
+  
+  constructor(type: PlayerErrorType, message: string, code: number = 0) {
+    super(message);
+    this.type = type;
+    this.code = code;
+    this.recoverable = this.isRecoverable(type);
+    this.retryCount = 0;
+  }
+  
+  private isRecoverable(type: PlayerErrorType): boolean {
+    return type !== PlayerErrorType.FILE_NOT_FOUND;
+  }
+}/**
+
+ * 播放器状态模型类
+ * 管理播放状态并提供状态验证和转换方法
+ */
+export class PlayerStateModel {
+  private state: PlayerState;
+  private listeners: Set<PlayerStateListener> = new Set();
+  
+  constructor() {
+    this.state = {
+      isPlaying: false,
+      isPaused: true,
+      isLoading: false,
+      currentPosition: 0,
+      duration: 0,
+      currentIndex: 0,
+      playMode: PlayMode.SEQUENCE,
+      volume: 1.0,
+      speed: 1.0,
+      hasNext: false,
+      hasPrevious: false,
+      totalCount: 0,
+      currentSong: undefined
+    };
+  }
+
+  /**
+   * 获取当前状态
+   */
+  getState(): PlayerState {
+    return {
+      isPlaying: this.state.isPlaying,
+      isPaused: this.state.isPaused,
+      isLoading: this.state.isLoading,
+      currentPosition: this.state.currentPosition,
+      duration: this.state.duration,
+      currentIndex: this.state.currentIndex,
+      playMode: this.state.playMode,
+      volume: this.state.volume,
+      speed: this.state.speed,
+      hasNext: this.state.hasNext,
+      hasPrevious: this.state.hasPrevious,
+      totalCount: this.state.totalCount,
+      currentSong: this.state.currentSong
+    };
+  }
+
+  /**
+   * 更新播放状态
+   */
+  updatePlayingState(isPlaying: boolean): void {
+    if (this.state.isPlaying !== isPlaying) {
+      this.state.isPlaying = isPlaying;
+      this.state.isPaused = !isPlaying;
+      this.state.isLoading = false;
+      this.notifyStateChanged();
+      LogUtils.getInstance().LOGI(`PlayerStateModel: Playing state updated to ${isPlaying}`);
+    }
+  }
+
+  /**
+   * 更新加载状态
+   */
+  updateLoadingState(isLoading: boolean): void {
+    if (this.state.isLoading !== isLoading) {
+      this.state.isLoading = isLoading;
+      this.notifyStateChanged();
+      LogUtils.getInstance().LOGI(`PlayerStateModel: Loading state updated to ${isLoading}`);
+    }
+  }
+
+  /**
+   * 更新播放进度
+   */
+  updateProgress(currentPosition: number, duration: number): void {
+    const positionChanged = this.state.currentPosition !== currentPosition;
+    const durationChanged = this.state.duration !== duration;
+    
+    if (positionChanged || durationChanged) {
+      this.state.currentPosition = currentPosition;
+      this.state.duration = duration;
+      
+      if (positionChanged || durationChanged) {
+        this.notifyProgressChanged();
+      }
+    }
+  }
+
+  /**
+   * 更新当前播放索引
+   */
+  updateCurrentIndex(index: number): void {
+    if (this.state.currentIndex !== index) {
+      this.state.currentIndex = index;
+      this.notifyStateChanged();
+      LogUtils.getInstance().LOGI(`PlayerStateModel: Current index updated to ${index}`);
+    }
+  }  /**
+  
+ * 更新播放模式
+   */
+  updatePlayMode(mode: PlayMode): void {
+    if (this.state.playMode !== mode) {
+      this.state.playMode = mode;
+      this.notifyStateChanged();
+      LogUtils.getInstance().LOGI(`PlayerStateModel: Play mode updated to ${mode}`);
+    }
+  }
+
+  /**
+   * 更新音量
+   */
+  updateVolume(volume: number): void {
+    if (this.state.volume !== volume) {
+      this.state.volume = volume;
+      this.notifyStateChanged();
+      LogUtils.getInstance().LOGI(`PlayerStateModel: Volume updated to ${volume}`);
+    }
+  }
+
+  /**
+   * 更新播放速度
+   */
+  updateSpeed(speed: number): void {
+    if (this.state.speed !== speed) {
+      this.state.speed = speed;
+      this.notifyStateChanged();
+      LogUtils.getInstance().LOGI(`PlayerStateModel: Speed updated to ${speed}`);
+    }
+  }
+
+  /**
+   * 更新播放列表状态
+   */
+  updatePlaylistState(hasNext: boolean, hasPrevious: boolean, totalCount: number): void {
+    let changed = false;
+    
+    if (this.state.hasNext !== hasNext) {
+      this.state.hasNext = hasNext;
+      changed = true;
+    }
+    
+    if (this.state.hasPrevious !== hasPrevious) {
+      this.state.hasPrevious = hasPrevious;
+      changed = true;
+    }
+    
+    if (this.state.totalCount !== totalCount) {
+      this.state.totalCount = totalCount;
+      changed = true;
+    }
+    
+    if (changed) {
+      this.notifyStateChanged();
+      LogUtils.getInstance().LOGI(`PlayerStateModel: Playlist state updated - hasNext=${hasNext}, hasPrevious=${hasPrevious}, totalCount=${totalCount}`);
+    }
+  }
+
+  /**
+   * 更新当前歌曲
+   */
+  updateCurrentSong(song: VideoItem | null): void {
+    if (this.state.currentSong !== song) {
+      this.state.currentSong = song||undefined;
+      this.notifyStateChanged();
+      if (song) {
+        this.notifySongChanged(song);
+      }
+      LogUtils.getInstance().LOGI(`PlayerStateModel: Current song updated to ${song?.name || 'null'}`);
+    }
+  }
+
+  /**
+   * 状态验证
+   */
+  validate(): boolean {
+    const state = this.state;
+    
+    // 基本状态验证
+    if (state.isPlaying && state.isPaused) {
+      LogUtils.getInstance().LOGI('PlayerStateModel: Invalid state - cannot be playing and paused simultaneously');
+      return false;
+    }
+    
+    // 进度验证
+    if (state.currentPosition < 0 || (state.duration > 0 && state.currentPosition > state.duration)) {
+      LogUtils.getInstance().LOGI('PlayerStateModel: Invalid progress - position out of range');
+      return false;
+    }
+    
+    // 音量验证
+    if (state.volume < 0 || state.volume > 1) {
+      LogUtils.getInstance().LOGI('PlayerStateModel: Invalid volume - must be between 0 and 1');
+      return false;
+    }
+    
+    // 速度验证
+    if (state.speed <= 0) {
+      LogUtils.getInstance().LOGI('PlayerStateModel: Invalid speed - must be positive');
+      return false;
+    }
+    
+    return true;
+  } 
+ /**
+   * 转换为卡片数据格式
+   */
+  toWidgetData(currentSong?: VideoItem): WidgetData {
+    const playState: PlayState = {
+      isPlaying: this.state.isPlaying,
+      isPaused: this.state.isPaused,
+      isLoading: this.state.isLoading
+    };
+    
+    const songInfo: SongInfo = currentSong ? {
+      id: currentSong.id || '',
+      title: currentSong.name || '未知歌曲',
+      artist: currentSong.artist || '未知艺术家',
+      album: currentSong.album || '未知专辑',
+      coverImagePath: currentSong.pixelMapPath || '',
+      duration: currentSong.duration ? parseInt(currentSong.duration) : 0
+    } : {
+      id: '',
+      title: '未知歌曲',
+      artist: '未知艺术家', 
+      album: '未知专辑',
+      coverImagePath: '',
+      duration: 0
+    };
+
+    const progress: PlayProgress = {
+      currentPosition: this.state.currentPosition,
+      duration: this.state.duration,
+      percentage: this.state.duration > 0 ? (this.state.currentPosition / this.state.duration) * 100 : 0,
+      currentTimeText: this.formatTime(Math.floor(this.state.currentPosition / 1000)),
+      totalTimeText: this.formatTime(Math.floor(this.state.duration / 1000))
+    };
+
+    const playlistState: PlaylistState = {
+      hasNext: this.state.hasNext || false,
+      hasPrevious: this.state.hasPrevious || false,
+      currentIndex: this.state.currentIndex,
+      totalCount: this.state.totalCount || 0
+    };
+
+    const config: WidgetConfig = {
+      size: WidgetSize.MEDIUM,
+      theme: WidgetTheme.AUTO,
+      showProgress: true,
+      showCover: true
+    };
+
+    return {
+      playState,
+      currentSong: songInfo,
+      progress,
+      playlist: playlistState,
+      config
+    };
+  }
+
+  /**
+   * 格式化时间显示
+   */
+  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')}`;
+  }
+
+  /**
+   * 添加状态监听器
+   */
+  addStateListener(listener: PlayerStateListener): void {
+    this.listeners.add(listener);
+    LogUtils.getInstance().LOGI('PlayerStateModel: State listener added');
+  }
+
+  /**
+   * 移除状态监听器
+   */
+  removeStateListener(listener: PlayerStateListener): void {
+    this.listeners.delete(listener);
+    LogUtils.getInstance().LOGI('PlayerStateModel: State listener removed');
+  }
+
+  /**
+   * 通知状态变化
+   */
+  private notifyStateChanged(): void {
+    const state = this.getState();
+    this.listeners.forEach(listener => {
+      try {
+        listener.onStateChanged(state);
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`PlayerStateModel: Error notifying state change: ${error}`);
+      }
+    });
+  }
+
+  /**
+   * 通知进度变化
+   */
+  private notifyProgressChanged(): void {
+    const progress: PlayProgress = {
+      currentPosition: this.state.currentPosition,
+      duration: this.state.duration,
+      percentage: this.state.duration > 0 ? (this.state.currentPosition / this.state.duration) * 100 : 0,
+      currentTimeText: this.formatTime(Math.floor(this.state.currentPosition / 1000)),
+      totalTimeText: this.formatTime(Math.floor(this.state.duration / 1000))
+    };
+    
+    this.listeners.forEach(listener => {
+      try {
+        listener.onProgressChanged(progress);
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`PlayerStateModel: Error notifying progress change: ${error}`);
+      }
+    });
+  }
+
+  /**
+   * 通知歌曲变化
+   */
+  notifySongChanged(song: VideoItem): void {
+    this.listeners.forEach(listener => {
+      try {
+        listener.onSongChanged(song);
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`PlayerStateModel: Error notifying song change: ${error}`);
+      }
+    });
+  }
+
+  /**
+   * 通知错误
+   */
+  notifyError(error: PlayerError): void {
+    this.listeners.forEach(listener => {
+      try {
+        listener.onError(error);
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`PlayerStateModel: Error notifying error: ${error}`);
+      }
+    });
+  }
+}

+ 456 - 0
entry/src/main/ets/common/service/PlaylistModel.ets

@@ -0,0 +1,456 @@
+import { VideoItem } from '../../viewmodel/VideoItem';
+import { PlayMode } from './PlayerStateModel';
+import { LogUtils } from '@ohos/ijkplayer';
+import { ArrayUtil, RandomUtil } from '@pura/harmony-utils';
+
+/**
+ * 播放列表模型类
+ * 管理播放列表和播放导航逻辑
+ */
+export class PlaylistModel {
+  private songs: VideoItem[] = [];
+  private currentIndex: number = 0;
+  private playedIndices: Set<number> = new Set(); // 用于随机播放的历史记录
+  private playHistory: VideoItem[] = []; // 播放历史记录
+
+  constructor(songs: VideoItem[] = [], currentIndex: number = 0) {
+    this.songs = [];
+    for (const song of songs) {
+      this.songs.push(song);
+    }
+    this.currentIndex = Math.max(0, Math.min(currentIndex, songs.length - 1));
+    LogUtils.getInstance().LOGI(`PlaylistModel: Initialized with ${songs.length} songs, index ${this.currentIndex}`);
+  }
+
+  /**
+   * 获取歌曲列表副本
+   */
+  getSongs(): VideoItem[] {
+    const result: VideoItem[] = [];
+    for (const song of this.songs) {
+      result.push(song);
+    }
+    return result;
+  }
+
+  /**
+   * 获取当前播放索引
+   */
+  getCurrentIndex(): number {
+    return this.currentIndex;
+  }
+
+  /**
+   * 设置当前播放索引
+   */
+  setCurrentIndex(index: number): boolean {
+    if (index >= 0 && index < this.songs.length) {
+      this.currentIndex = index;
+      LogUtils.getInstance().LOGI(`PlaylistModel: Current index set to ${index}`);
+      return true;
+    }
+    LogUtils.getInstance().LOGI(`PlaylistModel: Invalid index ${index}, playlist size: ${this.songs.length}`);
+    return false;
+  }
+
+  /**
+   * 获取当前播放的歌曲
+   */
+  getCurrentSong(): VideoItem | null {
+    if (this.isEmpty() || this.currentIndex < 0 || this.currentIndex >= this.songs.length) {
+      return null;
+    }
+    return this.songs[this.currentIndex];
+  }
+
+  /**
+   * 获取总歌曲数量
+   */
+  getTotalCount(): number {
+    return this.songs.length;
+  }
+
+  /**
+   * 检查播放列表是否为空
+   */
+  isEmpty(): boolean {
+    return this.songs.length === 0;
+  }  
+/**
+   * 播放列表操作:添加歌曲
+   */
+  addSong(song: VideoItem, index?: number): void {
+    if (index !== undefined && index >= 0 && index <= this.songs.length) {
+      this.songs.splice(index, 0, song);
+      // 如果插入位置在当前播放位置之前,需要调整当前索引
+      if (index <= this.currentIndex) {
+        this.currentIndex++;
+      }
+    } else {
+      this.songs.push(song);
+    }
+    LogUtils.getInstance().LOGI(`PlaylistModel: Song added, total count: ${this.songs.length}`);
+  }
+
+  /**
+   * 播放列表操作:添加多首歌曲
+   */
+  addSongs(songs: VideoItem[], index?: number): void {
+    if (songs.length === 0) return;
+    
+    if (index !== undefined && index >= 0 && index <= this.songs.length) {
+      for (let i = 0; i < songs.length; i++) {
+        this.songs.splice(index + i, 0, songs[i]);
+      }
+      // 如果插入位置在当前播放位置之前,需要调整当前索引
+      if (index <= this.currentIndex) {
+        this.currentIndex += songs.length;
+      }
+    } else {
+      for (const song of songs) {
+        this.songs.push(song);
+      }
+    }
+    LogUtils.getInstance().LOGI(`PlaylistModel: ${songs.length} songs added, total count: ${this.songs.length}`);
+  }
+
+  /**
+   * 播放列表操作:移除歌曲
+   */
+  removeSong(index: number): VideoItem | null {
+    if (index < 0 || index >= this.songs.length) {
+      LogUtils.getInstance().LOGI(`PlaylistModel: Invalid remove index ${index}`);
+      return null;
+    }
+
+    const removedSong = this.songs.splice(index, 1)[0];
+    
+    // 调整当前播放索引
+    if (index < this.currentIndex) {
+      this.currentIndex--;
+    } else if (index === this.currentIndex) {
+      // 如果删除的是当前播放的歌曲,保持索引不变(播放下一首)
+      // 但如果删除的是最后一首,需要调整到前一首
+      if (this.currentIndex >= this.songs.length && this.songs.length > 0) {
+        this.currentIndex = this.songs.length - 1;
+      }
+    }
+    
+    LogUtils.getInstance().LOGI(`PlaylistModel: Song removed at index ${index}, total count: ${this.songs.length}`);
+    return removedSong;
+  }
+
+  /**
+   * 播放列表操作:移动歌曲
+   */
+  moveSong(fromIndex: number, toIndex: number): boolean {
+    if (fromIndex < 0 || fromIndex >= this.songs.length || 
+        toIndex < 0 || toIndex >= this.songs.length || 
+        fromIndex === toIndex) {
+      LogUtils.getInstance().LOGI(`PlaylistModel: Invalid move indices from ${fromIndex} to ${toIndex}`);
+      return false;
+    }
+
+    const song = this.songs.splice(fromIndex, 1)[0];
+    this.songs.splice(toIndex, 0, song);
+    
+    // 调整当前播放索引
+    if (fromIndex === this.currentIndex) {
+      this.currentIndex = toIndex;
+    } else if (fromIndex < this.currentIndex && toIndex >= this.currentIndex) {
+      this.currentIndex--;
+    } else if (fromIndex > this.currentIndex && toIndex <= this.currentIndex) {
+      this.currentIndex++;
+    }
+    
+    LogUtils.getInstance().LOGI(`PlaylistModel: Song moved from ${fromIndex} to ${toIndex}`);
+    return true;
+  }  /**
+
+   * 播放列表操作:清空播放列表
+   */
+  clear(): void {
+    this.songs = [];
+    this.currentIndex = 0;
+    this.playedIndices.clear();
+    this.playHistory = [];
+    LogUtils.getInstance().LOGI('PlaylistModel: Playlist cleared');
+  }
+
+  /**
+   * 播放列表操作:替换整个播放列表
+   */
+  replaceSongs(songs: VideoItem[], currentIndex: number = 0): void {
+    this.songs = [];
+    for (const song of songs) {
+      this.songs.push(song);
+    }
+    this.currentIndex = Math.max(0, Math.min(currentIndex, songs.length - 1));
+    this.playedIndices.clear();
+    this.playHistory = [];
+    LogUtils.getInstance().LOGI(`PlaylistModel: Playlist replaced with ${songs.length} songs, index ${this.currentIndex}`);
+  }
+
+  /**
+   * 播放列表操作:随机打乱播放列表
+   */
+  shuffle(): void {
+    if (this.songs.length <= 1) return;
+    
+    // 保存当前播放的歌曲
+    const currentSong = this.getCurrentSong();
+    
+    // 打乱播放列表
+    for (let i = this.songs.length - 1; i > 0; i--) {
+      const j = Math.floor(Math.random() * (i + 1));
+      const temp = this.songs[i];
+      this.songs[i] = this.songs[j];
+      this.songs[j] = temp;
+    }
+    
+    // 重新找到当前播放歌曲的位置
+    if (currentSong) {
+      const newIndex = this.songs.findIndex(song => song.filePath === currentSong.filePath);
+      if (newIndex !== -1) {
+        this.currentIndex = newIndex;
+      }
+    }
+    
+    this.playedIndices.clear();
+    LogUtils.getInstance().LOGI('PlaylistModel: Playlist shuffled');
+  }
+
+  /**
+   * 导航操作:检查是否有下一首
+   */
+  hasNext(playMode: PlayMode = PlayMode.SEQUENCE): boolean {
+    if (this.isEmpty()) return false;
+    
+    switch (playMode) {
+      case PlayMode.SINGLE_REPEAT:
+        return true; // 单曲循环总是有下一首(自己)
+      case PlayMode.SEQUENCE:
+        return this.currentIndex < this.songs.length - 1;
+      case PlayMode.NORMAL:
+        return this.currentIndex < this.songs.length - 1;
+      case PlayMode.RANDOM:
+        return this.playedIndices.size < this.songs.length; // 还有未播放的歌曲
+      default:
+        return false;
+    }
+  }
+
+  /**
+   * 导航操作:检查是否有上一首
+   */
+  hasPrevious(playMode: PlayMode = PlayMode.SEQUENCE): boolean {
+    if (this.isEmpty()) return false;
+    
+    switch (playMode) {
+      case PlayMode.SINGLE_REPEAT:
+        return true; // 单曲循环总是有上一首(自己)
+      case PlayMode.SEQUENCE:
+        return this.currentIndex > 0;
+      case PlayMode.NORMAL:
+        return this.currentIndex > 0;
+      case PlayMode.RANDOM:
+        return this.playHistory.length > 1; // 有播放历史记录
+      default:
+        return false;
+    }
+  }  
+/**
+   * 导航操作:获取下一首歌曲
+   */
+  getNext(playMode: PlayMode = PlayMode.SEQUENCE): VideoItem | null {
+    if (this.isEmpty()) return null;
+    
+    let nextIndex = this.currentIndex;
+    
+    switch (playMode) {
+      case PlayMode.SINGLE_REPEAT:
+        // 单曲循环,返回当前歌曲
+        break;
+      case PlayMode.SEQUENCE:
+        // 顺序播放,循环到开头
+        nextIndex = (this.currentIndex + 1) % this.songs.length;
+        break;
+      case PlayMode.NORMAL:
+        // 正常播放,不循环
+        if (this.currentIndex < this.songs.length - 1) {
+          nextIndex = this.currentIndex + 1;
+        } else {
+          return null; // 已经是最后一首
+        }
+        break;
+      case PlayMode.RANDOM:
+        // 随机播放
+        nextIndex = this.getRandomNextIndex();
+        if (nextIndex === -1) return null;
+        break;
+    }
+    
+    return this.songs[nextIndex];
+  }
+
+  /**
+   * 导航操作:获取上一首歌曲
+   */
+  getPrevious(playMode: PlayMode = PlayMode.SEQUENCE): VideoItem | null {
+    if (this.isEmpty()) return null;
+    
+    let prevIndex = this.currentIndex;
+    
+    switch (playMode) {
+      case PlayMode.SINGLE_REPEAT:
+        // 单曲循环,返回当前歌曲
+        break;
+      case PlayMode.SEQUENCE:
+        // 顺序播放,循环到末尾
+        prevIndex = this.currentIndex === 0 ? this.songs.length - 1 : this.currentIndex - 1;
+        break;
+      case PlayMode.NORMAL:
+        // 正常播放,不循环
+        if (this.currentIndex > 0) {
+          prevIndex = this.currentIndex - 1;
+        } else {
+          return null; // 已经是第一首
+        }
+        break;
+      case PlayMode.RANDOM:
+        // 随机播放,从历史记录获取
+        return this.getRandomPrevious();
+    }
+    
+    return this.songs[prevIndex];
+  }
+
+  /**
+   * 导航操作:移动到下一首
+   */
+  moveToNext(playMode: PlayMode = PlayMode.SEQUENCE): boolean {
+    const nextSong = this.getNext(playMode);
+    if (!nextSong) return false;
+    
+    // 添加当前歌曲到播放历史
+    const currentSong = this.getCurrentSong();
+    if (currentSong && playMode === PlayMode.RANDOM) {
+      this.addToPlayHistory(currentSong);
+      this.playedIndices.add(this.currentIndex);
+    }
+    
+    // 更新索引
+    const nextIndex = this.songs.findIndex(song => song.filePath === nextSong.filePath);
+    if (nextIndex !== -1) {
+      this.currentIndex = nextIndex;
+      LogUtils.getInstance().LOGI(`PlaylistModel: Moved to next song at index ${this.currentIndex}`);
+      return true;
+    }
+    
+    return false;
+  } 
+ /**
+   * 导航操作:移动到上一首
+   */
+  moveToPrevious(playMode: PlayMode = PlayMode.SEQUENCE): boolean {
+    const prevSong = this.getPrevious(playMode);
+    if (!prevSong) return false;
+    
+    // 更新索引
+    const prevIndex = this.songs.findIndex(song => song.filePath === prevSong.filePath);
+    if (prevIndex !== -1) {
+      this.currentIndex = prevIndex;
+      
+      // 随机播放模式下,从历史记录中移除
+      if (playMode === PlayMode.RANDOM && this.playHistory.length > 0) {
+        this.playHistory.pop(); // 移除最后一个(当前播放的)
+      }
+      
+      LogUtils.getInstance().LOGI(`PlaylistModel: Moved to previous song at index ${this.currentIndex}`);
+      return true;
+    }
+    
+    return false;
+  }
+
+  /**
+   * 根据文件路径查找歌曲索引
+   */
+  findSongIndex(filePath: string): number {
+    return this.songs.findIndex(song => song.filePath === filePath);
+  }
+
+  /**
+   * 播放指定索引的歌曲
+   */
+  playSongAtIndex(index: number): boolean {
+    if (index >= 0 && index < this.songs.length) {
+      this.currentIndex = index;
+      LogUtils.getInstance().LOGI(`PlaylistModel: Playing song at index ${index}`);
+      return true;
+    }
+    LogUtils.getInstance().LOGI(`PlaylistModel: Invalid play index ${index}`);
+    return false;
+  }
+
+  /**
+   * 获取随机播放的下一个索引
+   */
+  private getRandomNextIndex(): number {
+    const unplayedIndices: number[] = [];
+    for (let i = 0; i < this.songs.length; i++) {
+      if (!this.playedIndices.has(i)) {
+        unplayedIndices.push(i);
+      }
+    }
+    
+    if (unplayedIndices.length === 0) {
+      // 所有歌曲都播放过了,重置并重新开始
+      this.playedIndices.clear();
+      this.playHistory = [];
+      for (let i = 0; i < this.songs.length; i++) {
+        if (i !== this.currentIndex) {
+          unplayedIndices.push(i);
+        }
+      }
+    }
+    
+    if (unplayedIndices.length === 0) return -1;
+    
+    const randomIndex = Math.floor(Math.random() * unplayedIndices.length);
+    return unplayedIndices[randomIndex];
+  }
+
+  /**
+   * 获取随机播放模式下的上一首
+   */
+  private getRandomPrevious(): VideoItem | null {
+    if (this.playHistory.length >= 2) {
+      // 返回历史记录的第二首(第一首是当前播放的)
+      return this.playHistory[this.playHistory.length - 2];
+    }
+    return null;
+  }
+
+  /**
+   * 添加到播放历史记录
+   */
+  private addToPlayHistory(song: VideoItem): void {
+    this.playHistory.push(song);
+    // 限制历史记录长度,避免内存占用过多
+    if (this.playHistory.length > 50) {
+      this.playHistory.shift();
+    }
+  }
+
+  /**
+   * 获取播放历史记录
+   */
+  getPlayHistory(): VideoItem[] {
+    const result: VideoItem[] = [];
+    for (const item of this.playHistory) {
+      result.push(item);
+    }
+    return result;
+  }
+}

+ 644 - 0
entry/src/main/ets/common/service/StateSyncService.ets

@@ -0,0 +1,644 @@
+import commonEventManager from '@ohos.commonEventManager';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { common } from '@kit.AbilityKit';
+import { VideoItem } from '../../viewmodel/VideoItem';
+import { PlayerState, PlayMode } from './PlayerStateModel';
+import { PlayProgress, WidgetData } from '../widget/WidgetTypes';
+import { 
+  PLAYER_STATE_CHANGED_EVENT,
+  PLAYER_SONG_CHANGED_EVENT,
+  PLAYER_PROGRESS_CHANGED_EVENT,
+  WIDGET_CONTROL_EVENT,
+  WIDGET_REQUEST_STATE_EVENT
+} from '../widget/WidgetEventConstants';
+
+const TAG = 'StateSyncService';
+
+/**
+ * 状态同步服务接口
+ */
+export interface IStateSyncService {
+  broadcastState(state: PlayerState): Promise<void>;
+  broadcastSongChange(song: VideoItem): Promise<void>;
+  broadcastProgress(progress: PlayProgress): Promise<void>;
+  subscribeToStateChanges(callback: StateChangeCallback): void;
+  unsubscribeFromStateChanges(callback: StateChangeCallback): void;
+  subscribeToWidgetControl(callback: WidgetControlCallback): void;
+  unsubscribeFromWidgetControl(callback: WidgetControlCallback): void;
+  initialize(context: common.UIAbilityContext): Promise<void>;
+  release(): void;
+}
+
+/**
+ * 状态变化回调接口
+ */
+export interface StateChangeCallback {
+  onStateChanged?(state: PlayerState): void;
+  onSongChanged?(song: VideoItem): void;
+  onProgressChanged?(progress: PlayProgress): void;
+}
+
+/**
+ * 卡片控制命令回调接口
+ */
+export interface WidgetControlCallback {
+  onPlayPause?(): Promise<void>;
+  onNextSong?(): Promise<void>;
+  onPreviousSong?(): Promise<void>;
+  onSeekTo?(position: number): Promise<void>;
+  onStateRequest?(): Promise<void>;
+}
+
+/**
+ * 卡片控制事件数据
+ */
+interface WidgetControlEventData {
+  command: string;
+  params?: Record<string, Object>;
+  timestamp: number;
+  source: string;
+}
+
+/**
+ * 播放状态数据接口
+ */
+interface PlayStateBroadcast {
+  isPlaying: boolean;
+  isPaused: boolean;
+  isLoading: boolean;
+  currentPosition: number;
+  duration: number;
+}
+
+/**
+ * 当前歌曲数据接口
+ */
+interface CurrentSongBroadcast {
+  id: string;
+  title: string;
+  artist: string;
+  album: string;
+  filePath: 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 PlayerStateBroadcastData {
+  playState: PlayStateBroadcast;
+  currentSong: CurrentSongBroadcast;
+  progress: ProgressBroadcast;
+  playlist: PlaylistBroadcast;
+}
+
+/**
+ * 歌曲变化广播数据
+ */
+interface SongChangeBroadcastData {
+  currentSong: CurrentSongBroadcast;
+  playlist: PlaylistBroadcast;
+}
+
+/**
+ * 进度更新广播数据
+ */
+interface ProgressBroadcastData {
+  currentPosition: number;
+  duration: number;
+  percentage: number;
+  currentTimeText: string;
+  totalTimeText: string;
+}
+
+/**
+ * 状态同步服务实现
+ * 负责在不同组件和进程间同步播放状态
+ */
+export class StateSyncService implements IStateSyncService {
+  private static instance: StateSyncService | null = null;
+  private context: common.UIAbilityContext | null = null;
+  private stateChangeCallbacks: StateChangeCallback[] = [];
+  private widgetControlCallbacks: WidgetControlCallback[] = [];
+  private isInitialized: boolean = false;
+  private lastStateBroadcastTime: number = 0;
+  private lastProgressBroadcastTime: number = 0;
+  private readonly STATE_BROADCAST_THROTTLE: number = 500; // 状态广播节流间隔(毫秒)
+  private readonly PROGRESS_BROADCAST_THROTTLE: number = 1000; // 进度广播节流间隔(毫秒)
+  private readonly COMMAND_EXECUTION_TIMEOUT: number = 5000; // 命令执行超时时间(毫秒)
+
+  private constructor() {}
+
+  public static getInstance(): StateSyncService {
+    if (!StateSyncService.instance) {
+      StateSyncService.instance = new StateSyncService();
+    }
+    return StateSyncService.instance;
+  }
+
+  /**
+   * 初始化状态同步服务
+   */
+  async initialize(context: common.UIAbilityContext): Promise<void> {
+    if (this.isInitialized) {
+      hilog.info(0x0000, TAG, 'StateSyncService already initialized');
+      return;
+    }
+
+    try {
+      this.context = context;
+      
+      // 注册状态请求事件监听器
+      await this.registerStateRequestListener();
+      
+      // 注册卡片控制事件监听器
+      await this.registerWidgetControlListener();
+      
+      this.isInitialized = true;
+      hilog.info(0x0000, TAG, 'StateSyncService initialized successfully');
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to initialize StateSyncService: ${error}`);
+      throw new Error(`Failed to initialize StateSyncService: ${error}`);
+    }
+  }
+
+  /**
+   * 广播播放状态变化
+   */
+  async broadcastState(state: PlayerState): Promise<void> {
+    try {
+      // 节流控制,避免过于频繁的广播
+      const now = Date.now();
+      if (now - this.lastStateBroadcastTime < this.STATE_BROADCAST_THROTTLE) {
+        return;
+      }
+      this.lastStateBroadcastTime = now;
+
+      const playStateBroadcast: PlayStateBroadcast = {
+        isPlaying: state.isPlaying,
+        isPaused: state.isPaused,
+        isLoading: state.isLoading,
+        currentPosition: state.currentPosition,
+        duration: state.duration
+      };
+
+      const currentSongBroadcast: CurrentSongBroadcast = {
+        id: state.currentSong?.id || '',
+        title: state.currentSong?.name || '暂无播放',
+        artist: state.currentSong?.artist || '未知艺术家',
+        album: state.currentSong?.album || '未知专辑',
+        filePath: state.currentSong?.filePath || '',
+        duration: state.currentSong?.duration ? parseInt(state.currentSong.duration) : 0
+      };
+
+      const progressBroadcast: ProgressBroadcast = {
+        currentPosition: state.currentPosition,
+        duration: state.duration,
+        percentage: this.calculatePercentage(state.currentPosition, state.duration),
+        currentTimeText: this.formatTime(Math.floor(state.currentPosition / 1000)),
+        totalTimeText: this.formatTime(Math.floor(state.duration / 1000))
+      };
+
+      const broadcastData: PlayerStateBroadcastData = {
+        playState: playStateBroadcast,
+        currentSong: currentSongBroadcast,
+        progress: progressBroadcast,
+        playlist: {
+          hasNext: state.hasNext || false,
+          hasPrevious: state.hasPrevious || false,
+          currentIndex: state.currentIndex,
+          totalCount: state.totalCount || 0
+        } as PlaylistBroadcast
+      };
+
+      const publishInfo: commonEventManager.CommonEventPublishData = {
+        data: JSON.stringify(broadcastData)
+      };
+
+      await commonEventManager.publish(PLAYER_STATE_CHANGED_EVENT, publishInfo, (err) => {
+        if (err) {
+          hilog.error(0x0000, TAG, `Failed to broadcast state: ${err}`);
+        } else {
+          hilog.info(0x0000, TAG, `State broadcasted: isPlaying=${state.isPlaying}, song=${state.currentSong?.name || 'none'}`);
+        }
+      });
+
+      // 通知本地监听器
+      this.notifyLocalStateListeners(state);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to broadcast state: ${error}`);
+    }
+  }
+
+  /**
+   * 广播歌曲切换事件
+   */
+  async broadcastSongChange(song: VideoItem): Promise<void> {
+    try {
+      const currentSongBroadcast: CurrentSongBroadcast = {
+        id: song.id || '',
+        title: song.name || '暂无播放',
+        artist: song.artist || '未知艺术家',
+        album: song.album || '未知专辑',
+        filePath: song.filePath || '',
+        duration: song.duration ? parseInt(song.duration) : 0
+      };
+
+      const playlistBroadcast: PlaylistBroadcast = {
+        hasNext: false, // 这些值需要从播放列表服务获取
+        hasPrevious: false,
+        currentIndex: 0,
+        totalCount: 0
+      };
+
+      const broadcastData: SongChangeBroadcastData = {
+        currentSong: currentSongBroadcast,
+        playlist: playlistBroadcast
+      };
+
+      const publishInfo: commonEventManager.CommonEventPublishData = {
+        data: JSON.stringify(broadcastData)
+      };
+
+      await commonEventManager.publish(PLAYER_SONG_CHANGED_EVENT, publishInfo, (err) => {
+        if (err) {
+          hilog.error(0x0000, TAG, `Failed to broadcast song change: ${err}`);
+        } else {
+          hilog.info(0x0000, TAG, `Song change broadcasted: ${song.name} by ${song.artist || '未知艺术家'}`);
+        }
+      });
+
+      // 通知本地监听器
+      this.notifyLocalSongChangeListeners(song);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to broadcast song change: ${error}`);
+    }
+  }
+
+  /**
+   * 广播播放进度更新
+   */
+  async broadcastProgress(progress: PlayProgress): Promise<void> {
+    try {
+      // 节流控制,避免过于频繁的进度广播
+      const now = Date.now();
+      if (now - this.lastProgressBroadcastTime < this.PROGRESS_BROADCAST_THROTTLE) {
+        return;
+      }
+      this.lastProgressBroadcastTime = now;
+
+      const broadcastData: ProgressBroadcastData = {
+        currentPosition: progress.currentPosition,
+        duration: progress.duration,
+        percentage: this.calculatePercentage(progress.currentPosition, progress.duration),
+        currentTimeText: this.formatTime(Math.floor(progress.currentPosition / 1000)),
+        totalTimeText: this.formatTime(Math.floor(progress.duration / 1000))
+      };
+
+      const publishInfo: commonEventManager.CommonEventPublishData = {
+        data: JSON.stringify(broadcastData)
+      };
+
+      await commonEventManager.publish(PLAYER_PROGRESS_CHANGED_EVENT, publishInfo, (err) => {
+        if (err) {
+          hilog.error(0x0000, TAG, `Failed to broadcast progress: ${err}`);
+        } else {
+          hilog.info(0x0000, TAG, `Progress broadcasted: ${broadcastData.percentage.toFixed(1)}% (${broadcastData.currentTimeText}/${broadcastData.totalTimeText})`);
+        }
+      });
+
+      // 通知本地监听器
+      this.notifyLocalProgressListeners(progress);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to broadcast progress: ${error}`);
+    }
+  }
+
+  /**
+   * 订阅状态变化
+   */
+  subscribeToStateChanges(callback: StateChangeCallback): void {
+    if (this.stateChangeCallbacks.indexOf(callback) === -1) {
+      this.stateChangeCallbacks.push(callback);
+      hilog.info(0x0000, TAG, `State change callback registered, total: ${this.stateChangeCallbacks.length}`);
+    }
+  }
+
+  /**
+   * 取消订阅状态变化
+   */
+  unsubscribeFromStateChanges(callback: StateChangeCallback): void {
+    const index = this.stateChangeCallbacks.indexOf(callback);
+    if (index !== -1) {
+      this.stateChangeCallbacks.splice(index, 1);
+      hilog.info(0x0000, TAG, `State change callback unregistered, remaining: ${this.stateChangeCallbacks.length}`);
+    }
+  }
+
+  /**
+   * 订阅卡片控制事件
+   */
+  subscribeToWidgetControl(callback: WidgetControlCallback): void {
+    if (this.widgetControlCallbacks.indexOf(callback) === -1) {
+      this.widgetControlCallbacks.push(callback);
+      hilog.info(0x0000, TAG, `Widget control callback registered, total: ${this.widgetControlCallbacks.length}`);
+    }
+  }
+
+  /**
+   * 取消订阅卡片控制事件
+   */
+  unsubscribeFromWidgetControl(callback: WidgetControlCallback): void {
+    const index = this.widgetControlCallbacks.indexOf(callback);
+    if (index !== -1) {
+      this.widgetControlCallbacks.splice(index, 1);
+      hilog.info(0x0000, TAG, `Widget control callback unregistered, remaining: ${this.widgetControlCallbacks.length}`);
+    }
+  }
+
+  /**
+   * 释放资源
+   */
+  release(): void {
+    try {
+      this.stateChangeCallbacks = [];
+      this.widgetControlCallbacks = [];
+      this.isInitialized = false;
+      hilog.info(0x0000, TAG, 'StateSyncService released');
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to release StateSyncService: ${error}`);
+    }
+  }
+
+  // ==================== 私有辅助方法 ====================
+
+  /**
+   * 注册状态请求事件监听器
+   */
+  private async registerStateRequestListener(): Promise<void> {
+    try {
+      const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
+        events: [WIDGET_REQUEST_STATE_EVENT]
+      };
+
+      const subscriber = await commonEventManager.createSubscriber(subscribeInfo);
+      
+      await commonEventManager.subscribe(subscriber, (err, data: commonEventManager.CommonEventData) => {
+        if (!err) {
+          hilog.info(0x0000, TAG, `Received state request from widget: ${data.event}`);
+          this.handleStateRequest(data);
+        } else {
+          hilog.error(0x0000, TAG, `State request listener error: ${JSON.stringify(err)}`);
+        }
+      });
+
+      hilog.info(0x0000, TAG, 'State request listener registered successfully');
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to register state request listener: ${error}`);
+    }
+  }
+
+  /**
+   * 注册卡片控制事件监听器
+   */
+  private async registerWidgetControlListener(): Promise<void> {
+    try {
+      const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
+        events: [WIDGET_CONTROL_EVENT]
+      };
+
+      const subscriber = await commonEventManager.createSubscriber(subscribeInfo);
+      
+      await commonEventManager.subscribe(subscriber, (err, data: commonEventManager.CommonEventData) => {
+        if (!err) {
+          hilog.info(0x0000, TAG, `Received widget control command: ${data.event}`);
+          this.handleWidgetControlCommand(data);
+        } else {
+          hilog.error(0x0000, TAG, `Widget control listener error: ${JSON.stringify(err)}`);
+        }
+      });
+
+      hilog.info(0x0000, TAG, 'Widget control listener registered successfully');
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to register widget control listener: ${error}`);
+    }
+  }
+
+  /**
+   * 处理状态请求
+   */
+  private handleStateRequest(eventData: commonEventManager.CommonEventData): void {
+    try {
+      const requestData: Record<string, string> = JSON.parse(eventData.data || '{}');
+      const source: string = requestData.source || 'unknown';
+      
+      hilog.info(0x0000, TAG, `Handling state request from: ${source}`);
+      
+      // 通知控制回调处理状态请求
+      this.notifyWidgetControlCallbacks('onStateRequest');
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to handle state request: ${error}`);
+    }
+  }
+
+  /**
+   * 处理卡片控制命令
+   */
+  private async handleWidgetControlCommand(eventData: commonEventManager.CommonEventData): Promise<void> {
+    try {
+      const controlData: WidgetControlEventData = JSON.parse(eventData.data || '{}');
+      const command = controlData.command;
+      const params = controlData.params;
+      const source = controlData.source;
+      const timestamp = controlData.timestamp;
+      
+      hilog.info(0x0000, TAG, `Processing widget control command: ${command} from ${source}`);
+      
+      // 验证命令时效性(防止过期命令执行)
+      const now = Date.now();
+      if (now - timestamp > this.COMMAND_EXECUTION_TIMEOUT) {
+        hilog.warn(0x0000, TAG, `Command ${command} expired, ignoring (age: ${now - timestamp}ms)`);
+        return;
+      }
+      
+      // 验证命令来源
+      if (!this.isValidCommandSource(source)) {
+        hilog.warn(0x0000, TAG, `Invalid command source: ${source}, ignoring command ${command}`);
+        return;
+      }
+      
+      // 执行命令
+      await this.executeWidgetCommand(command, params);
+      
+      hilog.info(0x0000, TAG, `Widget control command ${command} executed successfully`);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to handle widget control command: ${error}`);
+    }
+  }
+
+  /**
+   * 通知本地状态监听器
+   */
+  private notifyLocalStateListeners(state: PlayerState): void {
+    this.stateChangeCallbacks.forEach(callback => {
+      try {
+        if (callback.onStateChanged) {
+          callback.onStateChanged(state);
+        }
+      } catch (error) {
+        hilog.error(0x0000, TAG, `Error in state change callback: ${error}`);
+      }
+    });
+  }
+
+  /**
+   * 通知本地歌曲变化监听器
+   */
+  private notifyLocalSongChangeListeners(song: VideoItem): void {
+    this.stateChangeCallbacks.forEach(callback => {
+      try {
+        if (callback.onSongChanged) {
+          callback.onSongChanged(song);
+        }
+      } catch (error) {
+        hilog.error(0x0000, TAG, `Error in song change callback: ${error}`);
+      }
+    });
+  }
+
+  /**
+   * 通知本地进度监听器
+   */
+  private notifyLocalProgressListeners(progress: PlayProgress): void {
+    this.stateChangeCallbacks.forEach(callback => {
+      try {
+        if (callback.onProgressChanged) {
+          callback.onProgressChanged(progress);
+        }
+      } catch (error) {
+        hilog.error(0x0000, TAG, `Error in progress change callback: ${error}`);
+      }
+    });
+  }
+
+  /**
+   * 执行卡片控制命令
+   */
+  private async executeWidgetCommand(command: string, params?: Record<string, Object>): Promise<void> {
+    try {
+      switch (command) {
+        case 'PLAY_PAUSE':
+          await this.notifyWidgetControlCallbacks('onPlayPause');
+          break;
+        case 'NEXT_SONG':
+          await this.notifyWidgetControlCallbacks('onNextSong');
+          break;
+        case 'PREV_SONG':
+          await this.notifyWidgetControlCallbacks('onPreviousSong');
+          break;
+        case 'SEEK_TO':
+          const position = params?.position as number || 0;
+          await this.notifyWidgetControlCallbacks('onSeekTo', position);
+          break;
+        default:
+          hilog.warn(0x0000, TAG, `Unknown widget command: ${command}`);
+      }
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to execute widget command ${command}: ${error}`);
+      throw new Error(`Failed to execute widget command ${command}: ${error}`);
+    }
+  }
+
+  /**
+   * 验证命令来源是否有效
+   */
+  private isValidCommandSource(source: string): boolean {
+    const validSources = ['widget', 'form', 'card', 'desktop_widget'];
+    return validSources.includes(source);
+  }
+
+  /**
+   * 通知卡片控制回调
+   */
+  private async notifyWidgetControlCallbacks(method: string, ...args: Object[]): Promise<void> {
+    const promises: Promise<void>[] = [];
+    
+    this.widgetControlCallbacks.forEach(callback => {
+      try {
+        let promise: Promise<void> | undefined;
+        
+        switch (method) {
+          case 'onPlayPause':
+            promise = callback.onPlayPause?.();
+            break;
+          case 'onNextSong':
+            promise = callback.onNextSong?.();
+            break;
+          case 'onPreviousSong':
+            promise = callback.onPreviousSong?.();
+            break;
+          case 'onSeekTo':
+            promise = callback.onSeekTo?.(args[0] as number);
+            break;
+          case 'onStateRequest':
+            promise = callback.onStateRequest?.();
+            break;
+        }
+        
+        if (promise) {
+          promises.push(promise);
+        }
+      } catch (error) {
+        hilog.error(0x0000, TAG, `Error in widget control callback ${method}: ${error}`);
+      }
+    });
+    
+    // 等待所有回调执行完成
+    if (promises.length > 0) {
+      try {
+        await Promise.all(promises);
+        hilog.info(0x0000, TAG, `All widget control callbacks for ${method} completed`);
+      } catch (error) {
+        hilog.error(0x0000, TAG, `Some widget control callbacks for ${method} failed: ${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')}`;
+  }
+}

+ 1190 - 0
entry/src/main/ets/common/service/UnifiedPlayerService.ets

@@ -0,0 +1,1190 @@
+import { VideoItem } from '../../viewmodel/VideoItem';
+import { PlayerManager, IPlayerManager, PlayerStateCallback } from './PlayerManager';
+import { PlayerStateModel, PlayerState, PlayerStateListener, PlayMode, PlayerError, PlayerErrorType } from './PlayerStateModel';
+import { PlaylistModel } from './PlaylistModel';
+import { PlayProgress } from '../widget/WidgetTypes';
+import { LogUtils } from '@ohos/ijkplayer';
+import { common } from '@kit.AbilityKit';
+import { PreferencesUtil, StrUtil } from '@pura/harmony-utils';
+import { DataPersistenceService, PlaylistSyncService, PlaylistSyncListener, IDataPersistenceService, PlaylistData } from './DataPersistenceService';
+import { StateSyncService, IStateSyncService, StateChangeCallback, WidgetControlCallback } from './StateSyncService';
+import { ErrorRecoveryStrategy, IErrorRecoveryStrategy, ErrorContext, ErrorRecoveryAction } from './ErrorRecoveryStrategy';
+
+/**
+ * 统一播放器服务接口
+ * 提供统一的播放控制接口,替代LocalMusic中的播放器逻辑
+ */
+export interface IPlayerService {
+  // 播放控制 - 基于LocalMusic现有方法
+  startPlayOrResumePlay(): Promise<void>;
+  pause(): Promise<void>;
+  stop(): Promise<void>;
+  seekTo(position: string): Promise<void>;
+  
+  // 播放列表控制 - 基于LocalMusic现有方法
+  playNext(): Promise<void>;
+  playPrevious(): Promise<void>;
+  playSongAtIndex(index: number): Promise<void>;
+  
+  // 状态查询 - 兼容LocalMusic数据结构
+  getCurrentState(): PlayerState;
+  getCurrentSong(): VideoItem | null;
+  getPlaylist(): VideoItem[];
+  getCurrentIndex(): number;
+  
+  // 播放模式控制 - 基于LocalMusic现有功能
+  setPlayMode(mode: number): void;
+  getPlayMode(): number;
+  
+  // 音量和速度控制 - 基于LocalMusic现有功能
+  setVolume(volume: number): void;
+  setPlaybackSpeed(speed: number): void;
+  
+  // 播放列表管理
+  setPlaylist(songs: VideoItem[], currentIndex?: number): void;
+  addToPlaylist(song: VideoItem, index?: number): void;
+  removeFromPlaylist(index: number): VideoItem | null;
+  
+  // 事件监听
+  addStateListener(listener: PlayerStateListener): void;
+  removeStateListener(listener: PlayerStateListener): void;
+  
+  // 初始化和清理
+  initialize(context: common.UIAbilityContext): Promise<void>;
+  release(): void;
+}
+
+/**
+ * 统一播放器服务实现
+ * 整合PlayerManager、PlayerStateModel和PlaylistModel
+ */
+export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListener, StateChangeCallback, WidgetControlCallback, PlayerStateCallback {
+  private static instance: UnifiedPlayerService | null = null;
+  private playerManager: IPlayerManager;
+  private stateModel: PlayerStateModel;
+  private playlistModel: PlaylistModel;
+  private dataPersistence: IDataPersistenceService;
+  private playlistSync: PlaylistSyncService;
+  private stateSync: IStateSyncService;
+  private errorRecovery: IErrorRecoveryStrategy;
+  private context: common.UIAbilityContext | null = null;
+  private progressTimer: number = -1;
+  private isInitialized: boolean = false;
+  private currentRetryCount: number = 0;
+
+  private constructor() {
+    this.playerManager = PlayerManager.getInstance();
+    this.stateModel = new PlayerStateModel();
+    this.playlistModel = new PlaylistModel();
+    this.dataPersistence = DataPersistenceService.getInstance();
+    this.playlistSync = PlaylistSyncService.getInstance();
+    this.stateSync = StateSyncService.getInstance();
+    this.errorRecovery = ErrorRecoveryStrategy.getInstance();
+    
+    LogUtils.getInstance().LOGI('UnifiedPlayerService: Instance created');
+  }
+
+  public static getInstance(): UnifiedPlayerService {
+    if (!UnifiedPlayerService.instance) {
+      UnifiedPlayerService.instance = new UnifiedPlayerService();
+    }
+    return UnifiedPlayerService.instance;
+  }  
+async initialize(context: common.UIAbilityContext): Promise<void> {
+    if (this.isInitialized) {
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Already initialized');
+      return;
+    }
+
+    try {
+      this.context = context;
+      
+      // 初始化各个服务
+      await this.playerManager.initialize(context);
+      
+      // 设置播放器状态回调
+      this.playerManager.setStateCallback(this);
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: PlayerManager state callback set');
+      
+      await this.dataPersistence.initialize(context);
+      await this.playlistSync.initialize(context);
+      await this.stateSync.initialize(context);
+      
+      // 设置同步监听器
+      this.playlistSync.addSyncListener(this);
+      this.stateSync.subscribeToStateChanges(this);
+      this.stateSync.subscribeToWidgetControl(this);
+      
+      // 设置状态模型监听器,自动广播状态变化
+      class StateListenerImpl implements PlayerStateListener {
+        private stateSync: IStateSyncService;
+        
+        constructor(stateSync: IStateSyncService) {
+          this.stateSync = stateSync;
+        }
+        
+        onStateChanged(state: PlayerState): void {
+          this.stateSync.broadcastState(state)
+        }
+        onSongChanged(song: VideoItem): void {
+          this.stateSync.broadcastSongChange(song)
+        }
+        onProgressChanged(progress: PlayProgress): void {
+          this.stateSync.broadcastProgress(progress)
+        }
+        onError(error: PlayerError): void {
+          LogUtils.getInstance().LOGI(`Player error: ${error.message}`);
+        }
+      }
+      const stateListener = new StateListenerImpl(this.stateSync);
+      this.stateModel.addStateListener(stateListener);
+      
+      // 恢复保存的状态
+      await this.restorePersistedState();
+      
+      this.setupProgressTimer();
+      this.isInitialized = true;
+      
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Initialized successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService initialization error: ${error}`);
+      throw new Error;
+    }
+  }
+
+  // 播放控制方法
+  async startPlayOrResumePlay(): Promise<void> {
+    try {
+      const currentSong = this.playlistModel.getCurrentSong();
+      if (!currentSong) {
+        await this.handlePlaybackError(new Error('No song to play'), PlayerErrorType.PLAYBACK_ERROR);
+        return;
+      }
+
+      this.stateModel.updateLoadingState(true);
+      
+      const playerInstance = this.playerManager.getIjkPlayer();
+      if (!playerInstance) {
+        await this.handlePlaybackError(new Error('Player not initialized'), PlayerErrorType.INITIALIZATION_ERROR);
+        return;
+      }
+
+      // 如果是暂停状态,直接恢复播放
+      if (this.stateModel.getState().isPaused && !this.stateModel.getState().isLoading) {
+        await this.playerManager.startPlayOrResumePlay();
+        this.stateModel.updatePlayingState(true);
+        this.startProgressTimer();
+        return;
+      }
+
+      // 检查文件是否存在(对于本地文件)
+      if (!currentSong.filePath.startsWith('http')) {
+        const fileExists = await this.checkFileExists(currentSong.filePath);
+        if (!fileExists) {
+          await this.handlePlaybackError(new Error(`File not found: ${currentSong.filePath}`), PlayerErrorType.FILE_NOT_FOUND);
+          return;
+        }
+      } else {
+        // 检查网络连接(对于网络资源)
+        const networkAvailable = await this.checkNetworkConnection();
+        if (!networkAvailable) {
+          await this.handlePlaybackError(new Error('Network not available'), PlayerErrorType.NETWORK_ERROR);
+          return;
+        }
+      }
+
+      // 设置播放源和配置
+      await this.setupPlayerForSong(currentSong);
+      
+      // 准备播放器
+      const preparedPlayer = this.playerManager.getIjkPlayer();
+      if (preparedPlayer) {
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService: Preparing async for ${currentSong.name}`);
+        preparedPlayer.prepareAsync();
+        // 注意:实际播放和状态更新会在 onPrepared 回调中开始
+      }
+      
+      // 恢复播放位置(如果有记忆播放功能)
+      this.restorePlaybackPosition(currentSong);
+      
+      // 重置重试计数(播放成功)
+      this.currentRetryCount = 0;
+      
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Started playing ${currentSong.name}`);
+    } catch (error) {
+      this.stateModel.updateLoadingState(false);
+      this.stateModel.updatePlayingState(false);
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService startPlayOrResumePlay error: ${error}`);
+      
+      // 使用错误恢复机制处理错误
+      await this.handlePlaybackError(error as Error, PlayerErrorType.PLAYBACK_ERROR);
+    }
+  }
+
+  async pause(): Promise<void> {
+    try {
+      this.savePlaybackPosition();
+      this.playerManager.pausePlayback();
+      this.stateModel.updatePlayingState(false);
+      this.stopProgressTimer();
+      
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Playback paused');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService pause error: ${error}`);
+      throw new Error;
+    }
+  }
+
+  async stop(): Promise<void> {
+    try {
+      this.savePlaybackPosition();
+      this.playerManager.stopPlayback();
+      this.stateModel.updatePlayingState(false);
+      this.stateModel.updateProgress(0, 0);
+      this.stopProgressTimer();
+      
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Playback stopped');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService stop error: ${error}`);
+      throw new Error;
+    }
+  } 
+ async seekTo(position: string): Promise<void> {
+    try {
+      const currentSong = this.playlistModel.getCurrentSong();
+      if (!currentSong) {
+        throw new Error('No song to seek');
+      }
+
+      // 检查是否支持拖动(wma格式不支持)
+      if (StrUtil.isNotEmpty(currentSong.filePath) && 
+          currentSong.filePath.toLowerCase().endsWith('.wma')) {
+        throw new Error('WMA format does not support seeking');
+      }
+
+      this.playerManager.seekToPosition(position);
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Seeked to position ${position}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService seekTo error: ${error}`);
+      throw new Error;
+    }
+  }
+
+  // 播放列表控制方法
+  async playNext(): Promise<void> {
+    try {
+      const playMode = this.stateModel.getState().playMode;
+      
+      if (!this.playlistModel.hasNext(playMode)) {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: No next song available');
+        return;
+      }
+
+      const moved = this.playlistModel.moveToNext(playMode);
+      if (!moved) {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: Failed to move to next song');
+        return;
+      }
+
+      this.stateModel.updateCurrentIndex(this.playlistModel.getCurrentIndex());
+      
+      // 停止当前播放并开始新歌曲
+      await this.stop();
+      await this.startPlayOrResumePlay();
+      
+      // 更新状态模型中的播放列表状态
+      this.updatePlaylistStateInModel();
+      
+      // 通知歌曲变化
+      const currentSong = this.playlistModel.getCurrentSong();
+      if (currentSong) {
+        this.stateModel.updateCurrentSong(currentSong);
+      }
+      
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Moved to next song');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService playNext error: ${error}`);
+      await this.handlePlaybackError(error as Error, PlayerErrorType.PLAYBACK_ERROR);
+    }
+  }
+
+  async playPrevious(): Promise<void> {
+    try {
+      const playMode = this.stateModel.getState().playMode;
+      
+      if (!this.playlistModel.hasPrevious(playMode)) {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: No previous song available');
+        return;
+      }
+
+      const moved = this.playlistModel.moveToPrevious(playMode);
+      if (!moved) {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: Failed to move to previous song');
+        return;
+      }
+
+      this.stateModel.updateCurrentIndex(this.playlistModel.getCurrentIndex());
+      
+      // 停止当前播放并开始新歌曲
+      await this.stop();
+      await this.startPlayOrResumePlay();
+      
+      // 更新状态模型中的播放列表状态
+      this.updatePlaylistStateInModel();
+      
+      // 通知歌曲变化
+      const currentSong = this.playlistModel.getCurrentSong();
+      if (currentSong) {
+        this.stateModel.updateCurrentSong(currentSong);
+      }
+      
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Moved to previous song');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService playPrevious error: ${error}`);
+      await this.handlePlaybackError(error as Error, PlayerErrorType.PLAYBACK_ERROR);
+    }
+  }
+  async playSongAtIndex(index: number): Promise<void> {
+    try {
+      const success = this.playlistModel.playSongAtIndex(index);
+      if (!success) {
+        throw new Error(`Invalid song index: ${index}`);
+      }
+
+      this.stateModel.updateCurrentIndex(index);
+      
+      // 停止当前播放并开始新歌曲
+      await this.stop();
+      await this.startPlayOrResumePlay();
+      
+      // 更新状态模型中的播放列表状态
+      this.updatePlaylistStateInModel();
+      
+      // 通知歌曲变化
+      const currentSong = this.playlistModel.getCurrentSong();
+      if (currentSong) {
+        this.stateModel.updateCurrentSong(currentSong);
+      }
+      
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Playing song at index ${index}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService playSongAtIndex error: ${error}`);
+      throw new Error;
+    }
+  }
+
+  // 状态查询方法
+  getCurrentState(): PlayerState {
+    return this.stateModel.getState();
+  }
+
+  getCurrentSong(): VideoItem | null {
+    return this.playlistModel.getCurrentSong();
+  }
+
+  getPlaylist(): VideoItem[] {
+    return this.playlistModel.getSongs();
+  }
+
+  getCurrentIndex(): number {
+    return this.playlistModel.getCurrentIndex();
+  }
+
+  // 播放模式控制
+  setPlayMode(mode: number): void {
+    const playMode = mode as PlayMode;
+    this.stateModel.updatePlayMode(playMode);
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService: Play mode set to ${mode}`);
+  }
+
+  getPlayMode(): number {
+    return this.stateModel.getState().playMode;
+  }
+
+  // 音量和速度控制
+  setVolume(volume: number): void {
+    const volumeStr = volume.toString();
+    this.playerManager.setVolume(volumeStr, volumeStr);
+    this.stateModel.updateVolume(volume);
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService: Volume set to ${volume}`);
+  }
+
+  setPlaybackSpeed(speed: number): void {
+    const speedStr = speed.toString() + 'f';
+    this.playerManager.setPlaybackSpeed(speedStr);
+    this.stateModel.updateSpeed(speed);
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService: Speed set to ${speed}`);
+  }  
+  // 播放列表管理
+  setPlaylist(songs: VideoItem[], currentIndex: number = 0): void {
+    this.playlistModel.replaceSongs(songs, currentIndex);
+    this.stateModel.updateCurrentIndex(currentIndex);
+    
+    // 更新状态模型中的播放列表状态
+    this.updatePlaylistStateInModel();
+    
+    // 更新当前歌曲
+    const currentSong = this.playlistModel.getCurrentSong();
+    this.stateModel.updateCurrentSong(currentSong);
+    
+    // 同步到持久化存储
+    this.syncPlaylistToStorage();
+    
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService: Playlist set with ${songs.length} songs`);
+  }
+
+  addToPlaylist(song: VideoItem, index?: number): void {
+    this.playlistModel.addSong(song, index);
+    
+    // 更新状态模型中的播放列表状态
+    this.updatePlaylistStateInModel();
+    
+    // 同步到持久化存储
+    this.syncPlaylistToStorage();
+    
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService: Song added to playlist`);
+  }
+
+  removeFromPlaylist(index: number): VideoItem | null {
+    const removedSong = this.playlistModel.removeSong(index);
+    if (removedSong) {
+      this.stateModel.updateCurrentIndex(this.playlistModel.getCurrentIndex());
+      
+      // 更新状态模型中的播放列表状态
+      this.updatePlaylistStateInModel();
+      
+      // 更新当前歌曲
+      const currentSong = this.playlistModel.getCurrentSong();
+      this.stateModel.updateCurrentSong(currentSong);
+      
+      // 同步到持久化存储
+      this.syncPlaylistToStorage();
+      
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Song removed from playlist at index ${index}`);
+    }
+    return removedSong;
+  }
+
+  // 事件监听
+  addStateListener(listener: PlayerStateListener): void {
+    this.stateModel.addStateListener(listener);
+  }
+
+  removeStateListener(listener: PlayerStateListener): void {
+    this.stateModel.removeStateListener(listener);
+  }
+
+  // 清理资源
+  release(): void {
+    try {
+      this.stopProgressTimer();
+      
+      // 保存当前状态
+      this.saveCurrentState();
+      
+      // 清理同步监听器
+      this.playlistSync.removeSyncListener(this);
+      this.playlistSync.release();
+      this.stateSync.unsubscribeFromStateChanges(this);
+      this.stateSync.unsubscribeFromWidgetControl(this);
+      this.stateSync.release();
+      
+      this.playerManager.release();
+      this.playlistModel.clear();
+      this.isInitialized = false;
+      
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Resources released');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService release error: ${error}`);
+    }
+  }
+
+  // ==================== 错误处理和恢复方法 ====================
+  
+  /**
+   * 处理播放错误
+   */
+  private async handlePlaybackError(error: Error, errorType: PlayerErrorType = PlayerErrorType.PLAYBACK_ERROR): Promise<void> {
+    try {
+      // 创建播放器错误对象
+      const playerError = new PlayerError(errorType, error.message);
+      playerError.retryCount = this.currentRetryCount;
+      
+      // 创建错误上下文
+      const context: ErrorContext = {
+        currentSong: this.playlistModel.getCurrentSong(),
+        playlist: this.playlistModel.getSongs(),
+        currentIndex: this.playlistModel.getCurrentIndex(),
+        retryCount: this.currentRetryCount,
+        isNetworkAvailable: true // 这里可以实际检查网络状态
+      };
+      
+      // 获取恢复策略
+      const recoveryAction = await this.errorRecovery.handleError(playerError, context);
+      
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Error recovery action: ${recoveryAction}`);
+      
+      // 执行恢复动作
+      await this.executeRecoveryAction(recoveryAction, playerError, context);
+      
+    } catch (recoveryError) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Error recovery failed: ${recoveryError}`);
+      this.stateModel.notifyError(new PlayerError(PlayerErrorType.PLAYBACK_ERROR, `Recovery failed: ${recoveryError.message}`));
+    }
+  }
+  
+  /**
+   * 执行错误恢复动作
+   */
+  private async executeRecoveryAction(action: ErrorRecoveryAction, error: PlayerError, context: ErrorContext): Promise<void> {
+    switch (action) {
+      case ErrorRecoveryAction.RETRY:
+        await this.retryCurrentOperation(error);
+        break;
+        
+      case ErrorRecoveryAction.SKIP_TO_NEXT:
+        await this.skipToNextSong();
+        break;
+        
+      case ErrorRecoveryAction.STOP_PLAYBACK:
+        await this.stop();
+        this.stateModel.notifyError(error);
+        break;
+        
+      case ErrorRecoveryAction.WAIT_AND_RETRY:
+        await this.waitAndRetry(error);
+        break;
+        
+      case ErrorRecoveryAction.SHOW_ERROR:
+        this.stateModel.notifyError(error);
+        break;
+        
+      default:
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService: Unknown recovery action: ${action}`);
+        this.stateModel.notifyError(error);
+    }
+  }
+  
+  /**
+   * 重试当前操作
+   */
+  private async retryCurrentOperation(error: PlayerError): Promise<void> {
+    try {
+      this.currentRetryCount++;
+      const delay = this.errorRecovery.getRetryDelay(this.currentRetryCount);
+      
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Retrying operation in ${delay}ms (attempt ${this.currentRetryCount})`);
+      
+      // 等待指定时间后重试
+      setTimeout(async () => {
+        try {
+          await this.startPlayOrResumePlay();
+          this.currentRetryCount = 0; // 重试成功,重置计数
+        } catch (retryError) {
+          LogUtils.getInstance().LOGI(`UnifiedPlayerService: Retry failed: ${retryError}`);
+          await this.handlePlaybackError(retryError as Error, error.type);
+        }
+      }, delay);
+      
+    } catch (retryError) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Retry setup failed: ${retryError}`);
+      await this.skipToNextSong();
+    }
+  }
+  
+  /**
+   * 跳到下一首歌曲
+   */
+  private async skipToNextSong(): Promise<void> {
+    try {
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Skipping to next song due to error');
+      
+      // 重置重试计数
+      this.currentRetryCount = 0;
+      
+      // 检查是否有下一首
+      const playMode = this.stateModel.getState().playMode;
+      if (this.playlistModel.hasNext(playMode)) {
+        await this.playNext();
+      } else {
+        // 没有下一首,停止播放
+        await this.stop();
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: No next song available, stopping playback');
+      }
+      
+    } catch (skipError) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to skip to next song: ${skipError}`);
+      await this.stop();
+    }
+  }
+  
+  /**
+   * 等待后重试
+   */
+  private async waitAndRetry(error: PlayerError): Promise<void> {
+    try {
+      this.currentRetryCount++;
+      const delay = this.errorRecovery.getRetryDelay(this.currentRetryCount);
+      
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Waiting ${delay}ms before retry (network error)`);
+      
+      // 更新状态为加载中
+      this.stateModel.updateLoadingState(true);
+      
+      setTimeout(async () => {
+        try {
+          await this.startPlayOrResumePlay();
+          this.currentRetryCount = 0; // 重试成功,重置计数
+        } catch (retryError) {
+          LogUtils.getInstance().LOGI(`UnifiedPlayerService: Network retry failed: ${retryError}`);
+          await this.handlePlaybackError(retryError as Error, PlayerErrorType.NETWORK_ERROR);
+        }
+      }, delay);
+      
+    } catch (waitError) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Wait and retry setup failed: ${waitError}`);
+      await this.skipToNextSong();
+    }
+  }
+  
+  /**
+   * 检查文件是否存在
+   */
+  private async checkFileExists(filePath: string): Promise<boolean> {
+    try {
+      // 这里可以添加文件存在性检查逻辑
+      // 暂时返回true,实际实现需要使用文件系统API
+      return true;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: File check failed: ${error}`);
+      return false;
+    }
+  }
+  
+  /**
+   * 检查网络连接
+   */
+  private async checkNetworkConnection(): Promise<boolean> {
+    try {
+      // 这里可以添加网络连接检查逻辑
+      // 暂时返回true,实际实现需要使用网络API
+      return true;
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Network check failed: ${error}`);
+      return false;
+    }
+  }
+
+  // 私有辅助方法
+  private async setupPlayerForSong(song: VideoItem): Promise<void> {
+    const ijkPlayer = this.playerManager.getIjkPlayer();
+    if (!ijkPlayer) {
+      throw new Error('Player not initialized');
+    }
+
+    // 重置播放器
+    ijkPlayer.reset();
+    
+    // 重新设置音频模式 - 重置后需要重新设置
+    ijkPlayer.setAudioId('unifiedPlayer');
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService: Reset audio mode for ${song.name}`);
+    
+    // 重新设置配置
+    this.playerManager.setupIjkPlayerOptions();
+    
+    // 设置音量(针对dsf格式特殊处理)
+    const volume = this.stateModel.getState().volume;
+    if (song.filePath.toLowerCase().endsWith('.dsf')) {
+      this.playerManager.setVolume('1', '1');
+    } else {
+      this.playerManager.setVolume(volume.toString(), volume.toString());
+    }
+    
+    // 设置数据源
+    ijkPlayer.setDataSource(song.filePath);
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService: Set data source to ${song.filePath}`);
+    
+    // 设置HTTP请求头
+    const headers = new Map([
+      ["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (bbcallen@gmail.com)"],
+      ["referer", "https://www.bilibili.com"]
+    ]);
+    ijkPlayer.setDataSourceHeader(headers);
+    
+    // 设置播放速度
+    const speed = this.stateModel.getState().speed;
+    this.playerManager.setPlaybackSpeed(speed.toString() + 'f');
+    
+    // 设置消息监听器(重要:用于处理播放器内部事件)
+    ijkPlayer.setMessageListener();
+    
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService: Player setup for song ${song.name}`);
+  }  
+  private setupProgressTimer(): void {
+    this.progressTimer = setInterval(() => {
+      this.updateProgress();
+    }, 1000); // 每秒更新一次进度
+  }
+
+  private startProgressTimer(): void {
+    if (this.progressTimer === -1) {
+      this.setupProgressTimer();
+    }
+  }
+
+  private stopProgressTimer(): void {
+    if (this.progressTimer !== -1) {
+      clearInterval(this.progressTimer);
+      this.progressTimer = -1;
+    }
+  }
+
+  private updateProgress(): void {
+    try {
+      const ijkPlayer = this.playerManager.getIjkPlayer();
+      if (!ijkPlayer || !this.stateModel.getState().isPlaying) {
+        return;
+      }
+
+      const currentPosition = ijkPlayer.getCurrentPosition();
+      const duration = ijkPlayer.getDuration();
+      
+      this.stateModel.updateProgress(currentPosition, duration);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService updateProgress error: ${error}`);
+    }
+  }
+
+  private savePlaybackPosition(): void {
+    try {
+      const currentSong = this.playlistModel.getCurrentSong();
+      const ijkPlayer = this.playerManager.getIjkPlayer();
+      
+      if (!currentSong || !ijkPlayer) {
+        return;
+      }
+
+      const position = ijkPlayer.getCurrentPosition();
+      const duration = ijkPlayer.getDuration();
+      
+      // 使用DataPersistenceService保存播放进度
+      this.dataPersistence.savePlaybackProgress(
+        currentSong.filePath, // 使用filePath作为songId
+        currentSong.filePath,
+        position,
+        duration
+      )
+      
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Saved playback position ${position}ms for ${currentSong.name}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService savePlaybackPosition error: ${error}`);
+    }
+  }
+
+  private restorePlaybackPosition(song: VideoItem): void {
+    try {
+      // 使用DataPersistenceService恢复播放进度
+      this.dataPersistence.loadPlaybackProgress(song.filePath).then(progressData => {
+        if (progressData && progressData.position > 0 && !progressData.completed) {
+          this.playerManager.seekToPosition(progressData.position.toString());
+          LogUtils.getInstance().LOGI(`UnifiedPlayerService: Restored playback position ${progressData.position}ms for ${song.name}`);
+        }
+      })
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService restorePlaybackPosition error: ${error}`);
+    }
+  }
+ // ==================== 数据持久化和同步方法 ====================
+  
+  /**
+   * 恢复持久化的状态
+   */
+  private async restorePersistedState(): Promise<void> {
+    try {
+      // 恢复播放列表
+      const playlistData = await this.dataPersistence.loadPlaylist();
+      if (playlistData && playlistData.songs.length > 0) {
+        this.playlistModel.replaceSongs(playlistData.songs, playlistData.currentIndex);
+        this.stateModel.updateCurrentIndex(playlistData.currentIndex);
+        this.stateModel.updatePlayMode(playlistData.playMode);
+        
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService: Restored playlist with ${playlistData.songs.length} songs`);
+      }
+      
+      // 恢复播放状态
+      const stateData = await this.dataPersistence.loadPlayerState();
+      if (stateData) {
+        this.stateModel.updateVolume(stateData.volume);
+        this.stateModel.updateSpeed(stateData.speed);
+        this.stateModel.updatePlayMode(stateData.playMode);
+        
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: Restored player state');
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService restorePersistedState error: ${error}`);
+    }
+  }
+  
+  /**
+   * 保存当前状态
+   */
+  private saveCurrentState(): void {
+    try {
+      // 保存播放状态
+      const currentState = this.stateModel.getState();
+      this.dataPersistence.savePlayerState(currentState)
+      
+      // 保存播放进度
+      this.savePlaybackPosition();
+      
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Current state saved');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService saveCurrentState error: ${error}`);
+    }
+  }
+  
+  /**
+   * 同步播放列表到存储
+   */
+  private syncPlaylistToStorage(): void {
+    try {
+      const playlist = this.playlistModel.getSongs();
+      const currentIndex = this.playlistModel.getCurrentIndex();
+      const playMode = this.stateModel.getState().playMode;
+      
+      this.playlistSync.syncPlaylistToStorage(playlist, currentIndex, playMode);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService syncPlaylistToStorage error: ${error}`);
+    }
+  }
+  
+  // ==================== PlaylistSyncListener 接口实现 ====================
+  
+  /**
+   * 播放列表同步完成回调
+   */
+  onPlaylistSynced(playlist: VideoItem[], currentIndex: number, playMode: PlayMode): void {
+    try {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Playlist synced - ${playlist.length} songs, index ${currentIndex}`);
+      
+      // 播放列表同步完成,无需额外通知
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onPlaylistSynced error: ${error}`);
+    }
+  }
+  
+  /**
+   * 播放列表加载完成回调
+   */
+  onPlaylistLoaded(playlistData: PlaylistData): void {
+    try {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Playlist loaded from storage - ${playlistData.songs.length} songs`);
+      
+      // 检查是否需要更新本地播放列表
+      const currentPlaylist = this.playlistModel.getSongs();
+      const currentIndex = this.playlistModel.getCurrentIndex();
+      
+      // 如果存储的数据更新,更新本地播放列表
+      if (playlistData.songs.length !== currentPlaylist.length || 
+          playlistData.currentIndex !== currentIndex) {
+        
+        this.playlistModel.replaceSongs(playlistData.songs, playlistData.currentIndex);
+        this.stateModel.updateCurrentIndex(playlistData.currentIndex);
+        this.stateModel.updatePlayMode(playlistData.playMode);
+        
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: Local playlist updated from storage');
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onPlaylistLoaded error: ${error}`);
+    }
+  }
+  
+  /**
+   * 自动同步执行回调
+   */
+  onAutoSyncPerformed(): void {
+    try {
+      // 定期保存当前状态
+      this.saveCurrentState();
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onAutoSyncPerformed error: ${error}`);
+    }
+  }
+  
+  /**
+   * 同步错误回调
+   */
+  onSyncError(error: Error): void {
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService sync error: ${error.message}`);
+  }
+  
+  // ==================== 公共数据访问方法 ====================
+  
+  /**
+   * 获取数据持久化服务实例
+   */
+  getDataPersistenceService(): IDataPersistenceService {
+    return this.dataPersistence;
+  }
+  
+  /**
+   * 获取播放列表同步服务实例
+   */
+  getPlaylistSyncService(): PlaylistSyncService {
+    return this.playlistSync;
+  }
+  
+  /**
+   * 手动触发数据同步
+   */
+  async manualSync(): Promise<void> {
+    try {
+      const playlist = this.playlistModel.getSongs();
+      const currentIndex = this.playlistModel.getCurrentIndex();
+      const playMode = this.stateModel.getState().playMode;
+      
+      // 执行双向同步
+      const syncedData = await this.playlistSync.bidirectionalSync(playlist, currentIndex, playMode);
+      
+      // 如果同步后的数据与本地不同,更新本地数据
+      if (syncedData.songs.length !== playlist.length || 
+          syncedData.currentIndex !== currentIndex ||
+          syncedData.playMode !== playMode) {
+        
+        this.playlistModel.replaceSongs(syncedData.songs, syncedData.currentIndex);
+        this.stateModel.updateCurrentIndex(syncedData.currentIndex);
+        this.stateModel.updatePlayMode(syncedData.playMode);
+        
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: Manual sync completed with data update');
+      } else {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: Manual sync completed - no changes');
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService manualSync error: ${error}`);
+      throw new  Error;
+    }
+  }
+
+  // ==================== StateChangeCallback 接口实现 ====================
+  
+  /**
+   * 状态变化回调(来自StateSyncService的本地通知)
+   */
+  onStateChanged?(state: PlayerState): void {
+    try {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Received state change notification - isPlaying=${state.isPlaying}`);
+      // 这里可以处理来自其他组件的状态变化通知
+      // 通常情况下,状态变化是由本服务发起的,所以这里主要用于调试和监控
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onStateChanged error: ${error}`);
+    }
+  }
+  
+  /**
+   * 歌曲变化回调(来自StateSyncService的本地通知)
+   */
+  onSongChanged?(song: VideoItem): void {
+    try {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Received song change notification - ${song.name}`);
+      // 这里可以处理来自其他组件的歌曲变化通知
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onSongChanged error: ${error}`);
+    }
+  }
+  
+  /**
+   * 进度变化回调(来自StateSyncService的本地通知)
+   */
+  onProgressChanged?(progress: PlayProgress): void {
+    try {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Received progress change notification - ${progress.percentage.toFixed(1)}%`);
+      // 这里可以处理来自其他组件的进度变化通知
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onProgressChanged error: ${error}`);
+    }
+  }
+
+  // ==================== WidgetControlCallback 接口实现 ====================
+  
+  /**
+   * 处理来自卡片的播放/暂停命令
+   */
+  async onPlayPause?(): Promise<void> {
+    try {
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Received play/pause command from widget');
+      
+      const currentState = this.getCurrentState();
+      if (currentState.isPlaying) {
+        await this.pause();
+      } else {
+        await this.startPlayOrResumePlay();
+      }
+      
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Play/pause command executed successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onPlayPause error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 处理来自卡片的下一首命令
+   */
+  async onNextSong?(): Promise<void> {
+    try {
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Received next song command from widget');
+      await this.playNext();
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Next song command executed successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onNextSong error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 处理来自卡片的上一首命令
+   */
+  async onPreviousSong?(): Promise<void> {
+    try {
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Received previous song command from widget');
+      await this.playPrevious();
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Previous song command executed successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onPreviousSong error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 处理来自卡片的拖动进度命令
+   */
+  async onSeekTo?(position: number): Promise<void> {
+    try {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Received seek to command from widget - position: ${position}`);
+      await this.seekTo(position.toString());
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Seek to command executed successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onSeekTo error: ${error}`);
+      throw new Error;
+    }
+  }
+  
+  /**
+   * 处理来自卡片的状态请求命令
+   */
+  async onStateRequest?(): Promise<void> {
+    try {
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Received state request from widget');
+      await this.broadcastCurrentState();
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: State request handled successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService onStateRequest error: ${error}`);
+      throw new Error;
+    }
+  }
+
+  // ==================== 状态同步服务访问方法 ====================
+  
+  /**
+   * 获取状态同步服务实例
+   */
+  getStateSyncService(): IStateSyncService {
+    return this.stateSync;
+  }
+  
+  /**
+   * 手动广播当前状态(用于响应卡片的状态请求)
+   */
+  async broadcastCurrentState(): Promise<void> {
+    try {
+      const currentState = this.getCurrentState();
+      await this.stateSync.broadcastState(currentState);
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Current state broadcasted manually');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService broadcastCurrentState error: ${error}`);
+      throw new Error;
+    }
+  }
+
+  // ==================== 私有辅助方法 ====================
+  
+  /**
+   * 更新状态模型中的播放列表状态
+   */
+  private updatePlaylistStateInModel(): void {
+    try {
+      const currentIndex = this.playlistModel.getCurrentIndex();
+      const totalCount = this.playlistModel.getTotalCount();
+      const playMode = this.stateModel.getState().playMode;
+      
+      const hasNext = this.playlistModel.hasNext(playMode);
+      const hasPrevious = this.playlistModel.hasPrevious(playMode);
+      
+      this.stateModel.updatePlaylistState(hasNext, hasPrevious, totalCount);
+      
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Playlist state updated - hasNext=${hasNext}, hasPrevious=${hasPrevious}, totalCount=${totalCount}`);
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService updatePlaylistStateInModel error: ${error}`);
+    }
+  }
+
+  // ==================== PlayerStateCallback 实现 ====================
+
+  onPrepared(): void {
+    LogUtils.getInstance().LOGI('UnifiedPlayerService: Player prepared');
+    this.stateModel.updateLoadingState(false);
+  }
+
+  onPlaybackStarted(): void {
+    LogUtils.getInstance().LOGI('UnifiedPlayerService: Playback started');
+    this.stateModel.updatePlayingState(true);
+    this.startProgressTimer();
+  }
+
+  onPlaybackCompleted(): void {
+    LogUtils.getInstance().LOGI('UnifiedPlayerService: Playback completed');
+    this.stateModel.updatePlayingState(false);
+    this.stopProgressTimer();
+    
+    // 自动播放下一首(如果有的话)
+    const currentPlayMode = this.stateModel.getState().playMode;
+    if (this.playlistModel.hasNext(currentPlayMode)) {
+      setTimeout(() => {
+        this.playNext();
+      }, 500);
+    }
+  }
+
+  onPlaybackError(what: number, extra: number): void {
+    LogUtils.getInstance().LOGI(`UnifiedPlayerService: Playback error - what: ${what}, extra: ${extra}`);
+    this.stateModel.updateLoadingState(false);
+    this.stateModel.updatePlayingState(false);
+    this.stopProgressTimer();
+    
+    // 创建播放器错误对象
+    const playbackError = new PlayerError(
+      PlayerErrorType.PLAYBACK_ERROR,
+      `Playback error: what=${what}, extra=${extra}`,
+      what
+    );
+    playbackError.recoverable = what !== -1004 && what !== -1007; // 某些错误码可恢复
+    playbackError.retryCount = 0;
+    
+    // 创建错误上下文
+    const errorContext: ErrorContext = {
+      currentSong: this.getCurrentSong(),
+      playlist: this.getPlaylist(),
+      currentIndex: this.getCurrentIndex(),
+      retryCount: 0,
+      isNetworkAvailable: true // 这里可以实际检查网络状态
+    };
+    
+    // 使用错误恢复策略处理错误
+    this.errorRecovery.handleError(playbackError, errorContext).then((action: ErrorRecoveryAction) => {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Error recovery action: ${action}`);
+      // 这里可以根据 action 执行相应的恢复操作
+    }).catch((recoveryError: Error) => {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Error recovery failed: ${recoveryError}`);
+    });
+  }
+}

+ 275 - 7
entry/src/main/ets/common/widget/AvSessionWidgetListener.ets

@@ -4,10 +4,21 @@ import { WidgetTypeHelpers } from './WidgetTypeHelpers';
 
 
 const TAG = 'Heanup AvSessionWidgetListener';
 const TAG = 'Heanup AvSessionWidgetListener';
 
 
+/**
+ * 同步状态信息接口
+ */
+interface SyncStatusInfo {
+  processId: string;
+  listenerCount: number;
+  lastUpdateTime: number;
+  isProgressAnimating: boolean;
+  hasProgressTimer: boolean;
+}
+
 /**
 /**
  * AvSession卡片监听器
  * AvSession卡片监听器
  * 负责监听媒体会话状态变化并同步到卡片
  * 负责监听媒体会话状态变化并同步到卡片
- * 简化版本,避免API兼容性问题
+ * 增强版本:支持实时状态同步和平滑进度更新
  * 支持跨进程数据同步
  * 支持跨进程数据同步
  */
  */
 export class AvSessionWidgetListener {
 export class AvSessionWidgetListener {
@@ -16,6 +27,20 @@ export class AvSessionWidgetListener {
   private isInitialized: boolean = false;
   private isInitialized: boolean = false;
   private lastWidgetData: WidgetData | null = null;
   private lastWidgetData: WidgetData | null = null;
   private processId: string = '';
   private processId: string = '';
+  
+  // 实时同步相关
+  private progressUpdateTimer: number = -1;
+  private lastProgressUpdate: number = 0;
+  private readonly PROGRESS_UPDATE_INTERVAL = 1000; // 1秒更新一次进度
+  private readonly STATE_SYNC_DEBOUNCE = 100; // 状态同步防抖延迟
+  private lastStateSyncTime: number = 0;
+  
+  // 平滑动画相关
+  private isProgressAnimating: boolean = false;
+  private animationStartTime: number = 0;
+  private animationStartProgress: number = 0;
+  private animationTargetProgress: number = 0;
+  private animationDuration: number = 1000; // 1秒动画时长
 
 
   private constructor() {
   private constructor() {
     // 生成进程唯一标识
     // 生成进程唯一标识
@@ -79,32 +104,227 @@ export class AvSessionWidgetListener {
   }
   }
 
 
   /**
   /**
-   * 更新卡片数据(由主应用调用)
+   * 更新卡片数据(由主应用调用)- 增强版本
    */
    */
   public updateWidgetData(data: WidgetData): void {
   public updateWidgetData(data: WidgetData): void {
+    const now = Date.now();
+    
+    // 防抖处理,避免过于频繁的更新
+    if (now - this.lastStateSyncTime < this.STATE_SYNC_DEBOUNCE) {
+      return;
+    }
+    this.lastStateSyncTime = now;
+    
     // 检查数据是否真的发生了变化,避免无意义的更新
     // 检查数据是否真的发生了变化,避免无意义的更新
     if (this.lastWidgetData && this.isDataEqual(this.lastWidgetData, data)) {
     if (this.lastWidgetData && this.isDataEqual(this.lastWidgetData, data)) {
-      hilog.info(0x0000, TAG, `[${this.processId}] Data unchanged, skipping update`);
+      // 即使数据相同,也要更新进度(如果正在播放)
+      if (data.playState.isPlaying && !this.isProgressAnimating) {
+        this.updateProgressOnly(data);
+      }
       return;
       return;
     }
     }
     
     
+    // 检查是否需要启动平滑进度动画
+    const shouldAnimateProgress = this.shouldStartProgressAnimation(data);
+    
     this.lastWidgetData = data;
     this.lastWidgetData = data;
     
     
     // 添加调用栈信息以便调试
     // 添加调用栈信息以便调试
     const callerInfo = new Error().stack?.split('\n')[2]?.trim() || 'Unknown caller';
     const callerInfo = new Error().stack?.split('\n')[2]?.trim() || 'Unknown caller';
-    hilog.info(0x0000, TAG, `[${this.processId}] Updating widget data: isPlaying=${data.playState.isPlaying}, title=${data.currentSong.title}, listeners=${this.stateListeners.length}, caller: ${callerInfo}`);
+    hilog.info(0x0000, TAG, `[${this.processId}] Updating widget data: isPlaying=${data.playState.isPlaying}, title=${data.currentSong.title}, progress=${data.progress.percentage.toFixed(1)}%, listeners=${this.stateListeners.length}, caller: ${callerInfo}`);
+    
+    // 启动或停止进度更新定时器
+    this.manageProgressTimer(data.playState.isPlaying);
+    
+    // 如果需要平滑进度动画,启动动画
+    if (shouldAnimateProgress) {
+      this.startProgressAnimation(data);
+    }
     
     
     // 通知所有监听器
     // 通知所有监听器
+    this.notifyStateListeners(data);
+    
+    hilog.info(0x0000, TAG, `[${this.processId}] Widget data updated and broadcasted to ${this.stateListeners.length} listeners`);
+  }
+
+  /**
+   * 仅更新进度信息
+   */
+  private updateProgressOnly(data: WidgetData): void {
+    if (!this.lastWidgetData) {
+      return;
+    }
+    
+    // 创建更新后的数据,只修改进度部分
+    const updatedData: WidgetData = {
+      playState: this.lastWidgetData.playState,
+      currentSong: this.lastWidgetData.currentSong,
+      progress: {
+        currentPosition: data.progress.currentPosition,
+        duration: data.progress.duration,
+        percentage: data.progress.percentage,
+        currentTimeText: data.progress.currentTimeText,
+        totalTimeText: data.progress.totalTimeText
+      },
+      playlist: this.lastWidgetData.playlist,
+      config: this.lastWidgetData.config,
+      castingInfo: this.lastWidgetData.castingInfo
+    };
+    
+    this.lastWidgetData = updatedData;
+    this.notifyStateListeners(updatedData);
+  }
+
+  /**
+   * 判断是否应该启动进度动画
+   */
+  private shouldStartProgressAnimation(newData: WidgetData): boolean {
+    if (!this.lastWidgetData || !newData.playState.isPlaying) {
+      return false;
+    }
+    
+    // 如果进度变化较大(超过2%),启动平滑动画
+    const progressDiff = Math.abs(newData.progress.percentage - this.lastWidgetData.progress.percentage);
+    return progressDiff > 2.0 && progressDiff < 50.0; // 避免在拖拽时启动动画
+  }
+
+  /**
+   * 启动进度平滑动画
+   */
+  private startProgressAnimation(targetData: WidgetData): void {
+    if (!this.lastWidgetData) {
+      return;
+    }
+    
+    this.isProgressAnimating = true;
+    this.animationStartTime = Date.now();
+    this.animationStartProgress = this.lastWidgetData.progress.percentage;
+    this.animationTargetProgress = targetData.progress.percentage;
+    
+    hilog.info(0x0000, TAG, `Starting progress animation: ${this.animationStartProgress.toFixed(1)}% -> ${this.animationTargetProgress.toFixed(1)}%`);
+    
+    // 启动动画定时器
+    const animationTimer = setInterval(() => {
+      const elapsed = Date.now() - this.animationStartTime;
+      const progress = Math.min(elapsed / this.animationDuration, 1.0);
+      
+      // 使用缓动函数计算当前进度
+      const easedProgress = this.easeInOutQuad(progress);
+      const currentProgress = this.animationStartProgress + 
+        (this.animationTargetProgress - this.animationStartProgress) * easedProgress;
+      
+      // 更新进度数据
+      if (this.lastWidgetData) {
+        const animatedData: WidgetData = {
+          playState: this.lastWidgetData.playState,
+          currentSong: this.lastWidgetData.currentSong,
+          progress: {
+            currentPosition: targetData.progress.currentPosition,
+            duration: targetData.progress.duration,
+            percentage: currentProgress,
+            currentTimeText: targetData.progress.currentTimeText,
+            totalTimeText: targetData.progress.totalTimeText
+          },
+          playlist: this.lastWidgetData.playlist,
+          config: this.lastWidgetData.config,
+          castingInfo: this.lastWidgetData.castingInfo
+        };
+        
+        this.notifyStateListeners(animatedData);
+      }
+      
+      // 动画完成
+      if (progress >= 1.0) {
+        clearInterval(animationTimer);
+        this.isProgressAnimating = false;
+        hilog.info(0x0000, TAG, `Progress animation completed at ${currentProgress.toFixed(1)}%`);
+      }
+    }, 50); // 20fps动画
+  }
+
+  /**
+   * 缓动函数:二次缓入缓出
+   */
+  private easeInOutQuad(t: number): number {
+    return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
+  }
+
+  /**
+   * 管理进度更新定时器
+   */
+  private manageProgressTimer(isPlaying: boolean): void {
+    if (isPlaying && this.progressUpdateTimer === -1) {
+      // 启动进度更新定时器
+      this.progressUpdateTimer = setInterval(() => {
+        this.updateRealtimeProgress();
+      }, this.PROGRESS_UPDATE_INTERVAL);
+      
+      hilog.info(0x0000, TAG, 'Progress update timer started');
+    } else if (!isPlaying && this.progressUpdateTimer !== -1) {
+      // 停止进度更新定时器
+      clearInterval(this.progressUpdateTimer);
+      this.progressUpdateTimer = -1;
+      
+      hilog.info(0x0000, TAG, 'Progress update timer stopped');
+    }
+  }
+
+  /**
+   * 实时更新进度(基于时间推算)
+   */
+  private updateRealtimeProgress(): void {
+    if (!this.lastWidgetData || !this.lastWidgetData.playState.isPlaying || this.isProgressAnimating) {
+      return;
+    }
+    
+    const now = Date.now();
+    const timeSinceLastUpdate = now - this.lastProgressUpdate;
+    
+    if (timeSinceLastUpdate < this.PROGRESS_UPDATE_INTERVAL) {
+      return;
+    }
+    
+    // 基于时间推算当前进度
+    const estimatedProgress = this.lastWidgetData.progress.currentPosition + timeSinceLastUpdate;
+    const estimatedPercentage = this.calculatePercentage(estimatedProgress, this.lastWidgetData.progress.duration);
+    
+    // 创建更新后的数据
+    const updatedData: WidgetData = {
+      playState: this.lastWidgetData.playState,
+      currentSong: this.lastWidgetData.currentSong,
+      progress: {
+        currentPosition: estimatedProgress,
+        duration: this.lastWidgetData.progress.duration,
+        percentage: estimatedPercentage,
+        currentTimeText: this.formatTime(Math.floor(estimatedProgress / 1000)),
+        totalTimeText: this.lastWidgetData.progress.totalTimeText
+      },
+      playlist: this.lastWidgetData.playlist,
+      config: this.lastWidgetData.config,
+      castingInfo: this.lastWidgetData.castingInfo
+    };
+    
+    this.lastWidgetData = updatedData;
+    this.lastProgressUpdate = now;
+    
+    // 通知监听器(仅进度更新,不记录详细日志)
+    this.notifyStateListeners(updatedData, false);
+  }
+
+  /**
+   * 通知状态监听器
+   */
+  private notifyStateListeners(data: WidgetData, logDetails: boolean = true): void {
     this.stateListeners.forEach((listener: (data: WidgetData) => void, index: number) => {
     this.stateListeners.forEach((listener: (data: WidgetData) => void, index: number) => {
       try {
       try {
-        hilog.info(0x0000, TAG, `[${this.processId}] Notifying listener ${index}`);
+        if (logDetails) {
+          hilog.info(0x0000, TAG, `[${this.processId}] Notifying listener ${index}`);
+        }
         listener(data);
         listener(data);
       } catch (error) {
       } catch (error) {
         hilog.error(0x0000, TAG, `[${this.processId}] Error in state listener ${index}: ${error}`);
         hilog.error(0x0000, TAG, `[${this.processId}] Error in state listener ${index}: ${error}`);
       }
       }
     });
     });
-    
-    hilog.info(0x0000, TAG, `[${this.processId}] Widget data updated and broadcasted to ${this.stateListeners.length} listeners`);
   }
   }
 
 
   /**
   /**
@@ -148,11 +368,59 @@ export class AvSessionWidgetListener {
    * 销毁监听器
    * 销毁监听器
    */
    */
   public destroy(): void {
   public destroy(): void {
+    // 清理定时器
+    if (this.progressUpdateTimer !== -1) {
+      clearInterval(this.progressUpdateTimer);
+      this.progressUpdateTimer = -1;
+    }
+    
     this.stateListeners = [];
     this.stateListeners = [];
     this.lastWidgetData = null;
     this.lastWidgetData = null;
+    this.isProgressAnimating = false;
+    
     hilog.info(0x0000, TAG, 'AvSession widget listener destroyed');
     hilog.info(0x0000, TAG, 'AvSession widget listener destroyed');
   }
   }
 
 
+  /**
+   * 计算播放进度百分比
+   */
+  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')}`;
+  }
+
+  /**
+   * 强制同步状态(用于调试和故障恢复)
+   */
+  public forceSyncState(data: WidgetData): void {
+    hilog.info(0x0000, TAG, `[${this.processId}] Force syncing widget state`);
+    this.lastWidgetData = data;
+    this.lastStateSyncTime = 0; // 重置防抖时间
+    this.updateWidgetData(data);
+  }
+
+  /**
+   * 获取同步状态信息(用于调试)
+   */
+  public getSyncStatus(): SyncStatusInfo {
+    return {
+      processId: this.processId,
+      listenerCount: this.stateListeners.length,
+      lastUpdateTime: this.lastStateSyncTime,
+      isProgressAnimating: this.isProgressAnimating,
+      hasProgressTimer: this.progressUpdateTimer !== -1
+    };
+  }
+
   /**
   /**
    * 获取默认卡片数据
    * 获取默认卡片数据
    */
    */

+ 357 - 8
entry/src/main/ets/common/widget/PlayerControlService.ets

@@ -2,7 +2,7 @@ import commonEventManager from '@ohos.commonEventManager';
 import Want from '@ohos.app.ability.Want';
 import Want from '@ohos.app.ability.Want';
 import common from '@ohos.app.ability.common';
 import common from '@ohos.app.ability.common';
 import { hilog } from '@kit.PerformanceAnalysisKit';
 import { hilog } from '@kit.PerformanceAnalysisKit';
-import { WidgetData, WidgetCommand, EventData, RequestData, WidgetControlParams } from './WidgetTypes';
+import { WidgetData, WidgetCommand, EventData, RequestData, WidgetControlParams, PlayState as WidgetPlayState, SongInfo, PlayProgress, PlaylistState } from './WidgetTypes';
 import { WidgetTypeHelpers } from './WidgetTypeHelpers';
 import { WidgetTypeHelpers } from './WidgetTypeHelpers';
 import { 
 import { 
   WIDGET_CONTROL_EVENT,
   WIDGET_CONTROL_EVENT,
@@ -14,8 +14,11 @@ import {
   APP_ABILITY_NAME
   APP_ABILITY_NAME
 } from './WidgetEventConstants';
 } from './WidgetEventConstants';
 import { AvSessionWidgetListener } from './AvSessionWidgetListener';
 import { AvSessionWidgetListener } from './AvSessionWidgetListener';
+import { UnifiedPlayerService, IPlayerService } from '../service/UnifiedPlayerService';
+import { PlayerState, PlayerStateListener, PlayerError } from '../service/PlayerStateModel';
+import { VideoItem } from '../../viewmodel/VideoItem';
 
 
-const TAG = 'Heanup PlayerControlService';
+const TAG = 'PlayerControlService';
 
 
 /**
 /**
  * 启动参数接口
  * 启动参数接口
@@ -26,21 +29,83 @@ interface LaunchParameters {
   timestamp: string;
   timestamp: string;
 }
 }
 
 
-
+/**
+ * 命令执行状态
+ */
+interface CommandExecutionStatus {
+  command: WidgetCommand;
+  timestamp: number;
+  status: 'pending' | 'executing' | 'completed' | 'failed';
+  error?: string;
+}
 
 
 /**
 /**
  * 播放器控制服务
  * 播放器控制服务
  * 负责与主应用的播放器进行通信和状态同步
  * 负责与主应用的播放器进行通信和状态同步
+ * 优化版本:直接集成UnifiedPlayerService,减少响应延迟
  */
  */
 export class PlayerControlService {
 export class PlayerControlService {
   private stateListeners: Array<(data: WidgetData) => void> = [];
   private stateListeners: Array<(data: WidgetData) => void> = [];
   private isListenerRegistered: boolean = false;
   private isListenerRegistered: boolean = false;
   private avSessionListener: AvSessionWidgetListener;
   private avSessionListener: AvSessionWidgetListener;
+  private unifiedPlayerService: IPlayerService | null = null;
+  private commandExecutionQueue: Map<string, CommandExecutionStatus> = new Map();
+  private readonly COMMAND_TIMEOUT = 3000; // 3秒命令超时
+  private readonly MAX_RETRY_ATTEMPTS = 2;
 
 
   constructor() {
   constructor() {
     this.avSessionListener = AvSessionWidgetListener.getInstance();
     this.avSessionListener = AvSessionWidgetListener.getInstance();
     this.initializeEventListener();
     this.initializeEventListener();
     this.initializeAvSessionListener();
     this.initializeAvSessionListener();
+    this.initializeUnifiedPlayerService();
+    this.startPeriodicCleanup();
+  }
+
+  /**
+   * 初始化统一播放器服务连接
+   */
+  private async initializeUnifiedPlayerService(): Promise<void> {
+    try {
+      // 尝试获取UnifiedPlayerService实例
+      this.unifiedPlayerService = UnifiedPlayerService.getInstance();
+      
+      if (this.unifiedPlayerService) {
+        hilog.info(0x0000, TAG, 'UnifiedPlayerService connection established for widget control');
+        
+        // 添加状态监听器以实现实时状态同步
+        class WidgetStateListener implements PlayerStateListener {
+          private service: PlayerControlService;
+          
+          constructor(service: PlayerControlService) {
+            this.service = service;
+          }
+          
+          onStateChanged(state: PlayerState): void {
+            this.service.handleUnifiedPlayerStateChange(state);
+          }
+          
+          onSongChanged(song: VideoItem): void {
+            this.service.handleUnifiedPlayerSongChange(song);
+          }
+          
+          onProgressChanged(progress: PlayProgress): void {
+            this.service.handleUnifiedPlayerProgressChange(progress);
+          }
+          
+          onError(error: PlayerError): void {
+            hilog.error(0x0000, TAG, `UnifiedPlayerService error in widget: ${error.message}`);
+          }
+        }
+        
+        const listener = new WidgetStateListener(this);
+        this.unifiedPlayerService.addStateListener(listener);
+      } else {
+        hilog.warn(0x0000, TAG, 'UnifiedPlayerService not available, falling back to CommonEvent communication');
+      }
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to initialize UnifiedPlayerService connection: ${error}`);
+      // 继续使用CommonEvent作为备用方案
+    }
   }
   }
 
 
   /**
   /**
@@ -134,9 +199,126 @@ export class PlayerControlService {
   }
   }
 
 
   /**
   /**
-   * 发送控制命令到主应用
+   * 发送控制命令到主应用(优化版本)
+   * 优先使用UnifiedPlayerService直接调用,提供更快的响应速度
    */
    */
   async sendControlCommand(command: WidgetCommand, params?: WidgetControlParams): Promise<boolean> {
   async sendControlCommand(command: WidgetCommand, params?: WidgetControlParams): Promise<boolean> {
+    const commandId = `${command}_${Date.now()}`;
+    const executionStatus: CommandExecutionStatus = {
+      command: command,
+      timestamp: Date.now(),
+      status: 'pending'
+    };
+    
+    this.commandExecutionQueue.set(commandId, executionStatus);
+    
+    try {
+      // 更新状态为执行中
+      executionStatus.status = 'executing';
+      this.commandExecutionQueue.set(commandId, executionStatus);
+      
+      // 优先尝试直接调用UnifiedPlayerService
+      if (this.unifiedPlayerService) {
+        const success = await this.executeCommandDirectly(command, params);
+        if (success) {
+          executionStatus.status = 'completed';
+          this.commandExecutionQueue.set(commandId, executionStatus);
+          
+          hilog.info(0x0000, TAG, `Control command executed directly: ${command} (${Date.now() - executionStatus.timestamp}ms)`);
+          
+          // 清理执行状态(延迟清理以便状态查询)
+          setTimeout(() => {
+            this.commandExecutionQueue.delete(commandId);
+          }, 5000);
+          
+          return true;
+        }
+      }
+      
+      // 备用方案:使用CommonEvent
+      const success = await this.sendCommandViaCommonEvent(command, params);
+      
+      if (success) {
+        executionStatus.status = 'completed';
+      } else {
+        executionStatus.status = 'failed';
+        executionStatus.error = 'CommonEvent send failed';
+      }
+      
+      this.commandExecutionQueue.set(commandId, executionStatus);
+      
+      hilog.info(0x0000, TAG, `Control command sent via CommonEvent: ${command} (${Date.now() - executionStatus.timestamp}ms)`);
+      
+      // 清理执行状态
+      setTimeout(() => {
+        this.commandExecutionQueue.delete(commandId);
+      }, 5000);
+      
+      return success;
+    } catch (error) {
+      executionStatus.status = 'failed';
+      executionStatus.error = error.message;
+      this.commandExecutionQueue.set(commandId, executionStatus);
+      
+      hilog.error(0x0000, TAG, `Failed to send control command ${command}: ${error}`);
+      
+      // 清理执行状态
+      setTimeout(() => {
+        this.commandExecutionQueue.delete(commandId);
+      }, 5000);
+      
+      return false;
+    }
+  }
+
+  /**
+   * 直接执行控制命令(通过UnifiedPlayerService)
+   */
+  private async executeCommandDirectly(command: WidgetCommand, params?: WidgetControlParams): Promise<boolean> {
+    if (!this.unifiedPlayerService) {
+      return false;
+    }
+
+    try {
+      switch (command) {
+        case 'PLAY_PAUSE':
+          const currentState = this.unifiedPlayerService.getCurrentState();
+          if (currentState.isPlaying) {
+            await this.unifiedPlayerService.pause();
+          } else {
+            await this.unifiedPlayerService.startPlayOrResumePlay();
+          }
+          break;
+          
+        case 'NEXT_SONG':
+          await this.unifiedPlayerService.playNext();
+          break;
+          
+        case 'PREV_SONG':
+          await this.unifiedPlayerService.playPrevious();
+          break;
+          
+        case 'SEEK_TO':
+          const position = params?.position ? String(params.position) : '0';
+          await this.unifiedPlayerService.seekTo(position);
+          break;
+          
+        default:
+          hilog.warn(0x0000, TAG, `Unknown command for direct execution: ${command}`);
+          return false;
+      }
+      
+      return true;
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Direct command execution failed for ${command}: ${error}`);
+      return false;
+    }
+  }
+
+  /**
+   * 通过CommonEvent发送命令(备用方案)
+   */
+  private async sendCommandViaCommonEvent(command: WidgetCommand, params?: WidgetControlParams): Promise<boolean> {
     try {
     try {
       const defaultParams: WidgetControlParams = {};
       const defaultParams: WidgetControlParams = {};
       const eventData: EventData = {
       const eventData: EventData = {
@@ -146,24 +328,57 @@ export class PlayerControlService {
         source: 'widget'
         source: 'widget'
       };
       };
 
 
-      // 发送CommonEvent到主应用
       const publishInfo: commonEventManager.CommonEventPublishData = {
       const publishInfo: commonEventManager.CommonEventPublishData = {
         data: JSON.stringify(eventData)
         data: JSON.stringify(eventData)
       };
       };
+      
       await commonEventManager.publish(WIDGET_CONTROL_EVENT, publishInfo, (err) => {
       await commonEventManager.publish(WIDGET_CONTROL_EVENT, publishInfo, (err) => {
         if (err) {
         if (err) {
-          hilog.error(0x0000, TAG, `Failed to publish event: ${err}`);
+          hilog.error(0x0000, TAG, `Failed to publish CommonEvent: ${err}`);
         }
         }
       });
       });
 
 
-      hilog.info(0x0000, TAG, `Control command sent: ${command}`);
       return true;
       return true;
     } catch (error) {
     } catch (error) {
-      hilog.error(0x0000, TAG, `Failed to send control command: ${error}`);
+      hilog.error(0x0000, TAG, `Failed to send command via CommonEvent: ${error}`);
       return false;
       return false;
     }
     }
   }
   }
 
 
+  /**
+   * 获取命令执行状态
+   */
+  getCommandExecutionStatus(commandId?: string): CommandExecutionStatus[] {
+    if (commandId) {
+      const status = this.commandExecutionQueue.get(commandId);
+      return status ? [status] : [];
+    }
+    
+    return Array.from(this.commandExecutionQueue.values());
+  }
+
+  /**
+   * 清理过期的命令执行状态
+   */
+  private cleanupExpiredCommands(): void {
+    const now = Date.now();
+    const expiredCommands: string[] = [];
+    
+    this.commandExecutionQueue.forEach((status, commandId) => {
+      if (now - status.timestamp > this.COMMAND_TIMEOUT) {
+        expiredCommands.push(commandId);
+      }
+    });
+    
+    expiredCommands.forEach(commandId => {
+      this.commandExecutionQueue.delete(commandId);
+    });
+    
+    if (expiredCommands.length > 0) {
+      hilog.info(0x0000, TAG, `Cleaned up ${expiredCommands.length} expired command statuses`);
+    }
+  }
+
   /**
   /**
    * 获取当前播放状态
    * 获取当前播放状态
    */
    */
@@ -479,4 +694,138 @@ export class PlayerControlService {
     const secs = Math.floor(seconds % 60);
     const secs = Math.floor(seconds % 60);
     return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
     return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
   }
   }
+
+  // ==================== UnifiedPlayerService 状态处理方法 ====================
+
+  /**
+   * 处理UnifiedPlayerService状态变化
+   */
+  private handleUnifiedPlayerStateChange(state: PlayerState): void {
+    try {
+      hilog.info(0x0000, TAG, `📨 Widget received UnifiedPlayerService state change: isPlaying=${state.isPlaying}`);
+      
+      // 转换为WidgetData格式
+      const widgetData: WidgetData = {
+        playState: {
+          isPlaying: state.isPlaying || false,
+          isPaused: state.isPaused || true,
+          isLoading: state.isLoading || false
+        },
+        currentSong: {
+          id: state.currentSong?.id || '',
+          title: state.currentSong?.name || '暂无播放',
+          artist: state.currentSong?.artist || '未知艺术家',
+          album: state.currentSong?.album || '未知专辑',
+          coverImagePath: state.currentSong?.pixelMapPath || '',
+          duration: state.currentSong?.duration ? Number(state.currentSong.duration) : 0
+        },
+        progress: {
+          currentPosition: state.currentPosition || 0,
+          duration: state.duration || 0,
+          percentage: this.calculatePercentage(state.currentPosition || 0, state.duration || 0),
+          currentTimeText: this.formatTime(Math.floor((state.currentPosition || 0) / 1000)),
+          totalTimeText: this.formatTime(Math.floor((state.duration || 0) / 1000))
+        },
+        playlist: {
+          hasNext: state.hasNext || false,
+          hasPrevious: state.hasPrevious || false,
+          currentIndex: state.currentIndex || 0,
+          totalCount: state.totalCount || 0
+        },
+        config: {
+          size: 'medium',
+          theme: 'auto',
+          showProgress: true,
+          showCover: true
+        }
+      };
+      
+      // 更新AvSession监听器数据
+      this.avSessionListener.updateWidgetData(widgetData);
+      
+      hilog.info(0x0000, TAG, `📨 Widget state updated from UnifiedPlayerService: ${widgetData.currentSong.title}`);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `❌ Failed to handle UnifiedPlayerService state change: ${error}`);
+    }
+  }
+
+  /**
+   * 处理UnifiedPlayerService歌曲变化
+   */
+  private handleUnifiedPlayerSongChange(song: VideoItem): void {
+    try {
+      hilog.info(0x0000, TAG, `📨 Widget received UnifiedPlayerService song change: ${song.name}`);
+      
+      // 获取当前缓存数据并更新歌曲信息
+      const currentData = this.avSessionListener.getCurrentWidgetData();
+      
+      const currentSong: SongInfo = {
+        id: song.id || '',
+        title: song.name || '暂无播放',
+        artist: song.artist || '未知艺术家',
+        album: song.album || '未知专辑',
+        coverImagePath: song.pixelMapPath || '',
+        duration: song.duration ? Number(song.duration) : 0
+      };
+
+      const updatedData: WidgetData = {
+        playState: currentData.playState,
+        currentSong: currentSong,
+        progress: currentData.progress,
+        playlist: currentData.playlist,
+        config: currentData.config,
+        castingInfo: currentData.castingInfo
+      };
+      
+      // 更新AvSession监听器数据
+      this.avSessionListener.updateWidgetData(updatedData);
+      
+      hilog.info(0x0000, TAG, `📨 Widget song updated from UnifiedPlayerService: ${song.name} by ${song.artist || '未知艺术家'}`);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `❌ Failed to handle UnifiedPlayerService song change: ${error}`);
+    }
+  }
+
+  /**
+   * 处理UnifiedPlayerService进度变化
+   */
+  private handleUnifiedPlayerProgressChange(progress: PlayProgress): void {
+    try {
+      // 获取当前缓存数据并更新进度信息
+      const currentData = this.avSessionListener.getCurrentWidgetData();
+      
+      const progressInfo: PlayProgress = {
+        currentPosition: progress.currentPosition || 0,
+        duration: progress.duration || 0,
+        percentage: this.calculatePercentage(progress.currentPosition || 0, progress.duration || 0),
+        currentTimeText: this.formatTime(Math.floor((progress.currentPosition || 0) / 1000)),
+        totalTimeText: this.formatTime(Math.floor((progress.duration || 0) / 1000))
+      };
+
+      const updatedData: WidgetData = {
+        playState: currentData.playState,
+        currentSong: currentData.currentSong,
+        progress: progressInfo,
+        playlist: currentData.playlist,
+        config: currentData.config,
+        castingInfo: currentData.castingInfo
+      };
+      
+      // 更新AvSession监听器数据
+      this.avSessionListener.updateWidgetData(updatedData);
+      
+      hilog.info(0x0000, TAG, `📨 Widget progress updated from UnifiedPlayerService: ${updatedData.progress.percentage.toFixed(1)}%`);
+    } catch (error) {
+      hilog.error(0x0000, TAG, `❌ Failed to handle UnifiedPlayerService progress change: ${error}`);
+    }
+  }
+
+  /**
+   * 启动定期清理任务
+   */
+  private startPeriodicCleanup(): void {
+    setInterval(() => {
+      this.cleanupExpiredCommands();
+    }, 30000); // 每30秒清理一次过期命令
+  }
 }
 }

+ 237 - 19
entry/src/main/ets/entryformability/EntryFormAbility.ets

@@ -15,13 +15,21 @@ import { PreferencesUtil } from '../common/utils/PreferencesUtil';
 
 
 const TAG = 'Heanup';
 const TAG = 'Heanup';
 
 
-
+/**
+ * 同步状态信息接口
+ */
+interface SyncStatusInfo {
+  lastUpdate: number;
+  source: string;
+  processId: string;
+}
 
 
 /**
 /**
- * 扩展的卡片数据接口,支持图片传递
+ * 扩展的卡片数据接口,支持图片传递和同步状态
  */
  */
 interface ExtendedWidgetData extends FormattedWidgetData {
 interface ExtendedWidgetData extends FormattedWidgetData {
   formImages?: Record<string, number>;
   formImages?: Record<string, number>;
+  syncStatus?: SyncStatusInfo;
 }
 }
 
 
 /**
 /**
@@ -257,20 +265,33 @@ implements SizeChangeListener {
   /**
   /**
    * 直接更新卡片(无网络图片)
    * 直接更新卡片(无网络图片)
    */
    */
-  private updateWidgetDirectly(formId: string, adaptedData: ExtendedWidgetData, retryCount: number = 0): void {
-    const formData = formBindingData.createFormBindingData(adaptedData);
-    formProvider.updateForm(formId, formData).then(() => {
-      hilog.info(0x0000, TAG, `Heanup widget ${formId} updated successfully: isPlaying=${adaptedData.isPlaying}, title=${adaptedData.songTitle}, hasNext=${adaptedData.hasNext}, hasPrevious=${adaptedData.hasPrevious}`);
-    }).catch(() => {
-      hilog.error(0x0000, TAG, `Heanup widget ${formId} update failed, retry count: ${retryCount}`);
+  private async updateWidgetDirectly(formId: string, adaptedData: ExtendedWidgetData, retryCount: number = 0): Promise<void> {
+    const updateStartTime = Date.now();
+    
+    try {
+      const formData = formBindingData.createFormBindingData(adaptedData);
+      await formProvider.updateForm(formId, formData);
+      
+      const updateDuration = Date.now() - updateStartTime;
+      hilog.info(0x0000, TAG, `Widget ${formId} updated directly in ${updateDuration}ms: isPlaying=${adaptedData.isPlaying}, title=${adaptedData.songTitle}, progress=${adaptedData.progressPercentage?.toFixed(1)}%, hasNext=${adaptedData.hasNext}, hasPrevious=${adaptedData.hasPrevious}`);
+      
+    } catch (error) {
+      const updateDuration = Date.now() - updateStartTime;
+      hilog.error(0x0000, TAG, `Widget ${formId} direct update failed after ${updateDuration}ms: ${error}`);
 
 
       // 重试机制:最多重试2次
       // 重试机制:最多重试2次
       if (retryCount < 2) {
       if (retryCount < 2) {
-        setTimeout(() => {
-          this.updateWidgetDirectly(formId, adaptedData, retryCount + 1);
-        }, 1000 * (retryCount + 1)); // 递增延迟
+        hilog.warn(0x0000, TAG, `Widget ${formId} update failed, retrying... (${retryCount + 1}/3)`);
+        
+        const retryDelay = 1000 * (retryCount + 1);
+        setTimeout(async () => {
+          await this.updateWidgetDirectly(formId, adaptedData, retryCount + 1);
+        }, retryDelay);
+      } else {
+        hilog.error(0x0000, TAG, `Widget ${formId} update failed after ${retryCount + 1} attempts, giving up`);
+        throw new Error(`Widget ${formId} update failed after ${retryCount + 1} attempts: ${error}`);
       }
       }
-    });
+    }
   }
   }
 
 
   /**
   /**
@@ -694,23 +715,192 @@ implements SizeChangeListener {
   }
   }
 
 
   /**
   /**
-   * 更新卡片数据(简化版本
+   * 更新卡片数据(增强版本 - 支持实时同步
    */
    */
-  private async updateWidgetData(formId: string): Promise<void> {
+  private async updateWidgetData(formId: string, forceUpdate: boolean = false): Promise<void> {
+    const updateStartTime = Date.now();
+    
     try {
     try {
+      // 防抖处理,避免过于频繁的更新(除非强制更新)
+      if (!forceUpdate && Date.now() - this.lastUpdateTime < this.updateDebounceDelay) {
+        hilog.info(0x0000, TAG, `Widget ${formId} update skipped due to debounce`);
+        return;
+      }
+      
+      this.lastUpdateTime = Date.now();
+      
+      // 获取当前播放状态(优化:支持缓存)
       const currentState = await this.playerControlService.getCurrentPlayState();
       const currentState = await this.playerControlService.getCurrentPlayState();
+      
+      // 验证状态数据完整性
+      if (!this.validateWidgetData(currentState)) {
+        hilog.warn(0x0000, TAG, `Invalid widget data for ${formId}, using fallback`);
+        // 使用备用数据或重新请求
+        await this.handleInvalidWidgetData(formId);
+        return;
+      }
 
 
       // 获取卡片当前尺寸
       // 获取卡片当前尺寸
       const currentSize = this.globalWidgetManager.getWidgetSize(formId) || WidgetSize.MEDIUM;
       const currentSize = this.globalWidgetManager.getWidgetSize(formId) || WidgetSize.MEDIUM;
 
 
-      // 适配数据到当前尺寸并直接更新
+      // 适配数据到当前尺寸
       const adaptedData = this.layoutManager.adaptDataForSize(currentState, currentSize);
       const adaptedData = this.layoutManager.adaptDataForSize(currentState, currentSize);
-      const formData = formBindingData.createFormBindingData(adaptedData);
-      await formProvider.updateForm(formId, formData);
+      
+      // 添加实时状态标记
+      const syncStatus: SyncStatusInfo = {
+        lastUpdate: Date.now(),
+        source: 'realtime_sync',
+        processId: this.processStartTime.toString()
+      };
+
+      const enhancedData: ExtendedWidgetData = this.copyFormattedWidgetData(adaptedData, {
+        timestamp: Date.now(),
+        syncStatus: syncStatus
+      });
+
+      // 检查是否需要下载网络图片
+      if (this.needsImageDownload(enhancedData)) {
+        await this.handleImageDownloadAndUpdate(formId, enhancedData);
+      } else {
+        // 直接更新卡片
+        await this.updateWidgetDirectly(formId, enhancedData);
+      }
+      
+      const updateDuration = Date.now() - updateStartTime;
+      hilog.info(0x0000, TAG, `Widget ${formId} updated successfully in ${updateDuration}ms: isPlaying=${enhancedData.isPlaying}, progress=${enhancedData.progressPercentage?.toFixed(1)}%`);
+      
+    } catch (error) {
+      const updateDuration = Date.now() - updateStartTime;
+      hilog.error(0x0000, TAG, `Failed to update widget ${formId} after ${updateDuration}ms: ${error}`);
+      
+      // 尝试恢复性更新
+      await this.attemptRecoveryUpdate(formId);
+    }
+  }
+
+  /**
+   * 验证卡片数据完整性
+   */
+  private validateWidgetData(data: WidgetData): boolean {
+    return !!(
+      data &&
+      data.playState &&
+      data.currentSong &&
+      data.progress &&
+      data.playlist &&
+      typeof data.playState.isPlaying === 'boolean' &&
+      typeof data.currentSong.title === 'string' &&
+      typeof data.progress.percentage === 'number'
+    );
+  }
+
+  /**
+   * 处理无效的卡片数据
+   */
+  private async handleInvalidWidgetData(formId: string): Promise<void> {
+    try {
+      hilog.warn(0x0000, TAG, `Handling invalid widget data for ${formId}`);
+      
+      // 强制重新连接播放器服务
+      await this.playerControlService.forceReconnect();
+      
+      // 等待一段时间后重试
+      setTimeout(async () => {
+        await this.updateWidgetData(formId, true);
+      }, 1000);
+      
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to handle invalid widget data: ${error}`);
+    }
+  }
+
+  /**
+   * 检查是否需要下载图片
+   */
+  private needsImageDownload(data: ExtendedWidgetData): boolean {
+    return !!(
+      data.coverImage &&
+      data.coverImage.startsWith('http') &&
+      !this.imageCache.has(data.coverImage)
+    );
+  }
+
+  /**
+   * 处理图片下载并更新卡片
+   */
+  private async handleImageDownloadAndUpdate(formId: string, data: ExtendedWidgetData): Promise<void> {
+    try {
+      if (!data.coverImage) {
+        await this.updateWidgetDirectly(formId, data);
+        return;
+      }
+      
+      // 检查是否正在下载
+      if (this.downloadingImages.has(data.coverImage)) {
+        const fileName = await this.downloadingImages.get(data.coverImage);
+        if (fileName) {
+          const formImages: Record<string, number> = {};
+          formImages[fileName] = 0;
+          const dataWithImage: ExtendedWidgetData = this.copyFormattedWidgetData(data, {
+            imgName: fileName,
+            formImages: formImages
+          });
+          await this.updateWidgetDirectly(formId, dataWithImage);
+        } else {
+          await this.updateWidgetDirectly(formId, data);
+        }
+        return;
+      }
+      
+      // 启动图片下载
+      const downloadPromise = this.downloadNetworkImage(data.coverImage);
+      this.downloadingImages.set(data.coverImage, downloadPromise);
+      
+      const fileName = await downloadPromise;
+      
+      if (fileName) {
+        this.imageCache.set(data.coverImage, fileName);
+        const formImages: Record<string, number> = {};
+        formImages[fileName] = 0;
+        const dataWithImage: ExtendedWidgetData = this.copyFormattedWidgetData(data, {
+          imgName: fileName,
+          formImages: formImages
+        });
+        await this.updateWidgetDirectly(formId, dataWithImage);
+      } else {
+        await this.updateWidgetDirectly(formId, data);
+      }
+      
+    } catch (error) {
+      hilog.error(0x0000, TAG, `Failed to handle image download: ${error}`);
+      await this.updateWidgetDirectly(formId, data);
+    } finally {
+      if (data.coverImage) {
+        this.downloadingImages.delete(data.coverImage);
+      }
+    }
+  }
 
 
-      hilog.info(0x0000, TAG, `Heanup widget ${formId} updated successfully with size: ${currentSize}, isPlaying=${adaptedData.isPlaying}`);
+  /**
+   * 尝试恢复性更新
+   */
+  private async attemptRecoveryUpdate(formId: string): Promise<void> {
+    try {
+      hilog.info(0x0000, TAG, `Attempting recovery update for widget ${formId}`);
+      
+      // 使用默认数据进行恢复性更新
+      const defaultData = this.getDefaultWidgetData();
+      const currentSize = this.globalWidgetManager.getWidgetSize(formId) || WidgetSize.MEDIUM;
+      const formattedData = this.layoutManager.adaptDataForSize(defaultData, currentSize);
+      
+      // 转换为ExtendedWidgetData
+      const adaptedData: ExtendedWidgetData = this.copyFormattedWidgetData(formattedData, {});
+      
+      await this.updateWidgetDirectly(formId, adaptedData, 0);
+      
+      hilog.info(0x0000, TAG, `Recovery update completed for widget ${formId}`);
     } catch (error) {
     } catch (error) {
-      hilog.error(0x0000, TAG, `Failed to update widget ${formId}: ${error}`);
+      hilog.error(0x0000, TAG, `Recovery update failed for widget ${formId}: ${error}`);
     }
     }
   }
   }
 
 
@@ -770,4 +960,32 @@ implements SizeChangeListener {
       hilog.error(0x0000, TAG, `❌ Failed to remove Form ID: ${error}`);
       hilog.error(0x0000, TAG, `❌ Failed to remove Form ID: ${error}`);
     }
     }
   }
   }
+
+  /**
+   * 复制 FormattedWidgetData 对象
+   */
+  private copyFormattedWidgetData(target: FormattedWidgetData, overrides: Partial<ExtendedWidgetData>): ExtendedWidgetData {
+    return {
+      isPlaying: overrides.isPlaying !== undefined ? overrides.isPlaying : target.isPlaying,
+      isPaused: overrides.isPaused !== undefined ? overrides.isPaused : target.isPaused,
+      isLoading: overrides.isLoading !== undefined ? overrides.isLoading : target.isLoading,
+      songTitle: overrides.songTitle !== undefined ? overrides.songTitle : target.songTitle,
+      songArtist: overrides.songArtist !== undefined ? overrides.songArtist : target.songArtist,
+      songAlbum: overrides.songAlbum !== undefined ? overrides.songAlbum : target.songAlbum,
+      coverImage: overrides.coverImage !== undefined ? overrides.coverImage : target.coverImage,
+      currentTime: overrides.currentTime !== undefined ? overrides.currentTime : target.currentTime,
+      totalTime: overrides.totalTime !== undefined ? overrides.totalTime : target.totalTime,
+      progressPercentage: overrides.progressPercentage !== undefined ? overrides.progressPercentage : target.progressPercentage,
+      hasNext: overrides.hasNext !== undefined ? overrides.hasNext : target.hasNext,
+      hasPrevious: overrides.hasPrevious !== undefined ? overrides.hasPrevious : target.hasPrevious,
+      showProgress: overrides.showProgress !== undefined ? overrides.showProgress : target.showProgress,
+      showCover: overrides.showCover !== undefined ? overrides.showCover : target.showCover,
+      widgetSize: overrides.widgetSize !== undefined ? overrides.widgetSize : target.widgetSize,
+      timestamp: overrides.timestamp !== undefined ? overrides.timestamp : target.timestamp,
+      imgName: overrides.imgName !== undefined ? overrides.imgName : target.imgName,
+      formImages: overrides.formImages !== undefined ? overrides.formImages : target.formImages,
+      imageColorHex: overrides.imageColorHex !== undefined ? overrides.imageColorHex : target.imageColorHex,
+      syncStatus: overrides.syncStatus !== undefined ? overrides.syncStatus : undefined
+    };
+  }
 }
 }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 645 - 136
entry/src/main/ets/view/LocalMusic.ets


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio