upload android base code part9
This commit is contained in:
parent
5425409085
commit
071cdf34cd
2679 changed files with 329442 additions and 0 deletions
0
android/sdk/hierarchyviewer/MODULE_LICENSE_APACHE2
Normal file
0
android/sdk/hierarchyviewer/MODULE_LICENSE_APACHE2
Normal file
8
android/sdk/hierarchyviewer/README.txt
Normal file
8
android/sdk/hierarchyviewer/README.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
This version of HierarchyViewer is deprecated and obsolete.
|
||||
The sources are left here just for reference. Please do not change them.
|
||||
|
||||
HierarchyViewer2 is located in /tools/swt/hierarchyviewer2.
|
||||
This is the version that ships in the SDK.
|
||||
|
||||
--- RM 20130409
|
||||
|
20
android/sdk/hierarchyviewer/etc/Android.mk
Normal file
20
android/sdk/hierarchyviewer/etc/Android.mk
Normal file
|
@ -0,0 +1,20 @@
|
|||
# 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_PREBUILT_EXECUTABLES := hierarchyviewer1
|
||||
LOCAL_MODULE_TAGS := debug
|
||||
include $(BUILD_HOST_PREBUILT)
|
63
android/sdk/hierarchyviewer/etc/hierarchyviewer1
Executable file
63
android/sdk/hierarchyviewer/etc/hierarchyviewer1
Executable file
|
@ -0,0 +1,63 @@
|
|||
#!/bin/sh
|
||||
# Copyright 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.
|
||||
|
||||
# Set up prog to be the path of this script, including following symlinks,
|
||||
# and set up progdir to be the fully-qualified pathname of its directory.
|
||||
prog="$0"
|
||||
while [ -h "${prog}" ]; do
|
||||
newProg=`/bin/ls -ld "${prog}"`
|
||||
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
|
||||
if expr "x${newProg}" : 'x/' >/dev/null; then
|
||||
prog="${newProg}"
|
||||
else
|
||||
progdir=`dirname "${prog}"`
|
||||
prog="${progdir}/${newProg}"
|
||||
fi
|
||||
done
|
||||
oldwd=`pwd`
|
||||
progdir=`dirname "${prog}"`
|
||||
cd "${progdir}"
|
||||
progdir=`pwd`
|
||||
prog="${progdir}"/`basename "${prog}"`
|
||||
cd "${oldwd}"
|
||||
|
||||
jarfile=hierarchyviewer.jar
|
||||
frameworkdir="$progdir"
|
||||
if [ ! -r "$frameworkdir/$jarfile" ]
|
||||
then
|
||||
frameworkdir=`dirname "$progdir"`/tools/lib
|
||||
libdir=`dirname "$progdir"`/tools/lib
|
||||
fi
|
||||
if [ ! -r "$frameworkdir/$jarfile" ]
|
||||
then
|
||||
frameworkdir=`dirname "$progdir"`/framework
|
||||
libdir=`dirname "$progdir"`/lib
|
||||
fi
|
||||
if [ ! -r "$frameworkdir/$jarfile" ]
|
||||
then
|
||||
echo `basename "$prog"`": can't find $jarfile"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$OSTYPE" = "cygwin" ] ; then
|
||||
jarpath=`cygpath -w "$frameworkdir/$jarfile"`
|
||||
progdir=`cygpath -w "$progdir"`
|
||||
else
|
||||
jarpath="$frameworkdir/$jarfile"
|
||||
fi
|
||||
|
||||
# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
|
||||
# might need more memory, e.g. -Xmx128M
|
||||
exec java -Xmx512M -Djava.ext.dirs="$frameworkdir" -Dhierarchyviewer.adb="$progdir" -jar "$jarpath" "$@"
|
46
android/sdk/hierarchyviewer/etc/hierarchyviewer1.bat
Executable file
46
android/sdk/hierarchyviewer/etc/hierarchyviewer1.bat
Executable file
|
@ -0,0 +1,46 @@
|
|||
@echo off
|
||||
rem Copyright (C) 2008 The Android Open Source Project
|
||||
rem
|
||||
rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
rem you may not use this file except in compliance with the License.
|
||||
rem You may obtain a copy of the License at
|
||||
rem
|
||||
rem http://www.apache.org/licenses/LICENSE-2.0
|
||||
rem
|
||||
rem Unless required by applicable law or agreed to in writing, software
|
||||
rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
rem See the License for the specific language governing permissions and
|
||||
rem limitations under the License.
|
||||
|
||||
rem don't modify the caller's environment
|
||||
setlocal
|
||||
|
||||
rem Set up prog to be the path of this script, including following symlinks,
|
||||
rem and set up progdir to be the fully-qualified pathname of its directory.
|
||||
set prog=%~f0
|
||||
|
||||
rem Change current directory and drive to where the script is, to avoid
|
||||
rem issues with directories containing whitespaces.
|
||||
cd /d %~dp0
|
||||
|
||||
rem Check we have a valid Java.exe in the path.
|
||||
set java_exe=
|
||||
call lib\find_java.bat
|
||||
if not defined java_exe goto :EOF
|
||||
|
||||
set jarfile=hierarchyviewer.jar
|
||||
set frameworkdir=.
|
||||
set libdir=
|
||||
|
||||
if exist %frameworkdir%\%jarfile% goto JarFileOk
|
||||
set frameworkdir=lib
|
||||
|
||||
if exist %frameworkdir%\%jarfile% goto JarFileOk
|
||||
set frameworkdir=..\framework
|
||||
|
||||
:JarFileOk
|
||||
|
||||
set jarpath=%frameworkdir%\%jarfile%
|
||||
|
||||
call "%java_exe%" -Xmx512m "-Djava.ext.dirs=%frameworkdir%" -Dhierarchyviewer.adb= -jar %jarpath% %*
|
2
android/sdk/hierarchyviewer/etc/manifest.txt
Normal file
2
android/sdk/hierarchyviewer/etc/manifest.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
Main-Class: com.android.hierarchyviewer.HierarchyViewer
|
||||
Class-Path: ddmlib.jar org-openide-util.jar org-netbeans-api-visual.jar
|
29
android/sdk/hierarchyviewer/src/Android.mk
Normal file
29
android/sdk/hierarchyviewer/src/Android.mk
Normal file
|
@ -0,0 +1,29 @@
|
|||
# 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-prebuilt \
|
||||
org-openide-util \
|
||||
org-netbeans-api-visual
|
||||
LOCAL_MODULE := hierarchyviewer
|
||||
LOCAL_MODULE_TAGS := debug
|
||||
|
||||
include $(BUILD_HOST_JAVA_LIBRARY)
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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.ddmlib.IDevice;
|
||||
import com.android.hierarchyviewer.device.Window;
|
||||
import com.android.hierarchyviewer.scene.CaptureLoader;
|
||||
import com.android.hierarchyviewer.ui.Workspace;
|
||||
import com.android.hierarchyviewer.device.DeviceBridge;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import java.io.File;
|
||||
|
||||
public class HierarchyViewer {
|
||||
private static final CharSequence OS_WINDOWS = "Windows";
|
||||
private static final CharSequence OS_MACOSX = "Mac OS X";
|
||||
|
||||
private static boolean sProfilingEnabled = true;
|
||||
|
||||
public static boolean isProfilingEnabled() {
|
||||
return sProfilingEnabled;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private static void listDevices() {
|
||||
System.out.println("List of devices attached");
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
for (IDevice device : DeviceBridge.getDevices()) {
|
||||
printDevice(device);
|
||||
}
|
||||
DeviceBridge.terminate();
|
||||
}
|
||||
|
||||
private static void printDevice(IDevice device) {
|
||||
System.out.println(device.toString() + "\t\t" +
|
||||
(device.isEmulator() ? "emulator" : "device"));
|
||||
}
|
||||
|
||||
private static void outputPsd(String deviceName, String file) {
|
||||
IDevice device = selectDevice(deviceName);
|
||||
if (device != null) {
|
||||
if (DeviceBridge.isViewServerRunning(device)) {
|
||||
DeviceBridge.stopViewServer(device);
|
||||
}
|
||||
DeviceBridge.startViewServer(device);
|
||||
DeviceBridge.setupDeviceForward(device);
|
||||
System.out.println("Capturing layers to " + file);
|
||||
CaptureLoader.saveLayers(device, Window.FOCUSED_WINDOW, new File(file));
|
||||
} else {
|
||||
System.out.println("The selected device does not exist");
|
||||
}
|
||||
DeviceBridge.terminate();
|
||||
}
|
||||
|
||||
private static IDevice selectDevice(String deviceName) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (DeviceBridge.getDevices() == null) return null;
|
||||
if (deviceName == null) return DeviceBridge.getDevices()[0];
|
||||
for (IDevice device : DeviceBridge.getDevices()) {
|
||||
if (device.getSerialNumber().equalsIgnoreCase(deviceName)) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
DeviceBridge.initDebugBridge();
|
||||
|
||||
if (args.length > 0) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
String arg = args[i];
|
||||
if ("--help".equalsIgnoreCase(arg)) {
|
||||
System.out.println("Usage: hierarchyviewer1 [options]\n");
|
||||
System.out.println("Options:");
|
||||
System.out.println(" --help\t\t\t Show this help message and exit");
|
||||
System.out.println(" --no-profiling\t Disable views profiling");
|
||||
System.out.println(" --devices\t\t\t Show the list of available devices");
|
||||
System.out.println(" --psd [device] <file>\t Export psd and exit");
|
||||
System.exit(0);
|
||||
} else if ("--no-profiling".equalsIgnoreCase(arg)) {
|
||||
sProfilingEnabled = false;
|
||||
} else if ("--devices".equalsIgnoreCase(arg)) {
|
||||
listDevices();
|
||||
System.exit(0);
|
||||
} else if ("--psd".equalsIgnoreCase(arg)) {
|
||||
if (i == args.length - 1) {
|
||||
System.out.println("You must specify at least an output file with --psd");
|
||||
System.exit(1);
|
||||
}
|
||||
String device = null;
|
||||
String file = null;
|
||||
if (i < args.length - 2) {
|
||||
device = args[++i];
|
||||
}
|
||||
if (i < args.length - 1) {
|
||||
file = args[++i];
|
||||
}
|
||||
outputPsd(device, file);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initUserInterface();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
Workspace workspace = new Workspace();
|
||||
workspace.setDefaultCloseOperation(Workspace.EXIT_ON_CLOSE);
|
||||
workspace.setLocationRelativeTo(null);
|
||||
workspace.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* 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.AdbCommandRejectedException;
|
||||
import com.android.ddmlib.AndroidDebugBridge;
|
||||
import com.android.ddmlib.IDevice;
|
||||
import com.android.ddmlib.Log;
|
||||
import com.android.ddmlib.MultiLineReceiver;
|
||||
import com.android.ddmlib.ShellCommandUnresponsiveException;
|
||||
import com.android.ddmlib.TimeoutException;
|
||||
import com.android.hierarchyviewer.scene.VersionLoader;
|
||||
|
||||
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<IDevice, Integer> devicePortMap = new HashMap<IDevice, 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 IDevice[] getDevices() {
|
||||
return bridge.getDevices();
|
||||
}
|
||||
|
||||
public static boolean isViewServerRunning(IDevice device) {
|
||||
initDebugBridge();
|
||||
final boolean[] result = new boolean[1];
|
||||
try {
|
||||
if (device.isOnline()) {
|
||||
device.executeShellCommand(buildIsServerRunningShellCommand(),
|
||||
new BooleanResultReader(result));
|
||||
if (!result[0]) {
|
||||
if (VersionLoader.loadProtocolVersion(device) > 2) {
|
||||
result[0] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (TimeoutException e) {
|
||||
e.printStackTrace();
|
||||
} catch (AdbCommandRejectedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ShellCommandUnresponsiveException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
public static boolean startViewServer(IDevice device) {
|
||||
return startViewServer(device, Configuration.DEFAULT_SERVER_PORT);
|
||||
}
|
||||
|
||||
public static boolean startViewServer(IDevice 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();
|
||||
} catch (TimeoutException e) {
|
||||
e.printStackTrace();
|
||||
} catch (AdbCommandRejectedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ShellCommandUnresponsiveException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
public static boolean stopViewServer(IDevice device) {
|
||||
initDebugBridge();
|
||||
final boolean[] result = new boolean[1];
|
||||
try {
|
||||
if (device.isOnline()) {
|
||||
device.executeShellCommand(buildStopServerShellCommand(),
|
||||
new BooleanResultReader(result));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (TimeoutException e) {
|
||||
e.printStackTrace();
|
||||
} catch (AdbCommandRejectedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ShellCommandUnresponsiveException 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(IDevice device) {
|
||||
synchronized (devicePortMap) {
|
||||
if (device.getState() == IDevice.DeviceState.ONLINE) {
|
||||
int localPort = nextLocalPort++;
|
||||
try {
|
||||
device.createForward(localPort, Configuration.DEFAULT_SERVER_PORT);
|
||||
devicePortMap.put(device, localPort);
|
||||
} catch (TimeoutException e) {
|
||||
Log.e("hierarchy", "Timeout setting up port forwarding for " + device);
|
||||
} catch (AdbCommandRejectedException e) {
|
||||
Log.e("hierarchy", String.format(
|
||||
"Adb rejected forward command for device %1$s: %2$s",
|
||||
device, e.getMessage()));
|
||||
} catch (IOException e) {
|
||||
Log.e("hierarchy", String.format(
|
||||
"Failed to create forward for device %1$s: %2$s",
|
||||
device, e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeDeviceForward(IDevice device) {
|
||||
synchronized (devicePortMap) {
|
||||
final Integer localPort = devicePortMap.get(device);
|
||||
if (localPort != null) {
|
||||
try {
|
||||
device.removeForward(localPort, Configuration.DEFAULT_SERVER_PORT);
|
||||
devicePortMap.remove(device);
|
||||
} catch (TimeoutException e) {
|
||||
Log.e("hierarchy", "Timeout removing port forwarding for " + device);
|
||||
} catch (AdbCommandRejectedException e) {
|
||||
Log.e("hierarchy", String.format(
|
||||
"Adb rejected remove-forward command for device %1$s: %2$s",
|
||||
device, e.getMessage()));
|
||||
} catch (IOException e) {
|
||||
Log.e("hierarchy", String.format(
|
||||
"Failed to remove forward for device %1$s: %2$s",
|
||||
device, e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDeviceLocalPort(IDevice 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return title;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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);
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets(Component component) {
|
||||
return new Insets(1, 0, 2, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBorderOpaque() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* 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.IDevice;
|
||||
import com.android.hierarchyviewer.device.Window;
|
||||
import com.android.hierarchyviewer.device.DeviceBridge;
|
||||
import com.android.hierarchyviewer.ui.util.PsdFile;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
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 boolean saveLayers(IDevice device, Window window, File file) {
|
||||
Socket socket = null;
|
||||
DataInputStream in = null;
|
||||
BufferedWriter out = null;
|
||||
boolean result = false;
|
||||
|
||||
try {
|
||||
socket = new Socket();
|
||||
socket.connect(new InetSocketAddress("127.0.0.1",
|
||||
DeviceBridge.getDeviceLocalPort(device)));
|
||||
|
||||
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
||||
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
|
||||
|
||||
out.write("CAPTURE_LAYERS " + window.encode());
|
||||
out.newLine();
|
||||
out.flush();
|
||||
|
||||
int width = in.readInt();
|
||||
int height = in.readInt();
|
||||
|
||||
PsdFile psd = new PsdFile(width, height);
|
||||
|
||||
while (readLayer(in, psd)) {
|
||||
}
|
||||
|
||||
psd.write(new FileOutputStream(file));
|
||||
|
||||
result = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean readLayer(DataInputStream in, PsdFile psd) {
|
||||
try {
|
||||
if (in.read() == 2) {
|
||||
System.out.println("Found end of layers list");
|
||||
return false;
|
||||
}
|
||||
String name = in.readUTF();
|
||||
System.out.println("name = " + name);
|
||||
boolean visible = in.read() == 1;
|
||||
int x = in.readInt();
|
||||
int y = in.readInt();
|
||||
int dataSize = in.readInt();
|
||||
|
||||
byte[] data = new byte[dataSize];
|
||||
int read = 0;
|
||||
while (read < dataSize) {
|
||||
read += in.read(data, read, dataSize - read);
|
||||
}
|
||||
|
||||
ByteArrayInputStream arrayIn = new ByteArrayInputStream(data);
|
||||
BufferedImage chunk = ImageIO.read(arrayIn);
|
||||
|
||||
// Ensure the image is in the right format
|
||||
BufferedImage image = new BufferedImage(chunk.getWidth(), chunk.getHeight(),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
g.drawImage(chunk, null, 0, 0);
|
||||
g.dispose();
|
||||
|
||||
psd.addLayer(name, image, new Point(x, y), visible);
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Image loadCapture(IDevice 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.IDevice;
|
||||
import com.android.hierarchyviewer.HierarchyViewer;
|
||||
import com.android.hierarchyviewer.device.Window;
|
||||
import com.android.hierarchyviewer.device.DeviceBridge;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class ProfilesLoader {
|
||||
public static double[] loadProfiles(IDevice device, Window window, String params) {
|
||||
if (!HierarchyViewer.isProfilingEnabled()) {
|
||||
return new double[] { 0.0, 0.0, 0.0 };
|
||||
}
|
||||
|
||||
Socket socket = null;
|
||||
BufferedReader 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 BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
out.write("PROFILE " + window.encode() + " " + params);
|
||||
out.newLine();
|
||||
out.flush();
|
||||
|
||||
String response = in.readLine();
|
||||
String[] data = response.split(" ");
|
||||
|
||||
double[] profiles = new double[data.length];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
profiles[i] = (Long.parseLong(data[i]) / 1000.0) / 1000.0; // convert to ms
|
||||
}
|
||||
return profiles;
|
||||
} 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.IDevice;
|
||||
import com.android.hierarchyviewer.device.DeviceBridge;
|
||||
|
||||
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;
|
||||
|
||||
public class VersionLoader {
|
||||
public static int loadServerVersion(IDevice device) {
|
||||
return loadVersion(device, "SERVER");
|
||||
}
|
||||
|
||||
public static int loadProtocolVersion(IDevice device) {
|
||||
return loadVersion(device, "PROTOCOL");
|
||||
}
|
||||
|
||||
private static int loadVersion(IDevice device, String command) {
|
||||
Socket socket = null;
|
||||
BufferedReader 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 BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
out.write(command);
|
||||
out.newLine();
|
||||
out.flush();
|
||||
|
||||
return Integer.parseInt(in.readLine());
|
||||
} catch (Exception e) {
|
||||
// Empty
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Versioning of the protocol and server was added with version 2
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* 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.IDevice;
|
||||
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(IDevice 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(), "utf-8"));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
updateIndices(scene.getRoot());
|
||||
|
||||
} 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 void updateIndices(ViewNode root) {
|
||||
if (root == null) return;
|
||||
|
||||
root.computeIndex();
|
||||
|
||||
for (ViewNode node : root.children) {
|
||||
updateIndices(node);
|
||||
}
|
||||
}
|
||||
|
||||
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 colonIndex = property.name.indexOf(':');
|
||||
if (colonIndex != -1) {
|
||||
property.name = property.name.substring(colonIndex + 1);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* 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, node.name, node.id);
|
||||
widget.getActions().addAction(createSelectAction());
|
||||
widget.getActions().addAction(moveAction);
|
||||
widgetLayer.addChild(widget);
|
||||
return widget;
|
||||
}
|
||||
|
||||
private Widget createBox(ViewNode node, String nodeName, String id) {
|
||||
final String shortName = getShortName(nodeName);
|
||||
node.setShortName(shortName);
|
||||
|
||||
GradientWidget box = new GradientWidget(this, node);
|
||||
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(shortName);
|
||||
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(nodeName));
|
||||
label.setBorder(BorderFactory.createEmptyBorder(3, 6, 0, 6));
|
||||
label.setAlignment(LabelWidget.Alignment.CENTER);
|
||||
|
||||
box.addressWidget = label;
|
||||
|
||||
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 implements ViewNode.StateListener {
|
||||
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));
|
||||
public static final GradientPaint NIGHT_GRAY_VERY_LIGHT = new GradientPaint(
|
||||
new Point2D.Double(0, 0),
|
||||
new Color(129, 138, 155, 60),
|
||||
new Point2D.Double(0, 1),
|
||||
new Color(58, 66, 82, 60));
|
||||
|
||||
private static Color UNSELECTED = Color.BLACK;
|
||||
private static Color SELECTED = Color.WHITE;
|
||||
|
||||
private final ViewNode node;
|
||||
|
||||
private LabelWidget addressWidget;
|
||||
|
||||
private boolean isSelected = false;
|
||||
private final GradientPaint selectedGradient = MAC_OSX_SELECTED;
|
||||
private final GradientPaint filteredGradient = RED_XP;
|
||||
private final GradientPaint focusGradient = NIGHT_GRAY_VERY_LIGHT;
|
||||
|
||||
public GradientWidget(ViewHierarchyScene scene, ViewNode node) {
|
||||
super(scene);
|
||||
this.node = node;
|
||||
node.setStateListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyStateChanged(ObjectState previous, ObjectState state) {
|
||||
super.notifyStateChanged(previous, state);
|
||||
isSelected = state.isSelected() || state.isFocused() || state.isWidgetFocused();
|
||||
|
||||
pickChildrenColor();
|
||||
}
|
||||
|
||||
private void pickChildrenColor() {
|
||||
for (Widget child : getChildren()) {
|
||||
child.setForeground(isSelected || node.filtered ? SELECTED : UNSELECTED);
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground() {
|
||||
super.paintBackground();
|
||||
|
||||
Graphics2D g2 = getGraphics();
|
||||
Rectangle bounds = getBounds();
|
||||
|
||||
if (!isSelected) {
|
||||
if (!node.filtered) {
|
||||
if (!node.hasFocus) {
|
||||
g2.setColor(Color.WHITE);
|
||||
} else {
|
||||
g2.setPaint(new GradientPaint(bounds.x, bounds.y,
|
||||
focusGradient.getColor1(), bounds.x, bounds.x + bounds.height,
|
||||
focusGradient.getColor2()));
|
||||
}
|
||||
} else {
|
||||
g2.setPaint(new GradientPaint(bounds.x, bounds.y, filteredGradient.getColor1(),
|
||||
bounds.x, bounds.x + bounds.height, filteredGradient.getColor2()));
|
||||
}
|
||||
} else {
|
||||
g2.setPaint(new GradientPaint(bounds.x, bounds.y, selectedGradient.getColor1(),
|
||||
bounds.x, bounds.x + bounds.height, selectedGradient.getColor2()));
|
||||
}
|
||||
g2.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
}
|
||||
|
||||
public void nodeStateChanged(ViewNode node) {
|
||||
pickChildrenColor();
|
||||
}
|
||||
|
||||
public void nodeIndexChanged(ViewNode node) {
|
||||
if (addressWidget != null) {
|
||||
addressWidget.setLabel("#" + node.index + addressWidget.getLabel());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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.IDevice;
|
||||
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(IDevice device, Window window, String params) {
|
||||
sendCommand("INVALIDATE", device, window, params);
|
||||
}
|
||||
|
||||
public static void requestLayout(IDevice device, Window window, String params) {
|
||||
sendCommand("REQUEST_LAYOUT", device, window, params);
|
||||
}
|
||||
|
||||
public static void outputDisplayList(IDevice device, Window window, String params) {
|
||||
sendCommand("OUTPUT_DISPLAYLIST", device, window, params);
|
||||
}
|
||||
|
||||
private static void sendCommand(String command, IDevice 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* 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;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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;
|
||||
|
||||
boolean hasFocus;
|
||||
int index;
|
||||
|
||||
public boolean decoded;
|
||||
public boolean filtered;
|
||||
|
||||
private String shortName;
|
||||
private StateListener listener;
|
||||
|
||||
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);
|
||||
hasFocus = getBoolean("hasFocus()", 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;
|
||||
}
|
||||
|
||||
public void filter(Pattern pattern) {
|
||||
if (pattern == null || pattern.pattern().length() == 0) {
|
||||
filtered = false;
|
||||
} else {
|
||||
filtered = pattern.matcher(shortName).find() || pattern.matcher(id).find();
|
||||
}
|
||||
listener.nodeStateChanged(this);
|
||||
}
|
||||
|
||||
void computeIndex() {
|
||||
index = parent == null ? 0 : parent.children.indexOf(this);
|
||||
listener.nodeIndexChanged(this);
|
||||
}
|
||||
|
||||
void setShortName(String shortName) {
|
||||
this.shortName = shortName;
|
||||
}
|
||||
|
||||
void setStateListener(StateListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
interface StateListener {
|
||||
void nodeStateChanged(ViewNode node);
|
||||
void nodeIndexChanged(ViewNode node);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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.IDevice;
|
||||
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(IDevice device, int protocol, int server) {
|
||||
Socket socket = null;
|
||||
BufferedReader in = null;
|
||||
BufferedWriter out = null;
|
||||
System.out.println("protocol = " + protocol);
|
||||
System.out.println("version = " + server);
|
||||
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) {
|
||||
String windowId = line.substring(0, index);
|
||||
|
||||
int id;
|
||||
if (server > 2) {
|
||||
id = (int) Long.parseLong(windowId, 16);
|
||||
} else {
|
||||
id = Integer.parseInt(windowId, 16);
|
||||
}
|
||||
|
||||
Window w = new Window(line.substring(index + 1), id);
|
||||
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];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
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;
|
||||
private JComponent sceneView;
|
||||
|
||||
LayoutRenderer(ViewHierarchyScene scene, JComponent sceneView) {
|
||||
this.scene = scene;
|
||||
this.sceneView = sceneView;
|
||||
|
||||
setOpaque(true);
|
||||
setBorder(BorderFactory.createEmptyBorder(0, 0, 12, 0));
|
||||
setBackground(Color.BLACK);
|
||||
setForeground(Color.WHITE);
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent event) {
|
||||
selectChild(event.getX(), event.getY());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
private void selectChild(int x, int y) {
|
||||
|
||||
if (scene == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ViewNode root = scene.getRoot();
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Insets insets = getInsets();
|
||||
|
||||
int xoffset = (getWidth() - insets.left - insets.right - root.width) / 2 + insets.left + 1;
|
||||
int yoffset = (getHeight() - insets.top - insets.bottom - root.height) / 2 + insets.top + 1;
|
||||
|
||||
x -= xoffset;
|
||||
y -= yoffset;
|
||||
if (x >= 0 && x < EMULATED_SCREEN_WIDTH && y >= 0 && y < EMULATED_SCREEN_HEIGHT) {
|
||||
ViewNode hit = findChild(root, root, x, y);
|
||||
scene.setFocusedObject(hit);
|
||||
sceneView.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private ViewNode findChild(ViewNode root, ViewNode besthit, int x, int y) {
|
||||
ViewNode hit = besthit;
|
||||
for (ViewNode node : root.children) {
|
||||
|
||||
if (node.left <= x && x < node.left + node.width &&
|
||||
node.top <= y && y < node.top + node.height) {
|
||||
if (node.width <= hit.width && node.height <= hit.height) {
|
||||
hit = node;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.children.size() > 0) {
|
||||
hit = findChild(node, hit,
|
||||
x - (node.left - node.parent.scrollX),
|
||||
y - (node.top - node.parent.scrollY));
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,831 @@
|
|||
package com.android.hierarchyviewer.ui;
|
||||
|
||||
import com.android.ddmlib.IDevice;
|
||||
import com.android.ddmlib.RawImage;
|
||||
import com.android.hierarchyviewer.scene.ViewNode;
|
||||
import com.android.hierarchyviewer.ui.util.IconLoader;
|
||||
import com.android.hierarchyviewer.ui.util.PngFileFilter;
|
||||
import com.android.hierarchyviewer.util.WorkerThread;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionAdapter;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
class ScreenViewer extends JPanel implements ActionListener {
|
||||
private final Workspace workspace;
|
||||
private final IDevice 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;
|
||||
|
||||
private JSlider zoomSlider;
|
||||
|
||||
ScreenViewer(Workspace workspace, IDevice device, int spacing) {
|
||||
setLayout(new GridBagLayout());
|
||||
setOpaque(false);
|
||||
|
||||
this.workspace = workspace;
|
||||
this.device = device;
|
||||
|
||||
timer = new Timer(5000, this);
|
||||
timer.setInitialDelay(0);
|
||||
timer.setRepeats(true);
|
||||
|
||||
JPanel panel = buildViewerAndControls();
|
||||
add(panel, new GridBagConstraints(0, 0, 1, 1, 0.3f, 1.0f,
|
||||
GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH,
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
|
||||
JPanel loupePanel = buildLoupePanel(spacing);
|
||||
add(loupePanel, new GridBagConstraints(1, 0, 1, 1, 0.7f, 1.0f,
|
||||
GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH,
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
timer.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private JPanel buildLoupePanel(int spacing) {
|
||||
loupe = new LoupeViewer();
|
||||
loupe.addMouseWheelListener(new WheelZoomListener());
|
||||
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 class WheelZoomListener implements MouseWheelListener {
|
||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||
if (zoomSlider != null) {
|
||||
int val = zoomSlider.getValue();
|
||||
val -= e.getWheelRotation() * 2;
|
||||
zoomSlider.setValue(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JPanel buildViewerAndControls() {
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
crosshair = new Crosshair(new ScreenshotViewer());
|
||||
crosshair.addMouseWheelListener(new WheelZoomListener());
|
||||
JScrollPane scroller = new JScrollPane(crosshair);
|
||||
scroller.setPreferredSize(new Dimension(320, 480));
|
||||
scroller.setBorder(null);
|
||||
panel.add(scroller,
|
||||
new GridBagConstraints(0, y++, 2, 1, 1.0f, 1.0f,
|
||||
GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH,
|
||||
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();
|
||||
}
|
||||
});
|
||||
zoomSlider = buildSlider(panel, "Zoom:", "2x", "24x", 2, 24, 8, 2);
|
||||
zoomSlider.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;
|
||||
private final ScreenshotViewer screenshotViewer;
|
||||
|
||||
Crosshair(ScreenshotViewer screenshotViewer) {
|
||||
this.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 Dimension getPreferredSize() {
|
||||
return screenshotViewer.getPreferredSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMaximumSize() {
|
||||
return screenshotViewer.getPreferredSize();
|
||||
}
|
||||
|
||||
@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) {
|
||||
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;
|
||||
}
|
||||
|
||||
switch (rawImage.bpp) {
|
||||
case 16:
|
||||
rawImage16toARGB(rawImage);
|
||||
break;
|
||||
case 32:
|
||||
rawImage32toARGB(rawImage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
return resize;
|
||||
}
|
||||
|
||||
private int getMask(int length) {
|
||||
int res = 0;
|
||||
for (int i = 0 ; i < length ; i++) {
|
||||
res = (res << 1) + 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private void rawImage32toARGB(RawImage rawImage) {
|
||||
byte[] buffer = rawImage.data;
|
||||
int index = 0;
|
||||
|
||||
final int redOffset = rawImage.red_offset;
|
||||
final int redLength = rawImage.red_length;
|
||||
final int redMask = getMask(redLength);
|
||||
final int greenOffset = rawImage.green_offset;
|
||||
final int greenLength = rawImage.green_length;
|
||||
final int greenMask = getMask(greenLength);
|
||||
final int blueOffset = rawImage.blue_offset;
|
||||
final int blueLength = rawImage.blue_length;
|
||||
final int blueMask = getMask(blueLength);
|
||||
final int alphaLength = rawImage.alpha_length;
|
||||
final int alphaOffset = rawImage.alpha_offset;
|
||||
final int alphaMask = getMask(alphaLength);
|
||||
|
||||
for (int y = 0 ; y < rawImage.height ; y++) {
|
||||
for (int x = 0 ; x < rawImage.width ; x++) {
|
||||
int value = buffer[index++] & 0x00FF;
|
||||
value |= (buffer[index++] & 0x00FF) << 8;
|
||||
value |= (buffer[index++] & 0x00FF) << 16;
|
||||
value |= (buffer[index++] & 0x00FF) << 24;
|
||||
|
||||
int r = ((value >>> redOffset) & redMask) << (8 - redLength);
|
||||
int g = ((value >>> greenOffset) & greenMask) << (8 - greenLength);
|
||||
int b = ((value >>> blueOffset) & blueMask) << (8 - blueLength);
|
||||
int a = 0xFF;
|
||||
|
||||
if (alphaLength != 0) {
|
||||
a = ((value >>> alphaOffset) & alphaMask) << (8 - alphaLength);
|
||||
}
|
||||
|
||||
scanline[x] = a << 24 | r << 16 | g << 8 | b;
|
||||
}
|
||||
|
||||
image.setRGB(0, y, rawImage.width, 1, scanline,
|
||||
0, rawImage.width);
|
||||
}
|
||||
}
|
||||
|
||||
private void rawImage16toARGB(RawImage rawImage) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 javax.swing.AbstractAction;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
public abstract class BackgroundAction extends AbstractAction {
|
||||
protected void executeBackgroundTask(SwingWorker<?, ?> worker) {
|
||||
if (worker != null) {
|
||||
worker.execute();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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 CaptureLayersAction extends BackgroundAction {
|
||||
public static final String ACTION_NAME = "captureLayers";
|
||||
private Workspace mWorkspace;
|
||||
|
||||
public CaptureLayersAction(Workspace workspace) {
|
||||
putValue(NAME, "Capture PSD");
|
||||
putValue(SHORT_DESCRIPTION, "Capture PSD");
|
||||
putValue(LONG_DESCRIPTION, "Capture current window into a Photoshop PSD file");
|
||||
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_P,
|
||||
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
this.mWorkspace = workspace;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
executeBackgroundTask(mWorkspace.captureLayers());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2011 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 DumpDisplayListAction extends BackgroundAction {
|
||||
public static final String ACTION_NAME = "dumpDisplayList";
|
||||
private Workspace mWorkspace;
|
||||
|
||||
public DumpDisplayListAction(Workspace workspace) {
|
||||
putValue(NAME, "Dump DisplayList");
|
||||
putValue(SHORT_DESCRIPTION, "Dump DisplayList");
|
||||
putValue(LONG_DESCRIPTION, "Dump DisplayList");
|
||||
this.mWorkspace = workspace;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
executeBackgroundTask(mWorkspace.outputDisplayList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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 javax.swing.table.DefaultTableModel;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
public class ProfilesTableModel extends DefaultTableModel {
|
||||
private static final String[] NAMES = { "measure", "layout", "draw" };
|
||||
|
||||
private final double[] profiles;
|
||||
private final NumberFormat formatter;
|
||||
|
||||
public ProfilesTableModel(double[] profiles) {
|
||||
this.profiles = profiles;
|
||||
formatter = NumberFormat.getNumberInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return profiles == null ? 0 : profiles.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int column) {
|
||||
if (profiles == null) return "";
|
||||
|
||||
if (column == 0) {
|
||||
return NAMES[row];
|
||||
}
|
||||
|
||||
|
||||
return formatter.format(profiles[row]) + "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
return column == 0 ? "Operation" : "Duration (ms)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int arg0, int arg1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object arg0, int arg1, int arg2) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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)";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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 java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Writes PSD file.
|
||||
*
|
||||
* Supports only 8 bits, RGB images with 4 channels.
|
||||
*/
|
||||
public class PsdFile {
|
||||
private final Header mHeader;
|
||||
private final ColorMode mColorMode;
|
||||
private final ImageResources mImageResources;
|
||||
private final LayersMasksInfo mLayersMasksInfo;
|
||||
private final LayersInfo mLayersInfo;
|
||||
|
||||
private final BufferedImage mMergedImage;
|
||||
private final Graphics2D mGraphics;
|
||||
|
||||
public PsdFile(int width, int height) {
|
||||
mHeader = new Header(width, height);
|
||||
mColorMode = new ColorMode();
|
||||
mImageResources = new ImageResources();
|
||||
mLayersMasksInfo = new LayersMasksInfo();
|
||||
mLayersInfo = new LayersInfo();
|
||||
|
||||
mMergedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
mGraphics = mMergedImage.createGraphics();
|
||||
}
|
||||
|
||||
public void addLayer(String name, BufferedImage image, Point offset) {
|
||||
addLayer(name, image, offset, true);
|
||||
}
|
||||
|
||||
public void addLayer(String name, BufferedImage image, Point offset, boolean visible) {
|
||||
mLayersInfo.addLayer(name, image, offset, visible);
|
||||
if (visible) mGraphics.drawImage(image, null, offset.x, offset.y);
|
||||
}
|
||||
|
||||
public void write(OutputStream stream) {
|
||||
mLayersMasksInfo.setLayersInfo(mLayersInfo);
|
||||
|
||||
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(stream));
|
||||
try {
|
||||
mHeader.write(out);
|
||||
out.flush();
|
||||
|
||||
mColorMode.write(out);
|
||||
mImageResources.write(out);
|
||||
mLayersMasksInfo.write(out);
|
||||
mLayersInfo.write(out);
|
||||
out.flush();
|
||||
|
||||
mLayersInfo.writeImageData(out);
|
||||
out.flush();
|
||||
|
||||
writeImage(mMergedImage, out, false);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeImage(BufferedImage image, DataOutputStream out, boolean split)
|
||||
throws IOException {
|
||||
|
||||
if (!split) out.writeShort(0);
|
||||
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
|
||||
final int length = width * height;
|
||||
int[] pixels = new int[length];
|
||||
|
||||
image.getData().getDataElements(0, 0, width, height, pixels);
|
||||
|
||||
byte[] a = new byte[length];
|
||||
byte[] r = new byte[length];
|
||||
byte[] g = new byte[length];
|
||||
byte[] b = new byte[length];
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
final int pixel = pixels[i];
|
||||
a[i] = (byte) ((pixel >> 24) & 0xFF);
|
||||
r[i] = (byte) ((pixel >> 16) & 0xFF);
|
||||
g[i] = (byte) ((pixel >> 8) & 0xFF);
|
||||
b[i] = (byte) (pixel & 0xFF);
|
||||
}
|
||||
|
||||
if (split) out.writeShort(0);
|
||||
if (split) out.write(a);
|
||||
if (split) out.writeShort(0);
|
||||
out.write(r);
|
||||
if (split) out.writeShort(0);
|
||||
out.write(g);
|
||||
if (split) out.writeShort(0);
|
||||
out.write(b);
|
||||
if (!split) out.write(a);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
static class Header {
|
||||
static final short MODE_BITMAP = 0;
|
||||
static final short MODE_GRAYSCALE = 1;
|
||||
static final short MODE_INDEXED = 2;
|
||||
static final short MODE_RGB = 3;
|
||||
static final short MODE_CMYK = 4;
|
||||
static final short MODE_MULTI_CHANNEL = 7;
|
||||
static final short MODE_DUOTONE = 8;
|
||||
static final short MODE_LAB = 9;
|
||||
|
||||
final byte[] mSignature = "8BPS".getBytes();
|
||||
final short mVersion = 1;
|
||||
final byte[] mReserved = new byte[6];
|
||||
final short mChannelCount = 4;
|
||||
final int mHeight;
|
||||
final int mWidth;
|
||||
final short mDepth = 8;
|
||||
final short mMode = MODE_RGB;
|
||||
|
||||
Header(int width, int height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
void write(DataOutputStream out) throws IOException {
|
||||
out.write(mSignature);
|
||||
out.writeShort(mVersion);
|
||||
out.write(mReserved);
|
||||
out.writeShort(mChannelCount);
|
||||
out.writeInt(mHeight);
|
||||
out.writeInt(mWidth);
|
||||
out.writeShort(mDepth);
|
||||
out.writeShort(mMode);
|
||||
}
|
||||
}
|
||||
|
||||
// Unused at the moment
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
static class ColorMode {
|
||||
final int mLength = 0;
|
||||
|
||||
void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(mLength);
|
||||
}
|
||||
}
|
||||
|
||||
// Unused at the moment
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
static class ImageResources {
|
||||
static final short RESOURCE_RESOLUTION_INFO = 0x03ED;
|
||||
|
||||
int mLength = 0;
|
||||
|
||||
final byte[] mSignature = "8BIM".getBytes();
|
||||
final short mResourceId = RESOURCE_RESOLUTION_INFO;
|
||||
|
||||
final short mPad = 0;
|
||||
|
||||
final int mDataLength = 16;
|
||||
|
||||
final short mHorizontalDisplayUnit = 0x48; // 72 dpi
|
||||
final int mHorizontalResolution = 1;
|
||||
final short mWidthDisplayUnit = 1;
|
||||
|
||||
final short mVerticalDisplayUnit = 0x48; // 72 dpi
|
||||
final int mVerticalResolution = 1;
|
||||
final short mHeightDisplayUnit = 1;
|
||||
|
||||
ImageResources() {
|
||||
mLength = mSignature.length;
|
||||
mLength += 2;
|
||||
mLength += 2;
|
||||
mLength += 4;
|
||||
mLength += 8;
|
||||
mLength += 8;
|
||||
}
|
||||
|
||||
void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(mLength);
|
||||
out.write(mSignature);
|
||||
out.writeShort(mResourceId);
|
||||
out.writeShort(mPad);
|
||||
out.writeInt(mDataLength);
|
||||
out.writeShort(mHorizontalDisplayUnit);
|
||||
out.writeInt(mHorizontalResolution);
|
||||
out.writeShort(mWidthDisplayUnit);
|
||||
out.writeShort(mVerticalDisplayUnit);
|
||||
out.writeInt(mVerticalResolution);
|
||||
out.writeShort(mHeightDisplayUnit);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
static class LayersMasksInfo {
|
||||
int mMiscLength;
|
||||
int mLayerInfoLength;
|
||||
|
||||
void setLayersInfo(LayersInfo layersInfo) {
|
||||
mLayerInfoLength = layersInfo.getLength();
|
||||
// Round to the next multiple of 2
|
||||
if ((mLayerInfoLength & 0x1) == 0x1) mLayerInfoLength++;
|
||||
mMiscLength = mLayerInfoLength + 8;
|
||||
}
|
||||
|
||||
void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(mMiscLength);
|
||||
out.writeInt(mLayerInfoLength);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
static class LayersInfo {
|
||||
final List<Layer> mLayers = new ArrayList<Layer>();
|
||||
|
||||
void addLayer(String name, BufferedImage image, Point offset, boolean visible) {
|
||||
mLayers.add(new Layer(name, image, offset, visible));
|
||||
}
|
||||
|
||||
int getLength() {
|
||||
int length = 2;
|
||||
for (Layer layer : mLayers) {
|
||||
length += layer.getLength();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void write(DataOutputStream out) throws IOException {
|
||||
out.writeShort((short) -mLayers.size());
|
||||
for (Layer layer : mLayers) {
|
||||
layer.write(out);
|
||||
}
|
||||
}
|
||||
|
||||
void writeImageData(DataOutputStream out) throws IOException {
|
||||
for (Layer layer : mLayers) {
|
||||
layer.writeImageData(out);
|
||||
}
|
||||
// Global layer mask info length
|
||||
out.writeInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
static class Layer {
|
||||
static final byte OPACITY_TRANSPARENT = 0x0;
|
||||
static final byte OPACITY_OPAQUE = (byte) 0xFF;
|
||||
|
||||
static final byte CLIPPING_BASE = 0x0;
|
||||
static final byte CLIPPING_NON_BASE = 0x1;
|
||||
|
||||
static final byte FLAG_TRANSPARENCY_PROTECTED = 0x1;
|
||||
static final byte FLAG_INVISIBLE = 0x2;
|
||||
|
||||
final int mTop;
|
||||
final int mLeft;
|
||||
final int mBottom;
|
||||
final int mRight;
|
||||
|
||||
final short mChannelCount = 4;
|
||||
final Channel[] mChannelInfo = new Channel[mChannelCount];
|
||||
|
||||
final byte[] mBlendSignature = "8BIM".getBytes();
|
||||
final byte[] mBlendMode = "norm".getBytes();
|
||||
|
||||
final byte mOpacity = OPACITY_OPAQUE;
|
||||
final byte mClipping = CLIPPING_BASE;
|
||||
byte mFlags = 0x0;
|
||||
final byte mFiller = 0x0;
|
||||
|
||||
int mExtraSize = 4 + 4;
|
||||
|
||||
final int mMaskDataLength = 0;
|
||||
final int mBlendRangeDataLength = 0;
|
||||
|
||||
final byte[] mName;
|
||||
|
||||
final byte[] mLayerExtraSignature = "8BIM".getBytes();
|
||||
final byte[] mLayerExtraKey = "luni".getBytes();
|
||||
int mLayerExtraLength;
|
||||
final String mOriginalName;
|
||||
|
||||
private BufferedImage mImage;
|
||||
|
||||
Layer(String name, BufferedImage image, Point offset, boolean visible) {
|
||||
final int height = image.getHeight();
|
||||
final int width = image.getWidth();
|
||||
final int length = width * height;
|
||||
|
||||
mChannelInfo[0] = new Channel(Channel.ID_ALPHA, length);
|
||||
mChannelInfo[1] = new Channel(Channel.ID_RED, length);
|
||||
mChannelInfo[2] = new Channel(Channel.ID_GREEN, length);
|
||||
mChannelInfo[3] = new Channel(Channel.ID_BLUE, length);
|
||||
|
||||
mTop = offset.y;
|
||||
mLeft = offset.x;
|
||||
mBottom = offset.y + height;
|
||||
mRight = offset.x + width;
|
||||
|
||||
mOriginalName = name;
|
||||
byte[] data = name.getBytes();
|
||||
|
||||
try {
|
||||
mLayerExtraLength = 4 + mOriginalName.getBytes("UTF-16").length;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
final byte[] nameData = new byte[data.length + 1];
|
||||
nameData[0] = (byte) (data.length & 0xFF);
|
||||
System.arraycopy(data, 0, nameData, 1, data.length);
|
||||
|
||||
// This could be done in the same pass as above
|
||||
if (nameData.length % 4 != 0) {
|
||||
data = new byte[nameData.length + 4 - (nameData.length % 4)];
|
||||
System.arraycopy(nameData, 0, data, 0, nameData.length);
|
||||
mName = data;
|
||||
} else {
|
||||
mName = nameData;
|
||||
}
|
||||
mExtraSize += mName.length;
|
||||
mExtraSize += mLayerExtraLength + 4 + mLayerExtraKey.length +
|
||||
mLayerExtraSignature.length;
|
||||
|
||||
mImage = image;
|
||||
|
||||
if (!visible) {
|
||||
mFlags |= FLAG_INVISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
int getLength() {
|
||||
int length = 4 * 4 + 2;
|
||||
|
||||
for (Channel channel : mChannelInfo) {
|
||||
length += channel.getLength();
|
||||
}
|
||||
|
||||
length += mBlendSignature.length;
|
||||
length += mBlendMode.length;
|
||||
length += 4;
|
||||
length += 4;
|
||||
length += mExtraSize;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(mTop);
|
||||
out.writeInt(mLeft);
|
||||
out.writeInt(mBottom);
|
||||
out.writeInt(mRight);
|
||||
|
||||
out.writeShort(mChannelCount);
|
||||
for (Channel channel : mChannelInfo) {
|
||||
channel.write(out);
|
||||
}
|
||||
|
||||
out.write(mBlendSignature);
|
||||
out.write(mBlendMode);
|
||||
|
||||
out.write(mOpacity);
|
||||
out.write(mClipping);
|
||||
out.write(mFlags);
|
||||
out.write(mFiller);
|
||||
|
||||
out.writeInt(mExtraSize);
|
||||
out.writeInt(mMaskDataLength);
|
||||
|
||||
out.writeInt(mBlendRangeDataLength);
|
||||
|
||||
out.write(mName);
|
||||
|
||||
out.write(mLayerExtraSignature);
|
||||
out.write(mLayerExtraKey);
|
||||
out.writeInt(mLayerExtraLength);
|
||||
out.writeInt(mOriginalName.length() + 1);
|
||||
out.write(mOriginalName.getBytes("UTF-16"));
|
||||
}
|
||||
|
||||
void writeImageData(DataOutputStream out) throws IOException {
|
||||
writeImage(mImage, out, true);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
static class Channel {
|
||||
static final short ID_RED = 0;
|
||||
static final short ID_GREEN = 1;
|
||||
static final short ID_BLUE = 2;
|
||||
static final short ID_ALPHA = -1;
|
||||
static final short ID_LAYER_MASK = -2;
|
||||
|
||||
final short mId;
|
||||
final int mDataLength;
|
||||
|
||||
Channel(short id, int dataLength) {
|
||||
mId = id;
|
||||
mDataLength = dataLength + 2;
|
||||
}
|
||||
|
||||
int getLength() {
|
||||
return 2 + 4 + mDataLength;
|
||||
}
|
||||
|
||||
void write(DataOutputStream out) throws IOException {
|
||||
out.writeShort(mId);
|
||||
out.writeInt(mDataLength);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 PsdFileFilter extends FileFilter {
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return f.isDirectory() || f.getName().toLowerCase().endsWith(".psd");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Photoshop Document (*.psd)";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.
After Width: | Height: | Size: 749 B |
Binary file not shown.
After Width: | Height: | Size: 747 B |
Binary file not shown.
After Width: | Height: | Size: 734 B |
Binary file not shown.
After Width: | Height: | Size: 733 B |
Loading…
Add table
Add a link
Reference in a new issue