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