1 /* 2 * Copyright (C) 2020 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.compat.cts; 18 19 import java.util.Objects; 20 import java.util.regex.Matcher; 21 import java.util.regex.Pattern; 22 23 import org.w3c.dom.Element; 24 import org.w3c.dom.Node; 25 26 public class Change { 27 private static final Pattern CHANGE_REGEX = Pattern.compile("^ChangeId\\((?<changeId>[0-9]+)" 28 + "(; name=(?<changeName>[^;]+))?" 29 + "(; enableSinceTargetSdk=(?<sinceSdk>[0-9]+))?" 30 + "(; (?<disabled>disabled))?" 31 + "(; (?<loggingOnly>loggingOnly))?" 32 + "(; packageOverrides=(?<overrides>[^\\);]+))?" 33 + "(; rawOverrides=(?<rawOverrides>[^\\);]+))?" 34 + "(; (?<overridable>overridable))?" 35 + "\\)"); 36 public long changeId; 37 public String changeName; 38 public int sinceSdk; 39 public boolean disabled; 40 public boolean loggingOnly; 41 public boolean overridable; 42 public boolean hasRawOverrides; 43 public boolean hasOverrides; 44 public String rawOverrideStr; 45 public String overridesStr; 46 Change(long changeId, String changeName, int sinceSdk, boolean disabled, boolean loggingOnly, boolean overridable, boolean hasRawOverrides, boolean hasOverrides, String rawOverrideStr, String overridesStr)47 private Change(long changeId, String changeName, int sinceSdk, 48 boolean disabled, boolean loggingOnly, boolean overridable, 49 boolean hasRawOverrides, boolean hasOverrides, 50 String rawOverrideStr, String overridesStr) { 51 this.changeId = changeId; 52 this.changeName = changeName; 53 this.sinceSdk = sinceSdk; 54 this.disabled = disabled; 55 this.loggingOnly = loggingOnly; 56 this.overridable = overridable; 57 this.hasRawOverrides = hasRawOverrides; 58 this.hasOverrides = hasOverrides; 59 this.rawOverrideStr = rawOverrideStr; 60 this.overridesStr = overridesStr; 61 } 62 fromString(String line)63 public static Change fromString(String line) { 64 long changeId = 0; 65 String changeName; 66 int sinceSdk = -1; 67 boolean disabled = false; 68 boolean loggingOnly = false; 69 boolean overridable = false; 70 boolean hasRawOverrides = false; 71 boolean hasOverrides = false; 72 String rawOverridesStr = null; 73 String overridesStr = null; 74 75 Matcher matcher = CHANGE_REGEX.matcher(line); 76 if (!matcher.matches()) { 77 throw new RuntimeException("Could not match line " + line); 78 } 79 80 try { 81 changeId = Long.parseLong(matcher.group("changeId")); 82 } catch (NumberFormatException e) { 83 throw new RuntimeException("No or invalid changeId!", e); 84 } 85 changeName = matcher.group("changeName"); 86 String sinceSdkAsString = matcher.group("sinceSdk"); 87 if (sinceSdkAsString != null) { 88 try { 89 sinceSdk = Integer.parseInt(sinceSdkAsString); 90 } catch (NumberFormatException e) { 91 throw new RuntimeException("Invalid sinceSdk for change!", e); 92 } 93 } 94 if (matcher.group("disabled") != null) { 95 disabled = true; 96 } 97 if (matcher.group("loggingOnly") != null) { 98 loggingOnly = true; 99 } 100 if (matcher.group("overrides") != null) { 101 hasOverrides = true; 102 overridesStr = matcher.group("overrides"); 103 } 104 if (matcher.group("rawOverrides") != null) { 105 hasRawOverrides = true; 106 rawOverridesStr = matcher.group("rawOverrides"); 107 } 108 if (matcher.group("overridable") != null) { 109 overridable = true; 110 } 111 return new Change(changeId, changeName, sinceSdk, disabled, loggingOnly, overridable, 112 hasRawOverrides, hasOverrides, rawOverridesStr, 113 overridesStr); 114 } 115 fromNode(Node node)116 public static Change fromNode(Node node) { 117 Element element = (Element) node; 118 long changeId = Long.parseLong(element.getAttribute("id")); 119 String changeName = element.getAttribute("name"); 120 int sinceSdk = -1; 121 if (element.hasAttribute("enableAfterTargetSdk") 122 && element.hasAttribute("enableSinceTargetSdk")) { 123 throw new IllegalArgumentException("Invalid change node!" 124 + "Change contains both enableAfterTargetSdk and enableSinceTargetSdk"); 125 } 126 if (element.hasAttribute("enableAfterTargetSdk")) { 127 sinceSdk = Integer.parseInt(element.getAttribute("enableAfterTargetSdk")) + 1; 128 } 129 if (element.hasAttribute("enableSinceTargetSdk")) { 130 sinceSdk = Integer.parseInt(element.getAttribute("enableSinceTargetSdk")); 131 } 132 boolean disabled = false; 133 if (element.hasAttribute("disabled")) { 134 disabled = true; 135 } 136 boolean loggingOnly = false; 137 if (element.hasAttribute("loggingOnly")) { 138 loggingOnly = true; 139 } 140 boolean overridable = false; 141 if (element.hasAttribute("overridable")) { 142 overridable = true; 143 } 144 return new Change(changeId, changeName, sinceSdk, disabled, loggingOnly, overridable, 145 /* hasRawOverrides= */ false, /* hasOverrides= */ false, 146 /* rawOverridesStr= */ null, /* overridesStr= */null); 147 } 148 149 @Override hashCode()150 public int hashCode() { 151 return Objects.hash(changeId, changeName, sinceSdk, disabled, hasOverrides); 152 } 153 154 @Override equals(Object other)155 public boolean equals(Object other) { 156 if (this == other) { 157 return true; 158 } 159 if (other == null || !(other instanceof Change)) { 160 return false; 161 } 162 Change that = (Change) other; 163 return this.changeId == that.changeId 164 && Objects.equals(this.changeName, that.changeName) 165 && this.sinceSdk == that.sinceSdk 166 && this.disabled == that.disabled 167 && this.loggingOnly == that.loggingOnly 168 && this.overridable == that.overridable; 169 } 170 171 @Override toString()172 public String toString() { 173 final StringBuilder sb = new StringBuilder(); 174 sb.append("ChangeId(" + changeId); 175 if (changeName != null && !changeName.isEmpty()) { 176 sb.append("; name=" + changeName); 177 } 178 if (sinceSdk != 0) { 179 sb.append("; enableSinceTargetSdk=" + sinceSdk); 180 } 181 if (disabled) { 182 sb.append("; disabled"); 183 } 184 if (hasOverrides) { 185 sb.append("; packageOverrides={"); 186 sb.append(overridesStr); 187 sb.append("}"); 188 } 189 if (hasRawOverrides) { 190 sb.append("; rawOverrides={"); 191 sb.append(rawOverrideStr); 192 sb.append("}"); 193 } 194 if (overridable) { 195 sb.append("; overridable"); 196 } 197 sb.append(")"); 198 return sb.toString(); 199 } 200 } 201