Skip to main content
Picture-in-Picture (PiP) mode allows users to continue their call in a floating window while using other apps. This feature requires platform-specific configuration.

Enable Picture-in-Picture

Enable PiP mode programmatically:
import { CometChatCalls } from '@cometchat/calls-sdk-react-native';

CometChatCalls.enablePictureInPictureLayout();

Disable Picture-in-Picture

Exit PiP mode and return to full-screen:
CometChatCalls.disablePictureInPictureLayout();

Listen for PiP Events

CometChatCalls.addEventListener('onPictureInPictureLayoutEnabled', () => {
  console.log('PiP mode enabled');
});

CometChatCalls.addEventListener('onPictureInPictureLayoutDisabled', () => {
  console.log('PiP mode disabled');
});

iOS Configuration

Enable Background Modes

  1. Open your project in Xcode
  2. Select your target and go to Signing & Capabilities
  3. Add Background Modes capability
  4. Enable Audio, AirPlay, and Picture in Picture

Info.plist

No additional Info.plist entries are required for PiP on iOS.

Automatic PiP

iOS automatically enters PiP mode when:
  • The user presses the home button during a video call
  • The user swipes up to go to the app switcher

Android Configuration

Enable PiP Support

Add PiP support to your main activity in AndroidManifest.xml:
<activity
    android:name=".MainActivity"
    android:supportsPictureInPicture="true"
    android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
    <!-- ... -->
</activity>

Minimum SDK

PiP requires Android 8.0 (API level 26) or higher. Add to your build.gradle:
android {
    defaultConfig {
        minSdkVersion 26
    }
}

Handle PiP Mode Changes

In your React Native activity, handle PiP mode changes:
// MainActivity.java
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
    super.onPictureInPictureModeChanged(isInPictureInPictureMode);
    // Notify React Native about PiP state change
}

Complete Example

import React, { useState, useEffect } from 'react';
import { View, TouchableOpacity, Text, StyleSheet, AppState, Platform } from 'react-native';
import { CometChatCalls } from '@cometchat/calls-sdk-react-native';

function PictureInPictureControls() {
  const [isPiPEnabled, setIsPiPEnabled] = useState(false);
  const [appState, setAppState] = useState(AppState.currentState);

  useEffect(() => {
    const unsubscribeEnabled = CometChatCalls.addEventListener(
      'onPictureInPictureLayoutEnabled',
      () => {
        setIsPiPEnabled(true);
      }
    );

    const unsubscribeDisabled = CometChatCalls.addEventListener(
      'onPictureInPictureLayoutDisabled',
      () => {
        setIsPiPEnabled(false);
      }
    );

    // Listen for app state changes
    const subscription = AppState.addEventListener('change', (nextAppState) => {
      if (appState.match(/active/) && nextAppState === 'background') {
        // App going to background - enable PiP
        CometChatCalls.enablePictureInPictureLayout();
      }
      setAppState(nextAppState);
    });

    return () => {
      unsubscribeEnabled();
      unsubscribeDisabled();
      subscription.remove();
    };
  }, [appState]);

  const togglePiP = () => {
    if (isPiPEnabled) {
      CometChatCalls.disablePictureInPictureLayout();
    } else {
      CometChatCalls.enablePictureInPictureLayout();
    }
  };

  return (
    <TouchableOpacity
      style={[styles.button, isPiPEnabled && styles.activeButton]}
      onPress={togglePiP}
    >
      <Text style={styles.buttonText}>
        {isPiPEnabled ? 'Exit PiP' : 'Enter PiP'}
      </Text>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  button: {
    backgroundColor: '#333',
    paddingHorizontal: 16,
    paddingVertical: 12,
    borderRadius: 8,
  },
  activeButton: {
    backgroundColor: '#6851D6',
  },
  buttonText: {
    color: '#fff',
    fontSize: 14,
    fontWeight: '600',
  },
});

export default PictureInPictureControls;

Auto-Enable PiP on Background

Automatically enable PiP when the app goes to background:
import { useEffect, useRef } from 'react';
import { AppState, AppStateStatus } from 'react-native';
import { CometChatCalls } from '@cometchat/calls-sdk-react-native';

function useAutoPiP(enabled: boolean = true) {
  const appState = useRef(AppState.currentState);

  useEffect(() => {
    if (!enabled) return;

    const subscription = AppState.addEventListener(
      'change',
      (nextAppState: AppStateStatus) => {
        if (
          appState.current.match(/active/) &&
          nextAppState === 'background'
        ) {
          CometChatCalls.enablePictureInPictureLayout();
        } else if (
          appState.current === 'background' &&
          nextAppState === 'active'
        ) {
          CometChatCalls.disablePictureInPictureLayout();
        }
        appState.current = nextAppState;
      }
    );

    return () => {
      subscription.remove();
    };
  }, [enabled]);
}

export default useAutoPiP;

Platform Considerations

iOS

  • PiP is available on iOS 14.0 and later
  • Works automatically when the app enters background
  • User can resize and move the PiP window

Android

  • PiP requires Android 8.0 (API level 26) or higher
  • Must be explicitly enabled in the manifest
  • PiP window has fixed aspect ratio