chromium/third_party/android_sdk/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java

/*
 * Copyright 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.window.extensions.area;

import android.app.Activity;
import android.util.DisplayMetrics;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.window.extensions.WindowExtensions;
import androidx.window.extensions.core.util.function.Consumer;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * The interface definition that will be used by the WindowManager library to get custom
 * OEM-provided behavior around moving windows between displays or display areas on a device.
 *
 * Currently the only behavior supported is RearDisplay Mode, where the window
 * is moved to the display that faces the same direction as the rear camera.
 *
 * <p>This interface should be implemented by OEM and deployed to the target devices.
 * @see WindowExtensions#getWindowLayoutComponent()
 */
public interface WindowAreaComponent {

    /**
     * WindowArea status constant to signify that the feature is
     * unsupported on this device. Could be due to the device not supporting that
     * specific feature.
     *
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
     */
    int STATUS_UNSUPPORTED = 0;

    /**
     * WindowArea status constant to signify that the feature is
     * currently unavailable but is supported on this device. This value could signify
     * that the current device state does not support the specific feature or another
     * process is currently enabled in that feature.
     *
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
     */
    int STATUS_UNAVAILABLE = 1;

    /**
     * WindowArea status constant to signify that the feature is
     * available to be entered or enabled.
     *
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
     */
    int STATUS_AVAILABLE = 2;

    /**
     * WindowArea status constant to signify that the feature is
     * already enabled.
     *
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
     */
    int STATUS_ACTIVE = 3;

    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @Retention(RetentionPolicy.SOURCE)
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    @IntDef({
            STATUS_UNSUPPORTED,
            STATUS_UNAVAILABLE,
            STATUS_AVAILABLE,
            STATUS_ACTIVE
    })
    @interface WindowAreaStatus {}

    /**
     * Session state constant to represent there being no active session
     * currently in progress. Used by the library to call the correct callbacks if
     * a session is ended.
     */
    int SESSION_STATE_INACTIVE = 0;

    /**
     * Session state constant to represent that there is currently an active session. The library
     * uses this state to know when a session is created and active. Note that this state is
     * different from SESSION_STATE_CONTENT_VISIBLE, because the presentation content in this state
     * is not visible.
     */
    int SESSION_STATE_ACTIVE = 1;

    /**
     * Session state constant to represent that there is an
     * active presentation session currently in progress, and the content provided by the
     * application is visible.
     */
    int SESSION_STATE_CONTENT_VISIBLE = 2;

    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @Retention(RetentionPolicy.SOURCE)
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    @IntDef({
            SESSION_STATE_ACTIVE,
            SESSION_STATE_INACTIVE,
            SESSION_STATE_CONTENT_VISIBLE
    })
    @interface WindowAreaSessionState {}

    /**
     * Adds a listener interested in receiving updates on the RearDisplayStatus
     * of the device. Because this is being called from the OEM provided
     * extensions, the library will post the result of the listener on the executor
     * provided by the developer.
     *
     * The listener provided will receive values that
     * correspond to the [WindowAreaStatus] value that aligns with the current status
     * of the rear display.
     * @param consumer interested in receiving updates to WindowAreaStatus.
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
     */
    void addRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);

    /**
     * Removes a listener no longer interested in receiving updates.
     * @param consumer no longer interested in receiving updates to WindowAreaStatus
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
     */
    void removeRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);

    /**
     * Creates and starts a rear display session and sends state updates to the
     * consumer provided. This consumer will receive a constant represented by
     * [WindowAreaSessionState] to represent the state of the current rear display
     * session. We will translate to a more friendly interface in the library.
     *
     * Because this is being called from the OEM provided extensions, the library
     * will post the result of the listener on the executor provided by the developer.
     *
     * @param activity to allow that the OEM implementation will use as a base
     * context and to identify the source display area of the request.
     * The reference to the activity instance must not be stored in the OEM
     * implementation to prevent memory leaks.
     * @param consumer to provide updates to the client on the status of the session
     * @throws UnsupportedOperationException if this method is called when RearDisplay
     * mode is not available. This could be to an incompatible device state or when
     * another process is currently in this mode.
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
     */
    @SuppressWarnings("ExecutorRegistration") // Jetpack will post it on the app-provided executor.
    void startRearDisplaySession(@NonNull Activity activity,
            @NonNull Consumer<@WindowAreaSessionState Integer> consumer);

    /**
     * Ends a RearDisplaySession and sends [STATE_INACTIVE] to the consumer
     * provided in the {@code startRearDisplaySession} method. This method is only
     * called through the {@code RearDisplaySession} provided to the developer.
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
     */
    void endRearDisplaySession();

    /**
     * Adds a listener interested in receiving updates on the rear display presentation status
     * of the device. Because this is being called from the OEM provided
     * extensions, the library will post the result of the listener on the executor
     * provided by the developer.
     *
     * The listener provided will receive {@link ExtensionWindowAreaStatus} values that
     * correspond to the current status of the feature.
     *
     * @param consumer interested in receiving updates to {@link ExtensionWindowAreaStatus}.
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
     */
    default void addRearDisplayPresentationStatusListener(
            @NonNull Consumer<ExtensionWindowAreaStatus> consumer) {
        throw new UnsupportedOperationException("This method must not be called unless there is a"
                + " corresponding override implementation on the device.");
    }

    /**
     * Removes a listener no longer interested in receiving updates.
     *
     * @param consumer no longer interested in receiving updates to WindowAreaStatus
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
     */
    default void removeRearDisplayPresentationStatusListener(
            @NonNull Consumer<ExtensionWindowAreaStatus> consumer) {
        throw new UnsupportedOperationException("This method must not be called unless there is a"
                + " corresponding override implementation on the device.");
    }

    /**
     * Creates and starts a rear display presentation session and sends state updates to the
     * consumer provided. This consumer will receive a constant represented by
     * {@link WindowAreaSessionState} to represent the state of the current rear display
     * session. We will translate to a more friendly interface in the library.
     *
     * Because this is being called from the OEM provided extensions, the library
     * will post the result of the listener on the executor provided by the developer.
     *
     * Rear display presentation mode refers to a feature where an {@link Activity} can present
     * additional content on a device with a second display that is facing the same direction
     * as the rear camera (i.e. the cover display on a fold-in style device). The calling
     * {@link Activity} stays on the user-facing display.
     *
     * @param activity that the OEM implementation will use as a base
     * context and to identify the source display area of the request.
     * The reference to the activity instance must not be stored in the OEM
     * implementation to prevent memory leaks.
     * @param consumer to provide updates to the client on the status of the session
     * @throws UnsupportedOperationException if this method is called when rear display presentation
     * mode is not available. This could be to an incompatible device state or when
     * another process is currently in this mode.
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
     */
    default void startRearDisplayPresentationSession(@NonNull Activity activity,
            @NonNull Consumer<@WindowAreaSessionState Integer> consumer) {
        throw new UnsupportedOperationException("This method must not be called unless there is a"
                + " corresponding override implementation on the device.");
    }

    /**
     * Ends the current rear display presentation session and provides updates to the
     * callback provided. When this is ended, the presented content from the calling
     * {@link Activity} will also be removed from the rear facing display.
     * Because this is being called from the OEM provided extensions, the result of the listener
     * will be posted on the executor provided by the developer at the initial call site.
     *
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
     */
    default void endRearDisplayPresentationSession() {
        throw new UnsupportedOperationException("This method must not be called unless there is a"
                + " corresponding override implementation on the device.");
    }

    /**
     * Returns the {@link ExtensionWindowAreaPresentation} connected to the active
     * rear display presentation session. If there is no session currently active, then it will
     * return null.
     *
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
     */
    @Nullable
    default ExtensionWindowAreaPresentation getRearDisplayPresentation() {
        throw new UnsupportedOperationException("This method must not be called unless there is a"
                + " corresponding override implementation on the device.");
    }

    /**
     * Returns the {@link android.util.DisplayMetrics} associated with the rear facing display. If
     * there is no rear facing display available on the device, returns an empty
     * {@link android.util.DisplayMetrics} object.
     *
     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
     */
    // TODO(b/273807238): Investigate how we can provide a listener to get runtime changes in
    //  rear display metrics to better support other form-factors in the future.
    @NonNull
    default DisplayMetrics getRearDisplayMetrics() {
        throw new UnsupportedOperationException("This method must not be called unless there is a"
                + " corresponding override implementation on the device.");
    }
}