summaryrefslogtreecommitdiff
path: root/libs/WindowManager/Jetpack/src/androidx/window/common/CommonDisplayFeature.java
blob: eb9429747b66304ed6d6f5db81b68aae620ba44d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * 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+)]-?(flat|half-opened)?");

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

    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.
     *
     * @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);
            featureType = featureType == null ? "" : featureType;
            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);
            }
            String stateString = featureMatcher.group(6);
            stateString = stateString == null ? "" : stateString;
            Integer state;
            switch (stateString) {
                case PATTERN_STATE_FLAT:
                    state = COMMON_STATE_FLAT;
                    break;
                case PATTERN_STATE_HALF_OPENED:
                    state = COMMON_STATE_HALF_OPENED;
                    break;
                default:
                    state = null;
                    break;
            }
            return new CommonDisplayFeature(type, state, 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) {
        assertValidState(state);
        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);
    }

    private static void assertValidState(@Nullable Integer state) {
        if (state != null && state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED) {
            throw new IllegalArgumentException("Invalid state: " + state
                    + "must be either COMMON_STATE_FLAT or COMMON_STATE_HALF_OPENED");
        }
    }
}