StateSet.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.util;
18
19import com.android.internal.R;
20
21/**
22 * State sets are arrays of positive ints where each element
23 * represents the state of a {@link android.view.View} (e.g. focused,
24 * selected, visible, etc.).  A {@link android.view.View} may be in
25 * one or more of those states.
26 *
27 * A state spec is an array of signed ints where each element
28 * represents a required (if positive) or an undesired (if negative)
29 * {@link android.view.View} state.
30 *
31 * Utils dealing with state sets.
32 *
33 * In theory we could encapsulate the state set and state spec arrays
34 * and not have static methods here but there is some concern about
35 * performance since these methods are called during view drawing.
36 */
37
38public class StateSet {
39
40    public static final int[] WILD_CARD = new int[0];
41
42    /**
43     * Return whether the stateSetOrSpec is matched by all StateSets.
44     *
45     * @param stateSetOrSpec a state set or state spec.
46     */
47    public static boolean isWildCard(int[] stateSetOrSpec) {
48        return stateSetOrSpec.length == 0 || stateSetOrSpec[0] == 0;
49    }
50
51    /**
52     * Return whether the stateSet matches the desired stateSpec.
53     *
54     * @param stateSpec an array of required (if positive) or
55     *        prohibited (if negative) {@link android.view.View} states.
56     * @param stateSet an array of {@link android.view.View} states
57     */
58    public static boolean stateSetMatches(int[] stateSpec, int[] stateSet) {
59        if (stateSet == null) {
60            return (stateSpec == null || isWildCard(stateSpec));
61        }
62        int stateSpecSize = stateSpec.length;
63        int stateSetSize = stateSet.length;
64        for (int i = 0; i < stateSpecSize; i++) {
65            int stateSpecState = stateSpec[i];
66            if (stateSpecState == 0) {
67                // We've reached the end of the cases to match against.
68                return true;
69            }
70            final boolean mustMatch;
71            if (stateSpecState > 0) {
72                mustMatch = true;
73            } else {
74                // We use negative values to indicate must-NOT-match states.
75                mustMatch = false;
76                stateSpecState = -stateSpecState;
77            }
78            boolean found = false;
79            for (int j = 0; j < stateSetSize; j++) {
80                final int state = stateSet[j];
81                if (state == 0) {
82                    // We've reached the end of states to match.
83                    if (mustMatch) {
84                        // We didn't find this must-match state.
85                        return false;
86                    } else {
87                        // Continue checking other must-not-match states.
88                        break;
89                    }
90                }
91                if (state == stateSpecState) {
92                    if (mustMatch) {
93                        found = true;
94                        // Continue checking other other must-match states.
95                        break;
96                    } else {
97                        // Any match of a must-not-match state returns false.
98                        return false;
99                    }
100                }
101            }
102            if (mustMatch && !found) {
103                // We've reached the end of states to match and we didn't
104                // find a must-match state.
105                return false;
106            }
107        }
108        return true;
109    }
110
111    /**
112     * Return whether the state matches the desired stateSpec.
113     *
114     * @param stateSpec an array of required (if positive) or
115     *        prohibited (if negative) {@link android.view.View} states.
116     * @param state a {@link android.view.View} state
117     */
118    public static boolean stateSetMatches(int[] stateSpec, int state) {
119        int stateSpecSize = stateSpec.length;
120        for (int i = 0; i < stateSpecSize; i++) {
121            int stateSpecState = stateSpec[i];
122            if (stateSpecState == 0) {
123                // We've reached the end of the cases to match against.
124                return true;
125            }
126            if (stateSpecState > 0) {
127                if (state != stateSpecState) {
128                   return false;
129                }
130            } else {
131                // We use negative values to indicate must-NOT-match states.
132                if (state == -stateSpecState) {
133                    // We matched a must-not-match case.
134                    return false;
135                }
136            }
137        }
138        return true;
139    }
140
141    public static int[] trimStateSet(int[] states, int newSize) {
142        if (states.length == newSize) {
143            return states;
144        }
145
146        int[] trimmedStates = new int[newSize];
147        System.arraycopy(states, 0, trimmedStates, 0, newSize);
148        return trimmedStates;
149    }
150
151    public static String dump(int[] states) {
152        StringBuilder sb = new StringBuilder();
153
154        int count = states.length;
155        for (int i = 0; i < count; i++) {
156
157            switch (states[i]) {
158            case R.attr.state_window_focused:
159                sb.append("W ");
160                break;
161            case R.attr.state_pressed:
162                sb.append("P ");
163                break;
164            case R.attr.state_selected:
165                sb.append("S ");
166                break;
167            case R.attr.state_focused:
168                sb.append("F ");
169                break;
170            case R.attr.state_enabled:
171                sb.append("E ");
172                break;
173            }
174        }
175
176        return sb.toString();
177    }
178}
179