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 */ 15 16import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession'; 17import { EditableLeftIconType } from '@ohos.arkui.advanced.EditableTitleBar'; 18import { EditableTitleBar } from '@ohos.arkui.advanced.EditableTitleBar'; 19import ConnectService from '../common/share/ConnectService'; 20import { LengthMetrics } from '@ohos.arkui.node'; 21import dlpPermission from '@ohos.dlpPermission'; 22import promptAction from '@ohos.promptAction'; 23import { BusinessError } from '@ohos.base'; 24import Want from '@ohos.app.ability.Want'; 25import fs from '@ohos.file.fs'; 26import systemParameterEnhance from '@ohos.systemParameterEnhance'; 27import emitter from '@ohos.events.emitter'; 28import { HiLog } from '../common/HiLog'; 29import Constants from '../common/constant'; 30import FileUtils, { FileMsg } from '../common/FileUtils'; 31import { 32 getFileUriByPath, 33 getFileFd, 34 sendDlpFileCreateProperties, 35 getFileSizeByUri, 36 sendDlpManagerAccountLogin, 37 getAppId, 38 getOsAccountInfo, 39 getConnectionStatus 40} from '../common/utils'; 41import { SystemUtils } from '../common/systemUtils'; 42import FontSizeScale from '../common/FontSizeScale'; 43import { contact } from '@kit.ContactsKit'; 44import deviceInfo from '@ohos.deviceInfo'; 45 46const TAG = 'Share'; 47 48class Test { 49 public '0': number = 0; 50 public '1': number = 0; 51 public '4': string = ''; 52} 53 54class AuthUserList { 55 public authAccount: string = ''; 56 public authAccountType: number = 0; 57 public dlpFileAccess: number = 0; 58 public permExpiryTime: number = 0; 59} 60 61let defaultDlpProperty: dlpPermission.DLPProperty = { 62 ownerAccount: '', 63 ownerAccountType: dlpPermission.AccountType.CLOUD_ACCOUNT, 64 authUserList: [], 65 contactAccount: '', 66 offlineAccess: true, 67 ownerAccountID: '', 68 everyoneAccessList: [] 69}; 70 71let storage = LocalStorage.getShared(); 72 73@Entry(storage) 74@Component 75struct encryptedSharing { 76 static readonly GET_ACCOUNT_INFO_RESET = 'clear'; 77 private connectService: ConnectService = new ConnectService(getContext(this)); 78 private isPhoneDevice: boolean = true; 79 @State titlebarMargin: LocalizedMargin = { 80 start: LengthMetrics.vp(Constants.SHARE_TITLE_HEAD_MARGIN_RIGHT), 81 end: LengthMetrics.vp(Constants.SHARE_TITLE_HEAD_MARGIN_RIGHT), 82 }; 83 @LocalStorageLink('commandSearchUserInfo') @Watch('beginToGenerateDLPFile') isInputInvalid: string = ''; 84 @LocalStorageLink('commandGetAccountInfo') @Watch('changeAccountInfo') commandGetAccountInfo: string = ''; 85 @State dlpProperty: dlpPermission.DLPProperty = defaultDlpProperty; 86 @State enabledFocus: boolean = true; 87 @State isConfirmButtonEnabled: boolean = false; 88 @State isShowSheet: boolean = false; 89 @State showUIExtensionForAccountLogin: boolean = false; 90 @State actionWant: Want | undefined = storage.get<Want>('actionWant'); 91 @State inputValue: string = ''; 92 @State phoneFormatTips: boolean = false; 93 @State ownerAccount: string = ''; 94 @State ownerAccountID: string = ''; 95 @State contactExists: boolean = true; 96 @State credentialCallBackMsg: string | Resource = ''; 97 @State session: UIExtensionContentSession | undefined = 98 storage === undefined ? undefined : storage.get<UIExtensionContentSession>('session'); 99 @State placeHolderStr: ResourceStr = ''; 100 @State contactPerson: string = ''; 101 @State recordSuccessUid: string = ''; 102 @State osVersion: ResourceStr = ''; 103 @State isTextInputFocus: boolean = false; 104 @State generalType: string = 'general.file'; 105 @State scrollHeight: number = 188; 106 107 @Builder 108 contactsPicker() { 109 Column() { 110 UIExtensionComponent({ 111 bundleName: 'com.ohos.contacts', 112 abilityName: 'ContactUiExtentionAbility', 113 parameters: { 114 'ability.want.params.uiExtensionType': 'sys/commonUI', 115 'targetUrl': 'BatchSelectContactsPage', 116 'isContactMultiSelect': false, 117 } 118 }) 119 .onRelease((code) => { 120 }) 121 .onResult((data) => { 122 }) 123 .onReceive((data) => { 124 try { 125 let params: [] = JSON.parse((data.want as Want)?.parameters?.contactObjects as string); 126 for (let i = 0; i < params.length; i++) { 127 this.inputValue = (params[i] as Record<string, string>)?.telephone; 128 } 129 } catch (error) { 130 HiLog.error(TAG, `json parse exception, error is ${JSON.stringify(error)}`); 131 } 132 this.isShowSheet = false; 133 }) 134 .width(Constants.CONTACTS_PICKER_WIDTH) 135 .height(Constants.CONTACTS_PICKER_HEIGHT) 136 .hitTestBehavior(HitTestMode.Block) 137 } 138 .width(Constants.CONTACTS_PICKER_WIDTH) 139 .height(Constants.CONTACTS_PICKER_HEIGHT) 140 } 141 142 contactsAction = () => { 143 if (this.isPhoneDevice) { 144 contact.selectContacts({ isMultiSelect: false }).then((data) => { 145 HiLog.info(TAG, 'Succeeded in selecting Contacts.'); 146 if (!data || !data.length) { 147 HiLog.error(TAG, 'Contacts data is empty.'); 148 return; 149 } 150 const phoneNumbers = data[0].phoneNumbers; 151 if (!phoneNumbers || !phoneNumbers.length) { 152 HiLog.error(TAG, 'Contacts phoneNumbers is empty.'); 153 return; 154 } 155 const phoneNumber = phoneNumbers[0].phoneNumber; 156 if (phoneNumber) { 157 this.inputValue = phoneNumber; 158 } 159 }).catch((error: BusinessError) => { 160 HiLog.error(TAG, `Failed to select Contacts, Code: ${error.code}, message: ${error.message}`); 161 }); 162 } else { 163 this.isShowSheet = !this.isShowSheet; 164 } 165 } 166 167 private async beginShareEncrypt() { 168 HiLog.info(TAG, `begin Share Encrypt start`); 169 if (this.checkCloudPhone(this.inputValue)) { 170 this.enabledFocus = false; 171 this.isConfirmButtonEnabled = false; 172 this.getAccountInfo(); 173 } 174 } 175 176 async getAccountInfo() { 177 HiLog.info(TAG, `get Account Info start`); 178 if (await getConnectionStatus() === false) { 179 this.showToast($r('app.string.network_invalid')); 180 this.enabledFocus = true; 181 this.isConfirmButtonEnabled = this.inputValue.length > 0; 182 this.isTextInputFocus = true; 183 this.textInputGetFocus(); 184 return; 185 } 186 try { 187 let accountInfo = await getOsAccountInfo(); 188 if (accountInfo.distributedInfo.name === 'ohosAnonymousName' && 189 accountInfo.distributedInfo.id === 'ohosAnonymousUid') { 190 this.showUIExtensionForAccountLogin = true; 191 return; 192 } 193 if (accountInfo.distributedInfo.id !== this.recordSuccessUid) { 194 HiLog.info(TAG, `COMMAND_GET_ACCOUNT_INFO start`); 195 this.connectService.connectServiceShareAbility(Constants.COMMAND_GET_ACCOUNT_INFO); 196 this.recordSuccessUid = accountInfo.distributedInfo.id; 197 return; 198 } else { 199 this.connectService.connectServiceShareAbility(Constants.COMMAND_SEARCH_USER_INFO); 200 } 201 } catch (err) { 202 HiLog.error(TAG, `getOsAccountInfo failed: ${JSON.stringify(err)}`); 203 this.showToast($r('app.string.Share_File_Encrypted_Failed')); 204 this.enabledFocus = true; 205 this.isConfirmButtonEnabled = this.inputValue.length > 0; 206 } 207 } 208 209 changeAccountInfo() { 210 if (this.commandGetAccountInfo === encryptedSharing.GET_ACCOUNT_INFO_RESET) { 211 return; 212 } 213 HiLog.info(TAG, `changeAccountInfo start`); 214 try { 215 let commandGetAccountInfoCallBack = JSON.parse(this.commandGetAccountInfo) as Record<string, object>; 216 HiLog.info(TAG, `commandGetAccountInfo Call Back errorCode: ${commandGetAccountInfoCallBack.errorCode}`); 217 let res = commandGetAccountInfoCallBack.result as Record<string, string>; 218 if (Number(commandGetAccountInfoCallBack.errorCode) === Constants.ERR_CODE_SUCCESS && res?.uid) { 219 this.ownerAccount = res?.uid; 220 this.ownerAccountID = res?.uid; 221 this.connectService.connectServiceShareAbility(Constants.COMMAND_SEARCH_USER_INFO); 222 return; 223 } else { 224 this.enabledFocus = true; 225 this.isConfirmButtonEnabled = true; 226 this.recordSuccessUid = ''; 227 this.commandGetAccountInfo = encryptedSharing.GET_ACCOUNT_INFO_RESET; 228 if ([ 229 Constants.ERR_CODE_NETWORK_ERROR, 230 Constants.ERR_CODE_CONNECTION_FAIL, 231 Constants.ERR_CODE_CONNECTION_TIME_OUT 232 ].includes(Number(commandGetAccountInfoCallBack.errorCode))) { 233 this.showToast($r('app.string.network_invalid')); 234 } else { 235 this.showToast($r('app.string.Share_File_Encrypted_Failed')); 236 } 237 return; 238 } 239 } catch (error) { 240 HiLog.error(TAG, `get account info failed: ${JSON.stringify(error)}`); 241 this.showToast($r('app.string.Share_File_Encrypted_Failed')); 242 this.enabledFocus = true; 243 this.isConfirmButtonEnabled = true; 244 this.recordSuccessUid = ''; 245 this.commandGetAccountInfo = encryptedSharing.GET_ACCOUNT_INFO_RESET; 246 return; 247 } 248 } 249 250 checkCloudPhone(phone: string): boolean { 251 if (!phone) { 252 return false; 253 } 254 let reg = /^(?:(?:\+|00)86)?1[3456789]\d{9}$/; 255 if (!(reg.test(phone))) { 256 HiLog.info(TAG, `Please enter the phone.`); 257 this.phoneFormatTips = true; 258 this.credentialCallBackMsg = $r('app.string.Share_Tips_Phone_Format'); 259 HiLog.info(TAG, `phoneFormatTips: ${this.phoneFormatTips}`); 260 return false; 261 } 262 reg = /^(0086|\+86)/; 263 let formatPhone = this.inputValue.replace(reg, ''); 264 let cloudPhone = `${Constants.INTERNATIONAL_DIALING_CODE}${formatPhone}`; 265 AppStorage.setOrCreate('cloudPhone', cloudPhone); 266 return true; 267 } 268 269 async beginToGenerateDLPFile() { 270 HiLog.info(TAG, `beginToGenerateDLPFile start`); 271 if (!this.isInputValid()) { 272 this.enabledFocus = true; 273 this.isConfirmButtonEnabled = true; 274 return; 275 } 276 let parameters = this.actionWant?.parameters as Record<string, Array<string>>; 277 let inputUri: string = parameters['ability.params.stream'][0]; 278 let inputFileName: string = this.getFileName(parameters, inputUri); 279 let dlpFileName = decodeURIComponent(inputFileName) + '.dlp'; 280 let inFileFd = getFileFd(inputUri); 281 let srcFileSize: number = await getFileSizeByUri(inputUri); 282 AppStorage.setOrCreate('hiFileSize', srcFileSize); 283 let filePath = getContext(this).filesDir + `/Share/${new Date().getTime()}/`; 284 try { 285 await fs.mkdir(filePath, true); 286 } catch (error) { 287 HiLog.error(TAG, `mkdir failed: ${JSON.stringify(error)}`); 288 } 289 let newFilePath = filePath + dlpFileName; 290 let file: fs.File | undefined; 291 let filePathUri = getFileUriByPath(newFilePath); 292 try { 293 file = fs.openSync(newFilePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); 294 await dlpPermission.generateDLPFile(inFileFd, file.fd, this.dlpProperty); 295 this.showToast($r('app.string.Share_File_Encrypted_Success')); 296 let dstFileSize: number = await getFileSizeByUri(filePathUri); 297 AppStorage.setOrCreate('hiPolicySizeEnc', dstFileSize); 298 AppStorage.setOrCreate('hiCode', 201); 299 sendDlpFileCreateProperties(dlpPermission.AccountType.CLOUD_ACCOUNT); // 201: DLP_2C_FILE_CREATE_EVENT 300 this.backToPages(filePathUri, dlpFileName); 301 HiLog.info(TAG, `beginToGenerateDLPFile success`); 302 } catch (err) { 303 HiLog.error(TAG, `open temp failed: ${JSON.stringify(err)}`); 304 HiLog.info(TAG, `generateDLPFile file failed: ${JSON.stringify(err)}`); 305 storage.setOrCreate('commandSearchUserInfo', ''); 306 if (err.code === Constants.SHARE_FILE_NAME_TOO_LONG) { 307 this.showToast($r('app.string.Share_File_Name_Too_Long')); 308 return; 309 } 310 this.showToast($r('app.string.Share_File_Encrypted_Failed')); 311 this.enabledFocus = true; 312 this.isConfirmButtonEnabled = true; 313 } finally { 314 if (file) { 315 fs.closeSync(file); 316 } 317 } 318 } 319 320 getFileName(parameters: Record<string, Array<string>>, inputUri: string): string { 321 let abilityPickerRecords = parameters['ability.picker.records']; 322 let srcFileMsg: FileMsg = FileUtils.getSuffixFileMsgByUri(inputUri); 323 AppStorage.setOrCreate('hiFileType', srcFileMsg.fileType); 324 let res: string = ''; 325 Object.keys(abilityPickerRecords).forEach(key => { 326 this.generalType = key; 327 res = abilityPickerRecords[key][0]?.['4']; 328 }); 329 if (res === undefined) { 330 res = srcFileMsg.fileName + srcFileMsg.fileType; 331 } 332 return res; 333 } 334 335 showToast(msg: Resource) { 336 promptAction.showToast({ 337 message: msg, 338 duration: Constants.SHARE_SET_TIMEOUT 339 }); 340 } 341 342 backToPages(filePathUri: string, dlpFileName: string) { 343 HiLog.info(TAG, `backToPages start: ${dlpFileName}`); 344 if (this.actionWant && this.actionWant.parameters) { 345 this.actionWant.parameters['ability.params.stream'] = [filePathUri]; 346 let arr: Test[] = [ 347 { 348 '0': 0, 349 '1': 0, 350 '4': dlpFileName 351 } 352 ]; 353 let generalFile: Record<string, Test[]> = {}; 354 generalFile[this.generalType] = arr; 355 this.actionWant.parameters['ability.picker.records'] = generalFile; 356 setTimeout(() => { 357 this.session!.terminateSelfWithResult({ 358 resultCode: 2, 359 want: this.actionWant 360 }); 361 }, Constants.SHARE_SET_TIMEOUT) 362 } 363 } 364 365 isInputValid(): boolean { 366 if (!this.isInputInvalid) { 367 return false; 368 } 369 let credentialCallBack = JSON.parse(this.isInputInvalid) as Record<string, string>; 370 HiLog.info(TAG, `credential Call Back errorCode: ${credentialCallBack.errorCode}`); 371 if (!credentialCallBack.status && Number(credentialCallBack.errorCode) === Constants.ERR_CODE_SUCCESS) { 372 HiLog.info(TAG, `credentialCallBack msg`); 373 let str = this.getExternalResourceString(Constants.DLP_CREDMGR_BUNDLE_NAME, 'entry', 'no_user'); 374 this.credentialCallBackMsg = str.length > 0 ? str : credentialCallBack.errorMsg; 375 this.phoneFormatTips = true; 376 storage.setOrCreate('commandSearchUserInfo', ''); 377 return false; 378 } 379 if (!credentialCallBack.status && [ 380 Constants.ERR_CODE_NETWORK_ERROR, 381 Constants.ERR_CODE_CONNECTION_FAIL, 382 Constants.ERR_CODE_CONNECTION_TIME_OUT 383 ].includes(Number(credentialCallBack.errorCode))) { 384 this.showToast($r('app.string.network_invalid')); 385 storage.setOrCreate('commandSearchUserInfo', ''); 386 return false; 387 } 388 if (!credentialCallBack.status && Number(credentialCallBack.errorCode) !== Constants.ERR_CODE_SUCCESS) { 389 this.showToast($r('app.string.Share_File_Encrypted_Failed')); 390 storage.setOrCreate('commandSearchUserInfo', ''); 391 return false; 392 } 393 let authUserList: AuthUserList[] = [ 394 { 395 'authAccount': credentialCallBack.userIdCipher, 396 'authAccountType': 1, 397 'dlpFileAccess': 1, 398 'permExpiryTime': Date.UTC(9999, 1, 1), 399 } 400 ]; 401 this.dlpProperty = { 402 'ownerAccount': this.ownerAccount, 403 'ownerAccountID': this.ownerAccountID, 404 'ownerAccountType': 1, 405 'authUserList': authUserList, 406 'contactAccount': this.ownerAccount, 407 'offlineAccess': true, 408 } 409 return true; 410 } 411 412 async checkContacts() { 413 let callerBundleName = 'com.ohos.contacts'; 414 try { 415 await getAppId(callerBundleName); 416 this.contactExists = true; 417 } catch { 418 this.contactExists = false; 419 } 420 } 421 422 async getLoginStatus() { 423 HiLog.info(TAG, `get login status start.`); 424 if (await getConnectionStatus() === false) { 425 this.showToast($r('app.string.network_invalid')); 426 this.enabledFocus = true; 427 this.isConfirmButtonEnabled = this.inputValue.length > 0; 428 this.isTextInputFocus = true; 429 this.textInputGetFocus(); 430 return; 431 } 432 try { 433 let accountInfo = await getOsAccountInfo(); 434 if (accountInfo.distributedInfo.name === 'ohosAnonymousName' && 435 accountInfo.distributedInfo.id === 'ohosAnonymousUid') { 436 this.showUIExtensionForAccountLogin = true; 437 } else { 438 this.isTextInputFocus = true; 439 this.textInputGetFocus(); 440 } 441 } catch (err) { 442 HiLog.error(TAG, `getOsAccountInfo failed: ${JSON.stringify(err)}`); 443 } 444 } 445 446 447 onLanguageChange() { 448 let str = this.getExternalResourceString(Constants.DLP_CREDMGR_BUNDLE_NAME, 'entry', 'add_users_hint'); 449 if (str.length > 0) { 450 this.placeHolderStr = str; 451 } 452 str = this.getExternalResourceString(Constants.DLP_CREDMGR_BUNDLE_NAME, 'entry', 'no_user'); 453 if (str.length > 0) { 454 this.credentialCallBackMsg = str; 455 } 456 str = this.getExternalResourceString(Constants.DLP_CREDMGR_BUNDLE_NAME, 'entry', 'hmos_version_label'); 457 if (str.length > 0) { 458 this.osVersion = str; 459 } 460 this.getContactPersonString(); 461 } 462 463 subscribeLanguageChange() { 464 emitter.on('onConfigurationUpdate', () => { 465 this.onLanguageChange(); 466 }) 467 } 468 469 getExternalResourceString(bundle: string, module: string, resourceName: string): string { 470 try { 471 let ctx = getContext().createModuleContext(bundle, module); 472 HiLog.info(TAG, 'getExternalResourceString get context from: ' + ctx.applicationInfo.name); 473 let str = ctx.resourceManager.getStringByNameSync(resourceName); 474 return str; 475 } catch (e) { 476 let error = e as BusinessError; 477 HiLog.error(TAG, 'getExternalResourceString error: ' + error.code + ' ' + error.message); 478 return ''; 479 } 480 } 481 482 getContactPersonString() { 483 try { 484 getContext().resourceManager.getStringValue($r('app.string.Share_Contact_Person').id, 485 (error: BusinessError, value: string) => { 486 if (error === undefined || error === null) { 487 this.contactPerson = value; 488 } else { 489 HiLog.error(TAG, `error is ${JSON.stringify(error)}`); 490 } 491 }); 492 } catch (error) { 493 HiLog.error(TAG, `callback getStringValue failed, error ${JSON.stringify(error)}`); 494 } 495 } 496 497 private getSettingItemPadding(): number { 498 const FONT_SIZE_SCALE_PARAM = 'persist.sys.font_scale_for_user0'; 499 let fontSizeScale = Number.parseFloat(systemParameterEnhance.getSync(FONT_SIZE_SCALE_PARAM, '1')); 500 switch (fontSizeScale) { 501 case FontSizeScale.XXL1: 502 return Constants.GET_SETTING_ITEM_XXL1; 503 case FontSizeScale.XXL2: 504 return Constants.GET_SETTING_ITEM_XXL2; 505 case FontSizeScale.XXL3: 506 return Constants.GET_SETTING_ITEM_XXL3; 507 default: 508 return Constants.GET_SETTING_ITEM_DEFAULT; 509 } 510 } 511 512 clearHistoryDLPFile() { 513 let pathDir = getContext(this).filesDir + '/Share'; 514 fs.listFile(pathDir).then((filenames: Array<string>) => { 515 HiLog.info(TAG, `listFile succeed`); 516 let filenamesLists = filenames.sort((a, b) => Number(a) - Number(b)); 517 if (filenamesLists.length > Constants.SHARE_TEMP_SAVE_FILE_NUMBER) { 518 let deleteArray = filenamesLists.slice(0, filenamesLists.length - Constants.SHARE_TEMP_SAVE_FILE_NUMBER); 519 deleteArray.forEach((item) => { 520 fs.rmdirSync(pathDir + `/${item}`); 521 }) 522 } 523 }).catch((err: BusinessError) => { 524 HiLog.error(TAG, `list file failed with error message: ${JSON.stringify(err)}`); 525 }); 526 } 527 528 textInputGetFocus() { 529 setTimeout(() => { 530 try { 531 HiLog.info(TAG, `delay requestFocus start`); 532 this.getUIContext().getFocusController().requestFocus('phoneInput'); 533 } catch (error) { 534 HiLog.error(TAG, `requestFocus failed. Cause: ${JSON.stringify(error)}`); 535 } 536 }, Constants.ENCRYPTION_SET_TIMEOUT_TIME); 537 } 538 539 getScrollHeight(newValue: SizeOptions) { 540 const height = newValue.height as number; 541 this.scrollHeight = height - Constants.SHARE_BUTTON_COLUMN_BOTTOM - Constants.SHARE_TITLE_HEAD_HEIGHT - 542 Constants.SHARE_TITLE_HEAD_MARGIN_TOP - Constants.SHARE_TITLE_HEAD_MARGIN_BOTTOM; 543 if (this.scrollHeight > Constants.SHARE_TEXTAREA_MAX_HEIGHT) { 544 this.scrollHeight = Constants.SHARE_TEXTAREA_MAX_HEIGHT; 545 } 546 } 547 548 aboutToAppear() { 549 HiLog.info(TAG, `aboutToAppear enter: ${this.showUIExtensionForAccountLogin}`); 550 this.isPhoneDevice = deviceInfo.deviceType === 'phone'; 551 this.getLoginStatus(); 552 AppStorage.setOrCreate('hiAccountType', dlpPermission.AccountType.CLOUD_ACCOUNT); 553 sendDlpManagerAccountLogin(-1); 554 this.checkContacts(); 555 this.clearHistoryDLPFile(); 556 this.subscribeLanguageChange(); 557 let str = this.getExternalResourceString(Constants.DLP_CREDMGR_BUNDLE_NAME, 'entry', 'add_users_hint'); 558 this.placeHolderStr = str.length > 0 ? str : ''; 559 str = this.getExternalResourceString(Constants.DLP_CREDMGR_BUNDLE_NAME, 'entry', 'hmos_version_label'); 560 this.osVersion = str.length > 0 ? str : ''; 561 this.getContactPersonString(); 562 } 563 564 build() { 565 Stack() { 566 Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start }) { 567 EditableTitleBar({ 568 leftIconStyle: EditableLeftIconType.Back, 569 title: $r('app.string.Share_Add_Viewable_Users'), 570 contentMargin: this.titlebarMargin, 571 menuItems: [ 572 { 573 value: $r('sys.media.ohos_ic_public_cancel'), 574 isEnabled: true, 575 label: $r('app.string.ban'), 576 action: () => { 577 if (this.session !== undefined) { 578 this.session.terminateSelfWithResult({ 579 'resultCode': 1, 580 }); 581 } 582 } 583 } 584 ], 585 isSaveIconRequired: false, 586 onCancel: () => { 587 if (this.session !== undefined) { 588 this.session.terminateSelfWithResult({ 589 'resultCode': 0, 590 }); 591 } 592 }, 593 }) 594 .constraintSize({ minHeight: Constants.SHARE_TITLE_HEAD_HEIGHT }) 595 .margin({ 596 top: Constants.SHARE_TITLE_HEAD_MARGIN_TOP, 597 }) 598 Scroll() { 599 Column() { 600 Row() { 601 TextInput({ placeholder: this.placeHolderStr, text: this.inputValue }) 602 .id('phoneInput') 603 .padding({ 604 left: SystemUtils.isRTL() ? 605 Constants.SHARE_TEXT_INPUT_CONTENT_PADDING_RIGHT : Constants.SHARE_TEXT_INPUT_CONTENT_PADDING_LEFT, 606 right: SystemUtils.isRTL() ? 607 Constants.SHARE_TEXT_INPUT_CONTENT_PADDING_LEFT : Constants.SHARE_TEXT_INPUT_CONTENT_PADDING_RIGHT 608 }) 609 .enabled(this.enabledFocus) 610 .constraintSize({ minHeight: Constants.SHARE_TEXT_INPUT_HEIGHT }) 611 .focusable(this.isTextInputFocus) 612 .direction(Direction.Ltr) 613 .textAlign(SystemUtils.isRTL() ? TextAlign.End : TextAlign.Start) 614 .type(InputType.PhoneNumber) 615 .contentType(ContentType.PHONE_COUNTRY_CODE) 616 .enterKeyType(EnterKeyType.NEW_LINE) 617 .border(this.phoneFormatTips ? 618 { width: Constants.DIALOG_MD_OFFSET, color: $r('sys.color.ohos_id_color_warning') } : { width: 0 }) 619 .onChange((value: string) => { 620 HiLog.info(TAG, `input length: ${value.length}`); 621 this.inputValue = value; 622 this.phoneFormatTips = false; 623 this.isConfirmButtonEnabled = value.length > 0; 624 }) 625 if (this.contactExists) { 626 Column() { 627 SymbolGlyph($r('sys.symbol.person_2')) 628 .fontSize(`${Constants.SYMBOL_GLYPH_FONT_SIZE}vp`) 629 .fontColor(this.enabledFocus ? [$r('sys.color.icon_primary')] : [$r('sys.color.icon_tertiary')]) 630 } 631 .accessibilityText(this.contactPerson) 632 .enabled(this.enabledFocus) 633 .offset({ 634 x: SystemUtils.isRTL() 635 ? Constants.SHARE_CONTACTS_GROUP_OFFSET_X_RTL : Constants.SHARE_CONTACTS_GROUP_OFFSET_X, 636 y: Constants.SHARE_CONTACTS_GROUP_OFFSET_Y 637 }) 638 .onClick(this.contactsAction) 639 .bindSheet(this.isShowSheet, this.contactsPicker(), { 640 height: SheetSize.LARGE, 641 dragBar: false, 642 showClose: true, 643 onWillDisappear: () => { 644 this.isShowSheet = false; 645 }, 646 backgroundColor: Color.Transparent, 647 blurStyle: BlurStyle.COMPONENT_ULTRA_THICK 648 }) 649 } 650 } 651 652 Text(this.phoneFormatTips ? 653 this.credentialCallBackMsg : $r('app.string.Share_Enter_Mobile_Number', this.osVersion)) 654 .fontColor(this.phoneFormatTips ? 655 $r('sys.color.ohos_id_color_warning') : $r('sys.color.ohos_id_color_text_secondary')) 656 .fontSize($r('sys.float.ohos_id_text_size_body3')) 657 .fontWeight(FontWeight.Regular) 658 .margin({ top: Constants.ENCRYPTION_ADD_STAFF_BORDER_MARGIN_TOP }) 659 .backgroundColor(Color.Transparent) 660 .width(Constants.CONTACTS_PICKER_WIDTH) 661 .padding({ left: Constants.SHARE_TITLE_HEAD_PADDING_LEFT }) 662 } 663 .margin({ left: Constants.SHARE_TEXT_INPUT_MARGIN_LEFT, right: Constants.SHARE_TEXT_INPUT_MARGIN_RIGHT }) 664 } 665 .align(Alignment.TopStart) 666 .constraintSize({ 667 minHeight: `${this.scrollHeight}vp` 668 }) 669 .padding({ 670 top: Constants.SHARE_TITLE_HEAD_MARGIN_BOTTOM 671 }) 672 Column() { 673 Button($r('app.string.Share_Confirms'), { type: ButtonType.Capsule, stateEffect: true }) 674 .enabled(this.isConfirmButtonEnabled) 675 .backgroundColor($r('sys.color.ohos_id_color_text_primary_activated')) 676 .width(Constants.SHARE_BUTTON_WIDTH) 677 .controlSize(ControlSize.NORMAL) 678 .onClick(async () => { 679 this.beginShareEncrypt(); 680 }) 681 } 682 .justifyContent(FlexAlign.Center) 683 .margin({ 684 left: Constants.SHARE_BUTTON_MARGIN_LEFT, 685 right: Constants.SHARE_BUTTON_MARGIN_RIGHT, 686 bottom: Constants.SHARE_BUTTON_PADDING_BOTTOM 687 }) 688 .constraintSize({ 689 minHeight: `${Constants.SHARE_BUTTON_COLUMN_BOTTOM}vp` 690 }) 691 } 692 .width(Constants.SHARE_PAGES_COLUMN_WIDTH) 693 .height(Constants.SHARE_PAGES_COLUMN_HEIGHT) 694 if (this.showUIExtensionForAccountLogin) { 695 UIExtensionComponent({ 696 bundleName: 'com.huawei.hmos.dlpcredmgr', 697 abilityName: 'DlpCredAccountAbility', 698 parameters: { 699 'ability.want.params.uiExtensionType': 'sys/commonUI' 700 } 701 }) 702 .id('cloudAccountLoginUI') 703 .onRemoteReady(() => { 704 try { 705 HiLog.info(TAG, `cloudAccountLoginUI requestFocus start`); 706 this.getUIContext().getFocusController().requestFocus('cloudAccountLoginUI'); 707 } catch (error) { 708 HiLog.error(TAG, `requestFocus failed. Cause: ${JSON.stringify(error)}`) 709 } 710 }) 711 .onReceive((data) => { 712 HiLog.info(TAG, `data.status: ${JSON.stringify(data.status)}`); 713 let res = data.result as Record<string, string>; 714 HiLog.info(TAG, `res.code: ${JSON.stringify(res.code)}`); 715 if (data.status) { 716 this.ownerAccount = res?.uid; 717 this.ownerAccountID = res?.uid; 718 let checkCloudPhone = this.checkCloudPhone(this.inputValue); 719 HiLog.info(TAG, `checkCloudPhone: ${checkCloudPhone}`); 720 if (checkCloudPhone) { 721 this.enabledFocus = false; 722 this.isConfirmButtonEnabled = false; 723 this.connectService.connectServiceShareAbility(Constants.COMMAND_SEARCH_USER_INFO); 724 } 725 } else { 726 this.enabledFocus = true; 727 this.isConfirmButtonEnabled = this.inputValue.length > 0; 728 if (['12300001', '1001502005', '1001502009'].includes(res.code.toString())) { 729 this.showToast($r('app.string.network_invalid')); 730 } 731 } 732 this.isTextInputFocus = true; 733 this.textInputGetFocus(); 734 this.showUIExtensionForAccountLogin = false; 735 }) 736 .size({ 737 width: Constants.SHARE_PAGES_COLUMN_WIDTH, height: Constants.SHARE_PAGES_COLUMN_HEIGHT 738 }) 739 } 740 } 741 .onSizeChange((oldValue: SizeOptions, newValue: SizeOptions) => { 742 const newHeight = newValue.height as number; 743 const oldHeight = oldValue.height as number; 744 if (newHeight === oldHeight) { 745 return; 746 } 747 this.getScrollHeight(newValue); 748 }) 749 } 750}