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}