From 571d4a6d6258f347c4b28786133ca98acd4e0b90 Mon Sep 17 00:00:00 2001 From: Kenneth Ford Date: Fri, 4 Mar 2022 13:41:57 +0000 Subject: [PATCH 1/3] Adds extensions implementation for WindowAreaComponent and rear display status listeners This cl includes the functionality of adding/removing listeners for Rear Display status. Bug: 207686851 Test: ExtensionWindowAreaComponentTest Change-Id: I2d4d519a5e4933cd2b1319f2da99845f647006eb --- core/res/res/values/config.xml | 6 + core/res/res/values/symbols.xml | 1 + .../extensions/WindowExtensionsImpl.java | 23 +++ .../area/WindowAreaComponentImpl.java | 189 ++++++++++++++++++ .../Jetpack/window-extensions-release.aar | Bin 21364 -> 21513 bytes 5 files changed, 219 insertions(+) create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d13bc87f79228..b4d0b4a60c3a6 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5884,4 +5884,10 @@ 10 + + + -1 diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d7484c75b15ca..a155070b08a87 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4812,6 +4812,7 @@ + diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java index bdf703c9bd383..33519a3feab8c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java @@ -20,11 +20,14 @@ import android.app.ActivityThread; import android.content.Context; import androidx.annotation.NonNull; +import androidx.window.extensions.area.WindowAreaComponent; +import androidx.window.extensions.area.WindowAreaComponentImpl; import androidx.window.extensions.embedding.ActivityEmbeddingComponent; import androidx.window.extensions.embedding.SplitController; import androidx.window.extensions.layout.WindowLayoutComponent; import androidx.window.extensions.layout.WindowLayoutComponentImpl; + /** * The reference implementation of {@link WindowExtensions} that implements the initial API version. */ @@ -33,6 +36,7 @@ public class WindowExtensionsImpl implements WindowExtensions { private final Object mLock = new Object(); private volatile WindowLayoutComponent mWindowLayoutComponent; private volatile SplitController mSplitController; + private volatile WindowAreaComponent mWindowAreaComponent; @Override public int getVendorApiLevel() { @@ -75,4 +79,23 @@ public class WindowExtensionsImpl implements WindowExtensions { } return mSplitController; } + + /** + * Returns a reference implementation of {@link WindowAreaComponent} if available, + * {@code null} otherwise. The implementation must match the API level reported in + * {@link WindowExtensions#getWindowAreaComponent()}. + * @return {@link WindowAreaComponent} OEM implementation. + */ + public WindowAreaComponent getWindowAreaComponent() { + if (mWindowAreaComponent == null) { + synchronized (mLock) { + if (mWindowAreaComponent == null) { + Context context = ActivityThread.currentApplication(); + mWindowAreaComponent = + new WindowAreaComponentImpl(context); + } + } + } + return mWindowAreaComponent; + } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java new file mode 100644 index 0000000000000..76cd17cbe517b --- /dev/null +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2022 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 android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; + +import android.app.Activity; +import android.content.Context; +import android.hardware.devicestate.DeviceStateManager; +import android.util.ArraySet; + +import androidx.annotation.NonNull; + +import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; + +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * Reference implementation of androidx.window.extensions.area OEM interface for use with + * WindowManager Jetpack. + * + * This component currently supports Rear Display mode with the ability to add and remove + * status listeners for this mode. + * + * The public methods in this class are thread-safe. + **/ +public class WindowAreaComponentImpl implements WindowAreaComponent, + DeviceStateManager.DeviceStateCallback { + + private final Object mLock = new Object(); + + private final DeviceStateManager mDeviceStateManager; + private final Executor mExecutor; + + @GuardedBy("mLock") + private final ArraySet> mRearDisplayStatusListeners = new ArraySet<>(); + private final int mRearDisplayState; + + @GuardedBy("mLock") + private int mCurrentDeviceState = INVALID_DEVICE_STATE; + @GuardedBy("mLock") + private int mCurrentDeviceBaseState = INVALID_DEVICE_STATE; + + public WindowAreaComponentImpl(@NonNull Context context) { + mDeviceStateManager = context.getSystemService(DeviceStateManager.class); + mExecutor = context.getMainExecutor(); + + // TODO(b/236022708) Move rear display state to device state config file + mRearDisplayState = context.getResources().getInteger( + R.integer.config_deviceStateRearDisplay); + + mDeviceStateManager.registerCallback(mExecutor, this); + } + + /** + * Adds a listener interested in receiving updates on the RearDisplayStatus + * of the device. Because this is being called from the OEM provided + * extensions, we will post the result of the listener on the executor + * provided by the developer at the initial call site. + * + * Depending on the initial state of the device, we will return either + * {@link WindowAreaComponent#STATUS_AVAILABLE} or + * {@link WindowAreaComponent#STATUS_UNAVAILABLE} if the feature is supported or not in that + * state respectively. When the RearDisplay feature is triggered, we update the status to be + * {@link WindowAreaComponent#STATUS_UNAVAILABLE}. + * + * TODO(b/239833099) Add a STATUS_ACTIVE option to let apps know if a feature is currently + * enabled. + * + * @param consumer {@link Consumer} interested in receiving updates to the status of + * rear display mode. + */ + public void addRearDisplayStatusListener( + @NonNull Consumer<@WindowAreaStatus Integer> consumer) { + synchronized (mLock) { + mRearDisplayStatusListeners.add(consumer); + + // If current device state is still invalid, we haven't gotten our initial value yet + if (mCurrentDeviceState == INVALID_DEVICE_STATE) { + return; + } + consumer.accept(getCurrentStatus()); + } + } + + /** + * Removes a listener no longer interested in receiving updates. + * @param consumer no longer interested in receiving updates to RearDisplayStatus + */ + public void removeRearDisplayStatusListener( + @NonNull Consumer<@WindowAreaStatus Integer> consumer) { + synchronized (mLock) { + mRearDisplayStatusListeners.remove(consumer); + } + } + + /** + * Creates and starts a RearDisplaySession and provides updates to the + * callback provided. Because this is being called from the OEM provided + * extensions, we will post the result of the listener on the executor + * provided by the developer at the initial call site. + * + * When we enable rear display mode, we submit a request to {@link DeviceStateManager} + * to override the device state to the state that corresponds to RearDisplay + * mode. When the {@link DeviceStateRequest} is activated, we let the + * consumer know that the session is active by sending + * {@link WindowAreaComponent#SESSION_STATE_ACTIVE}. + * + * @param activity to provide updates to the client on + * the status of the Session + * @param rearDisplaySessionCallback to provide updates to the client on + * the status of the Session + */ + public void startRearDisplaySession(@NonNull Activity activity, + @NonNull Consumer<@WindowAreaSessionState Integer> rearDisplaySessionCallback) { + // Todo("Adding in chained cl") + } + + /** + * Ends the current RearDisplaySession and provides updates to the + * callback provided. Because this is being called from the OEM provided + * extensions, we will post the result of the listener on the executor + * provided by the developer. + */ + public void endRearDisplaySession() { + // Todo("Adding in chained cl") + } + + @Override + public void onBaseStateChanged(int state) { + synchronized (mLock) { + mCurrentDeviceBaseState = state; + } + } + + @Override + public void onStateChanged(int state) { + synchronized (mLock) { + mCurrentDeviceState = state; + updateStatusConsumers(getCurrentStatus()); + } + } + + @GuardedBy("mLock") + private int getCurrentStatus() { + if (isRearDisplayActive()) { + return WindowAreaComponent.STATUS_UNAVAILABLE; + } + return WindowAreaComponent.STATUS_AVAILABLE; + } + + /** + * Helper method to determine if a rear display session is currently active by checking + * if the current device configuration matches that of rear display. This would be true + * if there is a device override currently active (base state != current state) and the current + * state is that which corresponds to {@code mRearDisplayState} + * @return {@code true} if the device is in rear display mode and {@code false} if not + */ + @GuardedBy("mLock") + private boolean isRearDisplayActive() { + return (mCurrentDeviceState != mCurrentDeviceBaseState) && (mCurrentDeviceState + == mRearDisplayState); + } + + @GuardedBy("mLock") + private void updateStatusConsumers(@WindowAreaStatus int windowAreaStatus) { + synchronized (mLock) { + for (int i = 0; i < mRearDisplayStatusListeners.size(); i++) { + mRearDisplayStatusListeners.valueAt(i).accept(windowAreaStatus); + } + } + } +} diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar index 918e514f4c892d3f7f9bfbae3f1ee03bf37e7a1b..e9a1721fba2ab573fc314a439ab1a2937cf4820d 100644 GIT binary patch delta 17990 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 Date: Wed, 9 Mar 2022 21:00:56 +0000 Subject: [PATCH 2/3] Adds support for enabling and disabling rear display mode. This adds the functionality for enabling rear display mode in WindowAreaComponentImpl. Bug: 207686851 Test: ExtensionWindowAreaComponentTest Change-Id: If8ac9d23e16e7aa5e12bdedbe4688226aff32d38 --- .../area/WindowAreaComponentImpl.java | 80 +++++++++++++++++-- 1 file changed, 73 insertions(+), 7 deletions(-) diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java index 76cd17cbe517b..3adae7006369d 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java @@ -21,6 +21,7 @@ import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STA import android.app.Activity; import android.content.Context; import android.hardware.devicestate.DeviceStateManager; +import android.hardware.devicestate.DeviceStateRequest; import android.util.ArraySet; import androidx.annotation.NonNull; @@ -51,11 +52,15 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, @GuardedBy("mLock") private final ArraySet> mRearDisplayStatusListeners = new ArraySet<>(); private final int mRearDisplayState; + @WindowAreaSessionState + private int mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_INACTIVE; @GuardedBy("mLock") private int mCurrentDeviceState = INVALID_DEVICE_STATE; @GuardedBy("mLock") private int mCurrentDeviceBaseState = INVALID_DEVICE_STATE; + @GuardedBy("mLock") + private DeviceStateRequest mDeviceStateRequest; public WindowAreaComponentImpl(@NonNull Context context) { mDeviceStateManager = context.getSystemService(DeviceStateManager.class); @@ -77,8 +82,8 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, * Depending on the initial state of the device, we will return either * {@link WindowAreaComponent#STATUS_AVAILABLE} or * {@link WindowAreaComponent#STATUS_UNAVAILABLE} if the feature is supported or not in that - * state respectively. When the RearDisplay feature is triggered, we update the status to be - * {@link WindowAreaComponent#STATUS_UNAVAILABLE}. + * state respectively. When the rear display feature is triggered, we update the status to be + * {@link WindowAreaComponent#STATUS_UNAVAILABLE}. TODO(b/240727590) Prefix with AREA_ * * TODO(b/239833099) Add a STATUS_ACTIVE option to let apps know if a feature is currently * enabled. @@ -111,7 +116,7 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, } /** - * Creates and starts a RearDisplaySession and provides updates to the + * Creates and starts a rear display session and provides updates to the * callback provided. Because this is being called from the OEM provided * extensions, we will post the result of the listener on the executor * provided by the developer at the initial call site. @@ -129,23 +134,46 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, */ public void startRearDisplaySession(@NonNull Activity activity, @NonNull Consumer<@WindowAreaSessionState Integer> rearDisplaySessionCallback) { - // Todo("Adding in chained cl") + synchronized (mLock) { + if (mDeviceStateRequest != null) { + // Rear display session is already active + throw new IllegalStateException( + "Unable to start new rear display session as one is already active"); + } + mDeviceStateRequest = DeviceStateRequest.newBuilder(mRearDisplayState).build(); + mDeviceStateManager.requestState( + mDeviceStateRequest, + mExecutor, + new DeviceStateRequestCallbackAdapter(rearDisplaySessionCallback) + ); + } } /** - * Ends the current RearDisplaySession and provides updates to the + * Ends the current rear display session and provides updates to the * callback provided. Because this is being called from the OEM provided * extensions, we will post the result of the listener on the executor * provided by the developer. */ public void endRearDisplaySession() { - // Todo("Adding in chained cl") + synchronized (mLock) { + if (mDeviceStateRequest != null || isRearDisplayActive()) { + mDeviceStateRequest = null; + mDeviceStateManager.cancelStateRequest(); + } else { + throw new IllegalStateException( + "Unable to cancel a rear display session as there is no active session"); + } + } } @Override public void onBaseStateChanged(int state) { synchronized (mLock) { mCurrentDeviceBaseState = state; + if (state == mCurrentDeviceState) { + updateStatusConsumers(getCurrentStatus()); + } } } @@ -159,7 +187,8 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, @GuardedBy("mLock") private int getCurrentStatus() { - if (isRearDisplayActive()) { + if (mRearDisplaySessionStatus == WindowAreaComponent.SESSION_STATE_ACTIVE + || isRearDisplayActive()) { return WindowAreaComponent.STATUS_UNAVAILABLE; } return WindowAreaComponent.STATUS_AVAILABLE; @@ -186,4 +215,41 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, } } } + + /** + * Callback for the {@link DeviceStateRequest} to be notified of when the request has been + * activated or cancelled. This callback provides information to the client library + * on the status of the RearDisplay session through {@code mRearDisplaySessionCallback} + */ + private class DeviceStateRequestCallbackAdapter implements DeviceStateRequest.Callback { + + private final Consumer mRearDisplaySessionCallback; + + DeviceStateRequestCallbackAdapter(@NonNull Consumer callback) { + mRearDisplaySessionCallback = callback; + } + + @Override + public void onRequestActivated(@NonNull DeviceStateRequest request) { + synchronized (mLock) { + if (request.equals(mDeviceStateRequest)) { + mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_ACTIVE; + mRearDisplaySessionCallback.accept(mRearDisplaySessionStatus); + updateStatusConsumers(getCurrentStatus()); + } + } + } + + @Override + public void onRequestCanceled(DeviceStateRequest request) { + synchronized (mLock) { + if (request.equals(mDeviceStateRequest)) { + mDeviceStateRequest = null; + } + mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_INACTIVE; + mRearDisplaySessionCallback.accept(mRearDisplaySessionStatus); + updateStatusConsumers(getCurrentStatus()); + } + } + } } From 22740a10df717deefeda69bad6f1021aa06e2002 Mon Sep 17 00:00:00 2001 From: Kenneth Ford Date: Wed, 3 Aug 2022 22:38:52 +0000 Subject: [PATCH 3/3] Increments Extensions API version for Rear display API's Bug: 207686851 Test: Build & Run Change-Id: If417305d4974ee4c3fae4e2fe535e1095cfea459 --- .../src/androidx/window/extensions/WindowExtensionsImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java index 33519a3feab8c..7e9c4189dabbf 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java @@ -38,9 +38,10 @@ public class WindowExtensionsImpl implements WindowExtensions { private volatile SplitController mSplitController; private volatile WindowAreaComponent mWindowAreaComponent; + // TODO(b/241126279) Introduce constants to better version functionality @Override public int getVendorApiLevel() { - return 1; + return 2; } /**