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")
loadScene(IDevice device, Window window)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 
updateIndices(ViewNode root)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 
countFrontWhitespace(String line)146     private static int countFrontWhitespace(String line) {
147         int count = 0;
148         while (line.charAt(count) == ' ') {
149             count++;
150         }
151         return count;
152     }
153 
loadProperties(ViewNode node, String data)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