beautify NodeInfoView

This commit is contained in:
hyb1996 2017-06-26 15:57:44 +08:00
parent 0445497573
commit 59a1b5dffb
12 changed files with 243 additions and 189 deletions

View File

@ -78,21 +78,39 @@ dependencies {
exclude group: 'com.android.support', module: 'support-annotations'
})
testCompile 'junit:junit:4.12'
// LeakCanary (a memory leak tracer)
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
// Storio (Sqlite api library)
annotationProcessor 'com.pushtorefresh.storio:sqlite-annotations-processor:1.12.3'
compile 'com.pushtorefresh.storio:sqlite-annotations:1.12.3'
// Android Annotations
annotationProcessor "org.androidannotations:androidannotations:$AAVersion"
compile "org.androidannotations:androidannotations-api:$AAVersion"
// ButterKnife
compile 'com.jakewharton:butterknife:8.6.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'
// Android supports
compile 'com.android.support:appcompat-v7:25.3.0'
compile 'com.android.support:design:25.1.0'
compile 'com.android.support:design:25.3.0'
compile 'com.android.support:multidex:1.0.1'
// Personal libraries
compile 'com.github.hyb1996:MutableTheme:0.2.2'
compile 'com.github.hyb1996:EnhancedFloaty:0.17'
// Material Dialogs
compile 'com.afollestad.material-dialogs:core:0.9.2.3'
// Gson
compile 'com.google.code.gson:gson:2.8.0'
// Common Markdown
compile 'com.github.atlassian:commonmark-java:commonmark-parent-0.9.0'
// AlipayZeroSdk
compile 'moe.feng:AlipayZeroSdk:1.1'
// Console
compile 'com.jraska:console:0.4.3'
// Android issue reporter (a github issue reporter)
compile 'com.heinrichreimersoftware:android-issue-reporter:1.3.1'
compile 'de.codecrafters.tableview:tableview:2.5.0'
//
compile group: "pl.openrnd.android", name: "multi-level-listview", version: "1.0.1"
compile 'de.psdev.licensesdialog:licensesdialog:1.8.1'
compile 'io.mattcarroll.hover:hover:0.9.7'
@ -101,10 +119,8 @@ dependencies {
// Tasker Plugin
compile group: 'com.twofortyfouram', name: 'android-plugin-client-sdk-for-locale', version: '[4.0.2, 5.0['
compile 'com.android.volley:volley:1.0.0'
compile 'com.github.hyb1996:EnhancedFloaty:0.17'
compile 'com.flurry.android:analytics:7.0.0@aar'
compile 'com.pushtorefresh.storio:sqlite:1.12.3'
compile 'com.android.support:multidex:1.0.1'
// Terminal emulator
compile(name: 'libtermexec-release', ext: 'aar')
compile(name: 'emulatorview-release', ext: 'aar')

View File

@ -88,6 +88,7 @@ public class HoverMenuService extends Service {
private WindowViewController mWindowViewController;
private ContextThemeWrapper mThemeWrapper;
private FloatingLayoutHierarchyView mFloatingLayoutHierarchyView;
private FloatingLayoutBoundsView mFloatingLayoutBoundsView;
@ -121,15 +122,16 @@ public class HoverMenuService extends Service {
}
private void initViews() {
mFloatingLayoutHierarchyView = new FloatingLayoutHierarchyView(this);
mFloatingLayoutBoundsView = new FloatingLayoutBoundsView(this);
mThemeWrapper = new ContextThemeWrapper(this, R.style.AppTheme);
mFloatingLayoutHierarchyView = new FloatingLayoutHierarchyView(mThemeWrapper);
mFloatingLayoutBoundsView = new FloatingLayoutBoundsView(mThemeWrapper);
initWindowMenu();
mWindowViewController.addView(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, true, mFloatingLayoutHierarchyView);
mWindowViewController.addView(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, true, mFloatingLayoutBoundsView);
}
private void initWindowMenu() {
mWindowHoverMenu = (WindowHoverMenu) new HoverMenuBuilder(new ContextThemeWrapper(this, R.style.AppTheme))
mWindowHoverMenu = (WindowHoverMenu) new HoverMenuBuilder(mThemeWrapper)
.displayWithinWindow()
.useAdapter(new HoverMenuAdapter(this))
.restoreVisualState(loadPreferredLocation())

View File

@ -18,15 +18,27 @@ import java.util.List;
public class NodeInfo {
private List<NodeInfo> children = new ArrayList<>();
private Rect mBoundsInScreen;
public String id;
public CharSequence contentDesc, className, packageName, text;
public CharSequence contentDesc;
public CharSequence className;
public CharSequence packageName;
public CharSequence text;
public int drawingOrder;
public boolean accessibilityFocused, checked, clickable, contextClickable, dismissable, editable, enabled,
focusable, longClickable, selected, scrollable, visibleToUser;
public boolean accessibilityFocused;
public boolean checked;
public boolean clickable;
public boolean contextClickable;
public boolean dismissable;
public boolean editable;
public boolean enabled;
public boolean focusable;
public boolean longClickable;
public boolean selected;
public boolean scrollable;
public String bounds;
private Rect mBoundsInScreen;
public NodeInfo(AccessibilityNodeInfoCompat node) {
id = simplifyId(node.getViewIdResourceName());
@ -48,8 +60,6 @@ public class NodeInfo {
longClickable = node.isLongClickable();
selected = node.isSelected();
scrollable = node.isScrollable();
visibleToUser = node.isVisibleToUser();
mBoundsInScreen = new Rect();
node.getBoundsInScreen(mBoundsInScreen);
bounds = boundsToString(mBoundsInScreen);

View File

@ -1,86 +0,0 @@
package com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view;
import android.content.Context;
import android.os.Build;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.annotation.StyleRes;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ViewSwitcher;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
/**
* Created by Stardust on 2017/3/10.
*/
public class LayoutInspectView extends FrameLayout {
private ViewSwitcher mViewSwitcher;
private NodeInfoView mNodeInfoView;
private LayoutHierarchyView mLayoutBoundsView;
private View mCurrentView;
public LayoutInspectView(@NonNull Context context) {
super(context);
init();
}
public LayoutInspectView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public LayoutInspectView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public LayoutInspectView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
inflate(getContext(), R.layout.floating_window_expand, this);
mNodeInfoView = (NodeInfoView) findViewById(R.id.node_info);
mLayoutBoundsView = (LayoutHierarchyView) findViewById(R.id.bounds_view);
mViewSwitcher = (ViewSwitcher) findViewById(R.id.view_switcher);
mCurrentView = mNodeInfoView;
mLayoutBoundsView.setOnNodeInfoLongClickListener(new OnNodeInfoSelectListener() {
@Override
public void onNodeSelect(NodeInfo info) {
mNodeInfoView.setNodeInfo(info);
showNodeInfoView();
}
});
}
public void showNodeInfoView() {
if (mCurrentView != mNodeInfoView) {
mViewSwitcher.showPrevious();
mCurrentView = mNodeInfoView;
}
}
public boolean isLayoutBoundsViewShowing() {
return mCurrentView == mLayoutBoundsView;
}
public boolean isNodeInfoViewShowing() {
return mCurrentView == mNodeInfoView;
}
public void backToLayoutBoundsView() {
if (mCurrentView != mLayoutBoundsView) {
mViewSwitcher.showNext();
mCurrentView = mLayoutBoundsView;
}
}
}

View File

@ -1,9 +1,11 @@
package com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
@ -12,23 +14,67 @@ import android.widget.Toast;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
import com.stardust.util.ClipboardUtil;
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
import java.lang.reflect.Field;
import java.util.Arrays;
import de.codecrafters.tableview.TableDataAdapter;
import de.codecrafters.tableview.TableView;
import de.codecrafters.tableview.model.TableColumnWeightModel;
import de.codecrafters.tableview.toolkit.SimpleTableDataAdapter;
import de.codecrafters.tableview.toolkit.TableDataRowBackgroundProviders;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnLongClick;
import butterknife.Optional;
/**
* Created by Stardust on 2017/3/10.
*/
public class NodeInfoView extends TableView {
public class NodeInfoView extends RecyclerView {
private static final Field[] fields = NodeInfo.class.getFields();
private String[][] mData = new String[fields.length][2];
private static final String[] FIELD_NAMES = {"id",
"bounds",
"contentDesc",
"className",
"packageName",
"text",
"drawingOrder",
"accessibilityFocused",
"checked",
"clickable",
"contextClickable",
"dismissable",
"editable",
"enabled",
"focusable",
"longClickable",
"selected",
"scrollable",
};
private static final Field[] FIELDS = new Field[FIELD_NAMES.length];
static {
Arrays.sort(FIELD_NAMES);
for (int i = 0; i < FIELD_NAMES.length; i++) {
try {
FIELDS[i] = NodeInfo.class.getField(FIELD_NAMES[i]);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
}
private String[][] mData = new String[FIELDS.length + 1][2];
private OnLongClickListener itemLongClickListener = new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int pos = getChildAdapterPosition(v);
if (pos < 1 || pos >= mData.length)
return false;
ClipboardUtil.setClip(getContext(), mData[pos][0] + " = " + mData[pos][1]);
Toast.makeText(getContext(), R.string.text_copy_to_clip, Toast.LENGTH_SHORT).show();
return true;
}
};
public NodeInfoView(Context context) {
super(context);
@ -46,67 +92,88 @@ public class NodeInfoView extends TableView {
}
public void setNodeInfo(NodeInfo nodeInfo) {
for (int i = 0; i < fields.length; i++) {
for (int i = 1; i < FIELD_NAMES.length; i++) {
try {
Object value = fields[i].get(nodeInfo);
mData[i][1] = value == null ? "null" : value.toString();
Object value = FIELDS[i - 1].get(nodeInfo);
mData[i][1] = value == null ? "" : value.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
getDataAdapter().notifyDataSetChanged();
getAdapter().notifyDataSetChanged();
}
private void init() {
initData();
setUpTableConfig();
setAdapter();
setUpStyle();
}
private void setAdapter() {
setDataAdapter(new TableDataAdapter<String[]>(getContext(), mData) {
SimpleTableDataAdapter mSimpleTableDataAdapter = new SimpleTableDataAdapter(getContext(), mData);
@Override
public View getCellView(int rowIndex, int columnIndex, ViewGroup parentView) {
final TextView textView = (TextView) mSimpleTableDataAdapter.getCellView(rowIndex, columnIndex, parentView);
textView.setSingleLine(false);
textView.setMaxLines(3);
textView.setTextColor(0xcc000000);
textView.setTextIsSelectable(true);
textView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
ClipboardUtil.setClip(getContext(), textView.getText());
Toast.makeText(getContext(), R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show();
return true;
}
});
return textView;
}
});
}
private void setUpTableConfig() {
setColumnCount(2);
setColumnModel(new TableColumnWeightModel(2));
setAdapter(new Adapter());
setLayoutManager(new LinearLayoutManager(getContext()));
addItemDecoration(new HorizontalDividerItemDecoration.Builder(getContext())
.color(0x1e000000)
.size(2)
.build());
}
private void initData() {
for (int i = 0; i < mData.length; i++) {
mData[i][0] = fields[i].getName();
mData[0][0] = getResources().getString(R.string.text_attribute);
mData[0][1] = getResources().getString(R.string.text_value);
for (int i = 1; i < mData.length; i++) {
mData[i][0] = FIELD_NAMES[i - 1];
mData[i][1] = "";
}
}
private void setUpStyle() {
int colorEvenRows = Color.WHITE;
int colorOddRows = 0xffe7e7e7;
setDataRowBackgroundProvider(TableDataRowBackgroundProviders.alternatingRowColors(colorEvenRows, colorOddRows));
getChildAt(0).setVisibility(GONE);
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
final int VIEW_TYPE_HEADER = 0;
final int VIEW_TYPE_ITEM = 1;
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layoutRes = viewType == VIEW_TYPE_HEADER ? R.layout.node_info_view_header : R.layout.node_info_view_item;
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(layoutRes, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.attrName.setText(mData[position][0]);
holder.attrValue.setText(mData[position][1]);
}
@Override
public int getItemCount() {
return mData.length;
}
@Override
public int getItemViewType(int position) {
return position == 0 ? VIEW_TYPE_HEADER : VIEW_TYPE_ITEM;
}
}
class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.name)
TextView attrName;
@BindView(R.id.value)
TextView attrValue;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
@Optional
@OnClick(R.id.item)
void onItemClick() {
int pos = getAdapterPosition();
if (pos < 1 || pos >= mData.length)
return;
ClipboardUtil.setClip(getContext(), mData[pos][0] + " = " + mData[pos][1]);
Toast.makeText(getContext(), R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show();
}
}
}

View File

@ -51,9 +51,10 @@ public class FloatingLayoutBoundsView extends LayoutBoundsView {
mNodeInfoView = new NodeInfoView(getContext());
mNodeInfoDialog = new MaterialDialog.Builder(getContext())
.customView(mNodeInfoView, false)
.backgroundColor(0xddffffff)
.theme(Theme.LIGHT)
.build();
mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE);
}
}

View File

@ -57,7 +57,7 @@ public class FloatingLayoutHierarchyView extends LayoutHierarchyView {
.theme(Theme.LIGHT)
.build();
if (mNodeInfoDialog.getWindow() != null)
mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE);
}
}

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:state_pressed="true">
<set>
<objectAnimator android:duration="100"
android:propertyName="translationZ"
android:valueTo="4dp"
android:valueType="floatType"/>
<objectAnimator android:duration="0"
android:propertyName="elevation"
android:valueTo="2dp"
android:valueType="floatType"/>
</set>
</item>
<item>
<set>
<objectAnimator android:duration="0"
android:propertyName="translationZ"
android:valueTo="0"
android:valueType="floatType"/>
<objectAnimator android:duration="0"
android:propertyName="elevation"
android:valueTo="0"
android:valueType="floatType"/>
</set>
</item>
</selector>

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.stardust.theme.widget.ThemeColorToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@color/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="@string/_app_name"
app:titleTextColor="@android:color/white"/>
<ViewSwitcher
android:id="@+id/view_switcher"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.NodeInfoView
android:id="@+id/node_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"/>
<com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.LayoutHierarchyView
android:id="@+id/bounds_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"/>
</ViewSwitcher>
</LinearLayout>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#8a000000"
android:textSize="12sp"/>
<TextView
android:id="@+id/value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#8a000000"
android:textSize="12sp"/>
</LinearLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:clickable="true"
android:orientation="horizontal"
android:padding="8dp">
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#de000000"
android:textSize="13sp"/>
<TextView
android:id="@+id/value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#8a000000"
android:textSize="13sp"/>
</LinearLayout>

View File

@ -184,6 +184,8 @@
<string name="text_server_address">服务器地址</string>
<string name="text_annunciation">声明</string>
<string name="text_about_me_and_repo">关于项目与开发者</string>
<string name="text_attribute">属性</string>
<string name="text_value"></string>
<string-array name="record_control_keys">
<item></item>