目录

Extended Screen Casting Development

This topic describes how to obtain the casting device information after the system image casting to implement casting in extended screen mode and dual-screen collaboration.

Working Principles

Restrictions

Carry out the development only when the following conditions are met:

Available APIs

Read the API reference to obtain the detailed API description.

API Description
getAllCastDisplays(): Promise<Array<CastDisplayInfo>>; Obtains all devices that support extended screen casting in the current system.
on(type: 'castDisplayChange', callback: Callback<CastDisplayInfo>): void; Subscribes to cast display change events in the case of extended screen casting.
off(type: 'castDisplayChange', callback?: Callback<CastDisplayInfo>): void; Unsubscribes from cast display change events in the case of extended screen casting.

How to Develop

  1. UIAbility A creates an AVSession, obtains an available device that supports extended screen casting, and registers a listener.

    The obtained CastDisplayInfo contains the screen ID, name, state, resolution, width, and height. The screen ID is the same as the Display ID. For details, see Obtaining Device Information.

    import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
    import { avSession } from '@kit.AVSessionKit'; // Import the AVSession module.
    import { BusinessError } from '@kit.BasicServicesKit';
    
    export default class AbilityA extends UIAbility{
      private session: avSession.AVSession | undefined = undefined;
      private extCastDisplayInfo: avSession.CastDisplayInfo | undefined = undefined;
      // Register a callback to listen for cast device changes.
      private onCastDisplayChangedCallback = (castDisplayInfo: avSession.CastDisplayInfo) => {
        // Add an extended screen and access it.
        if (this.extCastDisplayInfo === undefined && castDisplayInfo.state === avSession.CastDisplayState.STATE_ON) {
          console.info('Succeeded in opening the cast display');
          this.extCastDisplayInfo = castDisplayInfo;
          this.startExternalDisplay();
        } else if (this.extCastDisplayInfo?.id == castDisplayInfo.id) {
          this.extCastDisplayInfo = castDisplayInfo;
          // When the extended screen is unavailable, exit the extended screen.
          if (castDisplayInfo.state === avSession.CastDisplayState.STATE_OFF){
            console.info('Succeeded in closing the cast display');
            this.stopExternalDisplay();
            this.extCastDisplayInfo = undefined;
          }
        }
      };
    
      // Create an AVSession, obtain an available device that supports extended screen casting, and register a listener.
      initAVSession(context: Context) {
        avSession.createAVSession(context, 'CastDisplay', 'video').then((session: avSession.AVSession) => {
          this.session = session;
          this.session?.on('castDisplayChange', this.onCastDisplayChangedCallback);
    
          // Obtain the available devices that support extended screen casting in the current system.
          session.getAllCastDisplays().then((infoArr: avSession.CastDisplayInfo[]) => {
            // If there are multiple extended screens, you can select one of them.
            if (infoArr.length > 0) {
              this.extCastDisplayInfo = infoArr[0];
              this.startExternalDisplay();
            }
          }).catch((err: BusinessError<void>) => {
            console.error(`Failed to get all CastDisplay. Code: ${err.code}, message: ${err.message}`);
          });
        });
      }
    
      async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
        super.onCreate(want, launchParam);
        this.initAVSession(this.context);
      }
    
      onDestroy() {
        this.stopExternalDisplay();
        // Deregister the listener.
        this.session?.off('castDisplayChange');
      }
    }
  2. Build the extended screen startup and exit capabilities in UIAbility A.

    // Start UIAbility B on the extended screen.
      startExternalDisplay() {
        if (this.extCastDisplayInfo !== undefined &&
          this.extCastDisplayInfo.id !== 0 &&
          this.extCastDisplayInfo.state === avSession.CastDisplayState.STATE_ON) {
          let id = this.extCastDisplayInfo?.id;
          console.info(`Succeeded in starting ability and the id of display is ${id}`);
          this.context.startAbility({
            bundleName: 'com.example.myapplication',// Bundle name of the application.
            abilityName: 'AbilityB'
          }, {
            displayId: id // Extended screen ID.
          });
          AppStorage.setOrCreate('CastDisplayState', 1);
        }
      }
    
      // Stop using the extended screen.
      stopExternalDisplay() {
        AppStorage.setOrCreate('CastDisplayState', 0);
        // Update the content displayed on the current UI.
      }
  3. Draw the content of UIAbility B on the extended screen, and respond to exit events.

    import { UIAbility } from '@kit.AbilityKit';
    import { window } from '@kit.ArkUI';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    export default class AbilityB extends UIAbility {
      onWindowStageCreate(windowStage: window.WindowStage): void {
        // Main window is created, set main page for this ability
        windowStage.getMainWindowSync().setWindowLayoutFullScreen(true);// Set the layout to full screen.
        windowStage.loadContent('pages/CastPage', (err: BusinessError) => {
          if (err.code) {
            console.error(`Failed to load the content. Code: ${err.code}, message: ${err.message}`);
            return;
          }
          console.info('Succeeded in loading the content. ');
        });
      }
    }
    import { BusinessError } from '@kit.BasicServicesKit';
    import { common } from '@kit.AbilityKit';
    
    @Entry
    @Component
    struct CastPage {
      // After a CastDisplayState change is detected, destroy the page when the device is disconnected.
      @StorageLink('CastDisplayState') @Watch('onDestroyExtend') private displayState: number = 1;
    
      private onDestroyExtend() {
        if (this.displayState === 1) return;
        let context = (getContext(this) as common.UIAbilityContext)
        context.terminateSelf().then(() => {
          console.info('CastPage finished');
        }).catch((err: BusinessError) => {
          console.error(`Failed to destroying CastPage. Code: ${err.code}, message: ${err.message}`);
        });
      }
      //...
    }