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

Commit 30846638 authored by Diego Vela's avatar Diego Vela
Browse files

Remove DisplayFeature from common package.

Remove DisplayFeature interface from the common package since it really
represents a CommonFoldingFeature. This makes the code a little
confusing since it is not properly named.

Bug: 205342008
Test: manual - run WindowManager samples.
Change-Id: I18e609fb71004544e7de1f346ccef9ac04efb0d7
parent 9801ab99
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