chromium/ash/webui/camera_app_ui/resources/js/app_window.ts

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {
  ErrorInfo,
  PerfEntry,
  PerfEvent,
  Resolution,
} from './type.js';
import {WaitableEvent} from './waitable_event.js';

const TOP_BAR_HEIGHT = 32;

const DEFAULT_WINDOW_WIDTH = 764;

/**
 * Gets default window size which minimizes the letterbox area for given preview
 * aspect ratio.
 *
 * @param aspectRatio Preview aspect ratio.
 */
export function getDefaultWindowSize(aspectRatio: number): Resolution {
  // For the call site from background.js cannot access letterbox space reserved
  // for controls on 3 sides around #preview-box directly from dom. The
  // letterbox size number is hard coded here.
  // TODO(b/172345161): Reference these number from left, right, bottom of
  // #preview-box's bounding client rect after background.js being removed.
  const bottom = 88;
  const left = 88;
  const right = 100;

  return new Resolution(
      DEFAULT_WINDOW_WIDTH,
      Math.round(
          (DEFAULT_WINDOW_WIDTH - (left + right)) / aspectRatio + bottom +
          TOP_BAR_HEIGHT));
}

/**
 * Class which is used to coordinate the setup of window between Tast side and
 * CCA side.
 */
export class AppWindow {
  /**
   * A waitable event which will resolve to the URL of the CCA instance just
   * launched.
   */
  private readonly readyOnCCASide = new WaitableEvent<string>();

  private readonly readyOnTastSide = new WaitableEvent();

  private readonly onClosed = new WaitableEvent();

  private inClosingItself = false;

  private readonly errors: ErrorInfo[] = [];

  private readonly perfs: PerfEntry[] = [];

  private readonly launchedTime = performance.now();

  /**
   * @param fromColdStart Whether this app is launched from a cold start. It is
   *     used for performance measurement.
   */
  constructor(private readonly fromColdStart: boolean) {}

  /**
   * Waits until the window is bound and returns the URL of the window.
   *
   * @return The URL of the window.
   */
  waitUntilWindowBound(): Promise<string> {
    return this.readyOnCCASide.wait();
  }

  /**
   * Binds the URL to the window.
   */
  bindUrl(url: string): void {
    this.readyOnCCASide.signal(url);
  }

  /**
   * Notifies the listener that the window setup is done on Tast side.
   */
  notifyReadyOnTastSide(): void {
    this.readyOnTastSide.signal();
  }

  /**
   * Waits until the setup for the window is done on Tast side.
   */
  waitUntilReadyOnTastSide(): Promise<void> {
    return this.readyOnTastSide.wait();
  }

  /**
   * Triggers when CCA is fully launched.
   */
  onAppLaunched(): void {
    const event = this.fromColdStart ?
        PerfEvent.LAUNCHING_FROM_LAUNCH_APP_COLD :
        PerfEvent.LAUNCHING_FROM_LAUNCH_APP_WARM;
    this.perfs.push({
      event: event,
      duration: (performance.now() - this.launchedTime),
      perfInfo: {},
    });
  }

  /**
   * Notifies the listener that the window is closed.
   */
  notifyClosed(): void {
    this.onClosed.signal();
  }

  /**
   * Waits until the window is closed.
   */
  waitUntilClosed(): Promise<void> {
    return this.onClosed.wait();
  }

  /**
   * Notifies the listener that the window is about to close itself.
   */
  notifyClosingItself(): void {
    this.inClosingItself = true;
  }

  /**
   * Check if it has received the signal that the window is about to close
   * itself.
   */
  isClosingItself(): boolean {
    return this.inClosingItself;
  }

  /**
   * Reports error and makes it visible on Tast side.
   */
  reportError(errorInfo: ErrorInfo): void {
    this.errors.push(errorInfo);
  }

  /**
   * Gets all the errors.
   */
  getErrors(): ErrorInfo[] {
    return this.errors;
  }

  /**
   * Reports perf information and makes it visible on Tast side.
   *
   * @param perfEntry Information of the perf event.
   */
  reportPerf(perfEntry: PerfEntry): void {
    this.perfs.push(perfEntry);
  }

  /**
   * Gets all the perf information.
   */
  getPerfs(): PerfEntry[] {
    return this.perfs;
  }
}