• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2023 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 abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
17import bundleManager from '@ohos.bundle.bundleManager';
18import rpc from '@ohos.rpc';
19import window from '@ohos.window';
20import common from '@ohos.app.ability.common';
21import pasteboard from '@ohos.pasteboard';
22import { BusinessError } from '@ohos.base';
23import { CustomContentDialog } from '@ohos.arkui.advanced.Dialog';
24import {
25  Log,
26  getPermissionGroup,
27  titleTrim,
28  getPermissionLabel,
29  getFontSizeScale,
30  supportPermission
31} from '../common/utils/utils';
32import { Permission, ButtonStatus } from '../common/model/definition';
33import { GroupInfo, WantInfo } from '../common/model/typedef';
34import { GlobalContext } from '../common/utils/globalContext';
35import Constants from '../common/utils/constant';
36import { showSubPermissionsGroup, buttonResource } from '../common/model/permissionGroup';
37import { LocationCanvas } from '../common/components/location';
38import { MeasureText } from '@kit.ArkUI';
39
40@Extend(Button)function customizeButton() {
41  .buttonStyle(ButtonStyleMode.TEXTUAL)
42  .fontColor($r('sys.color.font_emphasize'))
43  .width(Constants.HALF_LENGTH)
44}
45
46@Extend(Text)function titleText() {
47  .fontWeight(FontWeight.Bold)
48  .fontColor($r('sys.color.font_primary'))
49  .textAlign(TextAlign.Center)
50  .textOverflow({ overflow: TextOverflow.Ellipsis })
51  .maxLines(Constants.SECURITY_HEADER_MAX_LINES)
52}
53
54const fuzzyMarks = [Constants.LOCATION_FUZZY, Constants.LOCATION_BOTH_FUZZY, Constants.LOCATION_BOTH_PRECISE];
55const preciseMarks = [Constants.LOCATION_UPGRADE, Constants.LOCATION_BOTH_PRECISE];
56let storage = LocalStorage.getShared();
57
58@Entry(storage)
59@Component
60struct dialogPlusPage {
61  @LocalStorageLink('want') want: WantInfo = new WantInfo([]);
62  @LocalStorageLink('win') win: window.Window = {} as window.Window;
63  private context = getContext(this) as common.ServiceExtensionContext;
64  @State count: number = 0;
65  @State result: Array<number> = [];
66  @State accessTokenId: number = 0;
67  @State initStatus: number = Constants.INIT_NEED_TO_WAIT;
68  @State reqPerms: Array<Permission> = [];
69  @State grantGroups: Array<GroupInfo> = [];
70  @State userFixedFlag: number = 2; // means user fixed
71  @State grantStatus: number = -1;
72  @State appName: string = '';
73  @State locationFlag: number = Constants.LOCATION_NONE;
74  @State reqPermissionDetails: bundleManager.ReqPermissionDetail[] = [];
75  @State refresh: number = 0;
76  @State pasteBoardName: string = '';
77  @State isUpdate: number = -1;
78
79  dialogController: CustomDialogController | null = new CustomDialogController({
80    builder: CustomContentDialog({
81      contentBuilder: () => {
82        this.buildContent();
83      },
84      contentAreaPadding: { right: 0 }
85    }),
86    autoCancel: false
87  });
88
89  @Builder
90  DialogTitle() {
91    Row() {
92      Column() {
93        if (getFontSizeScale()) {
94          Text($r(this.showTitle(), this.appName))
95            .titleText()
96            .fontSize($r('sys.float.Title_S'))
97        } else {
98          Text($r(this.showTitle(), this.appName))
99            .titleText()
100            .minFontSize(Constants.TEXT_MIDDLE_FONT_SIZE)
101            .maxFontSize($r('sys.float.Title_S'))
102            .heightAdaptivePolicy(TextHeightAdaptivePolicy.MAX_LINES_FIRST)
103        }
104      }
105      .constraintSize({ minHeight: Constants.HEADLINE_HEIGHT })
106      .justifyContent(FlexAlign.Center)
107      .padding({
108        top: Constants.DEFAULT_PADDING_TOP,
109        bottom: Constants.DEFAULT_PADDING_BOTTOM,
110        left: Constants.PADDING_24,
111        right: Constants.PADDING_24
112      })
113    }
114  }
115
116  @Builder
117  buildContent(): void {
118    Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
119      Column() {
120        if ((this.initStatus != Constants.INIT_NEED_TO_WAIT) && this.verify()) {
121          Image(this.currentGroup().icon)
122            .width(Constants.DIALOG_ICON_WIDTH)
123            .height(Constants.DIALOG_ICON_HEIGHT)
124            .fillColor($r('sys.color.font_primary'))
125            .margin({ top: Constants.DIALOG_ICON_MARGIN_TOP })
126          if (this.grantGroups.length > 1) {
127            Text(`${this.count + 1} / ${this.grantGroups.length}`)
128              .fontSize(Constants.DIALOG_LABEL_FONT_SIZE)
129              .fontColor($r('sys.color.font_secondary'))
130              .lineHeight(Constants.DIALOG_LABEL_LINE_HEIGHT)
131              .margin({ top: Constants.DIALOG_LABEL_MARGIN_TOP })
132          }
133          Scroll() {
134            Column() {
135              this.DialogTitle();
136
137              Row() {
138                Flex({ justifyContent: FlexAlign.Center }) {
139                  Text() {
140                    if (
141                      this.currentGroup().name === 'LOCATION' &&
142                      ((this.locationFlag == Constants.LOCATION_FUZZY) ||
143                      (this.locationFlag == Constants.LOCATION_BOTH_FUZZY))
144                    ) {
145                      Span($r('app.string.close_exact_position'))
146                    } else if (this.currentGroup().name === 'PASTEBOARD') {
147                      if (this.pasteBoardName) {
148                        Span($r('app.string.pasteBoard_app', this.pasteBoardName))
149                      } else {
150                        Span($r('app.string.pasteBoard_desc'))
151                      }
152                    } else {
153                      if (this.currentGroup().description.length > 0) {
154                        ForEach(this.currentGroup().description, (item: ResourceStr) => {
155                          Span(item)
156                        })
157                        Span(this.currentGroup().reason ? $r('app.string.comma') : $r('app.string.period'))
158                      }
159                      Span(this.refresh >= 0 ? this.currentGroup().reason : '')
160                    }
161                  }
162                  .textAlign(TextAlign.Start)
163                  .fontColor($r('sys.color.font_primary'))
164                  .fontSize($r('sys.float.Body_L'))
165                  .maxFontScale(Constants.DIALOG_TEXT_MAX_SCALE)
166                  .margin({
167                    left: Constants.DIALOG_DESP_MARGIN_LEFT,
168                    right: Constants.DIALOG_DESP_MARGIN_RIGHT,
169                    bottom: Constants.DIALOG_DESP_MARGIN_BOTTOM
170                  })
171                }
172              }
173
174              if (this.locationFlag > Constants.LOCATION_NONE && this.currentGroup().name === 'LOCATION') {
175                LocationCanvas({ locationFlag: $locationFlag })
176              }
177            }
178          }.constraintSize({ maxHeight: Constants.MAXIMUM_HEADER_HEIGHT })
179          if (this.currentGroup().buttons.length <= 2 && this.calculateButtonWidth(this.currentGroup().buttons)) {
180            //横向布局
181            Row() {
182              Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
183                Button(buttonResource.get(this.currentGroup().buttons[0]))
184                  .customizeButton()
185                  .onClick(() => {
186                    this.clickHandle(this.currentGroup().buttons[0]);
187                  })
188                Divider()
189                  .color($r('sys.color.comp_divider'))
190                  .vertical(true)
191                  .strokeWidth(Constants.DIALOG_DIVIDER)
192                  .height(Constants.DIVIDER_HEIGHT)
193                  .opacity(0.2)
194                  .margin({ left: Constants.MARGIN_8, right: Constants.MARGIN_8 })
195                Button(buttonResource.get(this.currentGroup().buttons[1]))
196                  .customizeButton()
197                  .onClick(() => {
198                    this.clickHandle(this.currentGroup().buttons[1]);
199                  })
200              }.margin({
201                left: Constants.BUTTON_MARGIN_LEFT,
202                right: Constants.BUTTON_MARGIN_RIGHT,
203                bottom: Constants.MARGIN_8
204              })
205            }
206          } else {
207            //纵向布局
208            Column() {
209              ForEach(this.currentGroup().buttons, (buttonStatus: ButtonStatus, idx: number) => {
210                Button(buttonResource.get(buttonStatus))
211                  .customizeButton()
212                  .width(Constants.FULL_WIDTH)
213                  .margin({ bottom: idx + 1 < this.currentGroup().buttons.length ? Constants.MARGIN_4 : 0 })
214                  .onClick(() => {
215                    this.clickHandle(buttonStatus);
216                  })
217              })
218            }
219            .padding({ left: Constants.PADDING_16, right: Constants.PADDING_16 })
220          }
221        }
222      }
223      .padding({ bottom: Constants.PADDING_8 })
224      .clip(true)
225    }
226  }
227
228  build() {}
229
230  showTitle(): string {
231    let index = this.count >= this.grantGroups.length ? this.grantGroups.length - 1 : this.count;
232    if (this.grantGroups[index].name == 'LOCATION') {
233      if (this.locationFlag == Constants.LOCATION_FUZZY) {
234        return 'app.string.access_general_location';
235      }
236      if (this.locationFlag == Constants.LOCATION_UPGRADE) {
237        return 'app.string.fuzzy_to_exact';
238      }
239    }
240    return this.grantGroups[index].label;
241  }
242
243  currentGroup(): GroupInfo {
244    let index = this.count >= this.grantGroups.length ? this.grantGroups.length - 1 : this.count;
245    return this.grantGroups[index];
246  }
247
248  calculateButtonWidth(buttonStatus: ButtonStatus[]): boolean {
249    let denyText = buttonResource.get(buttonStatus[0]);
250    let allowText = buttonResource.get(buttonStatus[1]);
251    let maxButtonTextLength = Math.max(
252      MeasureText.measureText({ textContent: denyText }),
253      MeasureText.measureText({ textContent: allowText })
254    )
255
256    Log.info(`px2vp(maxButtonTextLength): ${px2vp(maxButtonTextLength)}`);
257    if (px2vp(maxButtonTextLength) > Constants.DIALOG_BUTTON_MAX_WIDTH) {
258      return false;
259    }
260
261    return true;
262  }
263
264  clickHandle(buttonStatus: ButtonStatus) {
265    switch (buttonStatus) {
266      case ButtonStatus.ALLOW:
267        this.privacyAccept(this.grantGroups[this.count], this.accessTokenId, this.reqPerms, this.userFixedFlag);
268        return;
269      case ButtonStatus.DENY:
270        this.privacyCancel(this.grantGroups[this.count], this.accessTokenId, this.reqPerms, this.userFixedFlag);
271        return;
272      case ButtonStatus.CANCEL:
273        this.count ++;
274        return;
275      case ButtonStatus.THIS_TIME_ONLY:
276        this.privacyAccept(
277          this.grantGroups[this.count], this.accessTokenId, this.reqPerms, Constants.PERMISSION_ALLOW_THIS_TIME
278        );
279        return;
280      case ButtonStatus.ALLOW_THIS_TIME:
281        this.privacyAccept(
282          this.grantGroups[this.count], this.accessTokenId, this.reqPerms, Constants.PERMISSION_ALLOW_THIS_TIME
283        );
284        return;
285      case ButtonStatus.ALLOW_ONLY_DURING_USE:
286        this.privacyAccept(this.grantGroups[this.count], this.accessTokenId, this.reqPerms, this.userFixedFlag);
287        return;
288    }
289  }
290
291  async privacyAccept(group: GroupInfo, accessTokenId: number, permissionList: string[], userFixedFlag: number) {
292    let num = 0;
293    group.permissions.forEach(async permission => {
294      this.grantStatus = -1;
295      if (showSubPermissionsGroup.indexOf(group.name) == -1) {
296        if (group.name == 'LOCATION') {
297          if (fuzzyMarks.includes(this.locationFlag) && permission === Permission.APPROXIMATELY_LOCATION) {
298            await this.operationPermission(true, accessTokenId, permission, userFixedFlag);
299          }
300          if (preciseMarks.includes(this.locationFlag) && permission === Permission.LOCATION) {
301            await this.operationPermission(true, accessTokenId, permission, userFixedFlag);
302          }
303        } else {
304          await this.operationPermission(true, accessTokenId, permission, userFixedFlag);
305        }
306      } else {
307        if (permissionList.includes(permission)) {
308          await this.operationPermission(true, accessTokenId, permission, userFixedFlag);
309        }
310      }
311      if (this.grantStatus == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
312        permissionList.forEach((req, idx) => {
313          if (req == permission) {
314            this.result[idx] = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
315          }
316        })
317      }
318      num ++;
319      if (num == group.permissions.length) {
320        this.count ++;
321      }
322    })
323  }
324
325  async privacyCancel(group: GroupInfo, accessTokenId: number, permissionList: string[], userFixedFlag: number) {
326    group.permissions.forEach(async permission => {
327      if (showSubPermissionsGroup.indexOf(group.name) == -1) {
328        await this.operationPermission(false, accessTokenId, permission, userFixedFlag);
329      } else {
330        if (permissionList.includes(permission)) {
331          await this.operationPermission(false, accessTokenId, permission, userFixedFlag);
332        }
333      }
334    })
335    this.count ++;
336  }
337
338  async operationPermission(status: boolean, token: number, permission: Permissions, flag: number) {
339    if (status) {
340      try {
341        Log.info('grantUserGrantedPermission: ' + permission);
342        await abilityAccessCtrl.createAtManager().grantUserGrantedPermission(token, permission, flag).then(() => {
343          this.grantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
344        })
345      } catch (err) {
346        Log.error('failed to grant permission: ' + permission);
347      }
348    } else {
349      try {
350        Log.info('revokeUserGrantedPermission: ' + permission)
351        await abilityAccessCtrl.createAtManager().revokeUserGrantedPermission(token, permission, flag);
352      } catch (err) {
353        Log.error('failed to revoke permission:' + permission);
354      }
355    }
356  }
357
358  aboutToAppear() {
359    this.count = 0;
360    this.initStatus = Constants.INIT_NEED_TO_WAIT;
361    this.result = [];
362    this.reqPerms = this.want.parameters['ohos.user.grant.permission'];
363    this.accessTokenId = this.want.parameters['ohos.aafwk.param.callerToken'];
364    if (this.reqPerms == undefined || this.accessTokenId == undefined || this.reqPerms.length == 0) {
365      Log.info('invalid parameters');
366      this.initStatus = Constants.INIT_NEED_TO_TERMINATED;
367      return;
368    }
369    Log.info(`request permission: ${JSON.stringify(this.reqPerms)}.`);
370    Log.info('permission state=' + JSON.stringify(this.want.parameters['ohos.user.grant.permission.state']));
371    this.result = new Array(this.reqPerms.length).fill(-1);
372    this.getPasteBoardInfo();
373    let bundleName: string = this.want.parameters['ohos.aafwk.param.callerBundleName'];
374    try {
375      bundleManager.getBundleInfo(bundleName, bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION)
376        .then(bundleInfo => {
377          this.reqPermissionDetails = bundleInfo.reqPermissionDetails;
378          this.getGrantGroups(this.want.parameters['ohos.user.grant.permission.state']);
379          this.getApplicationName(bundleName);
380          this.dialogController?.open();
381        }).catch((err: BusinessError) => {
382          Log.error('getBundleInfo error :' + JSON.stringify(err));
383          this.initStatus = Constants.INIT_NEED_TO_TERMINATED;
384        })
385    } catch (err) {
386      Log.error('getBundleInfo error :' + JSON.stringify(err));
387      this.initStatus = Constants.INIT_NEED_TO_TERMINATED;
388    }
389  }
390
391  aboutToDisappear() {
392    this.dialogController = null;
393  }
394
395  onPageShow() {
396    if (this.isUpdate > 0) {
397      this.getApplicationName(this.want.parameters['ohos.aafwk.param.callerBundleName'])
398    }
399    this.isUpdate ++;
400  }
401
402  getPasteBoardInfo() {
403    if (this.reqPerms.includes(Permission.READ_PASTEBOARD)) {
404      let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard();
405      this.pasteBoardName = systemPasteboard.getDataSource();
406    }
407  }
408
409  getGrantGroups(stateGroup: number[]) {
410    if (this.reqPerms.includes(Permission.APPROXIMATELY_LOCATION)) {
411      this.locationFlag = Constants.LOCATION_FUZZY;
412      if (this.reqPerms.includes(Permission.LOCATION)) {
413        this.locationFlag = Constants.LOCATION_BOTH_PRECISE;
414        let fuzzyIndex = this.reqPerms.indexOf(Permission.APPROXIMATELY_LOCATION);
415        if (stateGroup[fuzzyIndex] == Constants.PASS_OPER) {
416          this.locationFlag = Constants.LOCATION_UPGRADE;
417        }
418      }
419    } else if (this.reqPerms.includes(Permission.LOCATION)) {
420      this.locationFlag = Constants.LOCATION_UPGRADE;
421    }
422
423    this.reqPerms.forEach(async (permission, idx) => {
424      if (permission === Permission.APP_TRACKING_CONSENT) {
425        let toggleStatus = await this.appTrackHandle(idx);
426        if (toggleStatus === abilityAccessCtrl.PermissionRequestToggleStatus.CLOSED) {
427          return;
428        }
429      }
430      if (stateGroup[idx] == Constants.PASS_OPER) {
431        Log.info('permission has been fixed:' + permission);
432        this.result[idx] = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
433      } else if (stateGroup[idx] == Constants.DYNAMIC_OPER) {
434        let supportPermissions = supportPermission();
435        if (!supportPermissions.includes(permission)) {
436          Log.info('The permission does not exist or is not supported by the current device: ' + permission);
437        } else {
438          this.addGroup(permission);
439        }
440      }
441    })
442    this.initStatus = Constants.INIT_NEED_TO_VERIFY;
443  }
444
445  async appTrackHandle(index: number): Promise<abilityAccessCtrl.PermissionRequestToggleStatus> {
446    try {
447      let acManager = abilityAccessCtrl.createAtManager();
448      let toggleStatus = await acManager.getPermissionRequestToggleStatus(Permission.APP_TRACKING_CONSENT);
449      Log.info(`APP_TRACKING_CONSENT toggleStatus: ${toggleStatus}.`);
450      if (toggleStatus === abilityAccessCtrl.PermissionRequestToggleStatus.CLOSED) {
451        await acManager.grantUserGrantedPermission(
452          this.accessTokenId, Permission.APP_TRACKING_CONSENT, this.userFixedFlag
453        );
454        this.result[index] = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
455        Log.info('APP_TRACKING_CONSENT grant success.');
456      }
457      return toggleStatus;
458    } catch (err) {
459      Log.error(`APP_TRACKING_CONSENT getToggleStatus or grant fail: ${JSON.stringify(err)}`);
460      return abilityAccessCtrl.PermissionRequestToggleStatus.OPEN;
461    }
462  }
463
464  addGroup(permission: Permission) {
465    let group = getPermissionGroup(permission);
466    if (group.name === 'FOLDER') {
467      switch (permission) {
468        case Permission.READ_WRITE_DOWNLOAD_DIRECTORY:
469          let downloadGroup = new GroupInfo(
470            group.name, group.groupName, 'app.string.group_label_download_folder', group.icon, group.description,
471            group.reason, [Permission.READ_WRITE_DOWNLOAD_DIRECTORY], group.buttons, group.isShow
472          )
473          this.grantGroups.push(downloadGroup);
474          break;
475        case Permission.READ_WRITE_DESKTOP_DIRECTORY:
476          let desktopGroup = new GroupInfo(
477            group.name, group.groupName, 'app.string.group_label_desktop_folder', group.icon, group.description,
478            group.reason, [Permission.READ_WRITE_DESKTOP_DIRECTORY], group.buttons, group.isShow
479          )
480          this.grantGroups.push(desktopGroup);
481          break;
482        case Permission.READ_WRITE_DOCUMENTS_DIRECTORY:
483          let documentGroup = new GroupInfo(
484            group.name, group.groupName, 'app.string.group_label_document_folder', group.icon, group.description,
485            group.reason, [Permission.READ_WRITE_DOCUMENTS_DIRECTORY], group.buttons, group.isShow
486          )
487          this.grantGroups.push(documentGroup);
488          break;
489      }
490      return
491    }
492    let exist = this.grantGroups.find(grantGroup => grantGroup.name == group.name);
493    if (showSubPermissionsGroup.indexOf(group.name) != -1) {
494      let label = getPermissionLabel(permission)
495      if (!exist) {
496        group.description.push(label);
497        this.grantGroups.push(group);
498      } else {
499        if (exist.description.indexOf(label) == -1) {
500          exist.description.push($r('app.string.and'));
501          exist.description.push(label);
502        }
503      }
504    } else {
505      if (!exist) {
506        this.grantGroups.push(group);
507      }
508    }
509  }
510
511  getApplicationName(bundleName: string) {
512    Log.info('getApplicationName bundleName:' + bundleName);
513    bundleManager.getApplicationInfo(bundleName, bundleManager.ApplicationFlag.GET_APPLICATION_INFO_DEFAULT)
514    .then(applicationInfo => {
515      let context = this.context.createBundleContext(bundleName);
516      context.resourceManager.getStringValue(applicationInfo.labelId, (err, value) => {
517        if (value == undefined) {
518          this.appName = titleTrim(applicationInfo.label);
519        } else {
520          this.appName = titleTrim(value);
521        }
522        Log.info('hap label:' + applicationInfo.label + ', value:' + this.appName);
523      })
524    }).catch((err: BusinessError) => {
525      Log.error('applicationInfo error :' + err);
526      this.initStatus = Constants.INIT_NEED_TO_TERMINATED;
527    })
528    this.grantGroups.forEach((group) => {
529      group.reason = '';
530      this.getReason(group, bundleName);
531    })
532  }
533
534  getReason(group: GroupInfo, bundleName: string) {
535    group.permissions.forEach(permission => {
536      if (this.reqPerms.indexOf(permission) != -1) {
537        this.reqPermissionDetails.forEach(reqPermissionDetail => {
538          if (reqPermissionDetail.name == permission) {
539            Log.info('reqPermissionDetail: ' + JSON.stringify(reqPermissionDetail));
540            let context = this.context.createModuleContext(bundleName, reqPermissionDetail.moduleName);
541            context.resourceManager.getStringValue(reqPermissionDetail.reasonId, (err, value) => {
542              if (value !== undefined && group.reason === '') {
543                group.reason = value.slice(Constants.START_SUBSCRIPT, Constants.END_SUBSCRIPT);
544                this.refresh ++;
545              }
546              this.initStatus = Constants.INIT_NEED_TO_REFRESH;
547            })
548          }
549        })
550      }
551    })
552  }
553
554  verify() {
555    if ((this.initStatus == Constants.INIT_NEED_TO_TERMINATED) || (this.count >= this.grantGroups.length)) {
556      this.answerRequest();
557      this.initStatus = Constants.INIT_NEED_TO_WAIT;
558      return false;
559    }
560    return true;
561  }
562
563  answerRequest() {
564    let ret: number = Constants.RESULT_SUCCESS;
565    if (this.initStatus == Constants.INIT_NEED_TO_TERMINATED) {
566      ret = Constants.RESULT_FAILURE;
567    }
568    this.answer(ret, this.reqPerms);
569  }
570
571  answer(ret: number, reqPerms: string[]) {
572    Log.info('code:' + ret + ', perms=' + JSON.stringify(reqPerms) + ', result=' + JSON.stringify(this.result));
573    let perms: string[] = [];
574    let results: number[] = [];
575    reqPerms.forEach(perm => {
576      perms.push(perm);
577    })
578    this.result.forEach(result => {
579      results.push(result);
580    })
581    let option = new rpc.MessageOption();
582    let data = new rpc.MessageSequence();
583    let setDialogData = new rpc.MessageSequence();
584    let reply = new rpc.MessageSequence();
585    Promise.all([
586      data.writeInterfaceToken(Constants.ACCESS_TOKEN),
587      data.writeStringArray(perms),
588      data.writeIntArray(results),
589      setDialogData.writeInterfaceToken(Constants.ACCESS_TOKEN),
590    ]).then(() => {
591      let proxy = this.want.parameters['ohos.ability.params.callback'].value as rpc.RemoteObject;
592      proxy.sendMessageRequest(Constants.RESULT_CODE, data, reply, option);
593      proxy.sendMessageRequest(Constants.RESULT_CODE_1, setDialogData, reply, option);
594    }).catch(() => {
595      Log.error('write result failed!');
596    }).finally(() => {
597      data.reclaim();
598      reply.reclaim();
599      setDialogData.reclaim();
600      this.destruction();
601    })
602  }
603
604  destruction() {
605    let windowNum: number = GlobalContext.load('windowNum');
606    windowNum --;
607    Log.info('windowNum:' + windowNum);
608    GlobalContext.store('windowNum', windowNum);
609    this.win.destroyWindow();
610    if (windowNum == 0) {
611      this.context.terminateSelf();
612    }
613  }
614}