如何完成挖孔屏的适配
==========

1.  使用setWindowLayoutFullScreen和setWindowSystemBarEnable将窗口设置为全屏并隐藏顶部状态栏。
    
    onWindowStageCreate(windowStage: window.WindowStage): void {
      AppStorage.setOrCreate('context', this.context);
      windowStage.getMainWindow((err: BusinessError, window: window.Window) => {
       _ // The settings window is displayed in full screen_
        window.setWindowLayoutFullScreen(true)
          .then(() => {
            console.info('Succeeded in setting the window layout to full-screen mode.');
          }).catch((err: BusinessError) => {
          console.error(\`Failed to set the window layout to full-screen mode. Cause code: ${err.code}, message: ${err.message}\`);
        });
     _   // Set the top status bar to be hidden_
        let names: Array<'status' | 'navigation'> = \[\];
        window.setWindowSystemBarEnable(names)
          .then(() => {
            console.info('Succeeded in setting the system bar to be invisible.');
          }).catch((err: BusinessError) => {
          console.error(\`Failed to set the system bar to be invisible. Cause code: ${err.code}, message: ${err.message}\`);
        });
      })
      _// ..._
    }
    
2.  使用getDefaultDisplaySync获取同步display对象，再通过其异步方法getCutoutInfo回调获取挖孔区域信息，然后根据这些信息计算偏移量，实现对不可用区域的适配。
    
    import { display, window } from '@kit.ArkUI';
    import { common } from '@kit.AbilityKit';
    import { BusinessError, batteryInfo } from '@kit.BasicServicesKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    
    class TextMargin {
      left: number = 0; _// Status bar left offset_
      right: number = 0; _// Status bar right offset_
    }
    
    @Entry
    @Component
    struct Index {
      @State date: Date = new Date();
      @State currentTime: string = ''; _// Top status bar time_
      @State boundingRect: display.Rect\[\] = \[\]; _// Unavailable area data_
      @State screenWidth: number = 0; _// Screen width_
      @State displayClass: display.Display | null = null;
      @State topTextMargin: TextMargin = { left: 0, right: 0 }; _// Top status bar offset_
      @StorageLink('context') context: common.UIAbilityContext | undefined = AppStorage.get('context'); _// Get UIAbilityContext_
    
      aboutToAppear(): void {
        try {
          this.displayClass = display.getDefaultDisplaySync();
          display.getDefaultDisplaySync().getCutoutInfo((err, data) => {
            if (err.code) {
              console.log('getCutoutInfo failed. error is:', JSON.stringify(err));
              return;
            }
            this.boundingRect = data.boundingRects;
            this.topTextMargin = this.getBoundingRectPosition();
          })
        } catch (error) {
          let err = error as BusinessError;
          hilog.error(0x000, 'testTag', \`err.code=${err.code}, err.message=${err.message}\`);
        }
     _   // Get hour_
        let hours = this.date.getHours();
       _ // Get minute_
        let minutes = this.date.getMinutes();
      _  // Add 0 before minute if less than 10_
        this.currentTime = hours.toString() + ':' + (minutes < 10 ? '0' + minutes : minutes.toString());
      }
    
      _// Reset window to initial state when leaving the page_
      aboutToDisappear() {
        if (this.context !== undefined) {
          window.getLastWindow(this.context, async (err, data) => {
            if (err.code) {
              console.log('getLastWindow failed. error is:', JSON.stringify(err));
              return;
            }
            data.setWindowSystemBarEnable(\['status', 'navigation'\])
              .then(() => {
                hilog.info(0x000, 'testTag', \`setWindowSystemBarEnable succeed.\`);
              })
              .catch((err: BusinessError) => {
                hilog.error(0x000, 'testTag',
                  \`setWindowSystemBarEnable failed. err.code=${err.code}, err.message=${err.message}\`);
              })
            data.setWindowLayoutFullScreen(false)
              .then(() => {
                hilog.info(0x000, 'testTag', \`setWindowLayoutFullScreen succeed.\`);
              })
              .catch((err: BusinessError) => {
                hilog.error(0x000, 'testTag',
                  \`setWindowLayoutFullScreen failed. err.code=${err.code}, err.message=${err.message}\`);
              })
          })
        }
      }
    
      _/\*\*_
       _\* Calculate the left and right margins of the unusable areas of the punch hole screen_
       _\* @returns {TextMargin} Objects that include left/right offsets_
       _\*/_
      getBoundingRectPosition(): TextMargin {
        if (this.boundingRect !== null && this.displayClass !== null && this.boundingRect\[0\] !== undefined) {
          _// Distance from the right of the unavailable area to the right edge of the screen: screen width minus left width and unavailable area width_
          let boundingRectRight: number =
            this.displayClass.width - (this.boundingRect\[0\].left + this.boundingRect\[0\].width);
         _ // Distance from the left of the unavailable area to the left edge of the screen: can be obtained directly by getCutoutInfo_
          let boundingRectLeft: number = this.boundingRect\[0\].left;
         _ // For some devices, if the unavailable area is in the middle, the difference between the left and right distances is less than 10 pixels, treat it as being in the middle_
          if (Math.abs(boundingRectLeft - boundingRectRight) <= 10) {
            return { left: 0, right: 0 };
          }
          if (boundingRectLeft > boundingRectRight) {
           _ // Unavailable area on the right_
            return { left: 0, right: this.displayClass.width - boundingRectLeft };
          } else if (boundingRectLeft < boundingRectRight) {
           _ // Unavailable area on the left_
            return { left: this.boundingRect\[0\].left + this.boundingRect\[0\].width, right: 0 };
          }
        }
        return { left: 0, right: 0 };
      }
    
      build() {
        Stack() {
          Image($r('app.media.digging\_hole\_screen\_2048game'))
            .objectFit(ImageFit.Fill)
            .width('100%')
            .height('100%')
            .onClick(() => {
              try {
                this.getUIContext().getPromptAction().showToast({
                  message: 'This function is not yet developed',
                  duration: 2000
                })
              } catch (error) {
                let err = error as BusinessError;
                hilog.error(0x000, 'testTag', \`showToast failed. err.code=${err.code}, err.message=${err.message}\`);
              }
            })
          Column() {
            Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween }) {
              Text(this.currentTime) _// Time_
                .fontSize(16)
                .fontColor(Color.Black)
                .fontWeight(FontWeight.Regular)
                .padding({ left: 12 })
                .margin({
                  left: this.getUIContext().px2vp(this.topTextMargin.left),
                  top: 14
                }) _// The obtained offset is in px and needs to be converted_
              Text(batteryInfo.batterySOC.toString() + '%')_// Battery level_
                .fontSize(16)
                .fontColor(Color.Black)
                .fontWeight(FontWeight.Regular)
                .padding({ right: 16 })
                .margin({
                  right: this.getUIContext().px2vp(this.topTextMargin.right),
                  top: 14
                }) _// The obtained offset is in px and needs to be converted_
            }
            .width('100%')
          }
          .width('100%')
        }
        .width('100%')
        .height('100%')
        .alignContent(Alignment.TopStart)
      }
    }