auto import from //depot/cupcake/@135843

This commit is contained in:
The Android Open Source Project
2009-03-03 18:28:16 -08:00
parent d2f2b1d7b7
commit d4aee0c0ca
2356 changed files with 0 additions and 295812 deletions

View File

@@ -1,30 +0,0 @@
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_JAVA_RESOURCE_DIRS := resources
LOCAL_JAR_MANIFEST := ../etc/manifest.txt
LOCAL_JAVA_LIBRARIES := \
ddmlib \
swing-worker-1.1 \
org-openide-util \
org-netbeans-api-visual
LOCAL_MODULE := hierarchyviewer
include $(BUILD_HOST_JAVA_LIBRARY)

View File

@@ -1,67 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer;
import com.android.hierarchyviewer.ui.Workspace;
import com.android.hierarchyviewer.device.DeviceBridge;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class HierarchyViewer {
private static final CharSequence OS_WINDOWS = "Windows";
private static final CharSequence OS_MACOSX = "Mac OS X";
private static void initUserInterface() {
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("apple.awt.brushMetalLook", "true");
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "HierarchyViewer");
final String os = System.getProperty("os.name");
try {
if (os.contains(OS_WINDOWS) || os.contains(OS_MACOSX)) {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} else {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
initUserInterface();
DeviceBridge.initDebugBridge();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Workspace workspace = new Workspace();
workspace.setDefaultCloseOperation(Workspace.EXIT_ON_CLOSE);
workspace.setLocationRelativeTo(null);
workspace.setVisible(true);
}
});
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.device;
public class Configuration {
public static final int DEFAULT_SERVER_PORT = 4939;
// These codes must match the auto-generated codes in IWindowManager.java
// See IWindowManager.aidl as well
public static final int SERVICE_CODE_START_SERVER = 1;
public static final int SERVICE_CODE_STOP_SERVER = 2;
public static final int SERVICE_CODE_IS_SERVER_RUNNING = 3;
}

View File

@@ -1,190 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.device;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.Device;
import com.android.ddmlib.Log;
import com.android.ddmlib.MultiLineReceiver;
import java.io.IOException;
import java.io.File;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DeviceBridge {
private static AndroidDebugBridge bridge;
private static final HashMap<Device, Integer> devicePortMap = new HashMap<Device, Integer>();
private static int nextLocalPort = Configuration.DEFAULT_SERVER_PORT;
public static void initDebugBridge() {
if (bridge == null) {
AndroidDebugBridge.init(false /* debugger support */);
}
if (bridge == null || !bridge.isConnected()) {
String adbLocation = System.getProperty("hierarchyviewer.adb");
if (adbLocation != null && adbLocation.length() != 0) {
adbLocation += File.separator + "adb";
} else {
adbLocation = "adb";
}
bridge = AndroidDebugBridge.createBridge(adbLocation, true);
}
}
public static void startListenForDevices(AndroidDebugBridge.IDeviceChangeListener listener) {
AndroidDebugBridge.addDeviceChangeListener(listener);
}
public static void stopListenForDevices(AndroidDebugBridge.IDeviceChangeListener listener) {
AndroidDebugBridge.removeDeviceChangeListener(listener);
}
public static Device[] getDevices() {
return bridge.getDevices();
}
public static boolean isViewServerRunning(Device device) {
initDebugBridge();
final boolean[] result = new boolean[1];
try {
if (device.isOnline()) {
device.executeShellCommand(buildIsServerRunningShellCommand(),
new BooleanResultReader(result));
}
} catch (IOException e) {
e.printStackTrace();
}
return result[0];
}
public static boolean startViewServer(Device device) {
return startViewServer(device, Configuration.DEFAULT_SERVER_PORT);
}
public static boolean startViewServer(Device device, int port) {
initDebugBridge();
final boolean[] result = new boolean[1];
try {
if (device.isOnline()) {
device.executeShellCommand(buildStartServerShellCommand(port),
new BooleanResultReader(result));
}
} catch (IOException e) {
e.printStackTrace();
}
return result[0];
}
public static boolean stopViewServer(Device device) {
initDebugBridge();
final boolean[] result = new boolean[1];
try {
if (device.isOnline()) {
device.executeShellCommand(buildStopServerShellCommand(),
new BooleanResultReader(result));
}
} catch (IOException e) {
e.printStackTrace();
}
return result[0];
}
public static void terminate() {
AndroidDebugBridge.terminate();
}
/**
* Sets up a just-connected device to work with the view server.
* <p/>This starts a port forwarding between a local port and a port on the device.
* @param device
*/
public static void setupDeviceForward(Device device) {
synchronized (devicePortMap) {
if (device.getState() == Device.DeviceState.ONLINE) {
int localPort = nextLocalPort++;
device.createForward(localPort, Configuration.DEFAULT_SERVER_PORT);
devicePortMap.put(device, localPort);
}
}
}
public static void removeDeviceForward(Device device) {
synchronized (devicePortMap) {
final Integer localPort = devicePortMap.get(device);
if (localPort != null) {
device.removeForward(localPort, Configuration.DEFAULT_SERVER_PORT);
devicePortMap.remove(device);
}
}
}
public static int getDeviceLocalPort(Device device) {
synchronized (devicePortMap) {
Integer port = devicePortMap.get(device);
if (port != null) {
return port;
}
Log.e("hierarchy", "Missing forwarded port for " + device.getSerialNumber());
return -1;
}
}
private static String buildStartServerShellCommand(int port) {
return String.format("service call window %d i32 %d",
Configuration.SERVICE_CODE_START_SERVER, port);
}
private static String buildStopServerShellCommand() {
return String.format("service call window %d", Configuration.SERVICE_CODE_STOP_SERVER);
}
private static String buildIsServerRunningShellCommand() {
return String.format("service call window %d",
Configuration.SERVICE_CODE_IS_SERVER_RUNNING);
}
private static class BooleanResultReader extends MultiLineReceiver {
private final boolean[] mResult;
public BooleanResultReader(boolean[] result) {
mResult = result;
}
@Override
public void processNewLines(String[] strings) {
if (strings.length > 0) {
Pattern pattern = Pattern.compile(".*?\\([0-9]{8} ([0-9]{8}).*");
Matcher matcher = pattern.matcher(strings[0]);
if (matcher.matches()) {
if (Integer.parseInt(matcher.group(1)) == 1) {
mResult[0] = true;
}
}
}
}
public boolean isCancelled() {
return false;
}
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.device;
public class Window {
public static final Window FOCUSED_WINDOW = new Window("<Focused Window>", -1);
private String title;
private int hashCode;
public Window(String title, int hashCode) {
this.title = title;
this.hashCode = hashCode;
}
public String getTitle() {
return title;
}
public int getHashCode() {
return hashCode;
}
public String encode() {
return Integer.toHexString(hashCode);
}
public String toString() {
return title;
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.laf;
import javax.swing.border.AbstractBorder;
import java.awt.*;
public class UnifiedContentBorder extends AbstractBorder {
private static final Color BORDER_TOP_COLOR1 = new Color(0x575757);
private static final Color BORDER_BOTTOM_COLOR1 = new Color(0x404040);
private static final Color BORDER_BOTTOM_COLOR2 = new Color(0xd8d8d8);
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
g.setColor(BORDER_TOP_COLOR1);
g.drawLine(x, y, x + width, y);
g.setColor(BORDER_BOTTOM_COLOR1);
g.drawLine(x, y + height - 2, x + width, y + height - 2);
g.setColor(BORDER_BOTTOM_COLOR2);
g.drawLine(x, y + height - 1, x + width, y + height - 1);
}
public Insets getBorderInsets(Component component) {
return new Insets(1, 0, 2, 0);
}
public boolean isBorderOpaque() {
return true;
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.scene;
import com.android.ddmlib.Device;
import com.android.hierarchyviewer.device.Configuration;
import com.android.hierarchyviewer.device.Window;
import com.android.hierarchyviewer.device.DeviceBridge;
import java.awt.Image;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.imageio.ImageIO;
public class CaptureLoader {
public static Image loadCapture(Device device, Window window, String params) {
Socket socket = null;
BufferedInputStream in = null;
BufferedWriter out = null;
try {
socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1",
DeviceBridge.getDeviceLocalPort(device)));
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
in = new BufferedInputStream(socket.getInputStream());
out.write("CAPTURE " + window.encode() + " " + params);
out.newLine();
out.flush();
return ImageIO.read(in);
} catch (IOException e) {
// Empty
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return null;
}
}

View File

@@ -1,173 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.scene;
import com.android.ddmlib.Device;
import com.android.hierarchyviewer.device.DeviceBridge;
import com.android.hierarchyviewer.device.Window;
import org.openide.util.Exceptions;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Collections;
import java.util.Comparator;
import java.util.Stack;
public class ViewHierarchyLoader {
@SuppressWarnings("empty-statement")
public static ViewHierarchyScene loadScene(Device device, Window window) {
ViewHierarchyScene scene = new ViewHierarchyScene();
// Read the views tree
Socket socket = null;
BufferedReader in = null;
BufferedWriter out = null;
String line;
try {
System.out.println("==> Starting client");
socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1",
DeviceBridge.getDeviceLocalPort(device)));
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("==> DUMP");
out.write("DUMP " + window.encode());
out.newLine();
out.flush();
Stack<ViewNode> stack = new Stack<ViewNode>();
boolean setRoot = true;
ViewNode lastNode = null;
int lastWhitespaceCount = Integer.MAX_VALUE;
while ((line = in.readLine()) != null) {
if ("DONE.".equalsIgnoreCase(line)) {
break;
}
int whitespaceCount = countFrontWhitespace(line);
if (lastWhitespaceCount < whitespaceCount) {
stack.push(lastNode);
} else if (!stack.isEmpty()) {
final int count = lastWhitespaceCount - whitespaceCount;
for (int i = 0; i < count; i++) {
stack.pop();
}
}
lastWhitespaceCount = whitespaceCount;
line = line.trim();
int index = line.indexOf(' ');
lastNode = new ViewNode();
lastNode.name = line.substring(0, index);
line = line.substring(index + 1);
loadProperties(lastNode, line);
scene.addNode(lastNode);
if (setRoot) {
scene.setRoot(lastNode);
setRoot = false;
}
if (!stack.isEmpty()) {
final ViewNode parent = stack.peek();
final String edge = parent.name + lastNode.name;
scene.addEdge(edge);
scene.setEdgeSource(edge, parent);
scene.setEdgeTarget(edge, lastNode);
lastNode.parent = parent;
parent.children.add(lastNode);
}
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
socket.close();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
System.out.println("==> DONE");
return scene;
}
private static int countFrontWhitespace(String line) {
int count = 0;
while (line.charAt(count) == ' ') {
count++;
}
return count;
}
private static void loadProperties(ViewNode node, String data) {
int start = 0;
boolean stop;
do {
int index = data.indexOf('=', start);
ViewNode.Property property = new ViewNode.Property();
property.name = data.substring(start, index);
int index2 = data.indexOf(',', index + 1);
int length = Integer.parseInt(data.substring(index + 1, index2));
start = index2 + 1 + length;
property.value = data.substring(index2 + 1, index2 + 1 + length);
node.properties.add(property);
node.namedProperties.put(property.name, property);
stop = start >= data.length();
if (!stop) {
start += 1;
}
} while (!stop);
Collections.sort(node.properties, new Comparator<ViewNode.Property>() {
public int compare(ViewNode.Property source, ViewNode.Property destination) {
return source.name.compareTo(destination.name);
}
});
node.decode();
}
}

View File

@@ -1,219 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.scene;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import org.netbeans.api.visual.action.ActionFactory;
import org.netbeans.api.visual.action.WidgetAction;
import org.netbeans.api.visual.anchor.AnchorFactory;
import org.netbeans.api.visual.border.BorderFactory;
import org.netbeans.api.visual.graph.GraphScene;
import org.netbeans.api.visual.layout.LayoutFactory;
import org.netbeans.api.visual.model.ObjectState;
import org.netbeans.api.visual.widget.ConnectionWidget;
import org.netbeans.api.visual.widget.LabelWidget;
import org.netbeans.api.visual.widget.LayerWidget;
import org.netbeans.api.visual.widget.Widget;
public class ViewHierarchyScene extends GraphScene<ViewNode, String> {
private ViewNode root;
private LayerWidget widgetLayer;
private LayerWidget connectionLayer;
private WidgetAction moveAction = ActionFactory.createMoveAction();
public ViewHierarchyScene() {
widgetLayer = new LayerWidget(this);
connectionLayer = new LayerWidget(this);
addChild(widgetLayer);
addChild(connectionLayer);
}
public ViewNode getRoot() {
return root;
}
void setRoot(ViewNode root) {
this.root = root;
}
@Override
protected Widget attachNodeWidget(ViewNode node) {
Widget widget = createBox(node.name, node.id);
widget.getActions().addAction(createSelectAction());
widget.getActions().addAction(moveAction);
widgetLayer.addChild(widget);
return widget;
}
private Widget createBox(String node, String id) {
Widget box = new GradientWidget(this);
box.setLayout(LayoutFactory.createVerticalFlowLayout());
box.setBorder(BorderFactory.createLineBorder(2, Color.BLACK));
box.setOpaque(true);
LabelWidget label = new LabelWidget(this);
label.setFont(getDefaultFont().deriveFont(Font.PLAIN, 12.0f));
label.setLabel(getShortName(node));
label.setBorder(BorderFactory.createEmptyBorder(6, 6, 0, 6));
label.setAlignment(LabelWidget.Alignment.CENTER);
box.addChild(label);
label = new LabelWidget(this);
label.setFont(getDefaultFont().deriveFont(Font.PLAIN, 10.0f));
label.setLabel(getAddress(node));
label.setBorder(BorderFactory.createEmptyBorder(3, 6, 0, 6));
label.setAlignment(LabelWidget.Alignment.CENTER);
box.addChild(label);
label = new LabelWidget(this);
label.setFont(getDefaultFont().deriveFont(Font.PLAIN, 10.0f));
label.setLabel(id);
label.setBorder(BorderFactory.createEmptyBorder(3, 6, 6, 6));
label.setAlignment(LabelWidget.Alignment.CENTER);
box.addChild(label);
return box;
}
private static String getAddress(String name) {
String[] nameAndHashcode = name.split("@");
return "@" + nameAndHashcode[1];
}
private static String getShortName(String name) {
String[] nameAndHashcode = name.split("@");
String[] packages = nameAndHashcode[0].split("\\.");
return packages[packages.length - 1];
}
@Override
protected Widget attachEdgeWidget(String edge) {
ConnectionWidget connectionWidget = new ConnectionWidget(this);
connectionLayer.addChild(connectionWidget);
return connectionWidget;
}
@Override
protected void attachEdgeSourceAnchor(String edge, ViewNode oldSourceNode, ViewNode sourceNode) {
final ConnectionWidget connection = (ConnectionWidget) findWidget(edge);
final Widget source = findWidget(sourceNode);
connection.bringToBack();
source.bringToFront();
connection.setSourceAnchor(AnchorFactory.createRectangularAnchor(source));
}
@Override
protected void attachEdgeTargetAnchor(String edge, ViewNode oldTargetNode, ViewNode targetNode) {
final ConnectionWidget connection = (ConnectionWidget) findWidget(edge);
final Widget target = findWidget(targetNode);
connection.bringToBack();
target.bringToFront();
connection.setTargetAnchor(AnchorFactory.createRectangularAnchor(target));
}
private static class GradientWidget extends Widget {
public static final GradientPaint BLUE_EXPERIENCE = new GradientPaint(
new Point2D.Double(0, 0),
new Color(168, 204, 241),
new Point2D.Double(0, 1),
new Color(44, 61, 146));
public static final GradientPaint MAC_OSX_SELECTED = new GradientPaint(
new Point2D.Double(0, 0),
new Color(81, 141, 236),
new Point2D.Double(0, 1),
new Color(36, 96, 192));
public static final GradientPaint MAC_OSX = new GradientPaint(
new Point2D.Double(0, 0),
new Color(167, 210, 250),
new Point2D.Double(0, 1),
new Color(99, 147, 206));
public static final GradientPaint AERITH = new GradientPaint(
new Point2D.Double(0, 0),
Color.WHITE,
new Point2D.Double(0, 1),
new Color(64, 110, 161));
public static final GradientPaint GRAY = new GradientPaint(
new Point2D.Double(0, 0),
new Color(226, 226, 226),
new Point2D.Double(0, 1),
new Color(250, 248, 248));
public static final GradientPaint RED_XP = new GradientPaint(
new Point2D.Double(0, 0),
new Color(236, 81, 81),
new Point2D.Double(0, 1),
new Color(192, 36, 36));
public static final GradientPaint NIGHT_GRAY = new GradientPaint(
new Point2D.Double(0, 0),
new Color(102, 111, 127),
new Point2D.Double(0, 1),
new Color(38, 45, 61));
public static final GradientPaint NIGHT_GRAY_LIGHT = new GradientPaint(
new Point2D.Double(0, 0),
new Color(129, 138, 155),
new Point2D.Double(0, 1),
new Color(58, 66, 82));
private static Color UNSELECTED = Color.BLACK;
private static Color SELECTED = Color.WHITE;
private boolean isSelected = false;
private GradientPaint gradient = MAC_OSX_SELECTED;
public GradientWidget(ViewHierarchyScene scene) {
super(scene);
}
@Override
protected void notifyStateChanged(ObjectState previous, ObjectState state) {
super.notifyStateChanged(previous, state);
isSelected = state.isSelected() || state.isFocused() || state.isWidgetFocused();
for (Widget child : getChildren()) {
child.setForeground(isSelected ? SELECTED : UNSELECTED);
}
repaint();
}
@Override
protected void paintBackground() {
super.paintBackground();
Graphics2D g2 = getGraphics();
Rectangle bounds = getBounds();
if (!isSelected) {
g2.setColor(Color.WHITE);
} else {
g2.setPaint(new GradientPaint(bounds.x, bounds.y, gradient.getColor1(),
bounds.x, bounds.x + bounds.height, gradient.getColor2()));
}
g2.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.scene;
import com.android.ddmlib.Device;
import com.android.hierarchyviewer.device.Configuration;
import com.android.hierarchyviewer.device.Window;
import com.android.hierarchyviewer.device.DeviceBridge;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
public class ViewManager {
public static void invalidate(Device device, Window window, String params) {
sendCommand("INVALIDATE", device, window, params);
}
public static void requestLayout(Device device, Window window, String params) {
sendCommand("REQUEST_LAYOUT", device, window, params);
}
private static void sendCommand(String command, Device device, Window window, String params) {
Socket socket = null;
BufferedWriter out = null;
try {
socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1",
DeviceBridge.getDeviceLocalPort(device)));
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write(command + " " + window.encode() + " " + params);
out.newLine();
out.flush();
} catch (IOException e) {
// Empty
} finally {
try {
if (out != null) {
out.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}

View File

@@ -1,167 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.scene;
import java.awt.Image;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ViewNode {
public String id;
public String name;
public List<Property> properties = new ArrayList<Property>();
public Map<String, Property> namedProperties = new HashMap<String, Property>();
public ViewNode parent;
public List<ViewNode> children = new ArrayList<ViewNode>();
public Image image;
public int left;
public int top;
public int width;
public int height;
public int scrollX;
public int scrollY;
public int paddingLeft;
public int paddingRight;
public int paddingTop;
public int paddingBottom;
public int marginLeft;
public int marginRight;
public int marginTop;
public int marginBottom;
public int baseline;
public boolean willNotDraw;
public boolean hasMargins;
public boolean decoded;
void decode() {
id = namedProperties.get("mID").value;
left = getInt("mLeft", 0);
top = getInt("mTop", 0);
width = getInt("getWidth()", 0);
height = getInt("getHeight()", 0);
scrollX = getInt("mScrollX", 0);
scrollY = getInt("mScrollY", 0);
paddingLeft = getInt("mPaddingLeft", 0);
paddingRight = getInt("mPaddingRight", 0);
paddingTop = getInt("mPaddingTop", 0);
paddingBottom = getInt("mPaddingBottom", 0);
marginLeft = getInt("layout_leftMargin", Integer.MIN_VALUE);
marginRight = getInt("layout_rightMargin", Integer.MIN_VALUE);
marginTop = getInt("layout_topMargin", Integer.MIN_VALUE);
marginBottom = getInt("layout_bottomMargin", Integer.MIN_VALUE);
baseline = getInt("getBaseline()", 0);
willNotDraw = getBoolean("willNotDraw()", false);
hasMargins = marginLeft != Integer.MIN_VALUE &&
marginRight != Integer.MIN_VALUE &&
marginTop != Integer.MIN_VALUE &&
marginBottom != Integer.MIN_VALUE;
decoded = true;
}
private boolean getBoolean(String name, boolean defaultValue) {
Property p = namedProperties.get(name);
if (p != null) {
try {
return Boolean.parseBoolean(p.value);
} catch (NumberFormatException e) {
return defaultValue;
}
}
return defaultValue;
}
private int getInt(String name, int defaultValue) {
Property p = namedProperties.get(name);
if (p != null) {
try {
return Integer.parseInt(p.value);
} catch (NumberFormatException e) {
return defaultValue;
}
}
return defaultValue;
}
@SuppressWarnings({"StringEquality"})
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ViewNode other = (ViewNode) obj;
return !(this.name != other.name && (this.name == null || !this.name.equals(other.name)));
}
@Override
public String toString() {
return name;
}
@Override
public int hashCode() {
int hash = 5;
hash = 67 * hash + (this.name != null ? this.name.hashCode() : 0);
return hash;
}
public static class Property {
public String name;
public String value;
@Override
public String toString() {
return name + '=' + value;
}
@SuppressWarnings({"StringEquality"})
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Property other = (Property) obj;
if (this.name != other.name && (this.name == null || !this.name.equals(other.name))) {
return false;
}
return !(this.value != other.value && (this.value == null || !this.value.equals(other.value)));
}
@Override
public int hashCode() {
int hash = 5;
hash = 61 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 61 * hash + (this.value != null ? this.value.hashCode() : 0);
return hash;
}
}
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.scene;
import com.android.ddmlib.Device;
import com.android.hierarchyviewer.device.DeviceBridge;
import com.android.hierarchyviewer.device.Window;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
public class WindowsLoader {
public static Window[] loadWindows(Device device) {
Socket socket = null;
BufferedReader in = null;
BufferedWriter out = null;
try {
ArrayList<Window> windows = new ArrayList<Window>();
socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1",
DeviceBridge.getDeviceLocalPort(device)));
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.write("LIST");
out.newLine();
out.flush();
String line;
while ((line = in.readLine()) != null) {
if ("DONE.".equalsIgnoreCase(line)) {
break;
}
int index = line.indexOf(' ');
if (index != -1) {
Window w = new Window(line.substring(index + 1),
Integer.parseInt(line.substring(0, index), 16));
windows.add(w);
}
}
return windows.toArray(new Window[windows.size()]);
} catch (IOException e) {
// Empty
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return new Window[0];
}
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui;
import com.android.hierarchyviewer.scene.ViewNode;
import javax.swing.*;
import java.awt.*;
class CaptureRenderer extends JLabel {
private ViewNode node;
private boolean showExtras;
CaptureRenderer(ImageIcon icon, ViewNode node) {
super(icon);
this.node = node;
setBackground(Color.BLACK);
}
@Override
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
if (node.hasMargins) {
d.width += node.marginLeft + node.marginRight;
d.height += node.marginTop + node.marginBottom;
}
return d;
}
public void setShowExtras(boolean showExtras) {
this.showExtras = showExtras;
repaint();
}
@Override
protected void paintComponent(Graphics g) {
Icon icon = getIcon();
int width = icon.getIconWidth();
int height = icon.getIconHeight();
int x = (getWidth() - width) / 2;
int y = (getHeight() - height) / 2;
icon.paintIcon(this, g, x, y);
if (showExtras) {
g.translate(x, y);
g.setXORMode(Color.WHITE);
if ((node.paddingBottom | node.paddingLeft |
node.paddingTop | node.paddingRight) != 0) {
g.setColor(Color.RED);
g.drawRect(node.paddingLeft, node.paddingTop,
width - node.paddingRight - node.paddingLeft,
height - node.paddingBottom - node.paddingTop);
}
if (node.baseline != -1) {
g.setColor(Color.BLUE);
g.drawLine(0, node.baseline, width, node.baseline);
}
if (node.hasMargins && (node.marginLeft | node.marginBottom |
node.marginRight | node.marginRight) != 0) {
g.setColor(Color.BLACK);
g.drawRect(-node.marginLeft, -node.marginTop,
node.marginLeft + width + node.marginRight,
node.marginTop + height + node.marginBottom);
}
g.translate(-x, -y);
}
}
}

View File

@@ -1,121 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui;
import com.android.hierarchyviewer.scene.ViewHierarchyScene;
import com.android.hierarchyviewer.scene.ViewNode;
import javax.swing.JComponent;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.util.Set;
class LayoutRenderer extends JComponent {
private static final int EMULATED_SCREEN_WIDTH = 320;
private static final int EMULATED_SCREEN_HEIGHT = 480;
private static final int SCREEN_MARGIN = 24;
private boolean showExtras;
private ViewHierarchyScene scene;
LayoutRenderer(ViewHierarchyScene scene) {
this.scene = scene;
setOpaque(true);
setBorder(BorderFactory.createEmptyBorder(0, 0, 12, 0));
setBackground(Color.BLACK);
setForeground(Color.WHITE);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(EMULATED_SCREEN_WIDTH + SCREEN_MARGIN,
EMULATED_SCREEN_HEIGHT + SCREEN_MARGIN);
}
@Override
protected void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
Insets insets = getInsets();
g.clipRect(insets.left, insets.top,
getWidth() - insets.left - insets.right,
getHeight() - insets.top - insets.bottom);
if (scene == null) {
return;
}
ViewNode root = scene.getRoot();
if (root == null) {
return;
}
int x = (getWidth() - insets.left - insets.right - root.width) / 2;
int y = (getHeight() - insets.top - insets.bottom - root.height) / 2;
g.translate(insets.left + x, insets.top + y);
g.setColor(getForeground());
g.drawRect(root.left, root.top, root.width - 1, root.height - 1);
g.clipRect(root.left - 1, root.top - 1, root.width + 1, root.height + 1);
drawChildren(g, root, -root.scrollX, -root.scrollY);
Set<?> selection = scene.getSelectedObjects();
if (selection.size() > 0) {
ViewNode node = (ViewNode) selection.iterator().next();
g.setColor(Color.RED);
Graphics s = g.create();
ViewNode p = node.parent;
while (p != null) {
s.translate(p.left - p.scrollX, p.top - p.scrollY);
p = p.parent;
}
if (showExtras && node.image != null) {
s.drawImage(node.image, node.left, node.top, null);
}
s.drawRect(node.left, node.top, node.width - 1, node.height - 1);
s.dispose();
}
g.translate(-insets.left - x, -insets.top - y);
}
private void drawChildren(Graphics g, ViewNode root, int x, int y) {
g.translate(x, y);
for (ViewNode node : root.children) {
if (!node.willNotDraw) {
g.drawRect(node.left, node.top, node.width - 1, node.height - 1);
}
if (node.children.size() > 0) {
drawChildren(g, node,
node.left - node.parent.scrollX,
node.top - node.parent.scrollY);
}
}
g.translate(-x, -y);
}
public void setShowExtras(boolean showExtras) {
this.showExtras = showExtras;
repaint();
}
}

View File

@@ -1,732 +0,0 @@
package com.android.hierarchyviewer.ui;
import com.android.ddmlib.Device;
import com.android.ddmlib.RawImage;
import com.android.hierarchyviewer.util.WorkerThread;
import com.android.hierarchyviewer.scene.ViewNode;
import com.android.hierarchyviewer.ui.util.PngFileFilter;
import com.android.hierarchyviewer.ui.util.IconLoader;
import javax.swing.JComponent;
import javax.swing.Timer;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.Box;
import javax.swing.JCheckBox;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import javax.imageio.ImageIO;
import org.jdesktop.swingworker.SwingWorker;
import java.io.IOException;
import java.io.File;
import java.awt.image.BufferedImage;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Point;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.FlowLayout;
import java.awt.AlphaComposite;
import java.awt.RenderingHints;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.concurrent.ExecutionException;
class ScreenViewer extends JPanel implements ActionListener {
private final Workspace workspace;
private final Device device;
private GetScreenshotTask task;
private BufferedImage image;
private int[] scanline;
private volatile boolean isLoading;
private BufferedImage overlay;
private AlphaComposite overlayAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
private ScreenViewer.LoupeStatus status;
private ScreenViewer.LoupeViewer loupe;
private ScreenViewer.Crosshair crosshair;
private int zoom = 8;
private int y = 0;
private Timer timer;
private ViewNode node;
ScreenViewer(Workspace workspace, Device device, int spacing) {
setLayout(new BorderLayout());
setOpaque(false);
this.workspace = workspace;
this.device = device;
timer = new Timer(5000, this);
timer.setInitialDelay(0);
timer.setRepeats(true);
JPanel panel = buildViewerAndControls();
add(panel, BorderLayout.WEST);
JPanel loupePanel = buildLoupePanel(spacing);
add(loupePanel, BorderLayout.CENTER);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
timer.start();
}
});
}
private JPanel buildLoupePanel(int spacing) {
loupe = new LoupeViewer();
CrosshairPanel crosshairPanel = new CrosshairPanel(loupe);
JPanel loupePanel = new JPanel(new BorderLayout());
loupePanel.add(crosshairPanel);
status = new LoupeStatus();
loupePanel.add(status, BorderLayout.SOUTH);
loupePanel.setBorder(BorderFactory.createEmptyBorder(0, spacing, 0, 0));
return loupePanel;
}
private JPanel buildViewerAndControls() {
JPanel panel = new JPanel(new GridBagLayout());
crosshair = new Crosshair(new ScreenshotViewer());
panel.add(crosshair,
new GridBagConstraints(0, y++, 2, 1, 1.0f, 0.0f,
GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0));
buildSlider(panel, "Overlay:", "0%", "100%", 0, 100, 30, 1).addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent event) {
float opacity = ((JSlider) event.getSource()).getValue() / 100.0f;
overlayAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
repaint();
}
});
buildOverlayExtraControls(panel);
buildSlider(panel, "Refresh Rate:", "1s", "40s", 1, 40, 5, 1).addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent event) {
int rate = ((JSlider) event.getSource()).getValue() * 1000;
timer.setDelay(rate);
timer.setInitialDelay(0);
timer.restart();
}
});
buildSlider(panel, "Zoom:", "2x", "24x", 2, 24, 8, 2).addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent event) {
zoom = ((JSlider) event.getSource()).getValue();
loupe.clearGrid = true;
loupe.moveToPoint(crosshair.crosshair.x, crosshair.crosshair.y);
repaint();
}
});
panel.add(Box.createVerticalGlue(),
new GridBagConstraints(0, y++, 2, 1, 1.0f, 1.0f,
GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0));
return panel;
}
private void buildOverlayExtraControls(JPanel panel) {
JPanel extras = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
JButton loadOverlay = new JButton("Load...");
loadOverlay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
SwingWorker<?, ?> worker = openOverlay();
if (worker != null) {
worker.execute();
}
}
});
extras.add(loadOverlay);
JCheckBox showInLoupe = new JCheckBox("Show in Loupe");
showInLoupe.setSelected(false);
showInLoupe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
loupe.showOverlay = ((JCheckBox) event.getSource()).isSelected();
loupe.repaint();
}
});
extras.add(showInLoupe);
panel.add(extras, new GridBagConstraints(1, y++, 1, 1, 1.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0));
}
public SwingWorker<?, ?> openOverlay() {
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new PngFileFilter());
int choice = chooser.showOpenDialog(this);
if (choice == JFileChooser.APPROVE_OPTION) {
return new OpenOverlayTask(chooser.getSelectedFile());
} else {
return null;
}
}
private JSlider buildSlider(JPanel panel, String title, String minName, String maxName,
int min, int max, int value, int tick) {
panel.add(new JLabel(title), new GridBagConstraints(0, y, 1, 1, 1.0f, 0.0f,
GridBagConstraints.LINE_END, GridBagConstraints.NONE,
new Insets(0, 0, 0, 6), 0, 0));
JPanel sliderPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
sliderPanel.add(new JLabel(minName));
JSlider slider = new JSlider(min, max, value);
slider.setMinorTickSpacing(tick);
slider.setMajorTickSpacing(tick);
slider.setSnapToTicks(true);
sliderPanel.add(slider);
sliderPanel.add(new JLabel(maxName));
panel.add(sliderPanel, new GridBagConstraints(1, y++, 1, 1, 1.0f, 0.0f,
GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0));
return slider;
}
void stop() {
timer.stop();
}
void start() {
timer.start();
}
void select(ViewNode node) {
this.node = node;
repaint();
}
class LoupeViewer extends JComponent {
private final Color lineColor = new Color(1.0f, 1.0f, 1.0f, 0.3f);
private int width;
private int height;
private BufferedImage grid;
private int left;
private int top;
public boolean clearGrid;
private final Rectangle clip = new Rectangle();
private boolean showOverlay = false;
LoupeViewer() {
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent event) {
moveToPoint(event);
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent event) {
moveToPoint(event);
}
});
}
@Override
protected void paintComponent(Graphics g) {
if (isLoading) {
return;
}
g.translate(-left, -top);
if (image != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
g2.scale(zoom, zoom);
g2.drawImage(image, 0, 0, null);
if (overlay != null && showOverlay) {
g2.setComposite(overlayAlpha);
g2.drawImage(overlay, 0, image.getHeight() - overlay.getHeight(), null);
}
g2.dispose();
}
int width = getWidth();
int height = getHeight();
Graphics2D g2 = null;
if (width != this.width || height != this.height) {
this.width = width;
this.height = height;
grid = new BufferedImage(width + zoom + 1, height + zoom + 1,
BufferedImage.TYPE_INT_ARGB);
clearGrid = true;
g2 = grid.createGraphics();
} else if (clearGrid) {
g2 = grid.createGraphics();
g2.setComposite(AlphaComposite.Clear);
g2.fillRect(0, 0, grid.getWidth(), grid.getHeight());
g2.setComposite(AlphaComposite.SrcOver);
}
if (clearGrid) {
clearGrid = false;
g2.setColor(lineColor);
width += zoom;
height += zoom;
for (int x = zoom; x <= width; x += zoom) {
g2.drawLine(x, 0, x, height);
}
for (int y = 0; y <= height; y += zoom) {
g2.drawLine(0, y, width, y);
}
g2.dispose();
}
if (image != null) {
g.getClipBounds(clip);
g.clipRect(0, 0, image.getWidth() * zoom + 1, image.getHeight() * zoom + 1);
g.drawImage(grid, clip.x - clip.x % zoom, clip.y - clip.y % zoom, null);
}
g.translate(left, top);
}
void moveToPoint(MouseEvent event) {
int x = Math.max(0, Math.min((event.getX() + left) / zoom, image.getWidth() - 1));
int y = Math.max(0, Math.min((event.getY() + top) / zoom, image.getHeight() - 1));
moveToPoint(x, y);
crosshair.moveToPoint(x, y);
}
void moveToPoint(int x, int y) {
left = x * zoom - width / 2 + zoom / 2;
top = y * zoom - height / 2 + zoom / 2;
repaint();
}
}
class LoupeStatus extends JPanel {
private JLabel xLabel;
private JLabel yLabel;
private JLabel rLabel;
private JLabel gLabel;
private JLabel bLabel;
private JLabel hLabel;
private ScreenViewer.LoupeStatus.ColoredSquare square;
private Color color;
LoupeStatus() {
setOpaque(true);
setLayout(new GridBagLayout());
setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
square = new ColoredSquare();
add(square, new GridBagConstraints(0, 0, 1, 2, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 12), 0, 0 ));
JLabel label;
add(label = new JLabel("#ffffff"), new GridBagConstraints(0, 2, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 12), 0, 0 ));
label.setForeground(Color.WHITE);
hLabel = label;
add(label = new JLabel("R:"), new GridBagConstraints(1, 0, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 6, 0, 6), 0, 0 ));
label.setForeground(Color.WHITE);
add(label = new JLabel("255"), new GridBagConstraints(2, 0, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 12), 0, 0 ));
label.setForeground(Color.WHITE);
rLabel = label;
add(label = new JLabel("G:"), new GridBagConstraints(1, 1, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 6, 0, 6), 0, 0 ));
label.setForeground(Color.WHITE);
add(label = new JLabel("255"), new GridBagConstraints(2, 1, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 12), 0, 0 ));
label.setForeground(Color.WHITE);
gLabel = label;
add(label = new JLabel("B:"), new GridBagConstraints(1, 2, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 6, 0, 6), 0, 0 ));
label.setForeground(Color.WHITE);
add(label = new JLabel("255"), new GridBagConstraints(2, 2, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 12), 0, 0 ));
label.setForeground(Color.WHITE);
bLabel = label;
add(label = new JLabel("X:"), new GridBagConstraints(3, 0, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 6, 0, 6), 0, 0 ));
label.setForeground(Color.WHITE);
add(label = new JLabel("0 px"), new GridBagConstraints(4, 0, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 12), 0, 0 ));
label.setForeground(Color.WHITE);
xLabel = label;
add(label = new JLabel("Y:"), new GridBagConstraints(3, 1, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 6, 0, 6), 0, 0 ));
label.setForeground(Color.WHITE);
add(label = new JLabel("0 px"), new GridBagConstraints(4, 1, 1, 1, 0.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.NONE,
new Insets(0, 0, 0, 12), 0, 0 ));
label.setForeground(Color.WHITE);
yLabel = label;
add(Box.createHorizontalGlue(), new GridBagConstraints(5, 0, 1, 1, 1.0f, 0.0f,
GridBagConstraints.LINE_START, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0 ));
}
@Override
protected void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
}
void showPixel(int x, int y) {
xLabel.setText(x + " px");
yLabel.setText(y + " px");
int pixel = image.getRGB(x, y);
color = new Color(pixel);
hLabel.setText("#" + Integer.toHexString(pixel));
rLabel.setText(String.valueOf((pixel >> 16) & 0xff));
gLabel.setText(String.valueOf((pixel >> 8) & 0xff));
bLabel.setText(String.valueOf((pixel ) & 0xff));
square.repaint();
}
private class ColoredSquare extends JComponent {
@Override
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
d.width = 60;
d.height = 30;
return d;
}
@Override
protected void paintComponent(Graphics g) {
g.setColor(color);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.WHITE);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
}
}
class Crosshair extends JPanel {
// magenta = 0xff5efe
private final Color crosshairColor = new Color(0x00ffff);
Point crosshair = new Point();
private int width;
private int height;
Crosshair(ScreenshotViewer screenshotViewer) {
setOpaque(true);
setLayout(new BorderLayout());
add(screenshotViewer);
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent event) {
moveToPoint(event);
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent event) {
moveToPoint(event);
}
});
}
void moveToPoint(int x, int y) {
crosshair.x = x;
crosshair.y = y;
status.showPixel(crosshair.x, crosshair.y);
repaint();
}
private void moveToPoint(MouseEvent event) {
crosshair.x = Math.max(0, Math.min(image.getWidth() - 1, event.getX()));
crosshair.y = Math.max(0, Math.min(image.getHeight() - 1, event.getY()));
loupe.moveToPoint(crosshair.x, crosshair.y);
status.showPixel(crosshair.x, crosshair.y);
repaint();
}
@Override
public void paint(Graphics g) {
super.paint(g);
if (crosshair == null || width != getWidth() || height != getHeight()) {
width = getWidth();
height = getHeight();
crosshair = new Point(width / 2, height / 2);
}
g.setColor(crosshairColor);
g.drawLine(crosshair.x, 0, crosshair.x, height);
g.drawLine(0, crosshair.y, width, crosshair.y);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
class ScreenshotViewer extends JComponent {
private final Color boundsColor = new Color(0xff5efe);
ScreenshotViewer() {
setOpaque(true);
}
@Override
protected void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
if (isLoading) {
return;
}
if (image != null) {
g.drawImage(image, 0, 0, null);
if (overlay != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setComposite(overlayAlpha);
g2.drawImage(overlay, 0, image.getHeight() - overlay.getHeight(), null);
}
}
if (node != null) {
Graphics s = g.create();
s.setColor(boundsColor);
ViewNode p = node.parent;
while (p != null) {
s.translate(p.left - p.scrollX, p.top - p.scrollY);
p = p.parent;
}
s.drawRect(node.left, node.top, node.width - 1, node.height - 1);
s.translate(node.left, node.top);
s.setXORMode(Color.WHITE);
if ((node.paddingBottom | node.paddingLeft |
node.paddingTop | node.paddingRight) != 0) {
s.setColor(Color.BLACK);
s.drawRect(node.paddingLeft, node.paddingTop,
node.width - node.paddingRight - node.paddingLeft - 1,
node.height - node.paddingBottom - node.paddingTop - 1);
}
if (node.hasMargins && (node.marginLeft | node.marginBottom |
node.marginRight | node.marginRight) != 0) {
s.setColor(Color.BLACK);
s.drawRect(-node.marginLeft, -node.marginTop,
node.marginLeft + node.width + node.marginRight - 1,
node.marginTop + node.height + node.marginBottom - 1);
}
s.dispose();
}
}
@Override
public Dimension getPreferredSize() {
if (image == null) {
return new Dimension(320, 480);
}
return new Dimension(image.getWidth(), image.getHeight());
}
}
private class CrosshairPanel extends JPanel {
private final Color crosshairColor = new Color(0xff5efe);
private final Insets insets = new Insets(0, 0, 0, 0);
CrosshairPanel(LoupeViewer loupe) {
setLayout(new BorderLayout());
add(loupe);
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(crosshairColor);
int width = getWidth();
int height = getHeight();
getInsets(insets);
int x = (width - insets.left - insets.right) / 2;
int y = (height - insets.top - insets.bottom) / 2;
g.drawLine(insets.left + x, insets.top, insets.left + x, height - insets.bottom);
g.drawLine(insets.left, insets.top + y, width - insets.right, insets.top + y);
}
@Override
protected void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
Insets insets = getInsets();
g.fillRect(insets.left, insets.top, getWidth() - insets.left - insets.right,
getHeight() - insets.top - insets.bottom);
}
}
public void actionPerformed(ActionEvent event) {
if (task != null && !task.isDone()) {
return;
}
task = new GetScreenshotTask();
task.execute();
}
private class GetScreenshotTask extends SwingWorker<Boolean, Void> {
private GetScreenshotTask() {
workspace.beginTask();
}
@Override
@WorkerThread
protected Boolean doInBackground() throws Exception {
RawImage rawImage;
try {
rawImage = device.getScreenshot();
} catch (IOException ioe) {
return false;
}
boolean resize = false;
isLoading = true;
try {
if (rawImage != null && rawImage.bpp == 16) {
if (image == null || rawImage.width != image.getWidth() ||
rawImage.height != image.getHeight()) {
image = new BufferedImage(rawImage.width, rawImage.height,
BufferedImage.TYPE_INT_ARGB);
scanline = new int[rawImage.width];
resize = true;
}
byte[] buffer = rawImage.data;
int index = 0;
for (int y = 0 ; y < rawImage.height ; y++) {
for (int x = 0 ; x < rawImage.width ; x++) {
int value = buffer[index++] & 0x00FF;
value |= (buffer[index++] << 8) & 0x0FF00;
int r = ((value >> 11) & 0x01F) << 3;
int g = ((value >> 5) & 0x03F) << 2;
int b = ((value ) & 0x01F) << 3;
scanline[x] = 0xFF << 24 | r << 16 | g << 8 | b;
}
image.setRGB(0, y, rawImage.width, 1, scanline,
0, rawImage.width);
}
}
} finally {
isLoading = false;
}
return resize;
}
@Override
protected void done() {
workspace.endTask();
try {
if (get()) {
validate();
crosshair.crosshair = new Point(image.getWidth() / 2,
image.getHeight() / 2);
status.showPixel(image.getWidth() / 2, image.getHeight() / 2);
loupe.moveToPoint(image.getWidth() / 2, image.getHeight() / 2);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
repaint();
}
}
private class OpenOverlayTask extends SwingWorker<BufferedImage, Void> {
private File file;
private OpenOverlayTask(File file) {
this.file = file;
workspace.beginTask();
}
@Override
@WorkerThread
protected BufferedImage doInBackground() {
try {
return IconLoader.toCompatibleImage(ImageIO.read(file));
} catch (IOException ex) {
ex.printStackTrace();
}
return null;
}
@Override
protected void done() {
try {
overlay = get();
repaint();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
workspace.endTask();
}
}
}
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import org.jdesktop.swingworker.SwingWorker;
import javax.swing.AbstractAction;
public abstract class BackgroundAction extends AbstractAction {
protected void executeBackgroundTask(SwingWorker<?, ?> worker) {
if (worker != null) {
worker.execute();
}
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
public class CaptureNodeAction extends BackgroundAction {
public static final String ACTION_NAME = "captureNode";
private Workspace mWorkspace;
public CaptureNodeAction(Workspace workspace) {
putValue(NAME, "Display View");
putValue(SHORT_DESCRIPTION, "Display View");
putValue(LONG_DESCRIPTION, "Display View");
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_D,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
this.mWorkspace = workspace;
}
public void actionPerformed(ActionEvent e) {
executeBackgroundTask(mWorkspace.showNodeCapture());
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import com.android.hierarchyviewer.device.DeviceBridge;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
public class ExitAction extends AbstractAction {
public static final String ACTION_NAME = "exit";
private Workspace mWorkspace;
public ExitAction(Workspace workspace) {
putValue(NAME, "Quit");
putValue(SHORT_DESCRIPTION, "Quit");
putValue(LONG_DESCRIPTION, "Quit");
putValue(MNEMONIC_KEY, KeyEvent.VK_Q);
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Q,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
this.mWorkspace = workspace;
}
public void actionPerformed(ActionEvent e) {
mWorkspace.cleanupDevices();
mWorkspace.dispose();
DeviceBridge.terminate();
System.exit(0);
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
public class InvalidateAction extends BackgroundAction {
public static final String ACTION_NAME = "invalidate";
private Workspace mWorkspace;
public InvalidateAction(Workspace workspace) {
putValue(NAME, "Invalidate");
putValue(SHORT_DESCRIPTION, "Invalidate");
putValue(LONG_DESCRIPTION, "Invalidate");
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
this.mWorkspace = workspace;
}
public void actionPerformed(ActionEvent e) {
executeBackgroundTask(mWorkspace.invalidateView());
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
public class LoadGraphAction extends BackgroundAction {
public static final String ACTION_NAME = "loadGraph";
private Workspace mWorkspace;
public LoadGraphAction(Workspace workspace) {
putValue(NAME, "Load View Hierarchy");
putValue(SHORT_DESCRIPTION, "Load");
putValue(LONG_DESCRIPTION, "Load View Hierarchy");
putValue(MNEMONIC_KEY, KeyEvent.VK_L);
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_L,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
this.mWorkspace = workspace;
}
public void actionPerformed(ActionEvent e) {
executeBackgroundTask(mWorkspace.loadGraph());
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
public class RefreshWindowsAction extends BackgroundAction {
public static final String ACTION_NAME = "refreshWindows";
private Workspace mWorkspace;
public RefreshWindowsAction(Workspace workspace) {
putValue(NAME, "Refresh Windows");
putValue(SHORT_DESCRIPTION, "Refresh");
putValue(LONG_DESCRIPTION, "Refresh Windows");
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0));
this.mWorkspace = workspace;
}
public void actionPerformed(ActionEvent e) {
executeBackgroundTask(mWorkspace.loadWindows());
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
public class RequestLayoutAction extends BackgroundAction {
public static final String ACTION_NAME = "requestLayout";
private Workspace mWorkspace;
public RequestLayoutAction(Workspace workspace) {
putValue(NAME, "Request Layout");
putValue(SHORT_DESCRIPTION, "Request Layout");
putValue(LONG_DESCRIPTION, "Request Layout");
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
this.mWorkspace = workspace;
}
public void actionPerformed(ActionEvent e) {
executeBackgroundTask(mWorkspace.requestLayout());
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
public class SaveSceneAction extends BackgroundAction {
public static final String ACTION_NAME = "saveScene";
private Workspace mWorkspace;
public SaveSceneAction(Workspace workspace) {
mWorkspace = workspace;
putValue(NAME, "Save as PNG...");
putValue(SHORT_DESCRIPTION, "Save");
putValue(LONG_DESCRIPTION, "Save as PNG...");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
}
public void actionPerformed(ActionEvent e) {
executeBackgroundTask(mWorkspace.saveSceneAsImage());
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
public class ShowDevicesAction extends AbstractAction {
public static final String ACTION_NAME = "showDevices";
private Workspace mWorkspace;
public ShowDevicesAction(Workspace workspace) {
putValue(NAME, "Devices");
putValue(SHORT_DESCRIPTION, "Devices");
putValue(LONG_DESCRIPTION, "Show Devices");
putValue(MNEMONIC_KEY, KeyEvent.VK_D);
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_D,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
this.mWorkspace = workspace;
}
public void actionPerformed(ActionEvent e) {
mWorkspace.showDevicesSelector();
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
public class StartServerAction extends BackgroundAction {
public static final String ACTION_NAME = "startServer";
private Workspace mWorkspace;
public StartServerAction(Workspace workspace) {
putValue(NAME, "Start Server");
putValue(SHORT_DESCRIPTION, "Start");
putValue(LONG_DESCRIPTION, "Start Server");
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0));
this.mWorkspace = workspace;
}
public void actionPerformed(ActionEvent e) {
executeBackgroundTask(mWorkspace.startServer());
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.action;
import com.android.hierarchyviewer.ui.Workspace;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
public class StopServerAction extends BackgroundAction {
public static final String ACTION_NAME = "stopServer";
private Workspace mWorkspace;
public StopServerAction(Workspace workspace) {
putValue(NAME, "Stop Server");
putValue(SHORT_DESCRIPTION, "Stop");
putValue(LONG_DESCRIPTION, "Stop Server");
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0));
this.mWorkspace = workspace;
}
public void actionPerformed(ActionEvent e) {
executeBackgroundTask(mWorkspace.stopServer());
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.model;
import com.android.hierarchyviewer.scene.ViewNode;
import javax.swing.table.DefaultTableModel;
import java.util.List;
import java.util.ArrayList;
public class PropertiesTableModel extends DefaultTableModel {
private List<ViewNode.Property> properties;
private List<ViewNode.Property> privateProperties = new ArrayList<ViewNode.Property>();
public PropertiesTableModel(ViewNode node) {
properties = node.properties;
loadPrivateProperties(node);
}
private void loadPrivateProperties(ViewNode node) {
int x = node.left;
int y = node.top;
ViewNode p = node.parent;
while (p != null) {
x += p.left - p.scrollX;
y += p.top - p.scrollY;
p = p.parent;
}
ViewNode.Property property = new ViewNode.Property();
property.name = "absolute_x";
property.value = String.valueOf(x);
privateProperties.add(property);
property = new ViewNode.Property();
property.name = "absolute_y";
property.value = String.valueOf(y);
privateProperties.add(property);
}
@Override
public int getRowCount() {
return (privateProperties == null ? 0 : privateProperties.size()) +
(properties == null ? 0 : properties.size());
}
@Override
public Object getValueAt(int row, int column) {
ViewNode.Property property;
if (row < privateProperties.size()) {
property = privateProperties.get(row);
} else {
property = properties.get(row - privateProperties.size());
}
return column == 0 ? property.name : property.value;
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public String getColumnName(int column) {
return column == 0 ? "Property" : "Value";
}
@Override
public boolean isCellEditable(int arg0, int arg1) {
return false;
}
@Override
public void setValueAt(Object arg0, int arg1, int arg2) {
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.model;
import com.android.hierarchyviewer.scene.ViewNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.event.TreeModelListener;
public class ViewsTreeModel implements TreeModel {
private final ViewNode root;
public ViewsTreeModel(ViewNode root) {
this.root = root;
}
public Object getRoot() {
return root;
}
public Object getChild(Object o, int i) {
return ((ViewNode) o).children.get(i);
}
public int getChildCount(Object o) {
return ((ViewNode) o).children.size();
}
public boolean isLeaf(Object child) {
ViewNode node = (ViewNode) child;
return node.children == null || node.children.size() == 0;
}
public void valueForPathChanged(TreePath treePath, Object child) {
}
public int getIndexOfChild(Object parent, Object child) {
//noinspection SuspiciousMethodCalls
return ((ViewNode) parent).children.indexOf(child);
}
public void addTreeModelListener(TreeModelListener treeModelListener) {
}
public void removeTreeModelListener(TreeModelListener treeModelListener) {
}
}

View File

@@ -1,49 +0,0 @@
package com.android.hierarchyviewer.ui.util;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.awt.image.BufferedImage;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.GraphicsConfiguration;
public class IconLoader {
public static Icon load(Class<?> klass, String path) {
try {
return new ImageIcon(ImageIO.read(klass.getResourceAsStream(path)));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static GraphicsConfiguration getGraphicsConfiguration() {
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
return environment.getDefaultScreenDevice().getDefaultConfiguration();
}
private static boolean isHeadless() {
return GraphicsEnvironment.isHeadless();
}
public static BufferedImage toCompatibleImage(BufferedImage image) {
if (isHeadless()) {
return image;
}
if (image.getColorModel().equals(
getGraphicsConfiguration().getColorModel())) {
return image;
}
BufferedImage compatibleImage = getGraphicsConfiguration().createCompatibleImage(
image.getWidth(), image.getHeight(), image.getTransparency());
Graphics g = compatibleImage.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return compatibleImage;
}
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.ui.util;
import javax.swing.filechooser.FileFilter;
import java.io.File;
public class PngFileFilter extends FileFilter {
@Override
public boolean accept(File f) {
return f.isDirectory() || f.getName().toLowerCase().endsWith(".png");
}
@Override
public String getDescription() {
return "PNG Image (*.png)";
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.util;
public class OS {
private static boolean macOs;
private static boolean leopard;
private static boolean linux;
private static boolean windows;
static {
String osName = System.getProperty("os.name");
macOs = "Mac OS X".startsWith(osName);
linux = "Linux".startsWith(osName);
windows = "Windows".startsWith(osName);
String version = System.getProperty("os.version");
final String[] parts = version.split("\\.");
leopard = Integer.parseInt(parts[0]) >= 10 && Integer.parseInt(parts[1]) >= 5;
}
public static boolean isMacOsX() {
return macOs;
}
public static boolean isLeopardOrLater() {
return leopard;
}
public static boolean isLinux() {
return linux;
}
public static boolean isWindows() {
return windows;
}
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.hierarchyviewer.util;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Simple utility class used only to mark methods that are not executed on the UI thread
* (or Event Dispatch Thread in Swing/AWT.) This annotation's sole purpose is to help
* reading the source code. It has no additional effect.
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.SOURCE)
public @interface WorkerThread {
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B