aboutsummaryrefslogtreecommitdiffstats
path: root/hierarchyviewer2/libs/hierarchyviewerlib/src
diff options
context:
space:
mode:
Diffstat (limited to 'hierarchyviewer2/libs/hierarchyviewerlib/src')
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk4
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java15
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java48
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java17
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java6
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java20
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DevicePropertyEditingSupport.java302
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/InvokeMethodPrompt.java166
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java108
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/images/picker.pngbin0 -> 370 bytes
10 files changed, 678 insertions, 8 deletions
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk b/hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk
index 1afbc92..59753e1 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk
@@ -20,8 +20,10 @@ LOCAL_JAVA_RESOURCE_DIRS := ../src
LOCAL_JAR_MANIFEST := ../manifest.txt
-LOCAL_JAVA_LIBRARIES := ddmlib \
+LOCAL_JAVA_LIBRARIES := common \
+ ddmlib \
ddmuilib \
+ guava-tools \
swt \
org.eclipse.jface_3.6.2.M20110210-1200 \
org.eclipse.core.commands_3.6.0.I20100512-1500
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java
index 0f0cf65..cba35f2 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java
@@ -48,6 +48,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
@@ -615,6 +616,20 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener,
}
}
+ public void invokeMethodOnSelectedView(final String method, final List<Object> args) {
+ final DrawableViewNode selectedNode = TreeViewModel.getModel().getSelection();
+ if (selectedNode != null) {
+ executeInBackground("Invoke View Method", new Runnable() {
+ @Override
+ public void run() {
+ IHvDevice hvDevice = getHvDevice(selectedNode.viewNode.window.getDevice());
+ hvDevice.invokeViewMethod(selectedNode.viewNode.window, selectedNode.viewNode,
+ method, args);
+ }
+ });
+ }
+ }
+
public void loadAllViews() {
executeInBackground("Loading all views", new Runnable() {
@Override
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java
index 0a6e938..0172995 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java
@@ -144,7 +144,7 @@ public class DdmViewDebugDevice extends AbstractHvDevice implements IDeviceChang
try {
HandleViewDebug.listViewRoots(c, handler);
} catch (IOException e) {
- Log.e(TAG, e);
+ Log.i(TAG, "No connection to client: " + cd.getClientDescription());
continue;
}
@@ -215,7 +215,11 @@ public class DdmViewDebugDevice extends AbstractHvDevice implements IDeviceChang
return null;
}
- byte[] data = handler.getData(10, TimeUnit.SECONDS);
+ byte[] data = handler.getData(20, TimeUnit.SECONDS);
+ if (data == null) {
+ return null;
+ }
+
String viewHierarchy = new String(data, Charset.forName("UTF-8"));
return DeviceBridge.parseViewHierarchy(new BufferedReader(new StringReader(viewHierarchy)),
window);
@@ -370,4 +374,44 @@ public class DdmViewDebugDevice extends AbstractHvDevice implements IDeviceChang
reloadWindows();
}
}
+
+ @Override
+ public boolean isViewUpdateEnabled() {
+ return true;
+ }
+
+ @Override
+ public void invokeViewMethod(Window window, ViewNode viewNode, String method,
+ List<?> args) {
+ Client c = window.getClient();
+ if (c == null) {
+ return;
+ }
+
+ String viewRoot = window.getTitle();
+ try {
+ HandleViewDebug.invokeMethod(c, viewRoot, viewNode.toString(), method, args.toArray());
+ } catch (IOException e) {
+ Log.e(TAG, e);
+ }
+ }
+
+ @Override
+ public boolean setLayoutParameter(Window window, ViewNode viewNode, String property,
+ int value) {
+ Client c = window.getClient();
+ if (c == null) {
+ return false;
+ }
+
+ String viewRoot = window.getTitle();
+ try {
+ HandleViewDebug.setLayoutParameter(c, viewRoot, viewNode.toString(), property, value);
+ } catch (IOException e) {
+ Log.e(TAG, e);
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java
index c38a9cc..efc7926 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java
@@ -21,13 +21,26 @@ import com.android.ddmlib.ClientData;
import com.android.ddmlib.IDevice;
public class HvDeviceFactory {
- private static final boolean ALWAYS_USE_VIEWSERVER = false; // for debugging
+ private static final String sHvProtoEnvVar =
+ System.getenv("android.hvproto"); //$NON-NLS-1$
public static IHvDevice create(IDevice device) {
- if (ALWAYS_USE_VIEWSERVER) {
+ // default to old mechanism until the new one is fully tested
+ if (sHvProtoEnvVar == null ||
+ !"ddm".equalsIgnoreCase(sHvProtoEnvVar)) { //$NON-NLS-1$
return new ViewServerDevice(device);
}
+ // Wait for a few seconds after the device has been connected to
+ // allow all the clients to be initialized. Specifically, we need to wait
+ // until the client data is filled with the list of features supported
+ // by the client.
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
boolean ddmViewHierarchy = false;
// see if any of the clients on the device support view hierarchy via DDMS
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java
index fe8d1ba..6f1fd37 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java
@@ -24,6 +24,8 @@ import com.android.hierarchyviewerlib.ui.util.PsdFile;
import org.eclipse.swt.graphics.Image;
+import java.util.List;
+
/** Represents a device that can perform view debug operations. */
public interface IHvDevice {
/**
@@ -51,6 +53,10 @@ public interface IHvDevice {
void requestLayout(ViewNode viewNode);
void outputDisplayList(ViewNode viewNode);
+ boolean isViewUpdateEnabled();
+ void invokeViewMethod(Window window, ViewNode viewNode, String method, List<?> args);
+ boolean setLayoutParameter(Window window, ViewNode viewNode, String property, int value);
+
void addWindowChangeListener(IWindowChangeListener l);
void removeWindowChangeListener(IWindowChangeListener l);
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java
index 0febcef..4445e9a 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java
@@ -26,6 +26,8 @@ import com.android.hierarchyviewerlib.ui.util.PsdFile;
import org.eclipse.swt.graphics.Image;
+import java.util.List;
+
public class ViewServerDevice extends AbstractHvDevice {
static final String TAG = "ViewServerDevice";
@@ -146,4 +148,22 @@ public class ViewServerDevice extends AbstractHvDevice {
WindowUpdater.stopListenForWindowChanges(l, mDevice);
}
}
+
+ @Override
+ public boolean isViewUpdateEnabled() {
+ return false;
+ }
+
+ @Override
+ public void invokeViewMethod(Window window, ViewNode viewNode, String method,
+ List<?> args) {
+ // not supported
+ }
+
+ @Override
+ public boolean setLayoutParameter(Window window, ViewNode viewNode, String property,
+ int value) {
+ // not supported
+ return false;
+ }
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DevicePropertyEditingSupport.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DevicePropertyEditingSupport.java
new file mode 100644
index 0000000..1bbc97f
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DevicePropertyEditingSupport.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2013 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.hierarchyviewerlib.ui;
+
+import com.android.SdkConstants;
+import com.android.hierarchyviewerlib.device.IHvDevice;
+import com.android.hierarchyviewerlib.models.ViewNode;
+import com.android.hierarchyviewerlib.models.ViewNode.Property;
+import com.android.utils.SdkUtils;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableSet;
+
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+public class DevicePropertyEditingSupport {
+ public enum PropertyType {
+ INTEGER,
+ INTEGER_OR_CONSTANT,
+ ENUM,
+ };
+
+ private static final List<IDevicePropertyEditor> sDevicePropertyEditors = Arrays.asList(
+ new LayoutPropertyEditor(),
+ new PaddingPropertyEditor()
+ );
+
+ public boolean canEdit(Property p) {
+ return getPropertyEditorFor(p) != null;
+ }
+
+ private IDevicePropertyEditor getPropertyEditorFor(Property p) {
+ for (IDevicePropertyEditor pe: sDevicePropertyEditors) {
+ if (pe.canEdit(p)) {
+ return pe;
+ }
+ }
+
+ return null;
+ }
+
+ public PropertyType getPropertyType(Property p) {
+ return getPropertyEditorFor(p).getType(p);
+ }
+
+ public String[] getPropertyRange(Property p) {
+ return getPropertyEditorFor(p).getPropertyRange(p);
+ }
+
+ public boolean setValue(Collection<Property> properties, Property p, Object newValue,
+ ViewNode viewNode, IHvDevice device) {
+ return getPropertyEditorFor(p).setValue(properties, p, newValue, viewNode, device);
+ }
+
+ private static String stripCategoryPrefix(String name) {
+ return name.substring(name.indexOf(':') + 1);
+ }
+
+ private interface IDevicePropertyEditor {
+ boolean canEdit(Property p);
+ PropertyType getType(Property p);
+ String[] getPropertyRange(Property p);
+ boolean setValue(Collection<Property> properties, Property p, Object newValue,
+ ViewNode viewNode, IHvDevice device);
+ }
+
+ private static class LayoutPropertyEditor implements IDevicePropertyEditor {
+ private static final Set<String> sLayoutPropertiesWithStringValues =
+ ImmutableSet.of(SdkConstants.ATTR_LAYOUT_WIDTH,
+ SdkConstants.ATTR_LAYOUT_HEIGHT,
+ SdkConstants.ATTR_LAYOUT_GRAVITY);
+
+ private static final int MATCH_PARENT = -1;
+ private static final int FILL_PARENT = -1;
+ private static final int WRAP_CONTENT = -2;
+
+ private enum LayoutGravity {
+ top(0x30),
+ bottom(0x50),
+ left(0x03),
+ right(0x05),
+ center_vertical(0x10),
+ fill_vertical(0x70),
+ center_horizontal(0x01),
+ fill_horizontal(0x07),
+ center(0x11),
+ fill(0x77),
+ clip_vertical(0x80),
+ clip_horizontal(0x08),
+ start(0x00800003),
+ end(0x00800005);
+
+ private final int mValue;
+
+ private LayoutGravity(int v) {
+ mValue = v;
+ }
+ }
+
+ /**
+ * Returns true if this is a layout property with either a known string value, or an
+ * integer value.
+ */
+ @Override
+ public boolean canEdit(Property p) {
+ String name = stripCategoryPrefix(p.name);
+ if (!name.startsWith(SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX)) {
+ return false;
+ }
+
+ if (sLayoutPropertiesWithStringValues.contains(name)) {
+ return true;
+ }
+
+ try {
+ SdkUtils.parseLocalizedInt(p.value);
+ return true;
+ } catch (ParseException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public PropertyType getType(Property p) {
+ String name = stripCategoryPrefix(p.name);
+ if (sLayoutPropertiesWithStringValues.contains(name)) {
+ return PropertyType.INTEGER_OR_CONSTANT;
+ } else {
+ return PropertyType.INTEGER;
+ }
+ }
+
+ @Override
+ public String[] getPropertyRange(Property p) {
+ return new String[0];
+ }
+
+ @Override
+ public boolean setValue(Collection<Property> properties, Property p, Object newValue,
+ ViewNode viewNode, IHvDevice device) {
+ String name = stripCategoryPrefix(p.name);
+
+ // nothing to do if same as current value
+ if (p.value.equals(newValue)) {
+ return false;
+ }
+
+ int value = -1;
+ String textValue = null;
+
+ if (SdkConstants.ATTR_LAYOUT_GRAVITY.equals(name)) {
+ value = 0;
+ StringBuilder sb = new StringBuilder(20);
+ for (String attr: Splitter.on('|').split((String) newValue)) {
+ LayoutGravity g;
+ try {
+ g = LayoutGravity.valueOf(attr);
+ } catch (IllegalArgumentException e) {
+ // ignore this gravity attribute
+ continue;
+ }
+
+ value |= g.mValue;
+
+ if (sb.length() > 0) {
+ sb.append('|');
+ }
+ sb.append(g.name());
+ }
+ textValue = sb.toString();
+ } else if (SdkConstants.ATTR_LAYOUT_HEIGHT.equals(name)
+ || SdkConstants.ATTR_LAYOUT_WIDTH.equals(name)) {
+ // newValue is of type string, but its contents may be a named constant or a integer
+ String s = (String) newValue;
+ if (s.equalsIgnoreCase(SdkConstants.VALUE_MATCH_PARENT)) {
+ textValue = SdkConstants.VALUE_MATCH_PARENT;
+ value = MATCH_PARENT;
+ } else if (s.equalsIgnoreCase(SdkConstants.VALUE_FILL_PARENT)) {
+ textValue = SdkConstants.VALUE_FILL_PARENT;
+ value = FILL_PARENT;
+ } else if (s.equalsIgnoreCase(SdkConstants.VALUE_WRAP_CONTENT)) {
+ textValue = SdkConstants.VALUE_WRAP_CONTENT;
+ value = WRAP_CONTENT;
+ }
+ }
+
+ if (textValue == null) {
+ try {
+ value = Integer.parseInt((String) newValue);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ // attempt to set the value on the device
+ name = name.substring(SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX.length());
+ if (device.setLayoutParameter(viewNode.window, viewNode, name, value)) {
+ p.value = textValue != null ? textValue : (String) newValue;
+ }
+
+ return true;
+ }
+ }
+
+ private static class PaddingPropertyEditor implements IDevicePropertyEditor {
+ // These names should match the field names used for padding in the Framework's View class
+ private static final String PADDING_LEFT = "mPaddingLeft"; //$NON-NLS-1$
+ private static final String PADDING_RIGHT = "mPaddingRight"; //$NON-NLS-1$
+ private static final String PADDING_TOP = "mPaddingTop"; //$NON-NLS-1$
+ private static final String PADDING_BOTTOM = "mPaddingBottom"; //$NON-NLS-1$
+
+ private static final Set<String> sPaddingProperties = ImmutableSet.of(
+ PADDING_LEFT, PADDING_RIGHT, PADDING_TOP, PADDING_BOTTOM);
+
+ @Override
+ public boolean canEdit(Property p) {
+ return sPaddingProperties.contains(stripCategoryPrefix(p.name));
+ }
+
+ @Override
+ public PropertyType getType(Property p) {
+ return PropertyType.INTEGER;
+ }
+
+ @Override
+ public String[] getPropertyRange(Property p) {
+ return new String[0];
+ }
+
+ /**
+ * Set padding: Since the only view method is setPadding(l, t, r, b), we need access
+ * to all 4 padding's to update any particular one.
+ */
+ @Override
+ public boolean setValue(Collection<Property> properties, Property prop, Object newValue,
+ ViewNode viewNode, IHvDevice device) {
+ int v;
+ try {
+ v = Integer.parseInt((String) newValue);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+
+ int pLeft = 0;
+ int pRight = 0;
+ int pTop = 0;
+ int pBottom = 0;
+
+ String propName = stripCategoryPrefix(prop.name);
+ for (Property p: properties) {
+ String name = stripCategoryPrefix(p.name);
+ if (!sPaddingProperties.contains(name)) {
+ continue;
+ }
+
+ if (name.equals(PADDING_LEFT)) {
+ pLeft = propName.equals(PADDING_LEFT) ?
+ v : SdkUtils.parseLocalizedInt(p.value, 0);
+ } else if (name.equals(PADDING_RIGHT)) {
+ pRight = propName.equals(PADDING_RIGHT) ?
+ v : SdkUtils.parseLocalizedInt(p.value, 0);
+ } else if (name.equals(PADDING_TOP)) {
+ pTop = propName.equals(PADDING_TOP) ?
+ v : SdkUtils.parseLocalizedInt(p.value, 0);
+ } else if (name.equals(PADDING_BOTTOM)) {
+ pBottom = propName.equals(PADDING_BOTTOM) ?
+ v : SdkUtils.parseLocalizedInt(p.value, 0);
+ }
+ }
+
+ // invoke setPadding() on the device
+ device.invokeViewMethod(viewNode.window, viewNode, "setPadding", Arrays.asList(
+ Integer.valueOf(pLeft),
+ Integer.valueOf(pTop),
+ Integer.valueOf(pRight),
+ Integer.valueOf(pBottom)
+ ));
+
+ // update the value set in the property (to avoid reading all properties back from
+ // the device)
+ prop.value = Integer.toString(v);
+ return true;
+ }
+ }
+}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/InvokeMethodPrompt.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/InvokeMethodPrompt.java
new file mode 100644
index 0000000..944a57a
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/InvokeMethodPrompt.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2013 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.hierarchyviewerlib.ui;
+
+import com.android.ddmlib.Log;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+import com.android.hierarchyviewerlib.device.IHvDevice;
+import com.android.hierarchyviewerlib.models.TreeViewModel;
+import com.android.hierarchyviewerlib.models.TreeViewModel.ITreeChangeListener;
+import com.android.hierarchyviewerlib.models.ViewNode;
+import com.android.hierarchyviewerlib.ui.util.DrawableViewNode;
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Text;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class InvokeMethodPrompt extends Composite implements ITreeChangeListener {
+ private TreeViewModel mModel;
+ private DrawableViewNode mSelectedNode;
+ private Text mText;
+ private static final Splitter CMD_SPLITTER = Splitter.on(CharMatcher.anyOf(", "))
+ .trimResults().omitEmptyStrings();
+
+ public InvokeMethodPrompt(Composite parent) {
+ super(parent, SWT.NONE);
+ setLayout(new FillLayout());
+
+ mText = new Text(this, SWT.BORDER);
+ mText.addKeyListener(new KeyListener() {
+ @Override
+ public void keyReleased(KeyEvent ke) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent ke) {
+ onKeyPress(ke);
+ }
+ });
+
+ mModel = TreeViewModel.getModel();
+ mModel.addTreeChangeListener(this);
+ }
+
+ private void onKeyPress(KeyEvent ke) {
+ if (ke.keyCode == SWT.CR) {
+ String cmd = mText.getText().trim();
+ if (!cmd.isEmpty()) {
+ invokeViewMethod(cmd);
+ }
+ mText.setText("");
+ }
+ }
+
+ private void invokeViewMethod(String cmd) {
+ Iterator<String> segmentIterator = CMD_SPLITTER.split(cmd).iterator();
+
+ String method = null;
+ if (segmentIterator.hasNext()) {
+ method = segmentIterator.next();
+ } else {
+ return;
+ }
+
+ List<Object> args = new ArrayList<Object>(10);
+ while (segmentIterator.hasNext()) {
+ String arg = segmentIterator.next();
+
+ // check for boolean
+ if (arg.equalsIgnoreCase("true")) {
+ args.add(Boolean.TRUE);
+ continue;
+ } else if (arg.equalsIgnoreCase("false")) {
+ args.add(Boolean.FALSE);
+ continue;
+ }
+
+ // see if last character gives a clue regarding the argument type
+ char typeSpecifier = Character.toUpperCase(arg.charAt(arg.length() - 1));
+ try {
+ switch (typeSpecifier) {
+ case 'L':
+ args.add(Long.valueOf(arg.substring(0, arg.length())));
+ break;
+ case 'D':
+ args.add(Double.valueOf(arg.substring(0, arg.length())));
+ break;
+ case 'F':
+ args.add(Float.valueOf(arg.substring(0, arg.length())));
+ break;
+ case 'S':
+ args.add(Short.valueOf(arg.substring(0, arg.length())));
+ break;
+ case 'B':
+ args.add(Byte.valueOf(arg.substring(0, arg.length())));
+ break;
+ default: // default to integer
+ args.add(Integer.valueOf(arg));
+ break;
+ }
+ } catch (NumberFormatException e) {
+ Log.e("hv", "Unable to parse method argument: " + arg);
+ return;
+ }
+ }
+
+ HierarchyViewerDirector.getDirector().invokeMethodOnSelectedView(method, args);
+ }
+
+ @Override
+ public void selectionChanged() {
+ mSelectedNode = mModel.getSelection();
+ refresh();
+ }
+
+ private boolean isViewUpdateEnabled(ViewNode viewNode) {
+ IHvDevice device = viewNode.window.getHvDevice();
+ return device != null && device.isViewUpdateEnabled();
+ }
+
+ private void refresh() {
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ mText.setEnabled(mSelectedNode != null
+ && isViewUpdateEnabled(mSelectedNode.viewNode));
+ }
+ });
+ }
+
+ @Override
+ public void treeChanged() {
+ selectionChanged();
+ }
+
+ @Override
+ public void viewportChanged() {
+ }
+
+ @Override
+ public void zoomChanged() {
+ }
+}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java
index 90d2405..9456a0a 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java
@@ -16,17 +16,27 @@
package com.android.hierarchyviewerlib.ui;
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+import com.android.hierarchyviewerlib.device.IHvDevice;
import com.android.hierarchyviewerlib.models.TreeViewModel;
-import com.android.hierarchyviewerlib.models.ViewNode;
import com.android.hierarchyviewerlib.models.TreeViewModel.ITreeChangeListener;
+import com.android.hierarchyviewerlib.models.ViewNode;
import com.android.hierarchyviewerlib.models.ViewNode.Property;
+import com.android.hierarchyviewerlib.ui.DevicePropertyEditingSupport.PropertyType;
import com.android.hierarchyviewerlib.ui.util.DrawableViewNode;
import com.android.hierarchyviewerlib.ui.util.TreeColumnResizer;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ComboBoxCellEditor;
+import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
@@ -42,13 +52,17 @@ import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import java.util.ArrayList;
+import java.util.Collection;
public class PropertyViewer extends Composite implements ITreeChangeListener {
private TreeViewModel mModel;
private TreeViewer mTreeViewer;
-
private Tree mTree;
+ private TreeViewerColumn mValueColumn;
+ private PropertyValueEditingSupport mPropertyValueEditingSupport;
+
+ private Image mImage;
private DrawableViewNode mSelectedNode;
@@ -144,6 +158,13 @@ public class PropertyViewer extends Composite implements ITreeChangeListener {
@Override
public Image getColumnImage(Object element, int column) {
+ if (mSelectedNode == null) {
+ return null;
+ }
+ if (column == 1 && mPropertyValueEditingSupport.canEdit(element)) {
+ return mImage;
+ }
+
return null;
}
@@ -188,6 +209,79 @@ public class PropertyViewer extends Composite implements ITreeChangeListener {
}
}
+ private class PropertyValueEditingSupport extends EditingSupport {
+ private DevicePropertyEditingSupport mDevicePropertyEditingSupport =
+ new DevicePropertyEditingSupport();
+
+ public PropertyValueEditingSupport(ColumnViewer viewer) {
+ super(viewer);
+ }
+
+ @Override
+ protected boolean canEdit(Object element) {
+ if (mSelectedNode == null) {
+ return false;
+ }
+
+ return element instanceof Property
+ && mSelectedNode.viewNode.window.getHvDevice().isViewUpdateEnabled()
+ && mDevicePropertyEditingSupport.canEdit((Property) element);
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ Property p = (Property) element;
+ PropertyType type = mDevicePropertyEditingSupport.getPropertyType(p);
+ Composite parent = (Composite) getViewer().getControl();
+
+ switch (type) {
+ case INTEGER:
+ case INTEGER_OR_CONSTANT:
+ return new TextCellEditor(parent);
+ case ENUM:
+ String[] items = mDevicePropertyEditingSupport.getPropertyRange(p);
+ return new ComboBoxCellEditor(parent, items, SWT.READ_ONLY);
+ }
+
+ return null;
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ Property p = (Property) element;
+ PropertyType type = mDevicePropertyEditingSupport.getPropertyType(p);
+
+ if (type == PropertyType.ENUM) {
+ // for enums, return the index of the current value in the list of possible values
+ String[] items = mDevicePropertyEditingSupport.getPropertyRange(p);
+ return Integer.valueOf(indexOf(p.value, items));
+ }
+
+ return ((Property) element).value;
+ }
+
+ private int indexOf(String item, String[] items) {
+ for (int i = 0; i < items.length; i++) {
+ if (items[i].equals(item)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ @Override
+ protected void setValue(Object element, Object newValue) {
+ Property p = (Property) element;
+ IHvDevice device = mSelectedNode.viewNode.window.getHvDevice();
+ Collection<Property> properties = mSelectedNode.viewNode.namedProperties.values();
+ if (mDevicePropertyEditingSupport.setValue(properties, p, newValue,
+ mSelectedNode.viewNode, device)) {
+ doRefresh();
+ }
+ }
+ }
+
public PropertyViewer(Composite parent) {
super(parent, SWT.NONE);
setLayout(new FillLayout());
@@ -202,6 +296,10 @@ public class PropertyViewer extends Composite implements ITreeChangeListener {
TreeColumn valueColumn = new TreeColumn(mTree, SWT.NONE);
valueColumn.setText("Value");
+ mValueColumn = new TreeViewerColumn(mTreeViewer, valueColumn);
+ mPropertyValueEditingSupport = new PropertyValueEditingSupport(mTreeViewer);
+ mValueColumn.setEditingSupport(mPropertyValueEditingSupport);
+
mModel = TreeViewModel.getModel();
ContentProvider contentProvider = new ContentProvider();
mTreeViewer.setContentProvider(contentProvider);
@@ -211,10 +309,14 @@ public class PropertyViewer extends Composite implements ITreeChangeListener {
addDisposeListener(mDisposeListener);
- new TreeColumnResizer(this, propertyColumn, valueColumn);
+ @SuppressWarnings("unused")
+ TreeColumnResizer resizer = new TreeColumnResizer(this, propertyColumn, valueColumn);
addControlListener(mControlListener);
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ mImage = imageLoader.loadImage("picker.png", Display.getDefault()); //$NON-NLS-1$
+
treeChanged();
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/images/picker.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/images/picker.png
new file mode 100644
index 0000000..8ea2bed
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/images/picker.png
Binary files differ