1 /* 2 * Copyright (C) 2008 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 com.android.hierarchyviewerlib.device; 18 19 import org.eclipse.swt.graphics.Image; 20 21 import java.util.ArrayList; 22 import java.util.Collections; 23 import java.util.Comparator; 24 import java.util.HashMap; 25 import java.util.List; 26 import java.util.Map; 27 import java.util.Set; 28 import java.util.TreeSet; 29 30 public class ViewNode { 31 32 public static enum ProfileRating { 33 RED, YELLOW, GREEN, NONE 34 }; 35 36 private static final double RED_THRESHOLD = 0.8; 37 38 private static final double YELLOW_THRESHOLD = 0.5; 39 40 public static final String MISCELLANIOUS = "miscellaneous"; 41 42 public String id; 43 44 public String name; 45 46 public String hashCode; 47 48 public List<Property> properties = new ArrayList<Property>(); 49 50 public Map<String, Property> namedProperties = new HashMap<String, Property>(); 51 52 public ViewNode parent; 53 54 public List<ViewNode> children = new ArrayList<ViewNode>(); 55 56 public int left; 57 58 public int top; 59 60 public int width; 61 62 public int height; 63 64 public int scrollX; 65 66 public int scrollY; 67 68 public int paddingLeft; 69 70 public int paddingRight; 71 72 public int paddingTop; 73 74 public int paddingBottom; 75 76 public int marginLeft; 77 78 public int marginRight; 79 80 public int marginTop; 81 82 public int marginBottom; 83 84 public int baseline; 85 86 public boolean willNotDraw; 87 88 public boolean hasMargins; 89 90 public boolean hasFocus; 91 92 public int index; 93 94 public double measureTime; 95 96 public double layoutTime; 97 98 public double drawTime; 99 100 public ProfileRating measureRating = ProfileRating.NONE; 101 102 public ProfileRating layoutRating = ProfileRating.NONE; 103 104 public ProfileRating drawRating = ProfileRating.NONE; 105 106 public Set<String> categories = new TreeSet<String>(); 107 108 public Window window; 109 110 public Image image; 111 112 public int imageReferences = 1; 113 114 public int viewCount; 115 116 public boolean filtered; 117 118 public int protocolVersion; 119 120 public ViewNode(Window window, ViewNode parent, String data) { 121 this.window = window; 122 this.parent = parent; 123 index = this.parent == null ? 0 : this.parent.children.size(); 124 if (this.parent != null) { 125 this.parent.children.add(this); 126 } 127 int delimIndex = data.indexOf('@'); 128 name = data.substring(0, delimIndex); 129 data = data.substring(delimIndex + 1); 130 delimIndex = data.indexOf(' '); 131 hashCode = data.substring(0, delimIndex); 132 loadProperties(data.substring(delimIndex + 1).trim()); 133 134 measureTime = -1; 135 layoutTime = -1; 136 drawTime = -1; 137 } 138 139 public void dispose() { 140 final int N = children.size(); 141 for (int i = 0; i < N; i++) { 142 children.get(i).dispose(); 143 } 144 dereferenceImage(); 145 } 146 147 public void referenceImage() { 148 imageReferences++; 149 } 150 151 public void dereferenceImage() { 152 imageReferences--; 153 if (image != null && imageReferences == 0) { 154 image.dispose(); 155 } 156 } 157 158 private void loadProperties(String data) { 159 int start = 0; 160 boolean stop; 161 do { 162 int index = data.indexOf('=', start); 163 ViewNode.Property property = new ViewNode.Property(); 164 property.name = data.substring(start, index); 165 166 int index2 = data.indexOf(',', index + 1); 167 int length = Integer.parseInt(data.substring(index + 1, index2)); 168 start = index2 + 1 + length; 169 property.value = data.substring(index2 + 1, index2 + 1 + length); 170 171 properties.add(property); 172 namedProperties.put(property.name, property); 173 174 stop = start >= data.length(); 175 if (!stop) { 176 start += 1; 177 } 178 } while (!stop); 179 180 Collections.sort(properties, new Comparator<ViewNode.Property>() { 181 public int compare(ViewNode.Property source, ViewNode.Property destination) { 182 return source.name.compareTo(destination.name); 183 } 184 }); 185 186 id = namedProperties.get("mID").value; //$NON-NLS-1$ 187 188 left = 189 namedProperties.containsKey("mLeft") ? getInt("mLeft", 0) : getInt("layout:mLeft", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 190 0); 191 top = namedProperties.containsKey("mTop") ? getInt("mTop", 0) : getInt("layout:mTop", 0); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 192 width = 193 namedProperties.containsKey("getWidth()") ? getInt("getWidth()", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 194 "layout:getWidth()", 0); //$NON-NLS-1$ 195 height = 196 namedProperties.containsKey("getHeight()") ? getInt("getHeight()", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 197 "layout:getHeight()", 0); //$NON-NLS-1$ 198 scrollX = 199 namedProperties.containsKey("mScrollX") ? getInt("mScrollX", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 200 "scrolling:mScrollX", 0); //$NON-NLS-1$ 201 scrollY = 202 namedProperties.containsKey("mScrollY") ? getInt("mScrollY", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 203 "scrolling:mScrollY", 0); //$NON-NLS-1$ 204 paddingLeft = 205 namedProperties.containsKey("mPaddingLeft") ? getInt("mPaddingLeft", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 206 "padding:mPaddingLeft", 0); //$NON-NLS-1$ 207 paddingRight = 208 namedProperties.containsKey("mPaddingRight") ? getInt("mPaddingRight", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 209 "padding:mPaddingRight", 0); //$NON-NLS-1$ 210 paddingTop = 211 namedProperties.containsKey("mPaddingTop") ? getInt("mPaddingTop", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 212 "padding:mPaddingTop", 0); //$NON-NLS-1$ 213 paddingBottom = 214 namedProperties.containsKey("mPaddingBottom") ? getInt("mPaddingBottom", 0) //$NON-NLS-1$ //$NON-NLS-2$ 215 : getInt("padding:mPaddingBottom", 0); //$NON-NLS-1$ 216 marginLeft = 217 namedProperties.containsKey("layout_leftMargin") ? getInt("layout_leftMargin", //$NON-NLS-1$ //$NON-NLS-2$ 218 Integer.MIN_VALUE) : getInt("layout:layout_leftMargin", Integer.MIN_VALUE); //$NON-NLS-1$ 219 marginRight = 220 namedProperties.containsKey("layout_rightMargin") ? getInt("layout_rightMargin", //$NON-NLS-1$ //$NON-NLS-2$ 221 Integer.MIN_VALUE) : getInt("layout:layout_rightMargin", Integer.MIN_VALUE); //$NON-NLS-1$ 222 marginTop = 223 namedProperties.containsKey("layout_topMargin") ? getInt("layout_topMargin", //$NON-NLS-1$ //$NON-NLS-2$ 224 Integer.MIN_VALUE) : getInt("layout:layout_topMargin", Integer.MIN_VALUE); //$NON-NLS-1$ 225 marginBottom = 226 namedProperties.containsKey("layout_bottomMargin") ? getInt("layout_bottomMargin", //$NON-NLS-1$ //$NON-NLS-2$ 227 Integer.MIN_VALUE) 228 : getInt("layout:layout_bottomMargin", Integer.MIN_VALUE); //$NON-NLS-1$ 229 baseline = 230 namedProperties.containsKey("getBaseline()") ? getInt("getBaseline()", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 231 "layout:getBaseline()", 0); //$NON-NLS-1$ 232 willNotDraw = 233 namedProperties.containsKey("willNotDraw()") ? getBoolean("willNotDraw()", false) //$NON-NLS-1$ //$NON-NLS-2$ 234 : getBoolean("drawing:willNotDraw()", false); //$NON-NLS-1$ 235 hasFocus = 236 namedProperties.containsKey("hasFocus()") ? getBoolean("hasFocus()", false) //$NON-NLS-1$ //$NON-NLS-2$ 237 : getBoolean("focus:hasFocus()", false); //$NON-NLS-1$ 238 239 hasMargins = 240 marginLeft != Integer.MIN_VALUE && marginRight != Integer.MIN_VALUE 241 && marginTop != Integer.MIN_VALUE && marginBottom != Integer.MIN_VALUE; 242 243 for (String name : namedProperties.keySet()) { 244 int index = name.indexOf(':'); 245 if (index != -1) { 246 categories.add(name.substring(0, index)); 247 } 248 } 249 if (categories.size() != 0) { 250 categories.add(MISCELLANIOUS); 251 } 252 } 253 254 public void setProfileRatings() { 255 final int N = children.size(); 256 if (N > 1) { 257 double totalMeasure = 0; 258 double totalLayout = 0; 259 double totalDraw = 0; 260 for (int i = 0; i < N; i++) { 261 ViewNode child = children.get(i); 262 totalMeasure += child.measureTime; 263 totalLayout += child.layoutTime; 264 totalDraw += child.drawTime; 265 } 266 for (int i = 0; i < N; i++) { 267 ViewNode child = children.get(i); 268 if (child.measureTime / totalMeasure >= RED_THRESHOLD) { 269 child.measureRating = ProfileRating.RED; 270 } else if (child.measureTime / totalMeasure >= YELLOW_THRESHOLD) { 271 child.measureRating = ProfileRating.YELLOW; 272 } else { 273 child.measureRating = ProfileRating.GREEN; 274 } 275 if (child.layoutTime / totalLayout >= RED_THRESHOLD) { 276 child.layoutRating = ProfileRating.RED; 277 } else if (child.layoutTime / totalLayout >= YELLOW_THRESHOLD) { 278 child.layoutRating = ProfileRating.YELLOW; 279 } else { 280 child.layoutRating = ProfileRating.GREEN; 281 } 282 if (child.drawTime / totalDraw >= RED_THRESHOLD) { 283 child.drawRating = ProfileRating.RED; 284 } else if (child.drawTime / totalDraw >= YELLOW_THRESHOLD) { 285 child.drawRating = ProfileRating.YELLOW; 286 } else { 287 child.drawRating = ProfileRating.GREEN; 288 } 289 } 290 } 291 for (int i = 0; i < N; i++) { 292 children.get(i).setProfileRatings(); 293 } 294 } 295 296 public void setViewCount() { 297 viewCount = 1; 298 final int N = children.size(); 299 for (int i = 0; i < N; i++) { 300 ViewNode child = children.get(i); 301 child.setViewCount(); 302 viewCount += child.viewCount; 303 } 304 } 305 306 public void filter(String text) { 307 int dotIndex = name.lastIndexOf('.'); 308 String shortName = (dotIndex == -1) ? name : name.substring(dotIndex + 1); 309 filtered = 310 !text.equals("") //$NON-NLS-1$ 311 && (shortName.toLowerCase().contains(text.toLowerCase()) || (!id 312 .equals("NO_ID") && id.toLowerCase().contains(text.toLowerCase()))); //$NON-NLS-1$ 313 final int N = children.size(); 314 for (int i = 0; i < N; i++) { 315 children.get(i).filter(text); 316 } 317 } 318 319 private boolean getBoolean(String name, boolean defaultValue) { 320 Property p = namedProperties.get(name); 321 if (p != null) { 322 try { 323 return Boolean.parseBoolean(p.value); 324 } catch (NumberFormatException e) { 325 return defaultValue; 326 } 327 } 328 return defaultValue; 329 } 330 331 private int getInt(String name, int defaultValue) { 332 Property p = namedProperties.get(name); 333 if (p != null) { 334 try { 335 return Integer.parseInt(p.value); 336 } catch (NumberFormatException e) { 337 return defaultValue; 338 } 339 } 340 return defaultValue; 341 } 342 343 @Override 344 public String toString() { 345 return name + "@" + hashCode; //$NON-NLS-1$ 346 } 347 348 public static class Property { 349 public String name; 350 351 public String value; 352 353 @Override 354 public String toString() { 355 return name + '=' + value; 356 } 357 } 358 } 359