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

Commit 30cefedc authored by Darryl Johnson's avatar Darryl Johnson Committed by Android (Google) Code Review
Browse files

Merge changes from topic "jumbo-sidecar-posture" into sc-dev

* changes:
  Update sample Sidecar/Extension implementation to allow mapping system device state to posture via a config.
  Seperate SettingsConfigProvider into producers.
parents 7be2cf8c 7e607c17
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -4649,6 +4649,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
+1 −0
Original line number Diff line number Diff line
@@ -4182,6 +4182,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" />
+20 −6
Original line number Diff line number Diff line
@@ -30,13 +30,20 @@ android_library_import {

java_library {
    name: "androidx.window.sidecar",
    srcs: ["src/androidx/window/sidecar/**/*.java", "src/androidx/window/util/**/*.java"],
    srcs: [
        "src/androidx/window/sidecar/**/*.java",
        "src/androidx/window/util/**/*.java",
        "src/androidx/window/common/**/*.java",
    ],
    static_libs: ["window-sidecar"],
    installable: true,
    sdk_version: "core_platform",
    system_ext_specific: true,
    libs: ["framework", "androidx.annotation_annotation",],
    required: ["androidx.window.sidecar.xml",],
    libs: [
        "framework",
        "androidx.annotation_annotation",
    ],
    required: ["androidx.window.sidecar.xml"],
}

prebuilt_etc {
@@ -58,13 +65,20 @@ android_library_import {

java_library {
    name: "androidx.window.extensions",
    srcs: ["src/androidx/window/extensions/**/*.java", "src/androidx/window/util/**/*.java"],
    srcs: [
        "src/androidx/window/extensions/**/*.java",
        "src/androidx/window/util/**/*.java",
        "src/androidx/window/common/**/*.java",
    ],
    static_libs: ["window-extensions"],
    installable: true,
    sdk_version: "core_platform",
    system_ext_specific: true,
    libs: ["framework", "androidx.annotation_annotation",],
    required: ["androidx.window.extensions.xml",],
    libs: [
        "framework",
        "androidx.annotation_annotation",
    ],
    required: ["androidx.window.extensions.xml"],
}

prebuilt_etc {
+128 −0
Original line number Diff line number Diff line
/*
 * 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 androidx.window.util.ExtensionHelper.isZero;

import android.annotation.Nullable;
import android.graphics.Rect;

import androidx.annotation.NonNull;

import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
final class CommonDisplayFeature implements DisplayFeature {
    private static final Pattern FEATURE_PATTERN =
            Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]");

    private static final String FEATURE_TYPE_FOLD = "fold";
    private static final String FEATURE_TYPE_HINGE = "hinge";

    // TODO(b/183049815): Support feature strings that include the state of the feature.
    /**
     * Parses a display feature from a string.
     *
     * @throws IllegalArgumentException if the provided string is improperly formatted or could not
     * otherwise be parsed.
     *
     * @see #FEATURE_PATTERN
     */
    @NonNull
    static CommonDisplayFeature parseFromString(@NonNull String string) {
        Matcher featureMatcher = FEATURE_PATTERN.matcher(string);
        if (!featureMatcher.matches()) {
            throw new IllegalArgumentException("Malformed feature description format: " + string);
        }
        try {
            String featureType = featureMatcher.group(1);
            int type;
            switch (featureType) {
                case FEATURE_TYPE_FOLD:
                    type = 1 /* TYPE_FOLD */;
                    break;
                case FEATURE_TYPE_HINGE:
                    type = 2 /* TYPE_HINGE */;
                    break;
                default: {
                    throw new IllegalArgumentException("Malformed feature type: " + featureType);
                }
            }

            int left = Integer.parseInt(featureMatcher.group(2));
            int top = Integer.parseInt(featureMatcher.group(3));
            int right = Integer.parseInt(featureMatcher.group(4));
            int bottom = Integer.parseInt(featureMatcher.group(5));
            Rect featureRect = new Rect(left, top, right, bottom);
            if (isZero(featureRect)) {
                throw new IllegalArgumentException("Feature has empty bounds: " + string);
            }

            return new CommonDisplayFeature(type, null, featureRect);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Malformed feature description: " + string, e);
        }
    }

    private final int mType;
    @Nullable
    private final Integer mState;
    @NonNull
    private final Rect mRect;

    CommonDisplayFeature(int type, @Nullable Integer state, @NonNull Rect rect) {
        this.mType = type;
        this.mState = state;
        if (rect.width() == 0 && rect.height() == 0) {
            throw new IllegalArgumentException(
                    "Display feature rectangle cannot have zero width and height simultaneously.");
        }
        this.mRect = rect;
    }

    public int getType() {
        return mType;
    }

    /** Returns the state of the feature, or {@code null} if the feature has no state. */
    @Nullable
    public Integer getState() {
        return mState;
    }

    @NonNull
    public Rect getRect() {
        return mRect;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CommonDisplayFeature that = (CommonDisplayFeature) o;
        return mType == that.mType
                && Objects.equals(mState, that.mState)
                && mRect.equals(that.mRect);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mType, mState, mRect);
    }
}
+93 −0
Original line number Diff line number Diff line
/*
 * 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();
    }
}
Loading