fbshipit-source-id: b6fc29740c6875d2e78953b8a7123890a67930f2 Co-authored-by: Sebastian McKenzie <sebmck@fb.com> Co-authored-by: John Knox <jknox@fb.com> Co-authored-by: Emil Sjölander <emilsj@fb.com> Co-authored-by: Pritesh Nandgaonkar <prit91@fb.com>
709 lines
24 KiB
Java
709 lines
24 KiB
Java
/*
|
|
* Copyright (c) 2018-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the LICENSE
|
|
* file in the root directory of this source tree.
|
|
*
|
|
*/
|
|
|
|
package com.facebook.sonar.plugins.inspector.descriptors;
|
|
|
|
import static com.facebook.sonar.plugins.inspector.InspectorValue.Type.Color;
|
|
import static com.facebook.sonar.plugins.inspector.InspectorValue.Type.Enum;
|
|
|
|
import android.annotation.TargetApi;
|
|
import android.graphics.Rect;
|
|
import android.graphics.drawable.ColorDrawable;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.os.Build;
|
|
import android.support.v4.view.MarginLayoutParamsCompat;
|
|
import android.support.v4.view.ViewCompat;
|
|
import android.util.SparseArray;
|
|
import android.view.Gravity;
|
|
import android.view.View;
|
|
import android.view.View.OnClickListener;
|
|
import android.view.ViewGroup;
|
|
import android.view.ViewGroup.LayoutParams;
|
|
import android.view.ViewGroup.MarginLayoutParams;
|
|
import android.view.ViewParent;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.LinearLayout;
|
|
import com.facebook.sonar.core.SonarDynamic;
|
|
import com.facebook.sonar.core.SonarObject;
|
|
import com.facebook.sonar.plugins.inspector.HighlightedOverlay;
|
|
import com.facebook.sonar.plugins.inspector.InspectorValue;
|
|
import com.facebook.sonar.plugins.inspector.Named;
|
|
import com.facebook.sonar.plugins.inspector.NodeDescriptor;
|
|
import com.facebook.sonar.plugins.inspector.Touch;
|
|
import com.facebook.sonar.plugins.inspector.descriptors.utils.AccessibilityUtil;
|
|
import com.facebook.sonar.plugins.inspector.descriptors.utils.EnumMapping;
|
|
import com.facebook.stetho.common.android.ResourcesUtil;
|
|
import java.lang.reflect.Field;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import javax.annotation.Nullable;
|
|
|
|
public class ViewDescriptor extends NodeDescriptor<View> {
|
|
|
|
private static Field sKeyedTagsField;
|
|
private static Field sListenerInfoField;
|
|
private static Field sOnClickListenerField;
|
|
|
|
static {
|
|
try {
|
|
sKeyedTagsField = View.class.getDeclaredField("mKeyedTags");
|
|
sKeyedTagsField.setAccessible(true);
|
|
|
|
sListenerInfoField = View.class.getDeclaredField("mListenerInfo");
|
|
sListenerInfoField.setAccessible(true);
|
|
|
|
final String viewInfoClassName = View.class.getName() + "$ListenerInfo";
|
|
sOnClickListenerField = Class.forName(viewInfoClassName).getDeclaredField("mOnClickListener");
|
|
sOnClickListenerField.setAccessible(true);
|
|
} catch (Exception ignored) {
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void init(final View node) {}
|
|
|
|
@Override
|
|
public String getId(View node) {
|
|
return Integer.toString(System.identityHashCode(node));
|
|
}
|
|
|
|
@Override
|
|
public String getName(View node) {
|
|
return node.getClass().getSimpleName();
|
|
}
|
|
|
|
@Override
|
|
public int getChildCount(View node) {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public @Nullable Object getChildAt(View node, int index) {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public List<Named<SonarObject>> getData(View node) {
|
|
final SonarObject.Builder viewProps =
|
|
new SonarObject.Builder()
|
|
.put("height", InspectorValue.mutable(node.getHeight()))
|
|
.put("width", InspectorValue.mutable(node.getWidth()))
|
|
.put("alpha", InspectorValue.mutable(node.getAlpha()))
|
|
.put("visibility", sVisibilityMapping.get(node.getVisibility()))
|
|
.put("background", fromDrawable(node.getBackground()))
|
|
.put("tag", InspectorValue.mutable(node.getTag()))
|
|
.put("keyedTags", getTags(node))
|
|
.put("layoutParams", getLayoutParams(node))
|
|
.put(
|
|
"state",
|
|
new SonarObject.Builder()
|
|
.put("enabled", InspectorValue.mutable(node.isEnabled()))
|
|
.put("activated", InspectorValue.mutable(node.isActivated()))
|
|
.put("focused", node.isFocused())
|
|
.put("selected", InspectorValue.mutable(node.isSelected())))
|
|
.put(
|
|
"bounds",
|
|
new SonarObject.Builder()
|
|
.put("left", InspectorValue.mutable(node.getLeft()))
|
|
.put("right", InspectorValue.mutable(node.getRight()))
|
|
.put("top", InspectorValue.mutable(node.getTop()))
|
|
.put("bottom", InspectorValue.mutable(node.getBottom())))
|
|
.put(
|
|
"padding",
|
|
new SonarObject.Builder()
|
|
.put("left", InspectorValue.mutable(node.getPaddingLeft()))
|
|
.put("top", InspectorValue.mutable(node.getPaddingTop()))
|
|
.put("right", InspectorValue.mutable(node.getPaddingRight()))
|
|
.put("bottom", InspectorValue.mutable(node.getPaddingBottom())))
|
|
.put(
|
|
"rotation",
|
|
new SonarObject.Builder()
|
|
.put("x", InspectorValue.mutable(node.getRotationX()))
|
|
.put("y", InspectorValue.mutable(node.getRotationY()))
|
|
.put("z", InspectorValue.mutable(node.getRotation())))
|
|
.put(
|
|
"scale",
|
|
new SonarObject.Builder()
|
|
.put("x", InspectorValue.mutable(node.getScaleX()))
|
|
.put("y", InspectorValue.mutable(node.getScaleY())))
|
|
.put(
|
|
"pivot",
|
|
new SonarObject.Builder()
|
|
.put("x", InspectorValue.mutable(node.getPivotX()))
|
|
.put("y", InspectorValue.mutable(node.getPivotY())));
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
|
viewProps
|
|
.put("layoutDirection", sLayoutDirectionMapping.get(node.getLayoutDirection()))
|
|
.put("textDirection", sTextDirectionMapping.get(node.getTextDirection()))
|
|
.put("textAlignment", sTextAlignmentMapping.get(node.getTextAlignment()));
|
|
}
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
viewProps.put("elevation", InspectorValue.mutable(node.getElevation()));
|
|
}
|
|
|
|
SonarObject.Builder translation =
|
|
new SonarObject.Builder()
|
|
.put("x", InspectorValue.mutable(node.getTranslationX()))
|
|
.put("y", InspectorValue.mutable(node.getTranslationY()));
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
translation.put("z", InspectorValue.mutable(node.getTranslationZ()));
|
|
}
|
|
viewProps.put("translation", translation);
|
|
|
|
SonarObject.Builder position =
|
|
new SonarObject.Builder()
|
|
.put("x", InspectorValue.mutable(node.getX()))
|
|
.put("y", InspectorValue.mutable(node.getY()));
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
|
position.put("z", InspectorValue.mutable(node.getZ()));
|
|
}
|
|
viewProps.put("position", position);
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
viewProps.put("foreground", fromDrawable(node.getForeground()));
|
|
}
|
|
|
|
return Arrays.asList(
|
|
new Named<>("View", viewProps.build()),
|
|
new Named<>("Accessibility", getAccessibilityData(node)));
|
|
}
|
|
|
|
private static SonarObject getAccessibilityData(View view) {
|
|
final SonarObject.Builder accessibilityProps = new SonarObject.Builder();
|
|
|
|
// This needs to be an empty string to be mutable. See t20470623.
|
|
CharSequence contentDescription =
|
|
view.getContentDescription() != null ? view.getContentDescription() : "";
|
|
accessibilityProps.put("content-description", InspectorValue.mutable(contentDescription));
|
|
accessibilityProps.put("focusable", InspectorValue.mutable(view.isFocusable()));
|
|
accessibilityProps.put("node-info", AccessibilityUtil.getAccessibilityNodeInfoProperties(view));
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
|
accessibilityProps.put(
|
|
"important-for-accessibility",
|
|
AccessibilityUtil.sImportantForAccessibilityMapping.get(
|
|
view.getImportantForAccessibility()));
|
|
}
|
|
|
|
AccessibilityUtil.addTalkbackProperties(accessibilityProps, view);
|
|
|
|
return accessibilityProps.build();
|
|
}
|
|
|
|
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
|
@Override
|
|
public void setValue(View node, String[] path, SonarDynamic value) {
|
|
if (path[0].equals("Accessibility")) {
|
|
setAccessibilityValue(node, path, value);
|
|
}
|
|
|
|
if (!path[0].equals("View")) {
|
|
return;
|
|
}
|
|
|
|
switch (path[1]) {
|
|
case "elevation":
|
|
node.setElevation(value.asFloat());
|
|
break;
|
|
case "alpha":
|
|
node.setAlpha(value.asFloat());
|
|
break;
|
|
case "visibility":
|
|
node.setVisibility(sVisibilityMapping.get(value.asString()));
|
|
break;
|
|
case "layoutParams":
|
|
setLayoutParams(node, Arrays.copyOfRange(path, 1, path.length), value);
|
|
break;
|
|
case "layoutDirection":
|
|
node.setLayoutDirection(sLayoutDirectionMapping.get(value.asString()));
|
|
break;
|
|
case "textDirection":
|
|
node.setTextDirection(sTextDirectionMapping.get(value.asString()));
|
|
break;
|
|
case "textAlignment":
|
|
node.setTextAlignment(sTextAlignmentMapping.get(value.asString()));
|
|
break;
|
|
case "background":
|
|
node.setBackground(new ColorDrawable(value.asInt()));
|
|
break;
|
|
case "foreground":
|
|
node.setForeground(new ColorDrawable(value.asInt()));
|
|
break;
|
|
case "state":
|
|
switch (path[2]) {
|
|
case "enabled":
|
|
node.setEnabled(value.asBoolean());
|
|
break;
|
|
case "activated":
|
|
node.setActivated(value.asBoolean());
|
|
break;
|
|
case "selected":
|
|
node.setSelected(value.asBoolean());
|
|
break;
|
|
}
|
|
break;
|
|
case "bounds":
|
|
switch (path[2]) {
|
|
case "left":
|
|
node.setLeft(value.asInt());
|
|
break;
|
|
case "top":
|
|
node.setTop(value.asInt());
|
|
break;
|
|
case "right":
|
|
node.setRight(value.asInt());
|
|
break;
|
|
case "bottom":
|
|
node.setBottom(value.asInt());
|
|
break;
|
|
}
|
|
break;
|
|
case "padding":
|
|
switch (path[2]) {
|
|
case "left":
|
|
node.setPadding(
|
|
value.asInt(),
|
|
node.getPaddingTop(),
|
|
node.getPaddingRight(),
|
|
node.getPaddingBottom());
|
|
break;
|
|
case "top":
|
|
node.setPadding(
|
|
node.getPaddingLeft(),
|
|
value.asInt(),
|
|
node.getPaddingRight(),
|
|
node.getPaddingBottom());
|
|
break;
|
|
case "right":
|
|
node.setPadding(
|
|
node.getPaddingLeft(),
|
|
node.getPaddingTop(),
|
|
value.asInt(),
|
|
node.getPaddingBottom());
|
|
break;
|
|
case "bottom":
|
|
node.setPadding(
|
|
node.getPaddingLeft(), node.getPaddingTop(), node.getPaddingRight(), value.asInt());
|
|
break;
|
|
}
|
|
break;
|
|
case "rotation":
|
|
switch (path[2]) {
|
|
case "x":
|
|
node.setRotationX(value.asFloat());
|
|
break;
|
|
case "y":
|
|
node.setRotationY(value.asFloat());
|
|
break;
|
|
case "z":
|
|
node.setRotation(value.asFloat());
|
|
break;
|
|
}
|
|
break;
|
|
case "translation":
|
|
switch (path[2]) {
|
|
case "x":
|
|
node.setTranslationX(value.asFloat());
|
|
break;
|
|
case "y":
|
|
node.setTranslationY(value.asFloat());
|
|
break;
|
|
case "z":
|
|
node.setTranslationZ(value.asFloat());
|
|
break;
|
|
}
|
|
break;
|
|
case "position":
|
|
switch (path[2]) {
|
|
case "x":
|
|
node.setX(value.asFloat());
|
|
break;
|
|
case "y":
|
|
node.setY(value.asFloat());
|
|
break;
|
|
case "z":
|
|
node.setZ(value.asFloat());
|
|
break;
|
|
}
|
|
break;
|
|
case "scale":
|
|
switch (path[2]) {
|
|
case "x":
|
|
node.setScaleX(value.asFloat());
|
|
break;
|
|
case "y":
|
|
node.setScaleY(value.asFloat());
|
|
break;
|
|
}
|
|
break;
|
|
case "pivot":
|
|
switch (path[2]) {
|
|
case "x":
|
|
node.setPivotY(value.asFloat());
|
|
break;
|
|
case "y":
|
|
node.setPivotX(value.asFloat());
|
|
break;
|
|
}
|
|
break;
|
|
case "width":
|
|
LayoutParams lpw = node.getLayoutParams();
|
|
lpw.width = value.asInt();
|
|
node.setLayoutParams(lpw);
|
|
break;
|
|
case "height":
|
|
LayoutParams lph = node.getLayoutParams();
|
|
lph.height = value.asInt();
|
|
node.setLayoutParams(lph);
|
|
break;
|
|
}
|
|
|
|
invalidate(node);
|
|
}
|
|
|
|
private void setAccessibilityValue(View node, String[] path, SonarDynamic value) {
|
|
switch (path[1]) {
|
|
case "focusable":
|
|
node.setFocusable(value.asBoolean());
|
|
break;
|
|
case "important-for-accessibility":
|
|
node.setImportantForAccessibility(
|
|
AccessibilityUtil.sImportantForAccessibilityMapping.get(value.asString()));
|
|
break;
|
|
case "content-description":
|
|
node.setContentDescription(value.asString());
|
|
break;
|
|
}
|
|
invalidate(node);
|
|
}
|
|
|
|
@Override
|
|
public List<Named<String>> getAttributes(View node) throws Exception {
|
|
final List<Named<String>> attributes = new ArrayList<>();
|
|
|
|
final String resourceId = getResourceId(node);
|
|
if (resourceId != null) {
|
|
attributes.add(new Named<>("id", resourceId));
|
|
}
|
|
|
|
if (sListenerInfoField != null && sOnClickListenerField != null) {
|
|
final Object listenerInfo = sListenerInfoField.get(node);
|
|
if (listenerInfo != null) {
|
|
final OnClickListener clickListener =
|
|
(OnClickListener) sOnClickListenerField.get(listenerInfo);
|
|
if (clickListener != null) {
|
|
attributes.add(new Named<>("onClick", clickListener.getClass().getName()));
|
|
}
|
|
}
|
|
}
|
|
|
|
return attributes;
|
|
}
|
|
|
|
@Nullable
|
|
private static String getResourceId(View node) {
|
|
final int id = node.getId();
|
|
|
|
if (id == View.NO_ID) {
|
|
return null;
|
|
}
|
|
|
|
return ResourcesUtil.getIdStringQuietly(node.getContext(), node.getResources(), id);
|
|
}
|
|
|
|
@Override
|
|
public void setHighlighted(View node, boolean selected) {
|
|
// We need to figure out whether the given View has a parent View since margins are not
|
|
// included within a View's bounds. So, in order to display the margin values for a particular
|
|
// view, we need to apply an overlay on its parent rather than itself.
|
|
final View targetView;
|
|
final ViewParent parent = node.getParent();
|
|
if (parent instanceof View) {
|
|
targetView = (View) parent;
|
|
} else {
|
|
targetView = node;
|
|
}
|
|
|
|
if (!selected) {
|
|
HighlightedOverlay.removeHighlight(targetView);
|
|
return;
|
|
}
|
|
|
|
final Rect padding =
|
|
new Rect(
|
|
ViewCompat.getPaddingStart(node),
|
|
node.getPaddingTop(),
|
|
ViewCompat.getPaddingEnd(node),
|
|
node.getPaddingBottom());
|
|
|
|
final Rect margin;
|
|
final ViewGroup.LayoutParams params = node.getLayoutParams();
|
|
if (params instanceof ViewGroup.MarginLayoutParams) {
|
|
final ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) params;
|
|
margin =
|
|
new Rect(
|
|
MarginLayoutParamsCompat.getMarginStart(marginParams),
|
|
marginParams.topMargin,
|
|
MarginLayoutParamsCompat.getMarginEnd(marginParams),
|
|
marginParams.bottomMargin);
|
|
} else {
|
|
margin = new Rect();
|
|
}
|
|
|
|
final int left = node.getLeft();
|
|
final int top = node.getTop();
|
|
final Rect contentBounds = new Rect(left, top, left + node.getWidth(), top + node.getHeight());
|
|
if (targetView == node) {
|
|
// If the View doesn't have a parent View that we're applying the overlay to, then
|
|
// we need to ensure that it is aligned to 0, 0, rather than its relative location to its
|
|
// parent
|
|
contentBounds.offset(-left, -top);
|
|
}
|
|
|
|
HighlightedOverlay.setHighlighted(targetView, margin, padding, contentBounds);
|
|
}
|
|
|
|
@Override
|
|
public void hitTest(View node, Touch touch) {
|
|
touch.finish();
|
|
}
|
|
|
|
@Override
|
|
public @Nullable String getDecoration(View obj) {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public boolean matches(String query, View node) throws Exception {
|
|
final String resourceId = getResourceId(node);
|
|
|
|
if (resourceId != null && resourceId.toLowerCase().contains(query)) {
|
|
return true;
|
|
}
|
|
|
|
final NodeDescriptor objectDescriptor = descriptorForClass(Object.class);
|
|
return objectDescriptor.matches(query, node);
|
|
}
|
|
|
|
private SonarObject getTags(final View node) {
|
|
final SonarObject.Builder tags = new SonarObject.Builder();
|
|
if (sKeyedTagsField == null) {
|
|
return tags.build();
|
|
}
|
|
|
|
new ErrorReportingRunnable() {
|
|
@Override
|
|
protected void runOrThrow() throws Exception {
|
|
final SparseArray keyedTags = (SparseArray) sKeyedTagsField.get(node);
|
|
if (keyedTags != null) {
|
|
for (int i = 0, count = keyedTags.size(); i < count; i++) {
|
|
final String id =
|
|
ResourcesUtil.getIdStringQuietly(
|
|
node.getContext(), node.getResources(), keyedTags.keyAt(i));
|
|
tags.put(id, keyedTags.valueAt(i));
|
|
}
|
|
}
|
|
}
|
|
}.run();
|
|
|
|
return tags.build();
|
|
}
|
|
|
|
private static InspectorValue fromDrawable(Drawable d) {
|
|
if (d instanceof ColorDrawable) {
|
|
return InspectorValue.mutable(Color, ((ColorDrawable) d).getColor());
|
|
}
|
|
return InspectorValue.mutable(Color, 0);
|
|
}
|
|
|
|
private static SonarObject getLayoutParams(View node) {
|
|
final LayoutParams layoutParams = node.getLayoutParams();
|
|
final SonarObject.Builder params = new SonarObject.Builder();
|
|
|
|
params.put("width", fromSize(layoutParams.width));
|
|
params.put("height", fromSize(layoutParams.height));
|
|
|
|
if (layoutParams instanceof MarginLayoutParams) {
|
|
final MarginLayoutParams marginLayoutParams = (MarginLayoutParams) layoutParams;
|
|
params.put(
|
|
"margin",
|
|
new SonarObject.Builder()
|
|
.put("left", InspectorValue.mutable(marginLayoutParams.leftMargin))
|
|
.put("top", InspectorValue.mutable(marginLayoutParams.topMargin))
|
|
.put("right", InspectorValue.mutable(marginLayoutParams.rightMargin))
|
|
.put("bottom", InspectorValue.mutable(marginLayoutParams.bottomMargin)));
|
|
}
|
|
|
|
if (layoutParams instanceof FrameLayout.LayoutParams) {
|
|
final FrameLayout.LayoutParams frameLayoutParams = (FrameLayout.LayoutParams) layoutParams;
|
|
params.put("gravity", sGravityMapping.get(frameLayoutParams.gravity));
|
|
}
|
|
|
|
if (layoutParams instanceof LinearLayout.LayoutParams) {
|
|
final LinearLayout.LayoutParams linearLayoutParams = (LinearLayout.LayoutParams) layoutParams;
|
|
params
|
|
.put("weight", InspectorValue.mutable(linearLayoutParams.weight))
|
|
.put("gravity", sGravityMapping.get(linearLayoutParams.gravity));
|
|
}
|
|
|
|
return params.build();
|
|
}
|
|
|
|
private void setLayoutParams(View node, String[] path, SonarDynamic value) {
|
|
final LayoutParams params = node.getLayoutParams();
|
|
|
|
switch (path[0]) {
|
|
case "width":
|
|
params.width = toSize(value.asString());
|
|
break;
|
|
case "height":
|
|
params.height = toSize(value.asString());
|
|
break;
|
|
case "weight":
|
|
final LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) params;
|
|
linearParams.weight = value.asFloat();
|
|
break;
|
|
}
|
|
|
|
if (params instanceof MarginLayoutParams) {
|
|
final MarginLayoutParams marginParams = (MarginLayoutParams) params;
|
|
|
|
switch (path[0]) {
|
|
case "margin":
|
|
switch (path[1]) {
|
|
case "left":
|
|
marginParams.leftMargin = value.asInt();
|
|
break;
|
|
case "top":
|
|
marginParams.topMargin = value.asInt();
|
|
break;
|
|
case "right":
|
|
marginParams.rightMargin = value.asInt();
|
|
break;
|
|
case "bottom":
|
|
marginParams.bottomMargin = value.asInt();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (params instanceof FrameLayout.LayoutParams) {
|
|
final FrameLayout.LayoutParams frameLayoutParams = (FrameLayout.LayoutParams) params;
|
|
|
|
switch (path[0]) {
|
|
case "gravity":
|
|
frameLayoutParams.gravity = sGravityMapping.get(value.asString());
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (params instanceof LinearLayout.LayoutParams) {
|
|
final LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) params;
|
|
|
|
switch (path[0]) {
|
|
case "weight":
|
|
linearParams.weight = value.asFloat();
|
|
break;
|
|
case "gravity":
|
|
linearParams.gravity = sGravityMapping.get(value.asString());
|
|
break;
|
|
}
|
|
}
|
|
|
|
node.setLayoutParams(params);
|
|
}
|
|
|
|
private static InspectorValue fromSize(int size) {
|
|
switch (size) {
|
|
case LayoutParams.WRAP_CONTENT:
|
|
return InspectorValue.mutable(Enum, "WRAP_CONTENT");
|
|
case LayoutParams.MATCH_PARENT:
|
|
return InspectorValue.mutable(Enum, "MATCH_PARENT");
|
|
default:
|
|
return InspectorValue.mutable(Enum, Integer.toString(size));
|
|
}
|
|
}
|
|
|
|
private static int toSize(String size) {
|
|
switch (size) {
|
|
case "WRAP_CONTENT":
|
|
return LayoutParams.WRAP_CONTENT;
|
|
case "MATCH_PARENT":
|
|
return LayoutParams.MATCH_PARENT;
|
|
default:
|
|
return Integer.parseInt(size);
|
|
}
|
|
}
|
|
|
|
private static final EnumMapping sVisibilityMapping =
|
|
new EnumMapping("VISIBLE") {
|
|
{
|
|
put("VISIBLE", View.VISIBLE);
|
|
put("INVISIBLE", View.INVISIBLE);
|
|
put("GONE", View.GONE);
|
|
}
|
|
};
|
|
|
|
private static final EnumMapping sLayoutDirectionMapping =
|
|
new EnumMapping("LAYOUT_DIRECTION_INHERIT") {
|
|
{
|
|
put("LAYOUT_DIRECTION_INHERIT", View.LAYOUT_DIRECTION_INHERIT);
|
|
put("LAYOUT_DIRECTION_LOCALE", View.LAYOUT_DIRECTION_LOCALE);
|
|
put("LAYOUT_DIRECTION_LTR", View.LAYOUT_DIRECTION_LTR);
|
|
put("LAYOUT_DIRECTION_RTL", View.LAYOUT_DIRECTION_RTL);
|
|
}
|
|
};
|
|
|
|
private static final EnumMapping sTextDirectionMapping =
|
|
new EnumMapping("TEXT_DIRECTION_INHERIT") {
|
|
{
|
|
put("TEXT_DIRECTION_INHERIT", View.TEXT_DIRECTION_INHERIT);
|
|
put("TEXT_DIRECTION_FIRST_STRONG", View.TEXT_DIRECTION_FIRST_STRONG);
|
|
put("TEXT_DIRECTION_ANY_RTL", View.TEXT_DIRECTION_ANY_RTL);
|
|
put("TEXT_DIRECTION_LTR", View.TEXT_DIRECTION_LTR);
|
|
put("TEXT_DIRECTION_RTL", View.TEXT_DIRECTION_RTL);
|
|
put("TEXT_DIRECTION_LOCALE", View.TEXT_DIRECTION_LOCALE);
|
|
put("TEXT_DIRECTION_FIRST_STRONG_LTR", View.TEXT_DIRECTION_FIRST_STRONG_LTR);
|
|
put("TEXT_DIRECTION_FIRST_STRONG_RTL", View.TEXT_DIRECTION_FIRST_STRONG_RTL);
|
|
}
|
|
};
|
|
|
|
private static final EnumMapping sTextAlignmentMapping =
|
|
new EnumMapping("TEXT_ALIGNMENT_INHERIT") {
|
|
{
|
|
put("TEXT_ALIGNMENT_INHERIT", View.TEXT_ALIGNMENT_INHERIT);
|
|
put("TEXT_ALIGNMENT_GRAVITY", View.TEXT_ALIGNMENT_GRAVITY);
|
|
put("TEXT_ALIGNMENT_TEXT_START", View.TEXT_ALIGNMENT_TEXT_START);
|
|
put("TEXT_ALIGNMENT_TEXT_END", View.TEXT_ALIGNMENT_TEXT_END);
|
|
put("TEXT_ALIGNMENT_CENTER", View.TEXT_ALIGNMENT_CENTER);
|
|
put("TEXT_ALIGNMENT_VIEW_START", View.TEXT_ALIGNMENT_VIEW_START);
|
|
put("TEXT_ALIGNMENT_VIEW_END", View.TEXT_ALIGNMENT_VIEW_END);
|
|
}
|
|
};
|
|
|
|
private static final EnumMapping sGravityMapping =
|
|
new EnumMapping("NO_GRAVITY") {
|
|
{
|
|
put("NO_GRAVITY", Gravity.NO_GRAVITY);
|
|
put("LEFT", Gravity.LEFT);
|
|
put("TOP", Gravity.TOP);
|
|
put("RIGHT", Gravity.RIGHT);
|
|
put("BOTTOM", Gravity.BOTTOM);
|
|
put("CENTER", Gravity.CENTER);
|
|
put("CENTER_VERTICAL", Gravity.CENTER_VERTICAL);
|
|
put("FILL_VERTICAL", Gravity.FILL_VERTICAL);
|
|
put("CENTER_HORIZONTAL", Gravity.CENTER_HORIZONTAL);
|
|
put("FILL_HORIZONTAL", Gravity.FILL_HORIZONTAL);
|
|
}
|
|
};
|
|
}
|