Add baseline/margins to ViewInfo.
Also make it so that older layoutlib that are using API5 return the
value through reflection (done in LayoutLibrary.)
Change-Id: I3a32666e525f0f1d37a13e670d1d1c659b8e2027
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
index 337ad5c..e814b17 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
@@ -1480,6 +1480,7 @@
mMinSdkVersion,
mTargetSdkVersion,
logger);
+
if (noDecor) {
params.setForceNoDecor();
} else {
diff --git a/ide_common/src/com/android/ide/common/rendering/LayoutLibrary.java b/ide_common/src/com/android/ide/common/rendering/LayoutLibrary.java
index e1256fe..dd1a3dc 100644
--- a/ide_common/src/com/android/ide/common/rendering/LayoutLibrary.java
+++ b/ide_common/src/com/android/ide/common/rendering/LayoutLibrary.java
@@ -16,7 +16,7 @@
package com.android.ide.common.rendering;
-import static com.android.ide.common.rendering.api.Result.Status.NOT_IMPLEMENTED;
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_REFLECTION;
import com.android.ide.common.log.ILogger;
import com.android.ide.common.rendering.api.Bridge;
@@ -48,11 +48,13 @@
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -91,6 +93,16 @@
/** classloader used to load the jar file */
private final ClassLoader mClassLoader;
+ // Reflection data for older Layout Libraries.
+ private Method mViewGetParentMethod;
+ private Method mViewGetBaselineMethod;
+ private Method mViewParentIndexOfChildMethod;
+ private Class<?> mMarginLayoutParamClass;
+ private Field mLeftMarginField;
+ private Field mTopMarginField;
+ private Field mRightMarginField;
+ private Field mBottomMarginField;
+
/**
* Returns the {@link LoadStatus} of the loading of the layoutlib jar file.
*/
@@ -282,7 +294,18 @@
*/
public RenderSession createSession(SessionParams params) {
if (mBridge != null) {
- return mBridge.createSession(params);
+ RenderSession session = mBridge.createSession(params);
+ if (params.getExtendedViewInfoMode() &&
+ mBridge.getCapabilities().contains(Capability.EXTENDED_VIEWINFO) == false) {
+ // Extended view info was requested but the layoutlib does not support it.
+ // Add it manually.
+ List<ViewInfo> infoList = session.getRootViews();
+ for (ViewInfo info : infoList) {
+ addExtendedViewInfo(info);
+ }
+ }
+
+ return session;
} else if (mLegacyBridge != null) {
return createLegacySession(params);
}
@@ -333,10 +356,13 @@
*/
public Result getViewParent(Object viewObject) {
if (mBridge != null) {
- return mBridge.getViewParent(viewObject);
+ Result r = mBridge.getViewParent(viewObject);
+ if (r.isSuccess()) {
+ return r;
+ }
}
- return NOT_IMPLEMENTED.createResult();
+ return getViewParentWithReflection(viewObject);
}
/**
@@ -348,30 +374,15 @@
*/
public Result getViewIndex(Object viewObject) {
if (mBridge != null) {
- return mBridge.getViewIndex(viewObject);
+ Result r = mBridge.getViewIndex(viewObject);
+ if (r.isSuccess()) {
+ return r;
+ }
}
- return NOT_IMPLEMENTED.createResult();
+ return getViewIndexReflection(viewObject);
}
- /**
- * Utility method returning the baseline value for a given view object. This basically returns
- * View.getBaseline().
- *
- * @param viewObject the object for which to return the index.
- *
- * @return the baseline value or -1 if not applicable to the view object or if this layout
- * library does not implement this method.
- */
- public int getViewBaseline(Object viewObject) {
- if (mBridge != null) {
- return mBridge.getViewBaseline(viewObject);
- }
-
- return -1;
- }
-
-
// ------ Implementation
private LayoutLibrary(Bridge bridge, ILayoutBridge legacyBridge, ClassLoader classLoader,
@@ -440,7 +451,6 @@
};
-
// convert the map of ResourceValue into IResourceValue. Super ugly but works.
Map<String, Map<String, IResourceValue>> projectMap = convertMap(
@@ -584,4 +594,129 @@
// do nothing.
}
}
+
+ private Result getViewParentWithReflection(Object viewObject) {
+ // default implementation using reflection.
+ try {
+ if (mViewGetParentMethod == null) {
+ Class<?> viewClass = Class.forName("android.view.View");
+ mViewGetParentMethod = viewClass.getMethod("getParent");
+ }
+
+ return Status.SUCCESS.createResult(mViewGetParentMethod.invoke(viewObject));
+ } catch (Exception e) {
+ // Catch all for the reflection calls.
+ return ERROR_REFLECTION.createResult(null, e);
+ }
+ }
+
+ /**
+ * Utility method returning the index of a given view in its parent.
+ * @param viewObject the object for which to return the index.
+ *
+ * @return a {@link Result} indicating the status of the action, and if success, the index in
+ * the parent in {@link Result#getData()}
+ */
+ private Result getViewIndexReflection(Object viewObject) {
+ // default implementation using reflection.
+ try {
+ Class<?> viewClass = Class.forName("android.view.View");
+
+ if (mViewGetParentMethod == null) {
+ mViewGetParentMethod = viewClass.getMethod("getParent");
+ }
+
+ Object parentObject = mViewGetParentMethod.invoke(viewObject);
+
+ if (mViewParentIndexOfChildMethod == null) {
+ Class<?> viewParentClass = Class.forName("android.view.ViewParent");
+ mViewParentIndexOfChildMethod = viewParentClass.getMethod("indexOfChild",
+ viewClass);
+ }
+
+ return Status.SUCCESS.createResult(
+ mViewParentIndexOfChildMethod.invoke(parentObject, viewObject));
+ } catch (Exception e) {
+ // Catch all for the reflection calls.
+ return ERROR_REFLECTION.createResult(null, e);
+ }
+ }
+
+ private void addExtendedViewInfo(ViewInfo info) {
+ computeExtendedViewInfo(info);
+
+ List<ViewInfo> children = info.getChildren();
+ for (ViewInfo child : children) {
+ addExtendedViewInfo(child);
+ }
+ }
+
+ private void computeExtendedViewInfo(ViewInfo info) {
+ Object viewObject = info.getViewObject();
+ Object params = info.getLayoutParamsObject();
+
+ int baseLine = getViewBaselineReflection(viewObject);
+ int leftMargin = 0;
+ int topMargin = 0;
+ int rightMargin = 0;
+ int bottomMargin = 0;
+
+ try {
+ if (mMarginLayoutParamClass == null) {
+ mMarginLayoutParamClass = Class.forName(
+ "android.view.ViewGroup$MarginLayoutParams");
+
+ mLeftMarginField = mMarginLayoutParamClass.getField("leftMargin");
+ mTopMarginField = mMarginLayoutParamClass.getField("topMargin");
+ mRightMarginField = mMarginLayoutParamClass.getField("rightMargin");
+ mBottomMarginField = mMarginLayoutParamClass.getField("bottomMargin");
+ }
+
+ if (mMarginLayoutParamClass.isAssignableFrom(params.getClass())) {
+
+ leftMargin = (Integer)mLeftMarginField.get(params);
+ topMargin = (Integer)mTopMarginField.get(params);
+ rightMargin = (Integer)mRightMarginField.get(params);
+ bottomMargin = (Integer)mBottomMarginField.get(params);
+ }
+
+ } catch (Exception e) {
+ // just use 'unknown' value.
+ leftMargin = Integer.MIN_VALUE;
+ topMargin = Integer.MIN_VALUE;
+ rightMargin = Integer.MIN_VALUE;
+ bottomMargin = Integer.MIN_VALUE;
+ }
+
+ info.setExtendedInfo(baseLine, leftMargin, topMargin, rightMargin, bottomMargin);
+ }
+
+ /**
+ * Utility method returning the baseline value for a given view object. This basically returns
+ * View.getBaseline().
+ *
+ * @param viewObject the object for which to return the index.
+ *
+ * @return the baseline value or -1 if not applicable to the view object or if this layout
+ * library does not implement this method.
+ */
+ private int getViewBaselineReflection(Object viewObject) {
+ // default implementation using reflection.
+ try {
+ if (mViewGetBaselineMethod == null) {
+ Class<?> viewClass = Class.forName("android.view.View");
+ mViewGetBaselineMethod = viewClass.getMethod("getBaseline");
+ }
+
+ Object result = mViewGetBaselineMethod.invoke(viewObject);
+ if (result instanceof Integer) {
+ return ((Integer)result).intValue();
+ }
+
+ } catch (Exception e) {
+ // Catch all for the reflection calls.
+ }
+
+ return Integer.MIN_VALUE;
+ }
}
diff --git a/layoutlib_api/src/com/android/ide/common/rendering/api/Bridge.java b/layoutlib_api/src/com/android/ide/common/rendering/api/Bridge.java
index c044353..ad2dd38 100644
--- a/layoutlib_api/src/com/android/ide/common/rendering/api/Bridge.java
+++ b/layoutlib_api/src/com/android/ide/common/rendering/api/Bridge.java
@@ -143,8 +143,11 @@
*
* @return the baseline value or -1 if not applicable to the view object or if this layout
* library does not implement this method.
+ *
+ * @deprecated use the extended ViewInfo.
*/
- public int getViewBaseline(Object viewObject) {
- return -1;
+ @Deprecated
+ public Result getViewBaseline(Object viewObject) {
+ return NOT_IMPLEMENTED.createResult();
}
}
diff --git a/layoutlib_api/src/com/android/ide/common/rendering/api/Capability.java b/layoutlib_api/src/com/android/ide/common/rendering/api/Capability.java
index 6620571..a7ab7ae 100644
--- a/layoutlib_api/src/com/android/ide/common/rendering/api/Capability.java
+++ b/layoutlib_api/src/com/android/ide/common/rendering/api/Capability.java
@@ -42,7 +42,7 @@
* {@link RenderSession#setProperty(Object, String, String)}<br>
* The method that receives an animation listener can only use it if the
* ANIMATED_VIEW_MANIPULATION, or FULL_ANIMATED_VIEW_MANIPULATION is also supported.
- * */
+ */
VIEW_MANIPULATION,
/** Ability to play animations with<br>
* {@link RenderSession#animate(Object, String, boolean, IAnimationListener)}
@@ -60,5 +60,6 @@
* see {@link RenderSession#moveChild(Object, Object, int, java.util.Map, IAnimationListener)}
*/
FULL_ANIMATED_VIEW_MANIPULATION,
- ADAPTER_BINDING;
+ ADAPTER_BINDING,
+ EXTENDED_VIEWINFO;
}
diff --git a/layoutlib_api/src/com/android/ide/common/rendering/api/Result.java b/layoutlib_api/src/com/android/ide/common/rendering/api/Result.java
index 6152a28..a739e79 100644
--- a/layoutlib_api/src/com/android/ide/common/rendering/api/Result.java
+++ b/layoutlib_api/src/com/android/ide/common/rendering/api/Result.java
@@ -47,6 +47,7 @@
ERROR_RENDER,
ERROR_ANIM_NOT_FOUND,
ERROR_NOT_A_DRAWABLE,
+ ERROR_REFLECTION,
ERROR_UNKNOWN;
private Result mResult;
diff --git a/layoutlib_api/src/com/android/ide/common/rendering/api/SessionParams.java b/layoutlib_api/src/com/android/ide/common/rendering/api/SessionParams.java
index f4f6b5c..1af450e 100644
--- a/layoutlib_api/src/com/android/ide/common/rendering/api/SessionParams.java
+++ b/layoutlib_api/src/com/android/ide/common/rendering/api/SessionParams.java
@@ -54,6 +54,7 @@
private final RenderingMode mRenderingMode;
private boolean mLayoutOnly = false;
private Map<ResourceReference, AdapterBinding> mAdapterBindingMap;
+ private boolean mExtendedViewInfoMode = false;
/**
*
@@ -107,6 +108,7 @@
mAdapterBindingMap = new HashMap<ResourceReference, AdapterBinding>(
params.mAdapterBindingMap);
}
+ mExtendedViewInfoMode = params.mExtendedViewInfoMode;
}
public ILayoutPullParser getLayoutDescription() {
@@ -140,4 +142,12 @@
return Collections.unmodifiableMap(mAdapterBindingMap);
}
+
+ public void setExtendedViewInfoMode(boolean mode) {
+ mExtendedViewInfoMode = mode;
+ }
+
+ public boolean getExtendedViewInfoMode() {
+ return mExtendedViewInfoMode;
+ }
}
diff --git a/layoutlib_api/src/com/android/ide/common/rendering/api/ViewInfo.java b/layoutlib_api/src/com/android/ide/common/rendering/api/ViewInfo.java
index 2c0c829..2671fc0 100644
--- a/layoutlib_api/src/com/android/ide/common/rendering/api/ViewInfo.java
+++ b/layoutlib_api/src/com/android/ide/common/rendering/api/ViewInfo.java
@@ -34,6 +34,13 @@
private final Object mViewObject;
private final Object mLayoutParamsObject;
+ // optional info
+ private int mBaseLine = Integer.MIN_VALUE;
+ private int mLeftMargin = Integer.MIN_VALUE;
+ private int mTopMargin = Integer.MIN_VALUE;
+ private int mRightMargin = Integer.MIN_VALUE;
+ private int mBottomMargin = Integer.MIN_VALUE;
+
public ViewInfo(String name, Object cookie, int left, int top, int right, int bottom) {
this(name, cookie, left, top, right, bottom, null /*viewObject*/,
null /*layoutParamsObject*/);
@@ -62,6 +69,15 @@
}
}
+ public void setExtendedInfo(int baseLine, int leftMargin, int topMargin,
+ int rightMargin, int bottomMargin) {
+ mBaseLine = baseLine;
+ mLeftMargin = leftMargin;
+ mTopMargin = topMargin;
+ mRightMargin = rightMargin;
+ mBottomMargin = bottomMargin;
+ }
+
/**
* Returns the list of children views. This is never null, but can be empty.
*/
@@ -130,4 +146,39 @@
public Object getLayoutParamsObject() {
return mLayoutParamsObject;
}
+
+ /**
+ * Returns the baseline value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
+ */
+ public int getBaseLine() {
+ return mBaseLine;
+ }
+
+ /**
+ * Returns the left margin value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
+ */
+ public int getLeftMargin() {
+ return mLeftMargin;
+ }
+
+ /**
+ * Returns the top margin value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
+ */
+ public int getTopMargin() {
+ return mTopMargin;
+ }
+
+ /**
+ * Returns the right margin value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
+ */
+ public int getRightMargin() {
+ return mRightMargin;
+ }
+
+ /**
+ * Returns the bottom margin value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
+ */
+ public int getBottomMargin() {
+ return mBottomMargin;
+ }
}