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