| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942 |
- /**
- * 应用主Ability入口文件
- * 功能:
- * 1. 管理应用生命周期
- * 2. 处理窗口创建和尺寸变化
- * 3. 响应外部调用请求
- * 4. 全局状态管理
- */
- import UIAbility from '@ohos.app.ability.UIAbility';
- import hilog from '@ohos.hilog';
- import window from '@ohos.window';
- import { AbilityConstant, Want } from '@kit.AbilityKit';
- import { BusinessError, emitter } from '@kit.BasicServicesKit';
- import { AppUtil, ArrayUtil, GlobalContext, LogUtil, StrUtil } from '@pura/harmony-utils';
- import { rpc } from '@kit.IPCKit';
- import { Utility } from '../common/util/Utility';
- import { WXApi, WXEventHandler } from '../common/util/WXApiWrap';
- import { UnifiedPlayerService } from '../common/service/UnifiedPlayerService';
- import { WidgetRegistrationFix } from '../common/widget/WidgetRegistrationFix';
- import { systemShare } from '@kit.ShareKit';
- import { CustomCrashHandler } from '../common/utils/CustomCrashHandler';
- import { smartMobilityCommon } from '@kit.CarKit';
- import { url } from '@kit.ArkTS';
- import { display } from '@kit.ArkUI';
- /**
- * 播放状态广播数据接口
- */
- interface PlayStateBroadcast {
- isPlaying: boolean;
- isPaused: boolean;
- isLoading: boolean;
- }
- interface SongBroadcast {
- id: string;
- title: string;
- artist: string;
- album: string;
- coverImagePath: string;
- duration: number;
- }
- interface ProgressBroadcast {
- currentPosition: number;
- duration: number;
- percentage: number;
- currentTimeText: string;
- totalTimeText: string;
- }
- interface PlaylistBroadcast {
- hasNext: boolean;
- hasPrevious: boolean;
- currentIndex: number;
- totalCount: number;
- }
- interface BroadcastData {
- playState: PlayStateBroadcast;
- currentSong: SongBroadcast;
- progress: ProgressBroadcast;
- playlist: PlaylistBroadcast;
- }
- interface PublishInfo {
- data: string;
- }
- interface EventDataWrapper {
- data: BroadcastData;
- }
- /**
- * RPC通信返回类型的实现,用于RPC通信数据序列化和反序列化
- */
- class MyParcelable implements rpc.Parcelable {
- num: number;
- str: string;
- constructor(num: number, str: string) {
- this.num = num;
- this.str = str;
- }
- marshalling(messageSequence: rpc.MessageSequence): boolean {
- messageSequence.writeInt(this.num);
- messageSequence.writeString(this.str);
- return true;
- }
- unmarshalling(messageSequence: rpc.MessageSequence): boolean {
- this.num = messageSequence.readInt();
- this.str = messageSequence.readString();
- return true;
- }
- }
- /**
- * 主Ability类,继承自UIAbility
- * 负责:
- * - 应用初始化
- * - 窗口管理
- * - 事件分发
- */
- export default class EntryAbility extends UIAbility {
- // UI上下文对象,用于获取窗口信息
- private uiContext?: UIContext;
- // private awareness: smartMobilityCommon.SmartMobilityAwareness = smartMobilityCommon.getSmartMobilityAwareness();
- private awareness: smartMobilityCommon.SmartMobilityAwareness|undefined = canIUse("SystemCapability.SmartOptimizer.SmartMobility")?smartMobilityCommon.getSmartMobilityAwareness():undefined;
- /**
- * 窗口尺寸变化回调函数
- * @param windowSize 新的窗口尺寸对象
- * 功能:
- * 1. 获取最新的窗口断点尺寸
- * 2. 更新AppStorage中的尺寸状态
- * 3. 记录尺寸变化日志
- */
- private onWindowSizeChange: (windowSize: window.Size) => void = async (windowSize: window.Size) => {
- // 获取宽度断点并更新全局状态
- let widthBp = this.uiContext!.getWindowWidthBreakpoint();
- AppStorage.setOrCreate('currentWidthBreakpoint', widthBp);
- // 获取高度断点并更新全局状态
- let heightBp = this.uiContext!.getWindowHeightBreakpoint();
- AppStorage.setOrCreate('currentHeightBreakpoint', heightBp);
- // 记录尺寸变化日志
- // LogUtil.info('pura onWindowSizeChange currentHeightBreakpoint= '+heightBp);
- // LogUtil.info( 'pura onWindowSizeChange currentWidthBreakpoint= '+widthBp);
- AppStorage.setOrCreate('windowWidth', windowSize.width);
- AppStorage.setOrCreate('windowHeight', windowSize.height);
- if(windowSize.width > windowSize.height){
- AppStorage.setOrCreate('isLandscape', true);
- }else{
- AppStorage.setOrCreate('isLandscape', false);
- }
- // LogUtil.info('hicar onWindowSizeChange width= '+windowSize.width);
- // LogUtil.info( 'hicar onWindowSizeChange height= '+windowSize.height);
- };
- onAvoidAreaChange = (data: window.AvoidAreaOptions) => {
- if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {
- let topRectHeight = px2vp(data.area.topRect.height);
- AppStorage.setOrCreate('topRectHeight', topRectHeight);
- } else if (data.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) {
- let bottomRectHeight = px2vp(data.area.bottomRect.height);
- AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
- }
- }
- async onCreate(want:Want, launchParam:AbilityConstant.LaunchParam) {
- AppUtil.init(this.context);
- AppStorage.setOrCreate('context', this.context);
- hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onCreate');
- // 注册卡片call事件监听器
- this.registerWidgetCallListeners();
- // 异步初始化统一播放器服务,避免阻塞生命周期
- this.initializePlayerServiceAsync();
- // 执行卡片注册修复(异步执行,不阻塞启动)
- this.fixWidgetRegistrationAsync();
- // 异步处理Want参数,避免阻塞生命周期
- this.handleWantAsync(want);
- this.handleWeChatCallIfNeed(want)
- this.getHiCarStatus()
- }
- async onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
- hilog.info(0x0000, 'Heanup2', `onNewWant, want=${JSON.stringify(want)}`);
- super.onNewWant(want, launchParam);
- // 异步处理Want参数,避免阻塞生命周期
- this.handleWantAsync(want);
- this.handleWeChatCallIfNeed(want)
- }
- private handleWeChatCallIfNeed(want: Want) {
- WXApi.handleWant(want, WXEventHandler)
- }
- //处理其他app点击其他应用打开播放器播放视频或者音频
- loadDoWant(want: Want){
- // console.info('onecold KnockController 碰一碰 want ='+JSON.stringify(want));
- let uri = want.uri;
- if (uri == null || uri == undefined|| StrUtil.isEmpty(uri)) {
- console.info('uri is invalid');
- return;
- }
- hilog.info(0x0000, 'Heanup2', `onCreate or onNewWant, uri=${uri}`);
- this.doSendEmit(uri)
- }
- //广播通知打开播放器播放视频或者音频
- doSendEmit(uri:string){
- setTimeout(async ()=>{
- let eventData: emitter.EventData = {
- data: {
- message: uri
- }
- };
- if(Utility.isMeidaByExtension(uri)){
- emitter.emit({ eventId: 2 }, eventData); // 发送音频打开广播事件
- }else{
- emitter.emit({ eventId: 1 }, eventData); // 发送视频打开广播事件
- }
- },300)
- }
- // 华为分享拉起接收 处理分享数据
- // 1. 改造 handleParam 为异步函数,让其返回 Promise
- async handleParam(want: Want) {
- try {
- // 通过 await 等待异步操作完成
- const data = await systemShare.getSharedData(want);
- const records = data.getRecords();
- let uri = want.uri;
- for (const record of records) {
- if (record.uri) {
- uri = record.uri;
- this.doSendEmit(uri)
- break;
- }
- }
- } catch (error) {
- const businessError = error as BusinessError;
- console.error(`Failed: Code ${businessError.code}, ${businessError.message}`);
- }
- }
- onDestroy() {
- hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onDestroy');
- // 关键修复:在APP销毁时保存播放器状态
- try {
- const unifiedPlayerService = UnifiedPlayerService.getInstance();
- if (unifiedPlayerService) {
- // 确保在APP被杀掉时保存当前播放状态
- unifiedPlayerService.release();
- hilog.info(0x0000, 'Heanup2', 'UnifiedPlayerService released and state saved on app destroy');
- }
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `Failed to release UnifiedPlayerService: ${error}`);
- }
- // 注销卡片call事件监听器
- this.unregisterWidgetCallListeners();
- hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
- if(this.awareness){
- let types: smartMobilityCommon.SmartMobilityType[] = [smartMobilityCommon.SmartMobilityType.CAR_HOP];
- // 出行连接状态回调函数
- const callBack = (info: smartMobilityCommon.SmartMobilityInfo) => {
- hilog.info(0x0000, 'Received smart mobility info: ', JSON.stringify(info));
- };
- // 解注册智慧出行连接状态的监听 示例2
- this.awareness.off('smartMobilityStatus', types, callBack);
- }
- }
- onWindowStageCreate(windowStage: window.WindowStage) {
- // Main window is created, set main page for this ability
- hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onWindowStageCreate');
- // 使用自定义崩溃处理器替代 SpiderMan.init()
- // SpiderMan.init();
- CustomCrashHandler.init();
- AppUtil.init(this.context);
- //1.获取应用主窗口。
- let windowClass: window.Window | null = null;
- windowStage.getMainWindow((err: BusinessError, data) => {
- windowClass = data;
- // LogUtil.info( 'getMainWindow = ');
- GlobalContext.getContext().setObject('windowClass', data); // 使用GlobalContext替代globalThis
- let curDisplay = display.getDisplayByIdSync(windowClass.getWindowProperties().displayId);
- console.info('twocold curDisplay = '+curDisplay.name);
- if(curDisplay.name =='HiCar'||curDisplay.name =='SuperLauncher'){
- AppStorage.setOrCreate('curDisplayIsHiCar', true);
- }else{
- AppStorage.setOrCreate('curDisplayIsHiCar', false);
- }
- windowClass.setWindowLayoutFullScreen(true).then(() => {
- console.info('Succeeded in setting the window layout to full-screen mode.');
- }).catch((e: BusinessError) => {
- console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(e));
- })
- // let avoidArea = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)
- // let topRectHeight = px2vp(avoidArea.topRect.height);
- // AppStorage.setOrCreate('topRectHeight', topRectHeight);
- let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; // 以导航条避让为例
- let avoidArea = windowClass.getWindowAvoidArea(type);
- let bottomRectHeight = px2vp(avoidArea.bottomRect.height); // 获取到导航条区域的高度
- AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
- type = window.AvoidAreaType.TYPE_SYSTEM; // 以状态栏避让为例
- avoidArea = windowClass.getWindowAvoidArea(type);
- let topRectHeight = px2vp(avoidArea.topRect.height) // 获取状态栏区域高度
- AppStorage.setOrCreate('topRectHeight', topRectHeight);
- LogUtil.info('onecold topRectHeight = '+topRectHeight);
- windowClass.on('avoidAreaChange', this.onAvoidAreaChange)
- })
- AppStorage.setOrCreate('windowStage',windowStage);
- hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onWindowStageCreate');
- windowStage.loadContent('pages/SplashIndex', (err, data) => {
- if (err.code) {
- hilog.error(0x0000, 'Heanup2', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
- return;
- }
- //一多断点开发
- windowStage.getMainWindow().then((data: window.Window) => {
- this.uiContext = data.getUIContext();
- let widthBp = this.uiContext.getWindowWidthBreakpoint();
- let heightBp = this.uiContext.getWindowHeightBreakpoint();
- AppStorage.setOrCreate('currentWidthBreakpoint', widthBp);
- AppStorage.setOrCreate('currentHeightBreakpoint', heightBp);
- LogUtil.info( 'getMainWindow currentHeightBreakpoint= '+heightBp);
- LogUtil.info( 'getMainWindow currentWidthBreakpoint= '+widthBp);
- data.on('windowSizeChange', this.onWindowSizeChange);
- AppStorage.setOrCreate('windowWidth', data.getWindowProperties().windowRect.width);
- AppStorage.setOrCreate('windowHeight', data.getWindowProperties().windowRect.height);
- if(data.getWindowProperties().windowRect.width > data.getWindowProperties().windowRect.height){
- AppStorage.setOrCreate('isLandscape', true);
- }else{
- AppStorage.setOrCreate('isLandscape', false);
- }
- // LogUtil.info('hicar getMainWindow width= '+data.getWindowProperties().windowRect.width);
- // LogUtil.info( 'hicar getMainWindow height= '+data.getWindowProperties().windowRect.height);
- }).catch((err: BusinessError) => {
- console.error(`Failed to obtain the main window. Cause code: ${err.code}, message: ${err.message}`);
- });
- hilog.info(0x0000, 'Heanup2', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
- });
- }
- onWindowStageDestroy() {
- // Main window is destroyed, release UI related resources
- hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onWindowStageDestroy');
- }
- onForeground() {
- // Ability has brought to foreground
- hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onForeground start');
- // 异步处理前台逻辑,避免阻塞生命周期
- setTimeout(() => {
- this.handleForegroundAsync();
- }, 10);
- hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onForeground end');
- }
- onBackground() {
- // Ability has back to background
- hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onBackground start');
- // 异步处理后台逻辑,避免阻塞生命周期
- setTimeout(() => {
- this.handleBackgroundAsync();
- }, 10);
- hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onBackground end');
- }
- getHiCarStatus(){
- if(this.awareness){
- // this.awareness = smartMobilityCommon.getSmartMobilityAwareness();
- // 业务类型
- let types: smartMobilityCommon.SmartMobilityType[] = [smartMobilityCommon.SmartMobilityType.HICAR];
- // 获取出行业务连接状态
- let info = this.awareness.getSmartMobilityStatus(types[0]);
- hilog.info(0x0000, 'getHiCarStatus info: ', JSON.stringify(info));
- if(info&&info.status==1){
- AppStorage.setOrCreate('isHiCarStatus', true);
- }else{
- AppStorage.setOrCreate('isHiCarStatus', false);
- }
- // 出行连接状态回调函数
- const callBack = (info: smartMobilityCommon.SmartMobilityInfo) => {
- hilog.info(0x0000, 'getHiCarStatus Received smart mobility info: ', JSON.stringify(info));
- if(info&&info.status==1){
- AppStorage.setOrCreate('isHiCarStatus', true);
- }else{
- AppStorage.setOrCreate('isHiCarStatus', false);
- }
- this.sendChangeEvent()
- };
- // 注册智慧出行连接状态的监听
- this.awareness.on('smartMobilityStatus', types, callBack);
- }else{
- AppStorage.setOrCreate('isHiCarStatus', false);
- }
- }
- //发送广播通知更新UI
- sendChangeEvent() {
- const eventData: emitter.EventData = {};
- emitter.emit({ eventId: 333 }, eventData); // 发送广播通知更新doSwipBack
- }
- /**
- * 注册卡片call事件监听器(增强版本:服务就绪检查)
- */
- private registerWidgetCallListeners(): void {
- try {
- // 监听播放/暂停事件
- this.callee.on('playPause', (data: rpc.MessageSequence) => {
- try {
- const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
- hilog.info(0x0000, 'Heanup2', `🎵 Widget call: playPause received`);
- // 异步发送播放/暂停事件到主应用(包含服务就绪检查)
- this.sendWidgetControlEvent('PLAY_PAUSE', params).catch((error: Error) => {
- hilog.error(0x0000, 'Heanup2', `❌ playPause async error: ${error}`);
- });
- return new MyParcelable(1, 'playPause_success');
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ playPause handler error: ${error}`);
- return new MyParcelable(-1, 'playPause_error');
- }
- });
- // 监听下一首事件
- this.callee.on('nextSong', (data: rpc.MessageSequence) => {
- try {
- hilog.info(0x0000, 'Heanup2', `🎵 Widget call: nextSong received`);
- const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
- hilog.info(0x0000, 'Heanup2', `Widget nextSong params: ${JSON.stringify(params)}`);
- // 异步发送下一首事件到主应用(包含服务就绪检查)
- this.sendWidgetControlEvent('NEXT_SONG', params).catch((error: Error) => {
- hilog.error(0x0000, 'Heanup2', `❌ nextSong async error: ${error}`);
- });
- return new MyParcelable(2, 'nextSong_success');
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ nextSong handler error: ${error}`);
- return new MyParcelable(-2, 'nextSong_error');
- }
- });
- // 监听上一首事件
- this.callee.on('prevSong', (data: rpc.MessageSequence) => {
- try {
- hilog.info(0x0000, 'Heanup2', `🎵 Widget call: prevSong received`);
- const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
- hilog.info(0x0000, 'Heanup2', `Widget prevSong params: ${JSON.stringify(params)}`);
- // 异步发送上一首事件到主应用(包含服务就绪检查)
- this.sendWidgetControlEvent('PREV_SONG', params).catch((error: Error) => {
- hilog.error(0x0000, 'Heanup2', `❌ prevSong async error: ${error}`);
- });
- return new MyParcelable(3, 'prevSong_success');
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ prevSong handler error: ${error}`);
- return new MyParcelable(-3, 'prevSong_error');
- }
- });
- // 监听打开应用事件
- this.callee.on('openApp', (data: rpc.MessageSequence) => {
- try {
- hilog.info(0x0000, 'Heanup2', `🎵 Widget call: openApp received`);
- const params: Record<string, Object> = JSON.parse(data.readString()) as Record<string, Object>;
- hilog.info(0x0000, 'Heanup2', `Widget openApp params: ${JSON.stringify(params)}`);
- // 异步发送打开应用事件到主应用
- this.sendWidgetControlEvent('OPEN_APP', params).catch((error: Error) => {
- hilog.error(0x0000, 'Heanup2', `❌ openApp async error: ${error}`);
- });
- return new MyParcelable(4, 'openApp_success');
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ openApp handler error: ${error}`);
- return new MyParcelable(-4, 'openApp_error');
- }
- });
- hilog.info(0x0000, 'Heanup2', '🎵 Widget call listeners registered successfully (Enhanced)');
- } catch (err) {
- hilog.error(0x0000, 'Heanup2', `❌ Failed to register widget call listeners: ${JSON.stringify(err as BusinessError)}`);
- }
- }
- /**
- * 注销卡片call事件监听器
- */
- private unregisterWidgetCallListeners(): void {
- try {
- this.callee.off('playPause');
- this.callee.off('nextSong');
- this.callee.off('prevSong');
- // this.callee.off('openApp');
- // this.callee.off('playByAction');
- // this.callee.off('collectAction');
- // this.callee.off('requestUpdatePlayCard');
- hilog.info(0x0000, 'Heanup2', 'Widget call listeners unregistered successfully');
- } catch (err) {
- hilog.error(0x0000, 'Heanup2', `Failed to unregister widget call listeners: ${JSON.stringify(err as BusinessError)}`);
- }
- }
- /**
- * 发送卡片控制事件到主应用(增强版本,确保服务已初始化)
- */
- private async sendWidgetControlEvent(command: string, params: Record<string, Object>): Promise<void> {
- try {
- hilog.info(0x0000, 'Heanup2', `🎵 收到桌面卡片指令: ${command}`);
- // 获取UnifiedPlayerService实例
- const unifiedService = UnifiedPlayerService.getInstance();
- // 确保服务已经初始化
- if (!unifiedService) {
- hilog.error(0x0000, 'Heanup2', '❌ UnifiedPlayerService 未初始化');
- return;
- }
- // 获取详细的服务就绪状态信息
- const readinessInfo = unifiedService.getServiceReadinessInfo();
- hilog.info(0x0000, 'Heanup2', `🔍 Service readiness: ${JSON.stringify(readinessInfo.details)}`);
- // 智能等待服务完全就绪(多级检查)
- hilog.info(0x0000, 'Heanup2', '🔄 检查服务就绪状态...');
- let ready = await this.waitForServiceReady(unifiedService);
- if (ready) {
- hilog.info(0x0000, 'Heanup2', '✅ UnifiedPlayerService 已就绪');
- } else {
- hilog.warn(0x0000, 'Heanup2', '⚠️ UnifiedPlayerService 未完全就绪,尝试执行基础操作');
- // 检查是否至少可以进行基础操作
- if (!unifiedService.isAllServicesReady()) {
- const finalReadinessInfo = unifiedService.getServiceReadinessInfo();
- hilog.error(0x0000, 'Heanup2', `❌ 基础服务未就绪,无法执行操作: ${JSON.stringify(finalReadinessInfo.details)}`);
- return;
- }
- }
- // 检查初始化状态
- const currentState = unifiedService.getCurrentState();
- const playlist = unifiedService.getPlaylist();
- hilog.info(0x0000, 'Heanup2', `🎵 Widget command - Service state: isPlaying=${currentState.isPlaying}, currentIndex=${currentState.currentIndex}, playlistSize=${playlist.length}`);
- // 对于播放控制操作,检查是否有可播放内容
- if ((command === 'PLAY_PAUSE' || command === 'NEXT_SONG' || command === 'PREV_SONG') && playlist.length === 0) {
- hilog.warn(0x0000, 'Heanup2', '⚠️ 播放列表为空,尝试强制数据恢复');
- // 强制触发数据恢复
- await this.forceDataRestoration(unifiedService);
- // 重新检查播放列表
- const updatedPlaylist = unifiedService.getPlaylist();
- if (updatedPlaylist.length === 0) {
- hilog.warn(0x0000, 'Heanup2', '⚠️ 强制数据恢复后播放列表仍为空,无法执行播放控制操作');
- return;
- }
- hilog.info(0x0000, 'Heanup2', `✅ 强制数据恢复完成,播放列表大小: ${updatedPlaylist.length}`);
- }
- // 根据命令执行相应的播放控制
- switch (command) {
- case 'PLAY_PAUSE':
- // 获取卡片传递的当前显示状态
- const widgetIsPlaying = params['widgetIsPlaying'] as boolean;
- const hasWidgetState = widgetIsPlaying !== undefined;
- // 获取服务内部状态
- const latestState = unifiedService.getCurrentState();
- hilog.info(0x0000, 'Heanup2', `🎵 卡片显示状态: isPlaying=${widgetIsPlaying} (有效: ${hasWidgetState})`);
- hilog.info(0x0000, 'Heanup2', `🎵 服务内部状态: isPlaying=${latestState.isPlaying}`);
- if (hasWidgetState) {
- // 新逻辑:根据卡片显示的状态来决定操作
- // - 如果卡片显示播放按钮(widgetIsPlaying=false),则执行播放操作
- // - 如果卡片显示暂停按钮(widgetIsPlaying=true),则执行暂停操作
- if (widgetIsPlaying) {
- // 卡片显示暂停按钮,用户点击要暂停
- await unifiedService.pause();
- hilog.info(0x0000, 'Heanup2', '✅ 卡片操作:暂停播放');
- } else {
- // 卡片显示播放按钮,用户点击要播放
- hilog.info(0x0000, 'Heanup2', '🔄 卡片操作:开始播放');
- await unifiedService.startPlayOrResumePlay();
- hilog.info(0x0000, 'Heanup2', '✅ 卡片操作:开始播放');
- }
- } else {
- // 向后兼容:使用原来的逻辑(根据服务内部状态)
- hilog.info(0x0000, 'Heanup2', '⚠️ 使用向后兼容模式(基于服务状态)');
- if (latestState.isPlaying) {
- await unifiedService.pause();
- hilog.info(0x0000, 'Heanup2', '✅ 兼容模式:暂停播放');
- } else {
- hilog.info(0x0000, 'Heanup2', '🔄 兼容模式:开始播放');
- await unifiedService.startPlayOrResumePlay();
- hilog.info(0x0000, 'Heanup2', '✅ 兼容模式:开始播放');
- }
- }
- break;
- case 'NEXT_SONG':
- await unifiedService.playNext();
- hilog.info(0x0000, 'Heanup2', '✅ Widget command: Next song');
- break;
- case 'PREV_SONG':
- await unifiedService.playPrevious();
- hilog.info(0x0000, 'Heanup2', '✅ Widget command: Previous song');
- break;
- case 'OPEN_APP':
- hilog.info(0x0000, 'Heanup2', '✅ Widget command: Open app (handled by UI)');
- break;
- default:
- hilog.warn(0x0000, 'Heanup2', `❓ Unknown widget command: ${command}`);
- break;
- }
- // 操作完成后,广播最新状态给主应用UI和桌面卡片
- setTimeout(() => {
- this.broadcastCurrentPlayerState();
- hilog.info(0x0000, 'Heanup2', '📡 桌面卡片操作后广播状态更新');
- // 同时触发UnifiedPlayerService的状态广播,确保所有监听器都能收到更新
- try {
- unifiedService.broadcastCurrentState();
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ 触发服务状态广播失败: ${error}`);
- }
- }, 100); // 短延迟,确保操作完全完成
- hilog.info(0x0000, 'Heanup2', `✅ Widget control command processed: ${command}`);
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ Failed to process widget control command: ${error}`);
- }
- }
- /**
- * 强制数据恢复(用于桌面卡片冷启动场景)
- */
- private async forceDataRestoration(unifiedService: UnifiedPlayerService): Promise<void> {
- try {
- hilog.info(0x0000, 'Heanup2', '🔄 开始强制数据恢复...');
- // 检查是否已经有数据恢复完成
- if (unifiedService.isDataRestorationCompleted()) {
- hilog.info(0x0000, 'Heanup2', '✅ 数据已恢复,无需强制恢复');
- return;
- }
- // 调用UnifiedPlayerService的强制数据恢复方法
- const restored = await unifiedService.forceDataRestoration();
- if (restored) {
- hilog.info(0x0000, 'Heanup2', '✅ 强制数据恢复成功');
- } else {
- hilog.warn(0x0000, 'Heanup2', '⚠️ 强制数据恢复失败,尝试等待');
- // 如果强制恢复失败,再等待一段时间
- await unifiedService.waitForDataRestoration(2000);
- }
- // 额外等待一小段时间,确保播放列表数据完全加载
- await new Promise<void>(resolve => setTimeout(resolve, 300));
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ 强制数据恢复失败: ${error}`);
- }
- }
- /**
- * 智能等待服务就绪(增强版本)
- */
- private async waitForServiceReady(unifiedService: UnifiedPlayerService): Promise<boolean> {
- try {
- hilog.info(0x0000, 'Heanup2', '🔄 开始等待UnifiedPlayerService完全就绪');
- // 检查是否是刚启动的应用(数据还没恢复)
- const currentPlaylist = unifiedService.getPlaylist();
- const isJustStarted = currentPlaylist.length === 0;
- const isDataRestored = unifiedService.isDataRestorationCompleted();
- if (isJustStarted || !isDataRestored) {
- hilog.info(0x0000, 'Heanup2', `🔄 检测到冷启动状态 - 播放列表为空: ${isJustStarted}, 数据未恢复: ${!isDataRestored}`);
- // 对于冷启动,给予更长的等待时间,并强制检查数据恢复
- const isReady = await unifiedService.waitForAllServicesReady(10000, true);
- if (isReady) {
- hilog.info(0x0000, 'Heanup2', '✅ UnifiedPlayerService完全就绪(冷启动)');
- return true;
- }
- // 如果仍未就绪,尝试强制触发数据恢复
- hilog.warn(0x0000, 'Heanup2', '⚠️ 冷启动等待超时,尝试强制数据恢复');
- await this.forceDataRestoration(unifiedService);
- // 再次检查服务状态
- const retryReady = await unifiedService.waitForAllServicesReady(3000, false);
- if (retryReady) {
- hilog.info(0x0000, 'Heanup2', '✅ 强制恢复后服务就绪');
- return true;
- }
- } else {
- // 对于已经有数据的情况,使用正常的等待时间
- const isReady = await unifiedService.waitForAllServicesReady(5000, true);
- if (isReady) {
- hilog.info(0x0000, 'Heanup2', '✅ UnifiedPlayerService完全就绪');
- return true;
- }
- }
- // 如果主要服务就绪但数据未恢复,再做一次宽松检查
- hilog.info(0x0000, 'Heanup2', '⚠️ 主要检查超时,进行备用检查');
- const basicReady = await unifiedService.waitForAllServicesReady(2000, false);
- if (basicReady) {
- // 检查是否至少有播放数据
- const currentState = unifiedService.getCurrentState();
- const playlist = unifiedService.getPlaylist();
- if (playlist.length > 0 || currentState.currentIndex >= 0) {
- hilog.info(0x0000, 'Heanup2', `✅ 基础服务就绪,播放列表: ${playlist.length} 首歌曲`);
- return true;
- }
- }
- hilog.warn(0x0000, 'Heanup2', '⚠️ Service readiness check timeout, proceeding with limited functionality');
- return false;
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ Error waiting for service ready: ${error}`);
- return false;
- }
- }
- /**
- * 异步初始化播放器服务,避免阻塞生命周期
- */
- private initializePlayerServiceAsync(): void {
- // 使用 setTimeout 将初始化操作移到下一个事件循环
- setTimeout(async () => {
- try {
- hilog.info(0x0000, 'Heanup2', '🔄 开始异步初始化 UnifiedPlayerService');
- await UnifiedPlayerService.getInstance().initialize(this.context);
- hilog.info(0x0000, 'Heanup2', '✅ UnifiedPlayerService 异步初始化成功');
- // 对于冷启动场景,立即尝试数据恢复
- const unifiedService = UnifiedPlayerService.getInstance();
- if (!unifiedService.isDataRestorationCompleted()) {
- hilog.info(0x0000, 'Heanup2', '🔄 冷启动检测到数据未恢复,开始预恢复');
- await unifiedService.forceDataRestoration();
- }
- // 延迟广播当前状态,确保卡片能接收到初始状态
- setTimeout(() => {
- this.broadcastCurrentPlayerState();
- }, 500); // 缩短延迟,让卡片更快收到状态
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ UnifiedPlayerService 异步初始化失败: ${error}`);
- }
- }, 50); // 缩短延迟,让初始化更快开始
- }
- /**
- * 异步处理前台逻辑
- */
- private handleForegroundAsync(): void {
- try {
- hilog.info(0x0000, 'Heanup2', '🔄 处理前台逻辑');
- // 确保播放器服务可用
- const playerService = UnifiedPlayerService.getInstance();
- if (playerService) {
- // 广播当前状态给卡片
- this.broadcastCurrentPlayerState();
- }
- hilog.info(0x0000, 'Heanup2', '✅ 前台逻辑处理完成');
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ 前台逻辑处理失败: ${error}`);
- }
- }
- /**
- * 异步处理后台逻辑
- */
- private handleBackgroundAsync(): void {
- try {
- hilog.info(0x0000, 'Heanup2', '🔄 处理后台逻辑');
- // 后台时可以执行一些清理或保存操作
- // 但要确保不会阻塞生命周期
- hilog.info(0x0000, 'Heanup2', '✅ 后台逻辑处理完成');
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ 后台逻辑处理失败: ${error}`);
- }
- }
- /**
- * 异步处理Want参数,避免阻塞生命周期
- */
- private handleWantAsync(want: Want): void {
- setTimeout(async () => {
- try {
- this.loadDoWant(want);
- await this.handleParam(want);
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ 处理Want参数失败: ${error}`);
- }
- }, 200);
- }
- /**
- * 异步执行卡片注册修复
- */
- private async fixWidgetRegistrationAsync(): Promise<void> {
- // 延迟3秒执行,确保应用完全启动
- setTimeout(async () => {
- try {
- const widgetFix = WidgetRegistrationFix.getInstance();
- await widgetFix.fixWidgetRegistration(this.context);
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ 卡片注册修复失败: ${error}`);
- }
- }, 3000);
- }
- /**
- * 广播当前播放器状态给卡片
- */
- private broadcastCurrentPlayerState(): void {
- try {
- const unifiedService = UnifiedPlayerService.getInstance();
- const currentState = unifiedService.getCurrentState();
- const currentSong = unifiedService.getCurrentSong();
- const playlist = unifiedService.getPlaylist();
- const currentIndex = unifiedService.getCurrentIndex();
- if (currentSong) {
- // 构建播放器状态广播数据
- const broadcastData: BroadcastData = {
- playState: {
- isPlaying: currentState.isPlaying || false,
- isPaused: currentState.isPaused || true,
- isLoading: currentState.isLoading || false
- } as PlayStateBroadcast,
- currentSong: {
- id: currentSong.id || '',
- title: currentSong.name || '暂无播放',
- artist: currentSong.artist || '未知艺术家',
- album: currentSong.album || '未知专辑',
- coverImagePath: currentSong.pixelMapPath || '',
- duration: currentSong.duration ? Number(currentSong.duration) : 0
- } as SongBroadcast,
- progress: {
- currentPosition: currentState.currentPosition || 0,
- duration: currentState.duration || 0,
- percentage: this.calculatePercentage(currentState.currentPosition || 0, currentState.duration || 0),
- currentTimeText: this.formatTime(Math.floor((currentState.currentPosition || 0) / 1000)),
- totalTimeText: this.formatTime(Math.floor((currentState.duration || 0) / 1000))
- } as ProgressBroadcast,
- playlist: {
- hasNext: currentState.hasNext || false,
- hasPrevious: currentState.hasPrevious || false,
- currentIndex: currentIndex,
- totalCount: playlist.length
- } as PlaylistBroadcast
- };
- // 发送状态变化事件
- const publishInfo: PublishInfo = {
- data: JSON.stringify(broadcastData)
- };
- // 使用emitter发送事件
- const eventData: EventDataWrapper = {
- data: broadcastData
- };
- emitter.emit({ eventId: 1001 }, eventData); // 使用特定的事件ID
- hilog.info(0x0000, 'Heanup2', `📡 Broadcasted current player state: ${currentSong.name}, isPlaying=${currentState.isPlaying}`);
- } else {
- hilog.info(0x0000, 'Heanup2', '📡 No current song to broadcast');
- }
- } catch (error) {
- hilog.error(0x0000, 'Heanup2', `❌ Failed to broadcast current player state: ${error}`);
- }
- }
- /**
- * 计算播放进度百分比
- */
- private calculatePercentage(current: number, total: number): number {
- if (total <= 0) return 0;
- return Math.min(100, Math.max(0, (current / total) * 100));
- }
- /**
- * 格式化时间显示
- */
- private formatTime(seconds: number): string {
- const mins = Math.floor(seconds / 60);
- const secs = Math.floor(seconds % 60);
- return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
- }
- }
|