Stay organized with collections Save and categorize content based on your preferences.

SplitController

public final class SplitController


The controller class that gets information about the currently active activity splits and provides interaction points to customize the splits and form new splits.

A split is a pair of containers that host activities in the same or different processes, combined under the same parent window of the hosting task.

A pair of activities can be put into a split by providing a static or runtime split rule and then launching the activities in the same task using Activity.startActivity().

Summary

Nested types

public static class SplitController.Companion

A class to determine if activity splits with Activity Embedding are currently available.

Public methods

final void
@ExperimentalWindowApi
addSplitListener(
    @NonNull Activity activity,
    @NonNull Executor executor,
    @NonNull Consumer<@NonNull List<@NonNull SplitInfo>> consumer
)

This method is deprecated. Replace to provide Flow API to get SplitInfo list

final void

Clears the callback previously set by setSplitAttributesCalculator.

static final @NonNull SplitController

Obtains an instance of SplitController.

final @NonNull SplitController.SplitSupportStatus

Indicates whether split functionality is supported on the device.

final boolean

Returns whether setSplitAttributesCalculator is supported or not.

final boolean

This method is deprecated. Use splitSupportStatus instead

final void

This method is deprecated. Replace to provide Flow API to get SplitInfo list

final void

Sets or replaces the previously registered SplitAttributes calculator.

final @NonNull Flow<@NonNull List<@NonNull SplitInfo>>

A Flow of SplitInfo list that contains the current split states that this activity is part of.

Public methods

addSplitListener

@ExperimentalWindowApi
public final void addSplitListener(
    @NonNull Activity activity,
    @NonNull Executor executor,
    @NonNull Consumer<@NonNull List<@NonNull SplitInfo>> consumer
)

Use splitInfoList for kotlin usages or delegate to androidx.window.java.embedding.SplitControllerCallbackAdapter.addSplitListener for Java usages.

clearSplitAttributesCalculator

@ExperimentalWindowApi
public final void clearSplitAttributesCalculator()

Clears the callback previously set by setSplitAttributesCalculator. The caller must make sure isSplitAttributesCalculatorSupported before invoking.

Throws
kotlin.UnsupportedOperationException kotlin.UnsupportedOperationException

if isSplitAttributesCalculatorSupported reports false

getInstance

public static final @NonNull SplitController getInstance(@NonNull Context context)

Obtains an instance of SplitController.

Parameters
@NonNull Context context

the Context to initialize the controller with

getSplitSupportStatus

public final @NonNull SplitController.SplitSupportStatus getSplitSupportStatus()

Indicates whether split functionality is supported on the device. Note that devices might not enable splits in all states or conditions. For example, a foldable device with multiple screens can choose to collapse splits when apps run on the device's small display, but enable splits when apps run on the device's large display. In cases like this, splitSupportStatus always returns SplitSupportStatus.SPLIT_AVAILABLE, and if the split is collapsed, activities are launched on top, following the non-activity embedding model.

Also the androidx.window.WindowProperties.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED must be enabled in AndroidManifest within in order to get the correct state or SplitSupportStatus.SPLIT_ERROR_PROPERTY_NOT_DECLARED will be returned in some cases.

isSplitAttributesCalculatorSupported

@ExperimentalWindowApi
public final boolean isSplitAttributesCalculatorSupported()

Returns whether setSplitAttributesCalculator is supported or not.

isSplitSupported

@ExperimentalWindowApi
public final boolean isSplitSupported()

Indicates whether split functionality is supported on the device. Note that devices might not enable splits in all states or conditions. For example, a foldable device with multiple screens can choose to collapse splits when apps run on the device's small display, but enable splits when apps run on the device's large display. In cases like this, isSplitSupported always returns true, and if the split is collapsed, activities are launched on top, following the non-activity embedding model.

Also the androidx.window.WindowProperties.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED must be enabled in AndroidManifest within in order to get the correct state or false will be returned by default.

removeSplitListener

@ExperimentalWindowApi
public final void removeSplitListener(
    @NonNull Consumer<@NonNull List<@NonNull SplitInfo>> consumer
)

Use splitInfoList for kotlin usages or delegate to androidx.window.java.embedding.SplitControllerCallbackAdapter.removeSplitListener for Java usages.

setSplitAttributesCalculator

@ExperimentalWindowApi
public final void setSplitAttributesCalculator(
    @NonNull Function1<@NonNull SplitAttributesCalculatorParams, @NonNull SplitAttributes> calculator
)

Sets or replaces the previously registered SplitAttributes calculator.

Note that it's callers' responsibility to check if this API is supported by calling isSplitAttributesCalculatorSupported before using the this API. It is suggested to always set meaningful SplitRule.defaultSplitAttributes in case this API is not supported on some devices.

Also, replacing the calculator will only update existing split pairs after a change in the window or device state, such as orientation changes or folding state changes.

The SplitAttributes calculator is a function to compute the current SplitAttributes for the given SplitRule with the current device and window state. Then The calculator will be invoked if either:

  • An activity is started and matches a registered SplitRule.

  • A parent configuration is updated and there's an existing split pair.

By default, SplitRule.defaultSplitAttributes are applied if the parent container's WindowMetrics satisfies the SplitRule's dimensions requirements, which are SplitRule.minWidthDp, SplitRule.minHeightDp and SplitRule.minSmallestWidthDp. The SplitRule.defaultSplitAttributes can be set by

Developers may want to apply different SplitAttributes for different device or window states. For example, on foldable devices, developers may want to split the screen vertically if the device is in landscape, fill the screen if the device is in portrait and split the screen horizontally if the device is in tabletop posture. In this case, the SplitAttributes can be customized by the SplitAttributes calculator, which takes effects after calling this API. Developers can also clear the calculator by clearSplitAttributesCalculator. Then, developers could implement the SplitAttributes calculator as the sample linked below shows.

SplitController.getInstance(context)
    .setSplitAttributesCalculator { params ->
        val tag = params.splitRuleTag
        val parentWindowMetrics = params.parentWindowMetrics
        val parentConfig = params.parentConfiguration
        val foldingFeatures = params.parentWindowLayoutInfo.displayFeatures
            .filterIsInstance<FoldingFeature>()
        val foldingState = if (foldingFeatures.size == 1) foldingFeatures[0] else null
        // Tag can be used to filter the SplitRule to apply the SplitAttributes
        if (TAG_SPLIT_RULE_MAIN != tag && params.areDefaultConstraintsSatisfied) {
            return@setSplitAttributesCalculator params.defaultSplitAttributes
        }

        // This sample will make the app show a layout to
        // - split the task bounds vertically if the device is in landscape
        // - fill the task bounds if the device is in portrait and its folding state does not
        //   split the screen
        // - split the task bounds horizontally in tabletop mode
        val bounds = parentWindowMetrics.bounds
        if (foldingState?.isSeparating == true) {
            // Split the parent container that followed by the hinge if the hinge separates the
            // parent window.
            return@setSplitAttributesCalculator SplitAttributes.Builder()
                .setSplitType(SPLIT_TYPE_HINGE)
                .setLayoutDirection(
                    if (foldingState.orientation == FoldingFeature.Orientation.HORIZONTAL) {
                        SplitAttributes.LayoutDirection.TOP_TO_BOTTOM
                    } else {
                        SplitAttributes.LayoutDirection.LOCALE
                    }
                )
                .build()
        }
        return@setSplitAttributesCalculator if (
            parentConfig.screenWidthDp >= 600 && bounds.width() >= bounds.height()
        ) {
            // Split the parent container equally and vertically if the device is in landscape.
            SplitAttributes.Builder()
                .setSplitType(SPLIT_TYPE_EQUAL)
                .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
                .build()
        } else {
            // Expand containers if the device is in portrait or the width is less than 600 dp.
            SplitAttributes.Builder()
                .setSplitType(SPLIT_TYPE_EXPAND)
                .build()
        }
    }
Parameters
@NonNull Function1<@NonNull SplitAttributesCalculatorParams, @NonNull SplitAttributes> calculator

the function to calculate SplitAttributes based on the SplitAttributesCalculatorParams. It will replace the previously set if it exists.

Throws
kotlin.UnsupportedOperationException kotlin.UnsupportedOperationException

if isSplitAttributesCalculatorSupported reports false

splitInfoList

public final @NonNull Flow<@NonNull List<@NonNull SplitInfo>> splitInfoList(@NonNull Activity activity)

A Flow of SplitInfo list that contains the current split states that this activity is part of.

An activity can be in zero, one or more active splits. More than one active split is possible if an activity created multiple containers to side, stacked on top of each other. Or it can be in two different splits at the same time - in a secondary container for one (it was launched to the side) and in the primary for another (it launched another activity to the side). The reported splits in the list are ordered from bottom to top by their z-order, more recent splits appearing later. Guaranteed to be called at least once to report the most recent state.

Parameters
@NonNull Activity activity

The Activity that is interested in getting the split states

Returns
@NonNull Flow<@NonNull List<@NonNull SplitInfo>>

a Flow of SplitInfo list that includes this activity