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 17 package android.util; 18 19 import 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 38 public 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