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 */ 15import hilog from '@ohos.hilog'; 16import abilityManager from '@ohos.app.ability.abilityManager'; 17import common from '@ohos.app.ability.common'; 18import { ErrorCallback, Callback } from '@ohos.base'; 19import AtomicServiceOptions from '@ohos.app.ability.AtomicServiceOptions'; 20import commonEventManager from '@ohos.commonEventManager'; 21import Base from '@ohos.base'; 22 23const EMBEDDED_HALF_MODE = 2; 24@Component 25export struct HalfScreenLaunchComponent { 26 @BuilderParam content: Callback<void> = this.doNothingBuilder; 27 context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; 28 appId: string = ''; 29 options?: AtomicServiceOptions; 30 @State private isShow: boolean = false; 31 private subscriber: commonEventManager.CommonEventSubscriber | null = null; 32 onError?: ErrorCallback; 33 onTerminated?: Callback<TerminationInfo>; 34 35 aboutToAppear(): void { 36 let subscribeInfo: commonEventManager.CommonEventSubscribeInfo = { 37 events: [commonEventManager.Support.COMMON_EVENT_DISTRIBUTED_ACCOUNT_LOGOUT], 38 }; 39 40 commonEventManager.createSubscriber(subscribeInfo, 41 (err: Base.BusinessError, data: commonEventManager.CommonEventSubscriber) => { 42 if (err) { 43 hilog.error(0x3900, 'HalfScreenLaunchComponent', 44 'Failed to create subscriber, err: %{public}s.', JSON.stringify(err)); 45 return; 46 } 47 48 if (data === null || data === undefined) { 49 hilog.error(0x3900, 'HalfScreenLaunchComponent', 'Failed to create subscriber, data is null.'); 50 return; 51 } 52 53 this.subscriber = data; 54 commonEventManager.subscribe(this.subscriber, 55 (err: Base.BusinessError, data: commonEventManager.CommonEventData) => { 56 if (err) { 57 hilog.error(0x3900, 'HalfScreenLaunchComponent', 58 'Failed to subscribe common event, err: %{public}s.', JSON.stringify(err)); 59 return; 60 } 61 this.isShow = false; 62 }) 63 }) 64 } 65 66 aboutToDisappear(): void { 67 if (this.subscriber !== null) { 68 commonEventManager.unsubscribe(this.subscriber, (err) => { 69 if (err) { 70 hilog.error(0x3900, 'HalfScreenLaunchComponent', 71 'UnsubscribeCallBack, err: %{public}s.', JSON.stringify(err)); 72 } else { 73 hilog.info(0x3900, 'HalfScreenLaunchComponent', 'Unsubscribe.'); 74 this.subscriber = null; 75 } 76 }) 77 } 78 } 79 80 @Builder 81 doNothingBuilder() { 82 }; 83 84 resetOptions(): void { 85 if (this.options?.parameters) { 86 this.options.parameters['ohos.extra.param.key.showMode'] = EMBEDDED_HALF_MODE; 87 this.options.parameters['ability.want.params.IsNotifyOccupiedAreaChange'] = true; 88 this.options.parameters['ability.want.params.IsModal'] = true; 89 hilog.info(0x3900, 'HalfScreenLaunchComponent', 'replaced options is %{public}s !', JSON.stringify(this.options)); 90 } else { 91 this.options = { 92 parameters: { 93 'ohos.extra.param.key.showMode': EMBEDDED_HALF_MODE, 94 'ability.want.params.IsNotifyOccupiedAreaChange': true, 95 'ability.want.params.IsModal': true 96 } 97 } 98 } 99 } 100 101 async checkAbility(): void { 102 this.resetOptions(); 103 try { 104 const res: boolean = await abilityManager.isEmbeddedOpenAllowed(this.context, this.appId); 105 if (res) { 106 if (this.isShow) { 107 this.isShow = false; 108 hilog.error(0x3900, 'HalfScreenLaunchComponent', ' EmbeddedOpen is already show!'); 109 return; 110 } 111 this.isShow = true; 112 hilog.info(0x3900, 'HalfScreenLaunchComponent', ' EmbeddedOpen is Allowed!'); 113 } else { 114 this.popUp(); 115 } 116 } catch (e) { 117 hilog.error(0x3900, 'HalfScreenLaunchComponent', 'isEmbeddedOpenAllowed called error!%{public}s', e.message); 118 } 119 } 120 121 async popUp(): void { 122 this.isShow = false; 123 try { 124 const ability = await this.context.openAtomicService(this.appId, this.options); 125 hilog.info(0x3900, 'HalfScreenLaunchComponent', '%{public}s open service success!', ability.want); 126 } catch (e) { 127 hilog.error(0x3900, 'HalfScreenLaunchComponent', '%{public}s open service error!', e.message); 128 } 129 } 130 131 build() { 132 Row() { 133 this.content(); 134 }.justifyContent(FlexAlign.Center) 135 .onClick( 136 () => { 137 hilog.info(0x3900, 'HalfScreenLaunchComponent', 'on start atomicservice'); 138 this.checkAbility(); 139 } 140 ).bindContentCover($$this.isShow, this.uiExtensionBuilder(), { modalTransition: ModalTransition.NONE }); 141 142 } 143 144 @Builder 145 uiExtensionBuilder() { 146 UIExtensionComponent({ 147 bundleName: `com.atomicservice.${this.appId}`, 148 flags: this.options?.flags, 149 parameters: this.options?.parameters 150 }, 151 { 152 windowModeFollowStrategy: WindowModeFollowStrategy.FOLLOW_UI_EXTENSION_ABILITY_WINDOW_MODE 153 }) 154 .height('100%') 155 .width('100%') 156 .backgroundColor(Color.Transparent) 157 .onError( 158 err => { 159 if (this.onError) { 160 this.onError(err); 161 } 162 this.isShow = false; 163 hilog.error(0x3900, 'HalfScreenLaunchComponent', 'call up UIExtension error!%{public}s', err.message); 164 this.getUIContext().showAlertDialog({ 165 message: err.message 166 }); 167 } 168 ) 169 .onTerminated(info => { 170 this.isShow = false; 171 if (this.onTerminated) { 172 this.onTerminated(info); 173 } 174 }) 175 } 176}