Update sample Sidecar/Extension implementation to allow mapping system
device state to posture via a config.

This updates the sample Sidecar/Extension implementation for the WM
Jetpack Library to read the mapping of system DeviceState provided by
DeviceStateManager from a config and apply the translation to Jetpack
Posture when the device state changes.

Bug: 173428759
Bug: 181248887
Test: Manual - overlay config value on Jumbo and verify correct mapping
Test: ./gradlew window:window:test

Change-Id: I74d71a67e72976ade88122cd8eda5f16b2301c32
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f6fee88..ac94408 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4647,6 +4647,10 @@
     <!-- WindowsManager JetPack display features -->
     <string name="config_display_features" translatable="false" />
 
+    <!-- Map of System DeviceState supplied by DeviceStateManager to WM Jetpack posture. Must be in
+         the format [System DeviceState]:[WM Jetpack Posture], for example: "0:1". -->
+    <string-array name="config_device_state_postures" translatable="false" />
+
     <!-- Aspect ratio of letterboxing for fixed orientation. Values <= 1.0 will be ignored.
          Note: Activity min/max aspect ratio restrictions will still be respected.
          Therefore this override can control the maximum screen area that can be occupied by
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 567feee3..ed1731b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4179,6 +4179,7 @@
   <java-symbol type="dimen" name="default_background_blur_radius" />
   <java-symbol type="array" name="config_keep_warming_services" />
   <java-symbol type="string" name="config_display_features" />
+  <java-symbol type="array" name="config_device_state_postures" />
 
   <java-symbol type="dimen" name="controls_thumbnail_image_max_height" />
   <java-symbol type="dimen" name="controls_thumbnail_image_max_width" />
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerPostureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerPostureProducer.java
new file mode 100644
index 0000000..fa9a5a8
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerPostureProducer.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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.common;
+
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import androidx.window.util.BaseDataProducer;
+
+import com.android.internal.R;
+
+import java.util.Optional;
+
+/**
+ * An implementation of {@link androidx.window.util.DataProducer} that returns the device's posture
+ * by mapping the state returned from {@link DeviceStateManager} to values provided in the resources
+ * config at {@link R.array#config_device_state_postures}.
+ */
+public final class DeviceStateManagerPostureProducer extends BaseDataProducer<Integer> {
+    private static final String TAG = "ConfigDevicePostureProducer";
+    private static final boolean DEBUG = false;
+
+    private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
+
+    private int mCurrentDeviceState = INVALID_DEVICE_STATE;
+
+    private final DeviceStateCallback mDeviceStateCallback = (state) -> {
+        mCurrentDeviceState = state;
+        notifyDataChanged();
+    };
+
+    public DeviceStateManagerPostureProducer(@NonNull Context context) {
+        String[] deviceStatePosturePairs = context.getResources()
+                .getStringArray(R.array.config_device_state_postures);
+        for (String deviceStatePosturePair : deviceStatePosturePairs) {
+            String[] deviceStatePostureMapping = deviceStatePosturePair.split(":");
+            if (deviceStatePostureMapping.length != 2) {
+                if (DEBUG) {
+                    Log.e(TAG, "Malformed device state posture pair: " + deviceStatePosturePair);
+                }
+                continue;
+            }
+
+            int deviceState;
+            int posture;
+            try {
+                deviceState = Integer.parseInt(deviceStatePostureMapping[0]);
+                posture = Integer.parseInt(deviceStatePostureMapping[1]);
+            } catch (NumberFormatException e) {
+                if (DEBUG) {
+                    Log.e(TAG, "Failed to parse device state or posture: " + deviceStatePosturePair,
+                            e);
+                }
+                continue;
+            }
+
+            mDeviceStateToPostureMap.put(deviceState, posture);
+        }
+
+        if (mDeviceStateToPostureMap.size() > 0) {
+            context.getSystemService(DeviceStateManager.class)
+                    .registerCallback(context.getMainExecutor(), mDeviceStateCallback);
+        }
+    }
+
+    @Override
+    @Nullable
+    public Optional<Integer> getData() {
+        final int posture = mDeviceStateToPostureMap.get(mCurrentDeviceState, -1);
+        return posture != -1 ? Optional.of(posture) : Optional.empty();
+    }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
index 67030fc..ce9be6a 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
@@ -27,6 +27,7 @@
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.window.common.DeviceStateManagerPostureProducer;
 import androidx.window.common.DisplayFeature;
 import androidx.window.common.ResourceConfigDisplayFeatureProducer;
 import androidx.window.common.SettingsDevicePostureProducer;
@@ -57,7 +58,10 @@
 
     SampleExtensionImpl(Context context) {
         mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
-        mDevicePostureProducer = mSettingsDevicePostureProducer;
+        mDevicePostureProducer = new PriorityDataProducer<>(List.of(
+                mSettingsDevicePostureProducer,
+                new DeviceStateManagerPostureProducer(context)
+        ));
 
         mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context);
         mDisplayFeatureProducer = new PriorityDataProducer<>(List.of(
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
index 408c42f..ece198c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
@@ -29,6 +29,7 @@
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.window.common.DeviceStateManagerPostureProducer;
 import androidx.window.common.DisplayFeature;
 import androidx.window.common.ResourceConfigDisplayFeatureProducer;
 import androidx.window.common.SettingsDevicePostureProducer;
@@ -55,7 +56,10 @@
 
     SampleSidecarImpl(Context context) {
         mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
-        mDevicePostureProducer = mSettingsDevicePostureProducer;
+        mDevicePostureProducer = new PriorityDataProducer<>(List.of(
+                mSettingsDevicePostureProducer,
+                new DeviceStateManagerPostureProducer(context)
+        ));
 
         mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context);
         mDisplayFeatureProducer = new PriorityDataProducer<>(List.of(