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

Commit 09240125 authored by Diego Vela's avatar Diego Vela Committed by Presubmit Automerger Backend
Browse files

[automerge] DO NOT MERGE Remove DisplayFeature from common package. 2p: 88290180

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16373396

Bug: 205342008
Change-Id: I78c72e056bb08fbbbc5be942d56d06b36fcfccb2
parents d177e286 88290180
Loading
Loading
Loading
Loading
+55 −10
Original line number Diff line number Diff line
@@ -18,17 +18,60 @@ package androidx.window.common;

import static androidx.window.util.ExtensionHelper.isZero;

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

import androidx.annotation.NonNull;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
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 {
/** A representation of a folding feature for both Extension and Sidecar.
 * For Sidecar this is the same as combining {@link androidx.window.sidecar.SidecarDeviceState} and
 * {@link androidx.window.sidecar.SidecarDisplayFeature}. For Extensions this is the mirror of
 * {@link androidx.window.extensions.layout.FoldingFeature}.
 */
public final class CommonFoldingFeature {

    /**
     * A common type to represent a hinge where the screen is continuous.
     */
    public static final int COMMON_TYPE_FOLD = 1;

    /**
     * A common type to represent a hinge where there is a physical gap separating multiple
     * displays.
     */
    public static final int COMMON_TYPE_HINGE = 2;

    @IntDef({COMMON_TYPE_FOLD, COMMON_TYPE_HINGE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Type {
    }

    /**
     * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar
     * and Extensions do not match exactly.
     */
    public static final int COMMON_STATE_FLAT = 3;
    /**
     * A common state to represent a HALF_OPENED hinge. This is needed because the definitions in
     * Sidecar and Extensions do not match exactly.
     */
    public static final int COMMON_STATE_HALF_OPENED = 2;

    /**
     * The possible states for a folding hinge.
     */
    @IntDef({COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED})
    @Retention(RetentionPolicy.SOURCE)
    public @interface State {
    }

    private static final Pattern FEATURE_PATTERN =
            Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]-?(flat|half-opened)?");

@@ -38,8 +81,6 @@ final class CommonDisplayFeature implements DisplayFeature {
    private static final String PATTERN_STATE_FLAT = "flat";
    private static final String PATTERN_STATE_HALF_OPENED = "half-opened";

    // TODO(b/183049815): Support feature strings that include the state of the feature.

    /**
     * Parses a display feature from a string.
     *
@@ -48,7 +89,7 @@ final class CommonDisplayFeature implements DisplayFeature {
     * @see #FEATURE_PATTERN
     */
    @NonNull
    static CommonDisplayFeature parseFromString(@NonNull String string) {
    static CommonFoldingFeature parseFromString(@NonNull String string) {
        Matcher featureMatcher = FEATURE_PATTERN.matcher(string);
        if (!featureMatcher.matches()) {
            throw new IllegalArgumentException("Malformed feature description format: " + string);
@@ -59,10 +100,10 @@ final class CommonDisplayFeature implements DisplayFeature {
            int type;
            switch (featureType) {
                case FEATURE_TYPE_FOLD:
                    type = 1 /* TYPE_FOLD */;
                    type = COMMON_TYPE_FOLD;
                    break;
                case FEATURE_TYPE_HINGE:
                    type = 2 /* TYPE_HINGE */;
                    type = COMMON_TYPE_HINGE;
                    break;
                default: {
                    throw new IllegalArgumentException("Malformed feature type: " + featureType);
@@ -91,7 +132,7 @@ final class CommonDisplayFeature implements DisplayFeature {
                    state = null;
                    break;
            }
            return new CommonDisplayFeature(type, state, featureRect);
            return new CommonFoldingFeature(type, state, featureRect);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Malformed feature description: " + string, e);
        }
@@ -103,7 +144,7 @@ final class CommonDisplayFeature implements DisplayFeature {
    @NonNull
    private final Rect mRect;

    CommonDisplayFeature(int type, @Nullable Integer state, @NonNull Rect rect) {
    CommonFoldingFeature(int type, @Nullable Integer state, @NonNull Rect rect) {
        assertValidState(state);
        this.mType = type;
        this.mState = state;
@@ -114,16 +155,20 @@ final class CommonDisplayFeature implements DisplayFeature {
        this.mRect = rect;
    }

    /** Returns the type of the feature. */
    @Type
    public int getType() {
        return mType;
    }

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

    /** Returns the bounds of the feature. */
    @NonNull
    public Rect getRect() {
        return mRect;
@@ -133,7 +178,7 @@ final class CommonDisplayFeature implements DisplayFeature {
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CommonDisplayFeature that = (CommonDisplayFeature) o;
        CommonFoldingFeature that = (CommonFoldingFeature) o;
        return mType == that.mType
                && Objects.equals(mState, that.mState)
                && mRect.equals(that.mRect);
+0 −60
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 android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Rect;

import androidx.annotation.NonNull;

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

/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
public interface DisplayFeature {
    /** Returns the type of the feature. */
    int getType();

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

    /** Returns the bounds of the feature. */
    @NonNull
    Rect getRect();

    /**
     * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar
     * and Extensions do not match exactly.
     */
    int COMMON_STATE_FLAT = 3;
    /**
     * A common state to represent a HALF_OPENED hinge. This is needed because the definitions in
     * Sidecar and Extensions do not match exactly.
     */
    int COMMON_STATE_HALF_OPENED = 2;

    /**
     * The possible states for a folding hinge.
     */
    @IntDef({COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED})
    @Retention(RetentionPolicy.SOURCE)
    @interface State {}

}
+6 −6
Original line number Diff line number Diff line
@@ -32,11 +32,11 @@ import java.util.Optional;

/**
 * Implementation of {@link androidx.window.util.DataProducer} that produces
 * {@link CommonDisplayFeature} parsed from a string stored in the resources config at
 * {@link CommonFoldingFeature} parsed from a string stored in the resources config at
 * {@link R.string#config_display_features}.
 */
public final class ResourceConfigDisplayFeatureProducer extends
        BaseDataProducer<List<DisplayFeature>> {
        BaseDataProducer<List<CommonFoldingFeature>> {
    private static final boolean DEBUG = false;
    private static final String TAG = "ResourceConfigDisplayFeatureProducer";

@@ -48,19 +48,19 @@ public final class ResourceConfigDisplayFeatureProducer extends

    @Override
    @Nullable
    public Optional<List<DisplayFeature>> getData() {
    public Optional<List<CommonFoldingFeature>> getData() {
        String displayFeaturesString = mContext.getResources().getString(
                R.string.config_display_features);
        if (TextUtils.isEmpty(displayFeaturesString)) {
            return Optional.empty();
        }

        List<DisplayFeature> features = new ArrayList<>();
        List<CommonFoldingFeature> features = new ArrayList<>();
        String[] featureStrings =  displayFeaturesString.split(";");
        for (String featureString : featureStrings) {
            CommonDisplayFeature feature;
            CommonFoldingFeature feature;
            try {
                feature = CommonDisplayFeature.parseFromString(featureString);
                feature = CommonFoldingFeature.parseFromString(featureString);
            } catch (IllegalArgumentException e) {
                if (DEBUG) {
                    Log.w(TAG, "Failed to parse display feature: " + featureString, e);
+6 −6
Original line number Diff line number Diff line
@@ -36,10 +36,10 @@ import java.util.Optional;

/**
 * Implementation of {@link androidx.window.util.DataProducer} that produces
 * {@link CommonDisplayFeature} parsed from a string stored in {@link Settings}.
 * {@link CommonFoldingFeature} parsed from a string stored in {@link Settings}.
 */
public final class SettingsDisplayFeatureProducer
        extends BaseDataProducer<List<DisplayFeature>> {
        extends BaseDataProducer<List<CommonFoldingFeature>> {
    private static final boolean DEBUG = false;
    private static final String TAG = "SettingsDisplayFeatureProducer";
    private static final String DISPLAY_FEATURES = "display_features";
@@ -58,22 +58,22 @@ public final class SettingsDisplayFeatureProducer

    @Override
    @Nullable
    public Optional<List<DisplayFeature>> getData() {
    public Optional<List<CommonFoldingFeature>> getData() {
        String displayFeaturesString = Settings.Global.getString(mResolver, DISPLAY_FEATURES);
        if (displayFeaturesString == null) {
            return Optional.empty();
        }

        List<DisplayFeature> features = new ArrayList<>();
        List<CommonFoldingFeature> features = new ArrayList<>();
        if (TextUtils.isEmpty(displayFeaturesString)) {
            return Optional.of(features);
        }
        String[] featureStrings =  displayFeaturesString.split(";");

        for (String featureString : featureStrings) {
            CommonDisplayFeature feature;
            CommonFoldingFeature feature;
            try {
                feature = CommonDisplayFeature.parseFromString(featureString);
                feature = CommonFoldingFeature.parseFromString(featureString);
            } catch (IllegalArgumentException e) {
                if (DEBUG) {
                    Log.w(TAG, "Failed to parse display feature: " + featureString, e);
+35 −35
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@ package androidx.window.extensions.layout;

import static android.view.Display.DEFAULT_DISPLAY;

import static androidx.window.common.DisplayFeature.COMMON_STATE_FLAT;
import static androidx.window.common.DisplayFeature.COMMON_STATE_HALF_OPENED;
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_FLAT;
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_HALF_OPENED;
import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation;
import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;

@@ -30,8 +30,8 @@ import android.graphics.Rect;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.window.common.CommonFoldingFeature;
import androidx.window.common.DeviceStateManagerPostureProducer;
import androidx.window.common.DisplayFeature;
import androidx.window.common.ResourceConfigDisplayFeatureProducer;
import androidx.window.common.SettingsDevicePostureProducer;
import androidx.window.common.SettingsDisplayFeatureProducer;
@@ -56,7 +56,6 @@ import java.util.function.Consumer;
 */
public class WindowLayoutComponentImpl implements WindowLayoutComponent {
    private static final String TAG = "SampleExtension";
    private static WindowLayoutComponent sInstance;

    private final Map<Activity, Consumer<WindowLayoutInfo>> mWindowLayoutChangeListeners =
            new HashMap<>();
@@ -65,7 +64,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
    private final DataProducer<Integer> mDevicePostureProducer;

    private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
    private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
    private final DataProducer<List<CommonFoldingFeature>> mDisplayFeatureProducer;

    public WindowLayoutComponentImpl(Context context) {
        mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
@@ -123,17 +122,18 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
    }

    /**
     * Calculate the {@link DisplayFeature.State} from the feature or the device posture producer.
     * If the given {@link DisplayFeature.State} is not valid then {@code null} will be returned.
     * The {@link FoldingFeature} should be ignored in the case of an invalid
     * {@link DisplayFeature.State}.
     * Calculate the {@link CommonFoldingFeature.State} from the feature or the device posture
     * producer.
     * If the given {@link CommonFoldingFeature.State} is not valid then {@code null} will be
     * returned. The {@link FoldingFeature} should be ignored in the case of an invalid
     * {@link CommonFoldingFeature.State}.
     *
     * @param feature a {@link DisplayFeature} to provide the feature state if present.
     * @return {@link DisplayFeature.State} of the hinge if present or the state from the posture
     * produce if present.
     * @param feature a {@link CommonFoldingFeature} to provide the feature state if present.
     * @return {@link CommonFoldingFeature.State} of the hinge if present or the state from the
     * posture produce if present.
     */
    @Nullable
    private Integer getFeatureState(DisplayFeature feature) {
    private Integer getFeatureState(CommonFoldingFeature feature) {
        Integer featureState = feature.getState();
        Optional<Integer> posture = mDevicePostureProducer.getData();
        Integer state = featureState == null ? posture.orElse(null) : featureState;
@@ -142,13 +142,14 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {

    /**
     * A convenience method to translate from the common feature state to the extensions feature
     * state.  More specifically, translates from {@link DisplayFeature.State} to
     * state.  More specifically, translates from {@link CommonFoldingFeature.State} to
     * {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED}. If it is not
     * possible to translate, then we will return a {@code null} value.
     *
     * @param state if it matches a value in {@link DisplayFeature.State}, {@code null} otherwise.
     * @return a {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED} if
     * the given state matches a value in {@link DisplayFeature.State} and {@code null} otherwise.
     * @param state if it matches a value in {@link CommonFoldingFeature.State}, {@code null}
     * otherwise. @return a {@link FoldingFeature.STATE_FLAT} or
     * {@link FoldingFeature.STATE_HALF_OPENED} if the given state matches a value in
     * {@link CommonFoldingFeature.State} and {@code null} otherwise.
     */
    @Nullable
    private Integer convertToExtensionState(@Nullable Integer state) {
@@ -172,33 +173,32 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {

    @NonNull
    private WindowLayoutInfo getWindowLayoutInfo(@NonNull Activity activity) {
        List<androidx.window.extensions.layout.DisplayFeature> displayFeatures =
        List<DisplayFeature> displayFeatures =
                getDisplayFeatures(activity);
        return new WindowLayoutInfo(displayFeatures);
    }

    /**
     * Translate from the {@link DisplayFeature} to
     * {@link androidx.window.extensions.layout.DisplayFeature} for a given {@link Activity}. If a
     * {@link DisplayFeature} is not valid then it will be omitted.
     * Translate from the {@link CommonFoldingFeature} to
     * {@link DisplayFeature} for a given {@link Activity}. If a
     * {@link CommonFoldingFeature} is not valid then it will be omitted.
     *
     * For a {@link FoldingFeature} the bounds are localized into the {@link Activity} window
     * coordinate space and the state is calculated either from {@link DisplayFeature#getState()} or
     * {@link #mDisplayFeatureProducer}. The state from {@link #mDisplayFeatureProducer} may not be
     * valid since {@link #mDisplayFeatureProducer} is a general state controller. If the state is
     * not valid, the {@link FoldingFeature} is omitted from the {@link List} of
     * {@link androidx.window.extensions.layout.DisplayFeature}. If the bounds are not valid,
     * constructing a {@link FoldingFeature} will throw an {@link IllegalArgumentException} since
     * this can cause negative UI effects down stream.
     * coordinate space and the state is calculated either from
     * {@link CommonFoldingFeature#getState()} or {@link #mDisplayFeatureProducer}. The state from
     * {@link #mDisplayFeatureProducer} may not be valid since {@link #mDisplayFeatureProducer} is
     * a general state controller. If the state is not valid, the {@link FoldingFeature} is omitted
     * from the {@link List} of {@link DisplayFeature}. If the bounds are not valid, constructing a
     * {@link FoldingFeature} will throw an {@link IllegalArgumentException} since this can cause
     * negative UI effects down stream.
     *
     * @param activity a proxy for the {@link android.view.Window} that contains the
     * {@link androidx.window.extensions.layout.DisplayFeature}.
     * @return a {@link List} of valid {@link androidx.window.extensions.layout.DisplayFeature} that
     * {@link DisplayFeature}.
     * @return a {@link List} of valid {@link DisplayFeature} that
     * are within the {@link android.view.Window} of the {@link Activity}
     */
    private List<androidx.window.extensions.layout.DisplayFeature> getDisplayFeatures(
            @NonNull Activity activity) {
        List<androidx.window.extensions.layout.DisplayFeature> features = new ArrayList<>();
    private List<DisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
        List<DisplayFeature> features = new ArrayList<>();
        int displayId = activity.getDisplay().getDisplayId();
        if (displayId != DEFAULT_DISPLAY) {
            Log.w(TAG, "This sample doesn't support display features on secondary displays");
@@ -211,10 +211,10 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
            return features;
        }

        Optional<List<DisplayFeature>> storedFeatures = mDisplayFeatureProducer.getData();
        Optional<List<CommonFoldingFeature>> storedFeatures = mDisplayFeatureProducer.getData();
        if (storedFeatures.isPresent()) {

            for (DisplayFeature baseFeature : storedFeatures.get()) {
            for (CommonFoldingFeature baseFeature : storedFeatures.get()) {
                Integer state = getFeatureState(baseFeature);
                if (state == null) {
                    continue;
Loading