• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import { DialogUtils } from '../../../../../../../feature/ota/src/main/ets/dialog/DialogUtils';
2/*
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import {
18  CountDownDialogType,
19  OtaStatus,
20  UpdateState,
21  UpgradeCallResult,
22  UpgradeData
23} from '@ohos/common/src/main/ets/const/update_const';
24import update from '@ohos.update';
25import { TitleBar } from '@ohos/common/src/main/ets/component/TitleBar';
26import { FormatUtils } from '@ohos/common/src/main/ets/util/FormatUtils';
27import { LogUtils } from '@ohos/common/src/main/ets/util/LogUtils';
28import { DeviceUtils } from '@ohos/common/src/main/ets/util/DeviceUtils';
29import { ChangelogInfo, IPage, VersionPageInfo } from '@ohos/common/src/main/ets/manager/UpgradeInterface';
30import { NetUtils } from '@ohos/common/src/main/ets/util/NetUtils';
31import { DialogHelper } from '@ohos/ota/src/main/ets/dialog/DialogHelper';
32import { ChangelogContent } from '@ohos/ota/src/main/ets/components/ChangelogContent';
33import { ProgressContent } from '@ohos/ota/src/main/ets/components/ProgressContent';
34import { OtaUpdateManager } from '@ohos/ota/src/main/ets/manager/OtaUpdateManager';
35import { CountDownInstallDialogBuilder } from '@ohos/ota/src/main/ets/dialog/CountDownInstallDialogBuilder';
36import { MessageDialogBuilder, } from '@ohos/ota/src/main/ets/dialog/MessageDialogBuilder';
37import { StateManager, UpdateAction } from '@ohos/ota/src/main/ets/manager/StateManager';
38import { UpgradeAdapter } from '@ohos/ota/src/main/ets/UpgradeAdapter';
39import { VersionUtils } from '@ohos/ota/src/main/ets/util/VersionUtils';
40import { NotificationHelper } from '@ohos/ota/src/main/ets/notify/NotificationHelper';
41
42/**
43 * 新版本页面
44 *
45 * @since 2022-06-06
46 */
47@Entry
48@Component
49struct NewVersion {
50  @State private displayFileSize: string = '';
51  @State @Watch('refreshDescription') private changelogArray: Array<ChangelogInfo> = [];
52  @State private description: string = '';
53  @State private displayNewVersionName: string = '';
54  @State private isButtonEnable: boolean = true;
55  @State private isButtonVisible: boolean = true;
56  @StorageProp('updateStatus')
57  @Watch('initDataByStatus') private updateStatus: number = AppStorage.Get('updateStatus');
58  @StorageProp('isClickInstall') @Watch('onInstallClick')
59  private isClickInstall: number = AppStorage.Get('isClickInstall');
60  private dialogText: string | Resource = '';
61  @State private isInitComplete: boolean = false;
62  private effectiveMode: update.EffectiveMode = update.EffectiveMode.COLD;
63  private dialogType: CountDownDialogType = CountDownDialogType.OTA;
64  @State private buttonText: string = '';
65  @StorageProp('installStatusRefresh') @Watch('refresh')
66  private installStatusRefresh: string = AppStorage.Get('installStatusRefresh');
67
68  private countdownDialogController = new CustomDialogController({
69    builder: CountDownInstallDialogBuilder({
70      textString: this.dialogText,
71      dialogType: this.dialogType,
72      cancel: () => {
73        globalThis.displayCountdownDialog = false;
74      },
75      confirm: () => {
76        globalThis.displayCountdownDialog = false;
77        if (this.isABInstall()) {
78          this.reboot();
79        } else {
80          this.upgrade();
81        }
82      }
83    }),
84    autoCancel: false,
85    alignment: DeviceUtils.getDialogLocation(),
86    offset: ({
87      dx: '0vp',
88      dy: DeviceUtils.getDialogOffsetY()
89    })
90  });
91
92  private restartDialogController = new CustomDialogController({
93    builder: MessageDialogBuilder({ message: $r('app.string.reboot_wait') }),
94    autoCancel: false,
95    alignment: DeviceUtils.getDialogLocation(),
96    offset: ({
97      dx: '0vp',
98      dy: DeviceUtils.getDialogOffsetY()
99    })
100  });
101
102  private refreshDescription(): void {
103    this.log('refreshDescription');
104    this.description = JSON.stringify(this.changelogArray);
105  }
106
107  aboutToAppear() {
108    this.log('aboutToAppear');
109    globalThis.newVersionThis = this;
110  }
111
112  onPageShow() {
113    this.log('onPageShow NewVersionPage.');
114    globalThis.currentPage = 'pages/newVersion';
115    this.initDataByStatus();
116    new NotificationHelper().cancelAll();
117    this.handleAbnormalState();
118  }
119
120  private async handleAbnormalState(): Promise<void> {
121    let upgradeData: UpgradeData<OtaStatus> = await OtaUpdateManager.getInstance().getOtaStatus();
122    let otaStatus: OtaStatus = upgradeData.callResult == UpgradeCallResult.OK ? upgradeData.data : null;
123    let state = otaStatus?.status;
124    if (!state || state === UpdateState.INIT || state === UpdateState.UPGRADE_SUCCESS ||
125    state === UpdateState.UPGRADE_FAILED || state === UpdateState.INSTALL_FAILED) {
126      this.closeUpgradeDialog();
127      return;
128    }
129  }
130
131  onPageHide() {
132    this.log('onPageHide NewVersionPage');
133  }
134
135  onBackPress() {
136    return globalThis.displayCountdownDialog;
137  }
138
139  /**
140   * raise by notify installWantAgentInfo
141   */
142  private raiseCountDialogByClick(): void {
143    this.showCountdownDialog(UpdateState.DOWNLOAD_SUCCESS);
144    globalThis.abilityWant = null;
145  }
146
147  private onInstallClick(): void {
148    this.log('onInstallClick');
149    if (this.isClickInstall) {
150      this.raiseCountDialogByClick();
151    }
152  }
153
154  private async showCountdownDialog(updateStatus: number): Promise<void> {
155    this.log('showCountdownDialog');
156    if (StateManager.isAllowExecute(updateStatus, UpdateAction.INSTALL)) {
157      globalThis.displayCountdownDialog = true; // dialog display
158      AppStorage.Set('isClickInstall', 0); // reset
159      this.countdownDialogController.open();
160    }
161  }
162
163  public onLanguageChange(): void {
164    this.initDataByStatus();
165  }
166
167  private async initDataByStatus(): Promise<void> {
168    this.isButtonEnable = StateManager.isButtonEnable(this.updateStatus);
169    await this.initNewVersionPageInfo();
170    if (this.isClickInstall) {
171      this.raiseCountDialogByClick();
172    }
173    let stateButtonText = StateManager.getButtonText(this.updateStatus);
174    this.buttonText = FormatUtils.toUpperCase(globalThis.abilityContext, stateButtonText);
175    this.isButtonVisible = this.updateStatus !== UpdateState.INSTALLING
176      && this.updateStatus !== UpdateState.INSTALL_FAILED
177      && (this.isABInstall() || this.updateStatus !== UpdateState.INSTALL_SUCCESS)
178      && this.updateStatus !== UpdateState.UPGRADING
179      && this.updateStatus !== UpdateState.UPGRADE_FAILED
180      && this.updateStatus !== UpdateState.UPGRADE_SUCCESS;
181  }
182
183  public async initNewVersionPageInfo(): Promise<void> {
184    let newVersionInfo = globalThis.cachedNewVersionInfo || await OtaUpdateManager.getInstance().getNewVersion()
185      .then(upgradeData => {
186        this.log(`initDataByStatus upgradeData: ${upgradeData}`);
187        return upgradeData.callResult == UpgradeCallResult.OK ? upgradeData.data : null;
188      });
189    let componentDescription = await OtaUpdateManager.getInstance().getNewVersionDescription();
190    if (!newVersionInfo) {
191      return;
192    }
193    let components: Array<update.VersionComponent> = VersionUtils.sortComponents(newVersionInfo?.versionComponents);
194    let pageInfo: VersionPageInfo = await UpgradeAdapter.getInstance()
195      .getPageInstance()?.getNewVersionPageInfo(components);
196    this.displayNewVersionName = pageInfo?.version;
197    this.dialogText = pageInfo?.countDownDialogInfo?.dialogText;
198    this.dialogType = pageInfo?.countDownDialogInfo?.dialogType;
199    this.effectiveMode = pageInfo?.effectiveMode;
200    let size: number = 0;
201    let array :Array<ChangelogInfo> = [];
202
203    for (let index = 0; index < components?.length; index ++) {
204      let page: IPage = UpgradeAdapter.getInstance().getPageInstance();
205      if (!page) {
206        continue;
207      }
208      let versionPageInfo: VersionPageInfo = await page.getNewVersionPageInfo(components, componentDescription.data);
209      size += versionPageInfo.size;
210      array.push(versionPageInfo.changelog);
211    }
212    this.changelogArray = array;
213    this.displayFileSize = FormatUtils.formatFileSize(size);
214    this.isInitComplete = true;
215  }
216
217  private async upgrade(): Promise<void> {
218    this.log('upgrade effectiveMode ' + this.effectiveMode);
219    this.isButtonEnable = false;
220    let order = this.isABInstall() ? update.Order.INSTALL: update.Order.INSTALL_AND_APPLY
221    OtaUpdateManager.getInstance().upgrade(order).catch(err => {
222      this.isButtonEnable = true;
223    });
224  }
225
226  private async reboot(): Promise<void> {
227    this.log('reboot!');
228    if (this.isABInstall()) {
229      OtaUpdateManager.getInstance().upgrade(update.Order.APPLY);
230    }
231  }
232
233  private async handleButtonClick(): Promise<void> {
234    this.log('handleButtonClick');
235    switch (StateManager.getButtonClickAction(this.updateStatus)) {
236      case UpdateAction.DOWNLOAD:
237        if (await NetUtils.isCellularNetwork()) {
238          DialogHelper.displayNetworkDialog({
239            onConfirm: () => {
240              OtaUpdateManager.getInstance().download(update.NetType.CELLULAR);
241            } });
242        } else {
243          OtaUpdateManager.getInstance().download();
244        }
245        break;
246      case UpdateAction.INSTALL:
247        this.upgrade();
248        break;
249      case UpdateAction.REBOOT:
250        this.reboot();
251        break;
252      case UpdateAction.CANCEL:
253        OtaUpdateManager.getInstance().cancel();
254        break;
255      case UpdateAction.RESUME:
256        OtaUpdateManager.getInstance().resumeDownload();
257        break;
258      default:
259        break;
260    }
261  }
262
263  build() {
264    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
265      Column() {
266        TitleBar({ title: $r('app.string.title_new_version'), onBack: this.onBackPress.bind(this)});
267      }.flexShrink(0);
268      Column() {
269        Scroll() {
270          Column() {
271            ProgressContent();
272            if (this.isInitComplete) {
273              Text(this.displayNewVersionName)
274                .fontSize($r('app.float.text_size_version_name'))
275                .maxLines(5)
276                .textOverflow({ overflow: TextOverflow.Ellipsis })
277                .padding({
278                  right: $r('app.float.changelog_detail_content_padding_horizontal'),
279                  left: $r('app.float.changelog_detail_content_padding_horizontal'),
280                })
281                .fontWeight(FontWeight.Medium);
282              Text(this.displayFileSize)
283                .fontSize($r('app.float.text_size_version_size')).fontWeight(FontWeight.Regular).opacity(0.6)
284                .margin({
285                  top: $r('app.float.new_version_size_margin_top'),
286                  bottom: $r('app.float.new_version_size_margin_bottom')
287                })
288              ChangelogContent({
289                isCurrentPage: false,
290                isNeedFold: this.changelogArray?.length > 1,
291                description: this.description
292              })
293            }
294          }.width('100%').flexShrink(0)
295        }
296        .width('100%')
297        .scrollable(ScrollDirection.Vertical)
298        .scrollBar(BarState.Auto)
299      }.flexGrow(1)
300
301      Column() {
302        Button() {
303          Text(this.buttonText)
304            .fontSize($r('app.float.text_size_btn')).fontColor(Color.White).fontWeight(FontWeight.Medium)
305            .margin({ left: $r('app.float.custom_button_text_margin_left'),
306              right: $r('app.float.custom_button_text_margin_right') })
307        }
308        .type(ButtonType.Capsule)
309        .constraintSize({ minWidth: $r('app.float.custom_button_width') })
310        .height($r('app.float.custom_button_height'))
311        .backgroundColor($r('app.color.blue'))
312        .opacity(this.isButtonEnable ? 1 : 0.4)
313        .visibility(this.isButtonVisible ? Visibility.Visible : Visibility.None)
314        .onClick(() => {
315          if(this.isButtonEnable) {
316            this.handleButtonClick();
317          }
318        })
319      }
320      .flexShrink(0)
321      .padding({
322        top: $r('app.float.new_version_button_padding_top'),
323        bottom: $r('app.float.new_version_button_padding_bottom')
324      })
325    }
326    .width('100%')
327    .height('100%')
328    .backgroundColor($r('app.color.page_background'))
329  }
330
331  private log(message: string): void {
332    LogUtils.log('NewVersion', message);
333  }
334
335  private closeUpgradeDialog() {
336    this.restartDialogController.close();
337  }
338
339  private isABInstall(): boolean {
340    return this.effectiveMode === update.EffectiveMode.LIVE_AND_COLD;
341  }
342
343  private refresh() {
344    if (this.isABInstall()) {
345      return;
346    }
347    let otaStatus: OtaStatus = JSON.parse(this.installStatusRefresh);
348    let status: UpdateState = otaStatus?.status;
349    if (status === UpdateState.INSTALL_FAILED || status === UpdateState.UPGRADE_FAILED
350      || status === UpdateState.UPGRADE_SUCCESS) {
351      this.closeUpgradeDialog();
352    } else if (status === UpdateState.UPGRADING) {
353      this.restartDialogController.open();
354    }
355  }
356}