1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import common from '@ohos.app.ability.common'; 17import Want from '@ohos.app.ability.Want'; 18import Constants from '../../../common/constant'; 19import { HiLog } from '../../../common/HiLog'; 20import { rpc } from '@kit.IPCKit'; 21import OpeningDialogStub from '../stub/OpeningDialogStub'; 22import { ability } from '@kit.AbilityKit'; 23 24const TAG = 'OpeningDialogService'; 25 26export default class OpeningDialogService { 27 private static instance: OpeningDialogService; 28 private _context?: common.UIExtensionContext; 29 private remoteProxy: rpc.IRemoteObject | null = null; 30 private connectionId: number | undefined; 31 private _disconnectTimer: number | null = null; 32 private connectOptions: common.ConnectOptions = { 33 onConnect: async (elementName, remoteProxy) => { 34 HiLog.info(TAG, 'OpeningDialogService onConnect success'); 35 this.remoteProxy = remoteProxy; 36 await this.setRemoteObject(); 37 }, 38 onDisconnect: (elementName) => { 39 this.remoteProxy = null; 40 HiLog.info(TAG, 'OpeningDialogService onDisconnect'); 41 }, 42 onFailed: () => { 43 HiLog.info(TAG, 'OpeningDialogService onFailed'); 44 } 45 }; 46 47 static getInstance(): OpeningDialogService { 48 if (!OpeningDialogService.instance) { 49 OpeningDialogService.instance = new OpeningDialogService(); 50 } 51 return OpeningDialogService.instance; 52 } 53 54 private constructor() { 55 } 56 57 public setContext(value: common.UIExtensionContext) { 58 this._context = value; 59 } 60 61 public getContext(): common.UIExtensionContext | undefined { 62 return this._context; 63 } 64 65 public async terminateOpeningDialog(): Promise<void> { 66 HiLog.info(TAG, 'OpeningDialogService terminateOpeningDialog'); 67 if (!this._context) { 68 HiLog.error(TAG, 'terminateOpeningDialog context is undefined'); 69 return; 70 } 71 try { 72 if (this._disconnectTimer) { 73 clearTimeout(this._disconnectTimer); 74 this._disconnectTimer = null; 75 } 76 await this._context.terminateSelf(); 77 HiLog.info(TAG, 'terminateOpeningDialog success'); 78 } catch (error) { 79 HiLog.wrapError(TAG, error, 'terminateOpeningDialog exception'); 80 } 81 } 82 83 public connectViewAbility(): void { 84 HiLog.info(TAG, 'connectViewAbility start'); 85 if (!this._context) { 86 HiLog.error(TAG, 'connectViewAbility context is undefined'); 87 return; 88 } 89 let want: Want = { 90 bundleName: Constants.DLP_MANAGER_BUNDLE_NAME, 91 abilityName: Constants.DLP_VIEW_SERVICE, 92 }; 93 94 try { 95 this.connectionId = this._context.connectServiceExtensionAbility(want, this.connectOptions); 96 AppStorage.setOrCreate(Constants.CONNECT_VIEW_ABILITY, this.connectionId); 97 } catch (err) { 98 HiLog.wrapError(TAG, err, 'connectServiceExtensionAbility err'); 99 } 100 } 101 102 public async disconnectViewAbility(): Promise<void> { 103 HiLog.info(TAG, 'disconnectViewAbility start'); 104 if (!this._context || !this.connectionId) { 105 HiLog.error(TAG, 'disconnectViewAbility context or connectionId is null'); 106 return; 107 } 108 try { 109 await this._context.disconnectServiceExtensionAbility(this.connectionId); 110 HiLog.info(TAG, 'disconnectViewAbility success'); 111 } catch (error) { 112 HiLog.wrapError(TAG, error, 'Failed to disconnectViewAbility'); 113 } 114 } 115 116 public async disconnectViewAbilityWithTimeout(): Promise<void> { 117 HiLog.info(TAG, 'disconnectViewAbilityWithTimeout start'); 118 119 if (!this._context) { 120 HiLog.error(TAG, 'disconnectViewAbilityWithTimeout context is undefined'); 121 return; 122 } 123 124 if (this._disconnectTimer) { 125 clearTimeout(this._disconnectTimer); 126 this._disconnectTimer = null; 127 } 128 129 return new Promise<void>((resolve) => { 130 this._disconnectTimer = setTimeout(async () => { 131 try { 132 if (this._context && this.connectionId) { 133 await this._context.disconnectServiceExtensionAbility(this.connectionId); 134 HiLog.info(TAG, 'disconnectViewAbilityWithTimeout success'); 135 } else { 136 HiLog.warn(TAG, 'disconnectViewAbilityWithTimeout skipped context null or connectionId null'); 137 } 138 } catch (error) { 139 HiLog.wrapError(TAG, error, 'Failed to disconnectViewAbilityWithTimeout'); 140 } finally { 141 this._disconnectTimer = null; 142 resolve(); 143 } 144 }, Constants.DISCONNECT_VIEW_TIMEOUT); 145 }); 146 } 147 148 private async setRemoteObject(): Promise<void> { 149 HiLog.info(TAG, `setRemoteObject start`); 150 if (!this.remoteProxy) { 151 HiLog.error(TAG, 'setRemoteObject remoteProxy is null'); 152 return; 153 } 154 let option = new rpc.MessageOption(); 155 let data = new rpc.MessageSequence(); 156 let reply = new rpc.MessageSequence(); 157 try { 158 data.writeInterfaceToken(Constants.DLP_MGR_OPENING_DIALOG_TOKEN); 159 let callback: OpeningDialogStub = new OpeningDialogStub('OpeningDialogStub'); 160 data.writeRemoteObject(callback.asObject()); 161 await this.remoteProxy.sendMessageRequest(Constants.COMMAND_SET_REMOTE_OBJECT, data, reply, option); 162 HiLog.info(TAG, 'setRemoteObject sendmsg success.'); 163 } catch (error) { 164 HiLog.wrapError(TAG, error, 'setRemoteObject sendmsg error'); 165 } finally { 166 data.reclaim(); 167 reply.reclaim(); 168 } 169 } 170 171 public async dialogDisappear(requestId: string): Promise<void> { 172 HiLog.info(TAG, `dialogDisappear requestId ${requestId}`); 173 if (!this.remoteProxy) { 174 HiLog.error(TAG, 'dialogDisappear remoteProxy is null'); 175 return; 176 } 177 let option = new rpc.MessageOption(); 178 let data = new rpc.MessageSequence(); 179 let reply = new rpc.MessageSequence(); 180 try { 181 data.writeInterfaceToken(Constants.DLP_MGR_OPENING_DIALOG_TOKEN); 182 data.writeString(requestId); 183 await this.remoteProxy.sendMessageRequest(Constants.COMMAND_DIALOG_DISAPPEAR, data, reply, option); 184 HiLog.info(TAG, 'dialogDisappear sendmsg success.'); 185 } catch (error) { 186 HiLog.wrapError(TAG, error, 'dialogDisappear sendmsg error'); 187 } finally { 188 data.reclaim(); 189 reply.reclaim(); 190 } 191 } 192 193 public async dialogTimeout(requestId: string): Promise<void> { 194 HiLog.info(TAG, `dialogTimeout requestId ${requestId}`); 195 if (!this.remoteProxy) { 196 HiLog.error(TAG, 'dialogTimeout remoteProxy is null'); 197 return; 198 } 199 let option = new rpc.MessageOption(); 200 let data = new rpc.MessageSequence(); 201 let reply = new rpc.MessageSequence(); 202 try { 203 data.writeInterfaceToken(Constants.DLP_MGR_OPENING_DIALOG_TOKEN); 204 data.writeString(requestId); 205 await this.remoteProxy.sendMessageRequest(Constants.COMMAND_DIALOG_TIMEOUT, data, reply, option); 206 HiLog.info(TAG, 'dialogTimeout sendmsg success.'); 207 } catch (error) { 208 HiLog.wrapError(TAG, error, 'dialogTimeout sendmsg error'); 209 } finally { 210 data.reclaim(); 211 reply.reclaim(); 212 } 213 } 214}