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