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 ViewNode(Window window, ViewNode parent, String data)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 dispose()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 referenceImage()147 public void referenceImage() { 148 imageReferences++; 149 } 150 dereferenceImage()151 public void dereferenceImage() { 152 imageReferences--; 153 if (image != null && imageReferences == 0) { 154 image.dispose(); 155 } 156 } 157 loadProperties(String data)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 @Override 182 public int compare(ViewNode.Property source, ViewNode.Property destination) { 183 return source.name.compareTo(destination.name); 184 } 185 }); 186 187 id = namedProperties.get("mID").value; //$NON-NLS-1$ 188 189 left = 190 namedProperties.containsKey("mLeft") ? getInt("mLeft", 0) : getInt("layout:mLeft", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 191 0); 192 top = namedProperties.containsKey("mTop") ? getInt("mTop", 0) : getInt("layout:mTop", 0); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 193 width = 194 namedProperties.containsKey("getWidth()") ? getInt("getWidth()", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 195 "layout:getWidth()", 0); //$NON-NLS-1$ 196 height = 197 namedProperties.containsKey("getHeight()") ? getInt("getHeight()", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 198 "layout:getHeight()", 0); //$NON-NLS-1$ 199 scrollX = 200 namedProperties.containsKey("mScrollX") ? getInt("mScrollX", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 201 "scrolling:mScrollX", 0); //$NON-NLS-1$ 202 scrollY = 203 namedProperties.containsKey("mScrollY") ? getInt("mScrollY", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 204 "scrolling:mScrollY", 0); //$NON-NLS-1$ 205 paddingLeft = 206 namedProperties.containsKey("mPaddingLeft") ? getInt("mPaddingLeft", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 207 "padding:mPaddingLeft", 0); //$NON-NLS-1$ 208 paddingRight = 209 namedProperties.containsKey("mPaddingRight") ? getInt("mPaddingRight", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 210 "padding:mPaddingRight", 0); //$NON-NLS-1$ 211 paddingTop = 212 namedProperties.containsKey("mPaddingTop") ? getInt("mPaddingTop", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 213 "padding:mPaddingTop", 0); //$NON-NLS-1$ 214 paddingBottom = 215 namedProperties.containsKey("mPaddingBottom") ? getInt("mPaddingBottom", 0) //$NON-NLS-1$ //$NON-NLS-2$ 216 : getInt("padding:mPaddingBottom", 0); //$NON-NLS-1$ 217 marginLeft = 218 namedProperties.containsKey("layout_leftMargin") ? getInt("layout_leftMargin", //$NON-NLS-1$ //$NON-NLS-2$ 219 Integer.MIN_VALUE) : getInt("layout:layout_leftMargin", Integer.MIN_VALUE); //$NON-NLS-1$ 220 marginRight = 221 namedProperties.containsKey("layout_rightMargin") ? getInt("layout_rightMargin", //$NON-NLS-1$ //$NON-NLS-2$ 222 Integer.MIN_VALUE) : getInt("layout:layout_rightMargin", Integer.MIN_VALUE); //$NON-NLS-1$ 223 marginTop = 224 namedProperties.containsKey("layout_topMargin") ? getInt("layout_topMargin", //$NON-NLS-1$ //$NON-NLS-2$ 225 Integer.MIN_VALUE) : getInt("layout:layout_topMargin", Integer.MIN_VALUE); //$NON-NLS-1$ 226 marginBottom = 227 namedProperties.containsKey("layout_bottomMargin") ? getInt("layout_bottomMargin", //$NON-NLS-1$ //$NON-NLS-2$ 228 Integer.MIN_VALUE) 229 : getInt("layout:layout_bottomMargin", Integer.MIN_VALUE); //$NON-NLS-1$ 230 baseline = 231 namedProperties.containsKey("getBaseline()") ? getInt("getBaseline()", 0) : getInt( //$NON-NLS-1$ //$NON-NLS-2$ 232 "layout:getBaseline()", 0); //$NON-NLS-1$ 233 willNotDraw = 234 namedProperties.containsKey("willNotDraw()") ? getBoolean("willNotDraw()", false) //$NON-NLS-1$ //$NON-NLS-2$ 235 : getBoolean("drawing:willNotDraw()", false); //$NON-NLS-1$ 236 hasFocus = 237 namedProperties.containsKey("hasFocus()") ? getBoolean("hasFocus()", false) //$NON-NLS-1$ //$NON-NLS-2$ 238 : getBoolean("focus:hasFocus()", false); //$NON-NLS-1$ 239 240 hasMargins = 241 marginLeft != Integer.MIN_VALUE && marginRight != Integer.MIN_VALUE 242 && marginTop != Integer.MIN_VALUE && marginBottom != Integer.MIN_VALUE; 243 244 for (String name : namedProperties.keySet()) { 245 int index = name.indexOf(':'); 246 if (index != -1) { 247 categories.add(name.substring(0, index)); 248 } 249 } 250 if (categories.size() != 0) { 251 categories.add(MISCELLANIOUS); 252 } 253 } 254 setProfileRatings()255 public void setProfileRatings() { 256 final int N = children.size(); 257 if (N > 1) { 258 double totalMeasure = 0; 259 double totalLayout = 0; 260 double totalDraw = 0; 261 for (int i = 0; i < N; i++) { 262 ViewNode child = children.get(i); 263 totalMeasure += child.measureTime; 264 totalLayout += child.layoutTime; 265 totalDraw += child.drawTime; 266 } 267 for (int i = 0; i < N; i++) { 268 ViewNode child = children.get(i); 269 if (child.measureTime / totalMeasure >= RED_THRESHOLD) { 270 child.measureRating = ProfileRating.RED; 271 } else if (child.measureTime / totalMeasure >= YELLOW_THRESHOLD) { 272 child.measureRating = ProfileRating.YELLOW; 273 } else { 274 child.measureRating = ProfileRating.GREEN; 275 } 276 if (child.layoutTime / totalLayout >= RED_THRESHOLD) { 277 child.layoutRating = ProfileRating.RED; 278 } else if (child.layoutTime / totalLayout >= YELLOW_THRESHOLD) { 279 child.layoutRating = ProfileRating.YELLOW; 280 } else { 281 child.layoutRating = ProfileRating.GREEN; 282 } 283 if (child.drawTime / totalDraw >= RED_THRESHOLD) { 284 child.drawRating = ProfileRating.RED; 285 } else if (child.drawTime / totalDraw >= YELLOW_THRESHOLD) { 286 child.drawRating = ProfileRating.YELLOW; 287 } else { 288 child.drawRating = ProfileRating.GREEN; 289 } 290 } 291 } 292 for (int i = 0; i < N; i++) { 293 children.get(i).setProfileRatings(); 294 } 295 } 296 setViewCount()297 public void setViewCount() { 298 viewCount = 1; 299 final int N = children.size(); 300 for (int i = 0; i < N; i++) { 301 ViewNode child = children.get(i); 302 child.setViewCount(); 303 viewCount += child.viewCount; 304 } 305 } 306 filter(String text)307 public void filter(String text) { 308 int dotIndex = name.lastIndexOf('.'); 309 String shortName = (dotIndex == -1) ? name : name.substring(dotIndex + 1); 310 filtered = 311 !text.equals("") //$NON-NLS-1$ 312 && (shortName.toLowerCase().contains(text.toLowerCase()) || (!id 313 .equals("NO_ID") && id.toLowerCase().contains(text.toLowerCase()))); //$NON-NLS-1$ 314 final int N = children.size(); 315 for (int i = 0; i < N; i++) { 316 children.get(i).filter(text); 317 } 318 } 319 getBoolean(String name, boolean defaultValue)320 private boolean getBoolean(String name, boolean defaultValue) { 321 Property p = namedProperties.get(name); 322 if (p != null) { 323 try { 324 return Boolean.parseBoolean(p.value); 325 } catch (NumberFormatException e) { 326 return defaultValue; 327 } 328 } 329 return defaultValue; 330 } 331 getInt(String name, int defaultValue)332 private int getInt(String name, int defaultValue) { 333 Property p = namedProperties.get(name); 334 if (p != null) { 335 try { 336 return Integer.parseInt(p.value); 337 } catch (NumberFormatException e) { 338 return defaultValue; 339 } 340 } 341 return defaultValue; 342 } 343 344 @Override toString()345 public String toString() { 346 return name + "@" + hashCode; //$NON-NLS-1$ 347 } 348 349 public static class Property { 350 public String name; 351 352 public String value; 353 354 @Override toString()355 public String toString() { 356 return name + '=' + value; 357 } 358 } 359 } 360