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.hierarchyviewer.scene; 18 19 import com.android.ddmlib.IDevice; 20 import com.android.hierarchyviewer.device.DeviceBridge; 21 import com.android.hierarchyviewer.device.Window; 22 23 import org.openide.util.Exceptions; 24 25 import java.io.BufferedReader; 26 import java.io.BufferedWriter; 27 import java.io.IOException; 28 import java.io.InputStreamReader; 29 import java.io.OutputStreamWriter; 30 import java.net.InetSocketAddress; 31 import java.net.Socket; 32 import java.util.Collections; 33 import java.util.Comparator; 34 import java.util.Stack; 35 36 public class ViewHierarchyLoader { 37 @SuppressWarnings("empty-statement") 38 public static ViewHierarchyScene loadScene(IDevice device, Window window) { 39 ViewHierarchyScene scene = new ViewHierarchyScene(); 40 41 // Read the views tree 42 Socket socket = null; 43 BufferedReader in = null; 44 BufferedWriter out = null; 45 46 String line; 47 48 try { 49 System.out.println("==> Starting client"); 50 51 socket = new Socket(); 52 socket.connect(new InetSocketAddress("127.0.0.1", 53 DeviceBridge.getDeviceLocalPort(device))); 54 55 out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); 56 in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8")); 57 58 System.out.println("==> DUMP"); 59 60 out.write("DUMP " + window.encode()); 61 out.newLine(); 62 out.flush(); 63 64 Stack<ViewNode> stack = new Stack<ViewNode>(); 65 66 boolean setRoot = true; 67 ViewNode lastNode = null; 68 int lastWhitespaceCount = Integer.MAX_VALUE; 69 70 while ((line = in.readLine()) != null) { 71 if ("DONE.".equalsIgnoreCase(line)) { 72 break; 73 } 74 75 int whitespaceCount = countFrontWhitespace(line); 76 if (lastWhitespaceCount < whitespaceCount) { 77 stack.push(lastNode); 78 } else if (!stack.isEmpty()) { 79 final int count = lastWhitespaceCount - whitespaceCount; 80 for (int i = 0; i < count; i++) { 81 stack.pop(); 82 } 83 } 84 85 lastWhitespaceCount = whitespaceCount; 86 line = line.trim(); 87 int index = line.indexOf(' '); 88 89 lastNode = new ViewNode(); 90 lastNode.name = line.substring(0, index); 91 92 line = line.substring(index + 1); 93 loadProperties(lastNode, line); 94 95 scene.addNode(lastNode); 96 97 if (setRoot) { 98 scene.setRoot(lastNode); 99 setRoot = false; 100 } 101 102 if (!stack.isEmpty()) { 103 final ViewNode parent = stack.peek(); 104 final String edge = parent.name + lastNode.name; 105 scene.addEdge(edge); 106 scene.setEdgeSource(edge, parent); 107 scene.setEdgeTarget(edge, lastNode); 108 lastNode.parent = parent; 109 parent.children.add(lastNode); 110 } 111 } 112 113 updateIndices(scene.getRoot()); 114 115 } catch (IOException ex) { 116 Exceptions.printStackTrace(ex); 117 } finally { 118 try { 119 if (out != null) { 120 out.close(); 121 } 122 if (in != null) { 123 in.close(); 124 } 125 socket.close(); 126 } catch (IOException ex) { 127 Exceptions.printStackTrace(ex); 128 } 129 } 130 131 System.out.println("==> DONE"); 132 133 return scene; 134 } 135 136 private static void updateIndices(ViewNode root) { 137 if (root == null) return; 138 139 root.computeIndex(); 140 141 for (ViewNode node : root.children) { 142 updateIndices(node); 143 } 144 } 145 146 private static int countFrontWhitespace(String line) { 147 int count = 0; 148 while (line.charAt(count) == ' ') { 149 count++; 150 } 151 return count; 152 } 153 154 private static void loadProperties(ViewNode node, String data) { 155 int start = 0; 156 boolean stop; 157 158 do { 159 int index = data.indexOf('=', start); 160 ViewNode.Property property = new ViewNode.Property(); 161 property.name = data.substring(start, index); 162 163 int colonIndex = property.name.indexOf(':'); 164 if (colonIndex != -1) { 165 property.name = property.name.substring(colonIndex + 1); 166 } 167 168 int index2 = data.indexOf(',', index + 1); 169 int length = Integer.parseInt(data.substring(index + 1, index2)); 170 start = index2 + 1 + length; 171 property.value = data.substring(index2 + 1, index2 + 1 + length); 172 173 node.properties.add(property); 174 node.namedProperties.put(property.name, property); 175 176 stop = start >= data.length(); 177 if (!stop) { 178 start += 1; 179 } 180 } while (!stop); 181 182 Collections.sort(node.properties, new Comparator<ViewNode.Property>() { 183 public int compare(ViewNode.Property source, ViewNode.Property destination) { 184 return source.name.compareTo(destination.name); 185 } 186 }); 187 188 node.decode(); 189 } 190 } 191