Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d159371d authored by Kenneth Ford's avatar Kenneth Ford Committed by Andrii Kulian
Browse files

Creates implementation for Concurrent displays

Adds the ability to transition to the concurrent
display state, and then present content on that
display. Also provides the ability to add/remove
listeners to know when this feature is available

Extension interface cl: ag/21127264

Bug: 251747141
Test: ExtensionRearDisplayPresentationTest
Change-Id: I1edae8b084d3e3b3f66ce7ced7249812b97c5610
parent 65368b9f
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -6207,6 +6207,18 @@
         different from the home screen wallpaper. -->
    <bool name="config_independentLockscreenLiveWallpaper">false</bool>

    <!-- Device state that corresponds to concurrent display mode where the default display
         is the internal display. Public API for the feature is provided through Jetpack
         WindowManager.
         TODO(b/236022708) Move concurrent display state to device state config file
    -->
    <integer name="config_deviceStateConcurrentRearDisplay">-1</integer>

    <!-- Physical display address that corresponds to the rear display in rear display mode
         and concurrent display mode. Used to get information about the display before
         entering the corresponding modes -->
    <string name="config_rearDisplayPhysicalAddress" translatable="false"></string>

    <!-- List of certificate to be used for font fs-verity integrity verification -->
    <string-array translatable="false" name="config_fontManagerServiceCerts">
    </string-array>
+2 −0
Original line number Diff line number Diff line
@@ -4907,6 +4907,8 @@
  <java-symbol type="string" name="concurrent_display_notification_thermal_content"/>
  <java-symbol type="string" name="device_state_notification_turn_off_button"/>
  <java-symbol type="bool" name="config_independentLockscreenLiveWallpaper"/>
  <java-symbol type="integer" name="config_deviceStateConcurrentRearDisplay" />
  <java-symbol type="string" name="config_rearDisplayPhysicalAddress" />

  <!-- For app language picker -->
  <java-symbol type="string" name="system_locale_title" />
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.Presentation;
import android.content.Context;
import android.view.Display;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.window.extensions.core.util.function.Consumer;

/**
 * {@link Presentation} object that is used to present extra content
 * on the rear facing display when in a rear display presentation feature.
 */
class RearDisplayPresentation extends Presentation implements ExtensionWindowAreaPresentation {

    @NonNull
    private final Consumer<@WindowAreaComponent.WindowAreaSessionState Integer> mStateConsumer;

    RearDisplayPresentation(@NonNull Context outerContext, @NonNull Display display,
            @NonNull Consumer<@WindowAreaComponent.WindowAreaSessionState Integer> stateConsumer) {
        super(outerContext, display);
        mStateConsumer = stateConsumer;
    }

    /**
     * {@code mStateConsumer} is notified that their content is now visible when the
     * {@link Presentation} object is started. There is no comparable callback for
     * {@link WindowAreaComponent#SESSION_STATE_INVISIBLE} in {@link #onStop()} due to the
     * timing of when a {@link android.hardware.devicestate.DeviceStateRequest} is cancelled
     * ending rear display presentation mode happening before the {@link Presentation} is stopped.
     */
    @Override
    protected void onStart() {
        super.onStart();
        mStateConsumer.accept(WindowAreaComponent.SESSION_STATE_VISIBLE);
    }

    @NonNull
    @Override
    public Context getPresentationContext() {
        return getContext();
    }

    @Override
    public void setPresentationView(View view) {
        setContentView(view);
        if (!isShowing()) {
            show();
        }
    }
}
+100 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 static androidx.window.extensions.area.WindowAreaComponent.SESSION_STATE_ACTIVE;
import static androidx.window.extensions.area.WindowAreaComponent.SESSION_STATE_INACTIVE;

import android.content.Context;
import android.hardware.devicestate.DeviceStateRequest;
import android.hardware.display.DisplayManager;
import android.util.Log;
import android.view.Display;

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

import java.util.Objects;

/**
 * Controller class that keeps track of the status of the device state request
 * to enable the rear display presentation feature. This controller notifies the session callback
 * when the state request is active, and notifies the callback when the request is canceled.
 *
 * Clients are notified via {@link Consumer} provided with
 * {@link androidx.window.extensions.area.WindowAreaComponent.WindowAreaStatus} values to signify
 * when the request becomes active and cancelled.
 */
class RearDisplayPresentationController implements DeviceStateRequest.Callback {

    private static final String TAG = "RearDisplayPresentationController";

    // Original context that requested to enable rear display presentation mode
    @NonNull
    private final Context mContext;
    @NonNull
    private final Consumer<@WindowAreaComponent.WindowAreaSessionState Integer> mStateConsumer;
    @Nullable
    private ExtensionWindowAreaPresentation mExtensionWindowAreaPresentation;
    @NonNull
    private final DisplayManager mDisplayManager;

    /**
     * Creates the RearDisplayPresentationController
     * @param context Originating {@link android.content.Context} that is initiating the rear
     *                display presentation session.
     * @param stateConsumer {@link Consumer} that will be notified that the session is active when
     *        the device state request is active and the session has been created. If the device
     *        state request is cancelled, the callback will be notified that the session has been
     *        ended. This could occur through a call to cancel the feature or if the device is
     *        manipulated in a way that cancels any device state override.
     */
    RearDisplayPresentationController(@NonNull Context context,
            @NonNull Consumer<@WindowAreaComponent.WindowAreaSessionState Integer> stateConsumer) {
        Objects.requireNonNull(context);
        Objects.requireNonNull(stateConsumer);

        mContext = context;
        mStateConsumer = stateConsumer;
        mDisplayManager = context.getSystemService(DisplayManager.class);
    }

    @Override
    public void onRequestActivated(@NonNull DeviceStateRequest request) {
        Display[] rearDisplays = mDisplayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_REAR);
        if (rearDisplays.length == 0) {
            mStateConsumer.accept(SESSION_STATE_INACTIVE);
            Log.e(TAG, "Rear display list should not be empty");
            return;
        }

        mExtensionWindowAreaPresentation =
                new RearDisplayPresentation(mContext, rearDisplays[0], mStateConsumer);
        mStateConsumer.accept(SESSION_STATE_ACTIVE);
    }

    @Override
    public void onRequestCanceled(@NonNull DeviceStateRequest request) {
        mStateConsumer.accept(SESSION_STATE_INACTIVE);
    }

    @Nullable
    public ExtensionWindowAreaPresentation getWindowAreaPresentation() {
        return mExtensionWindowAreaPresentation;
    }
}
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.util.DisplayMetrics;

import androidx.annotation.NonNull;

/**
 * Class that provides information around the current status of a window area feature. Contains
 * the current {@link WindowAreaComponent.WindowAreaStatus} value corresponding to the
 * rear display presentation feature, as well as the {@link DisplayMetrics} for the rear facing
 * display.
 */
class RearDisplayPresentationStatus implements ExtensionWindowAreaStatus {

    @WindowAreaComponent.WindowAreaStatus
    private final int mWindowAreaStatus;

    @NonNull
    private final DisplayMetrics mDisplayMetrics;

    RearDisplayPresentationStatus(@WindowAreaComponent.WindowAreaStatus int status,
            @NonNull DisplayMetrics displayMetrics) {
        mWindowAreaStatus = status;
        mDisplayMetrics = displayMetrics;
    }

    /**
     * Returns the {@link androidx.window.extensions.area.WindowAreaComponent.WindowAreaStatus}
     * value that relates to the current status of a feature.
     */
    @Override
    @WindowAreaComponent.WindowAreaStatus
    public int getWindowAreaStatus() {
        return mWindowAreaStatus;
    }

    /**
     * Returns the {@link DisplayMetrics} that corresponds to the window area that a feature
     * interacts with. This is converted to size class information provided to developers.
     */
    @Override
    @NonNull
    public DisplayMetrics getWindowAreaDisplayMetrics() {
        return mDisplayMetrics;
    }
}
Loading