• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 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 { Callback, BusinessError } from '@ohos.base';
19import AtomicServiceOptions from '@ohos.app.ability.AtomicServiceOptions';
20import commonEventManager from '@ohos.commonEventManager';
21import Base from '@ohos.base';
22
23export class LaunchController {
24  public launchAtomicService = (appId: string, options?: AtomicServiceOptions) => {};
25}
26
27const EMBEDDED_FULL_MODE: number = 1;
28const atomicServiceDataTag: string = 'ohos.atomicService.window';
29const ERR_CODE_ABNORMAL: number = 100014;
30const ERR_CODE_CAPABILITY_NOT_SUPPORT: number = 801;
31const LOG_TAG: string = 'InnerFullScreenLaunchComponent';
32
33@Component
34export struct InnerFullScreenLaunchComponent {
35  @BuilderParam content: Callback<void> = this.doNothingBuilder;
36  private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
37  controller: LaunchController = new LaunchController();
38  private appId: string = '';
39  private options?: AtomicServiceOptions;
40  @State private isShow: boolean = false;
41  private subscriber: commonEventManager.CommonEventSubscriber | null = null;
42  private launchAtomicService = (appId: string, options?: AtomicServiceOptions) => {
43    hilog.info(0x3900, LOG_TAG,
44      'launchAtomicService, appId: %{public}s.', appId);
45    this.appId = appId;
46    this.options = options;
47    this.checkAbility();
48  }
49  onReceive?: Callback<Record<string, Object>>;
50
51  aboutToAppear() {
52    let subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
53      events: [commonEventManager.Support.COMMON_EVENT_DISTRIBUTED_ACCOUNT_LOGOUT],
54    };
55
56    commonEventManager.createSubscriber(subscribeInfo,
57      (err:Base.BusinessError, data: commonEventManager.CommonEventSubscriber) => {
58        if (err) {
59          hilog.error(0x3900, LOG_TAG,
60            'Failed to create subscriber, err: %{public}s.', err.message);
61          return;
62        }
63
64        if (data == null || data == undefined) {
65          hilog.error(0x3900, LOG_TAG, 'Failed to create subscriber, data is null.');
66          return;
67        }
68
69        this.subscriber = data;
70        commonEventManager.subscribe(this.subscriber,
71          (err: Base.BusinessError, data: commonEventManager.CommonEventData) => {
72            if (err) {
73              hilog.error(0x3900, LOG_TAG,
74                'Failed to subscribe common event, err: %{public}s.', err.message);
75              return;
76            }
77
78            hilog.info(0x3900, LOG_TAG, 'Received account logout event.');
79            this.isShow = false;
80          })
81      })
82      this.controller.launchAtomicService = this.launchAtomicService;
83  }
84
85  aboutToDisappear() {
86    if (this.subscriber !== null) {
87      commonEventManager.unsubscribe(this.subscriber, (err) => {
88        if (err) {
89          hilog.error(0x3900, LOG_TAG,
90            'UnsubscribeCallBack, err: %{public}s.', err.message);
91        } else {
92          this.subscriber = null;
93        }
94      })
95    }
96  }
97
98  @Builder
99  doNothingBuilder() {
100  };
101
102  resetOptions() {
103    if (this.options?.parameters) {
104      this.options.parameters['ohos.extra.param.key.showMode'] = EMBEDDED_FULL_MODE;
105      this.options.parameters['ability.want.params.IsNotifyOccupiedAreaChange'] = true;
106      hilog.info(0x3900, LOG_TAG, 'replaced options is %{public}s !', JSON.stringify(this.options));
107    } else {
108      this.options = {
109        parameters: {
110          'ohos.extra.param.key.showMode': EMBEDDED_FULL_MODE,
111          'ability.want.params.IsNotifyOccupiedAreaChange': true,
112        }
113      };
114    }
115  }
116
117  async checkAbility(): Promise<void> {
118    if (this.isShow) {
119      hilog.error(0x3900, LOG_TAG, 'EmbeddedAbility already shows');
120      this.isShow = false;
121      return;
122    }
123    this.resetOptions();
124    try {
125      abilityManager.queryAtomicServiceStartupRule(this.context, this.appId)
126        .then((data: abilityManager.AtomicServiceStartupRule) => {
127          if (data.isOpenAllowed) {
128            if (data.isEmbeddedAllowed) {
129              this.isShow = true;
130              hilog.info(0x3900, LOG_TAG, 'EmbeddedOpen is Allowed!');
131            } else {
132              this.popUp();
133            }
134          } else {
135            hilog.info(0x3900, LOG_TAG, 'is not allowed open!');
136          }
137        }).catch((err: BusinessError) => {
138          hilog.error(0x3900, LOG_TAG, 'queryAtomicServiceStartupRule called error!%{public}s', err.message);
139          if (ERR_CODE_CAPABILITY_NOT_SUPPORT === err.code) {
140            this.popUp();
141          }
142      });
143    } catch (err: BusinessError) {
144      hilog.error(0x3900, LOG_TAG, 'AtomicServiceStartupRule failed: %{public}s', err.message);
145      this.popUp();
146    }
147  }
148
149  async popUp(): Promise<void> {
150    this.isShow = false;
151    try {
152      const ability = await this.context.openAtomicService(this.appId, this.options);
153      hilog.info(0x3900, LOG_TAG, '%{public}s open service success!', ability.want);
154    } catch (e) {
155      hilog.error(0x3900, LOG_TAG, '%{public}s open service error!', e.message);
156    }
157  }
158
159  private handleOnReceiveEvent(data: Object): void {
160    if (data === undefined || data === null) {
161      return;
162    }
163    if (this.onReceive !== undefined) {
164      const sourceKeys = Object.keys(data);
165      let atomicServiceData: Record<string, Object> = {};
166      for (let i = 0; i < sourceKeys.length; i++) {
167        if (sourceKeys[i].includes(atomicServiceDataTag)) {
168          atomicServiceData[sourceKeys[i]] = data[sourceKeys[i]];
169        }
170      }
171      this.onReceive(atomicServiceData);
172    }
173  }
174
175  build() {
176    Row() {
177      this.content();
178    }
179    .justifyContent(FlexAlign.Center)
180    .bindContentCover($$this.isShow, this.uiExtensionBuilder(), {
181      modalTransition: ModalTransition.DEFAULT,
182      enableSafeArea: true
183    })
184  }
185
186  @Builder
187  uiExtensionBuilder() {
188    Column() {
189      UIExtensionComponent({
190        bundleName: `com.atomicservice.${this.appId}`,
191        flags: this.options?.flags,
192        parameters: this.options?.parameters
193      },{
194        windowModeFollowStrategy: WindowModeFollowStrategy.FOLLOW_HOST_WINDOW_MODE
195      })
196        .backgroundColor($r('sys.color.ohos_id_color_titlebar_bg'))
197        .defaultFocus(true)
198        .height('100%')
199        .width('100%')
200        .onRelease(
201          () => {
202            hilog.error(0x3900, LOG_TAG, 'onRelease');
203            this.isShow = false;
204          }
205        )
206        .onError(
207          err => {
208            this.isShow = false;
209            hilog.error(0x3900, LOG_TAG, 'call up UIExtension error! %{public}s', err.message);
210            if (err.code !== ERR_CODE_ABNORMAL) {
211              this.getUIContext().showAlertDialog({
212                message: err.message
213              });
214            }
215          }
216        )
217        .onReceive(data => {
218          this.handleOnReceiveEvent(data);
219        })
220    }
221    .height(LayoutPolicy.matchParent)
222    .width(LayoutPolicy.matchParent)
223    .ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM], [LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])
224  }
225}