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