diff --git a/.idea/misc.xml b/.idea/misc.xml index ace2cb0d..274735b3 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -2,15 +2,16 @@ - + - - - - - - + + + + + + + diff --git a/app/build.gradle b/app/build.gradle index 6f07b0f3..78bba16f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "com.stardust.scriptdroid" minSdkVersion 19 targetSdkVersion 23 - versionCode 137 - versionName "2.0.12 Beta" + versionCode 140 + versionName "2.0.13 Alpha3" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { @@ -78,22 +78,40 @@ 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 'com.github.hyb1996:android-multi-level-listview:1.1' compile 'de.psdev.licensesdialog:licensesdialog:1.8.1' compile 'io.mattcarroll.hover:hover:0.9.7' compile 'com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1' @@ -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') @@ -113,6 +129,7 @@ dependencies { compile 'com.afollestad.material-dialogs:commons:0.9.2.3' compile 'com.makeramen:roundedimageview:2.2.1' compile 'com.rengwuxian.materialedittext:library:2.0.3' + compile 'org.msgpack:msgpack-core:0.8.11' compile(name: '920-common-release', ext: 'aar') compile(name: '920-styles-release', ext: 'aar') compile(name: '920-file_explorer-release', ext: 'aar') diff --git a/app/src/main/java/com/stardust/app/OperationDialogBuilder.java b/app/src/main/java/com/stardust/app/OperationDialogBuilder.java new file mode 100644 index 00000000..000f5e1f --- /dev/null +++ b/app/src/main/java/com/stardust/app/OperationDialogBuilder.java @@ -0,0 +1,89 @@ +package com.stardust.app; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.scriptdroid.R; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +/** + * Created by Stardust on 2017/6/26. + */ + +public class OperationDialogBuilder extends MaterialDialog.Builder { + + private RecyclerView mOperations; + private ArrayList mIds = new ArrayList<>(); + private ArrayList mIcons = new ArrayList<>(); + private ArrayList mTexts = new ArrayList<>(); + private Object mOnItemClickTarget; + + public OperationDialogBuilder(@NonNull Context context) { + super(context); + mOperations = new RecyclerView(context); + mOperations.setLayoutManager(new LinearLayoutManager(context)); + mOperations.setAdapter(new RecyclerView.Adapter() { + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.operation_dialog_item, parent, false)); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + holder.itemView.setId(mIds.get(position)); + holder.text.setText(mTexts.get(position)); + holder.icon.setImageResource(mIcons.get(position)); + if (mOnItemClickTarget != null) { + //// TODO: 2017/6/26 效率 + ButterKnife.bind(mOnItemClickTarget, holder.itemView); + } + } + + @Override + public int getItemCount() { + return mIds.size(); + } + }); + customView(mOperations, false); + } + + public OperationDialogBuilder item(int id, int iconRes, int textRes) { + mIds.add(id); + mIcons.add(iconRes); + mTexts.add(textRes); + return this; + } + + public OperationDialogBuilder bindItemClick(Object target) { + mOnItemClickTarget = target; + return this; + } + + class ViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.icon) + ImageView icon; + @BindView(R.id.text) + TextView text; + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + + } + + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/HoverMenuService.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/HoverMenuService.java index 78833769..2ed3c88c 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/HoverMenuService.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/HoverMenuService.java @@ -18,11 +18,13 @@ import com.stardust.hover.WindowHoverMenu; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.autojs.AutoJs; import com.stardust.scriptdroid.external.floatingwindow.FloatingWindowManger; +import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo; import com.stardust.scriptdroid.external.floatingwindow.menu.view.FloatingLayoutBoundsView; import com.stardust.scriptdroid.external.floatingwindow.menu.view.FloatingLayoutHierarchyView; import com.stardust.scriptdroid.tool.AccessibilityServiceTool; import com.stardust.theme.ThemeColorManagerCompat; import com.stardust.util.MessageEvent; +import com.stardust.util.MessageIntent; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -45,13 +47,18 @@ public class HoverMenuService extends Service { public boolean state; } - public static final String MESSAGE_SHOW_AND_EXPAND_MENU = "MESSAGE_SHOW_AND_EXPAND_MENU"; - public static final String MESSAGE_SHOW_LAYOUT_HIERARCHY = "MESSAGE_SHOW_LAYOUT_HIERARCHY"; - public static final String MESSAGE_SHOW_LAYOUT_BOUNDS = "MESSAGE_SHOW_LAYOUT_BOUNDS"; - public static final String MESSAGE_COLLAPSE_MENU = "MESSAGE_COLLAPSE_MENU"; - public static final String MESSAGE_MENU_COLLAPSING = "MESSAGE_MENU_COLLAPSING"; - public static final String MESSAGE_MENU_EXPANDING = "MESSAGE_MENU_EXPANDING"; - public static final String MESSAGE_MENU_EXIT = "MESSAGE_MENU_EXIT"; + public static final String ACTION_SHOW_AND_EXPAND_MENU = "ACTION_SHOW_AND_EXPAND_MENU"; + public static final String ACTION_SHOW_LAYOUT_HIERARCHY = "ACTION_SHOW_LAYOUT_HIERARCHY"; + public static final String ACTION_SHOW_LAYOUT_BOUNDS = "ACTION_SHOW_LAYOUT_BOUNDS"; + public static final String ACTION_COLLAPSE_MENU = "ACTION_COLLAPSE_MENU"; + public static final String ACTION_MENU_COLLAPSING = "ACTION_MENU_COLLAPSING"; + public static final String ACTION_MENU_EXPANDING = "ACTION_MENU_EXPANDING"; + public static final String ACTION_MENU_EXIT = "ACTION_MENU_EXIT"; + public static final String ACTION_SHOW_NODE_LAYOUT_HIERARCHY = "ACTION_SHOW_NODE_LAYOUT_HIERARCHY"; + public static final String ACTION_SHOW_NODE_LAYOUT_BOUNDS = "ACTION_SHOW_NODE_LAYOUT_BOUNDS"; + + public static final String EXTRA_NODE_INFO = "EXTRA_NODE_INFO"; + private static boolean sIsRunning; private static EventBus eventBus = new EventBus(); @@ -70,8 +77,12 @@ public class HoverMenuService extends Service { eventBus.post(new ServiceStateChangedEvent(sIsRunning)); } - public static void postEvent(MessageEvent event) { - eventBus.post(event); + public static void postIntent(Intent intent) { + eventBus.post(new MessageIntent(intent)); + } + + public static void postMessageIntent(MessageIntent intent) { + eventBus.post(intent); } @@ -88,6 +99,7 @@ public class HoverMenuService extends Service { private WindowViewController mWindowViewController; + private ContextThemeWrapper mThemeWrapper; private FloatingLayoutHierarchyView mFloatingLayoutHierarchyView; private FloatingLayoutBoundsView mFloatingLayoutBoundsView; @@ -95,7 +107,7 @@ public class HoverMenuService extends Service { private HoverMenu.OnExitListener mWindowHoverMenuMenuExitListener = new HoverMenu.OnExitListener() { @Override public void onExitByUserRequest() { - eventBus.post(new MessageEvent(MESSAGE_MENU_EXIT)); + eventBus.post(new MessageEvent(ACTION_MENU_EXIT)); savePreferredLocation(); mWindowHoverMenu.hide(); stopSelf(); @@ -121,15 +133,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()) @@ -140,14 +153,14 @@ public class HoverMenuService extends Service { mWindowHoverMenu.setHoverMenuTransitionListener(new SimpleHoverMenuTransitionListener() { @Override public void onExpanding() { - eventBus.post(new MessageEvent(MESSAGE_MENU_EXPANDING)); + eventBus.post(new MessageEvent(ACTION_MENU_EXPANDING)); captureCurrentWindow(); } @Override public void onCollapsing() { AutoJs.getInstance().getLayoutInspector().clearCapture(); - eventBus.post(new MessageEvent(MESSAGE_MENU_COLLAPSING)); + eventBus.post(new MessageEvent(ACTION_MENU_COLLAPSING)); } }); } @@ -195,20 +208,30 @@ public class HoverMenuService extends Service { } @Subscribe - public void onMessageEvent(MessageEvent event) { - switch (event.message) { - case MESSAGE_SHOW_AND_EXPAND_MENU: + public void handleMessageIntent(MessageIntent intent) { + switch (intent.getAction()) { + case ACTION_SHOW_AND_EXPAND_MENU: showAndExpandMenu(); break; - case MESSAGE_SHOW_LAYOUT_HIERARCHY: + case ACTION_SHOW_LAYOUT_HIERARCHY: showLayoutHierarchy(); break; - case MESSAGE_SHOW_LAYOUT_BOUNDS: + case ACTION_SHOW_LAYOUT_BOUNDS: showLayoutBounds(); break; - case MESSAGE_COLLAPSE_MENU: + case ACTION_COLLAPSE_MENU: mWindowHoverMenu.collapseMenu(); break; + case ACTION_SHOW_NODE_LAYOUT_BOUNDS: + mFloatingLayoutHierarchyView.setVisibility(View.GONE); + showLayoutBounds(); + mFloatingLayoutBoundsView.setSelectedNode((NodeInfo) intent.getObjectExtra(EXTRA_NODE_INFO)); + break; + case ACTION_SHOW_NODE_LAYOUT_HIERARCHY: + mFloatingLayoutBoundsView.setVisibility(View.GONE); + showLayoutHierarchy(); + mFloatingLayoutHierarchyView.setSelectedNode((NodeInfo) intent.getObjectExtra(EXTRA_NODE_INFO)); + break; } } diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/MainMenuNavigatorContent.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/MainMenuNavigatorContent.java index a878a3cf..7d38e173 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/MainMenuNavigatorContent.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/MainMenuNavigatorContent.java @@ -51,7 +51,7 @@ public class MainMenuNavigatorContent implements NavigatorContent { if (!ensureCapture()) { return; } - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_HIERARCHY)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_SHOW_LAYOUT_HIERARCHY)); } private boolean ensureCapture() { @@ -72,7 +72,7 @@ public class MainMenuNavigatorContent implements NavigatorContent { if (!ensureCapture()) { return; } - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_BOUNDS)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_SHOW_LAYOUT_BOUNDS)); } @ViewBinding.Click(R.id.stop_all_running_scripts) @@ -84,7 +84,7 @@ public class MainMenuNavigatorContent implements NavigatorContent { private void openMainActivity() { App.getApp().startActivity(new Intent(App.getApp(), MainActivity.class) .addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK)); - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_COLLAPSE_MENU)); } @NonNull @@ -125,9 +125,9 @@ public class MainMenuNavigatorContent implements NavigatorContent { @Subscribe public void onMessageEvent(MessageEvent event) { - if (event.message.equals(HoverMenuService.MESSAGE_MENU_EXPANDING)) { + if (event.message.equals(HoverMenuService.ACTION_MENU_EXPANDING)) { syncCurrentInfo(); - } else if (event.message.equals(HoverMenuService.MESSAGE_MENU_EXIT)) { + } else if (event.message.equals(HoverMenuService.ACTION_MENU_EXIT)) { HoverMenuService.getEventBus().unregister(this); } } diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/RecordNavigatorContent.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/RecordNavigatorContent.java index 80d8125a..77792167 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/RecordNavigatorContent.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/RecordNavigatorContent.java @@ -1,6 +1,7 @@ package com.stardust.scriptdroid.external.floatingwindow.menu.content; import android.content.Context; +import android.content.Intent; import android.support.annotation.NonNull; import android.support.v7.widget.SwitchCompat; import android.view.View; @@ -124,7 +125,7 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat private void resumeRecord() { mRecorder.resume(); setState(Recorder.STATE_RECORDING); - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_COLLAPSE_MENU)); } private void pauseRecord() { @@ -137,7 +138,7 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat mRecorder.setOnStateChangedListener(this); mRecorder.start(); setState(Recorder.STATE_RECORDING); - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_COLLAPSE_MENU)); } private void setState(int state) { @@ -153,7 +154,7 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat private void stopRecord() { mRecorder.stop(); setState(Recorder.STATE_STOPPED); - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_COLLAPSE_MENU)); } @@ -163,10 +164,10 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat @Subscribe public void onMessageEvent(MessageEvent event) { - if (event.message.equals(HoverMenuService.MESSAGE_MENU_EXPANDING)) { + if (event.message.equals(HoverMenuService.ACTION_MENU_EXPANDING)) { if (mRecorder != null && mRecorder.getState() == Recorder.STATE_RECORDING) pauseRecord(); - } else if (event.message.equals(HoverMenuService.MESSAGE_MENU_EXIT)) { + } else if (event.message.equals(HoverMenuService.ACTION_MENU_EXIT)) { onMenuExit(); } } diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/ScriptListNavigatorContent.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/ScriptListNavigatorContent.java index 04b8abd2..a7fb3a1a 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/ScriptListNavigatorContent.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/content/ScriptListNavigatorContent.java @@ -1,6 +1,7 @@ package com.stardust.scriptdroid.external.floatingwindow.menu.content; import android.content.Context; +import android.content.Intent; import android.support.annotation.NonNull; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; @@ -15,7 +16,6 @@ import com.stardust.scriptdroid.script.StorageScriptProvider; import com.stardust.scriptdroid.ui.edit.EditActivity; import com.stardust.scriptdroid.ui.main.script_list.ScriptAndFolderListRecyclerView; import com.stardust.scriptdroid.ui.main.script_list.ScriptListWithProgressBarView; -import com.stardust.util.MessageEvent; import com.stardust.widget.ViewHolderSupplier; import io.mattcarroll.hover.Navigator; @@ -53,7 +53,7 @@ public class ScriptListNavigatorContent implements NavigatorContent { @Override public void onClick(ScriptFile file, int position) { Scripts.run(file); - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_COLLAPSE_MENU)); } }); @@ -94,7 +94,7 @@ public class ScriptListNavigatorContent implements NavigatorContent { int position = mFloatingScriptFileListView.getChildViewHolder((View) v.getParent()).getAdapterPosition(); ScriptFile file = mFloatingScriptFileListView.getAdapter().getScriptFileAt(position); EditActivity.editFile(v.getContext(), file); - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_COLLAPSE_MENU)); } }); diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/LayoutInspector.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/LayoutInspector.java index 40b120be..4cbfbbd0 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/LayoutInspector.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/LayoutInspector.java @@ -10,11 +10,8 @@ import java.util.concurrent.Executor; /** * Created by Stardust on 2017/3/10. - * */ -// TODO: 2017/5/8 - public class LayoutInspector { private volatile NodeInfo mCapture; @@ -22,7 +19,7 @@ public class LayoutInspector { private Executor mExecutor = UnderuseExecutors.getExecutor(); public void captureCurrentWindow() { - AccessibilityService service = AccessibilityWatchDogService.getInstance(); + AccessibilityWatchDogService service = AccessibilityWatchDogService.getInstance(); if (service == null) { mCapture = null; } else { diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/NodeInfo.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/NodeInfo.java index dbf9795c..7fd1b7c5 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/NodeInfo.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/NodeInfo.java @@ -18,19 +18,31 @@ import java.util.List; public class NodeInfo { private List children = new ArrayList<>(); + private Rect mBoundsInScreen; public String id; - public CharSequence contentDesc, className, packageName, text; + public CharSequence desc; + 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()); - contentDesc = node.getContentDescription(); + desc = node.getContentDescription(); className = node.getClassName(); packageName = node.getPackageName(); text = node.getText(); @@ -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); @@ -92,6 +102,7 @@ public class NodeInfo { return capture(r); } + @NonNull public List getChildren() { return children; } diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutBoundsView.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutBoundsView.java index ee23e498..b22fef68 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutBoundsView.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutBoundsView.java @@ -5,6 +5,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; +import android.graphics.Region; import android.os.Build; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; @@ -16,6 +17,8 @@ import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.No import com.stardust.util.ViewUtil; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; /** @@ -24,12 +27,16 @@ import java.util.List; public class LayoutBoundsView extends View { + private static final int COLOR_SHADOW = 0x6a000000; private NodeInfo mRootNode; - - - private Paint mPaint; + private NodeInfo mTouchedNode; + private Paint mBoundsPaint; + private Paint mFillingPaint; private int mStatusBarHeight; private OnNodeInfoSelectListener mOnNodeInfoSelectListener; + private int mTouchedNodeBoundsColor = Color.RED; + private int mNormalNodeBoundsColor = Color.GREEN; + private Rect mTouchedNodeBounds; public LayoutBoundsView(Context context) { super(context); @@ -59,32 +66,68 @@ public class LayoutBoundsView extends View { public void setRootNode(NodeInfo rootNode) { mRootNode = rootNode; + mTouchedNode = null; } private void init() { - mPaint = new Paint(); - mPaint.setColor(Color.GREEN); - mPaint.setStyle(Paint.Style.STROKE); + mBoundsPaint = new Paint(); + mBoundsPaint.setStyle(Paint.Style.STROKE); + mFillingPaint = new Paint(); + mFillingPaint.setStyle(Paint.Style.FILL); + mFillingPaint.setColor(COLOR_SHADOW); mStatusBarHeight = ViewUtil.getStatusBarHeight(getContext()); setWillNotDraw(false); } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); + if (mTouchedNode != null) { + canvas.save(); + if (mTouchedNodeBounds == null) { + mTouchedNodeBounds = new Rect(mTouchedNode.getBoundsInScreen()); + mTouchedNodeBounds.offset(0, -mStatusBarHeight); + } + canvas.clipRect(mTouchedNodeBounds, Region.Op.DIFFERENCE); + } + canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mFillingPaint); + if (mTouchedNode != null) { + canvas.restore(); + } + mBoundsPaint.setColor(mNormalNodeBoundsColor); draw(canvas, mRootNode); + if (mTouchedNode != null) { + mBoundsPaint.setColor(mTouchedNodeBoundsColor); + drawRect(canvas, mTouchedNode.getBoundsInScreen(), mStatusBarHeight, mBoundsPaint); + } } - public Paint getPaint() { - return mPaint; + public Paint getBoundsPaint() { + return mBoundsPaint; } + public Paint getFillingPaint() { + return mFillingPaint; + } + + public int getStatusBarHeight() { + return mStatusBarHeight; + } + + public void setTouchedNodeBoundsColor(int touchedNodeBoundsColor) { + mTouchedNodeBoundsColor = touchedNodeBoundsColor; + } + + public void setNormalNodeBoundsColor(int normalNodeBoundsColor) { + mNormalNodeBoundsColor = normalNodeBoundsColor; + } private void draw(Canvas canvas, NodeInfo node) { if (node == null) return; - drawRect(canvas, node.getBoundsInScreen(), mStatusBarHeight, mPaint); + drawRect(canvas, node.getBoundsInScreen(), mStatusBarHeight, mBoundsPaint); for (NodeInfo child : node.getChildren()) { draw(canvas, child); } @@ -98,25 +141,39 @@ public class LayoutBoundsView extends View { @Override public boolean onTouchEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN && mRootNode != null) { - ArrayList list = new ArrayList<>(); - findNodeAt(mRootNode, (int) event.getRawX(), (int) event.getRawY(), list); - showNodeInfoList(list); + if (mRootNode != null) { + setSelectedNode(findNodeAt(mRootNode, (int) event.getRawX(), (int) event.getRawY())); + } + if (event.getAction() == MotionEvent.ACTION_UP && mTouchedNode != null) { + onNodeInfoClick(mTouchedNode); + return true; } return super.onTouchEvent(event); } - private void showNodeInfoList(ArrayList list) { - onNodeInfoClick(list.get(list.size() - 1)); - } - private void onNodeInfoClick(NodeInfo nodeInfo) { if (mOnNodeInfoSelectListener != null) { mOnNodeInfoSelectListener.onNodeSelect(nodeInfo); } } + private NodeInfo findNodeAt(NodeInfo node, int x, int y) { + ArrayList list = new ArrayList<>(); + findNodeAt(node, x, y, list); + if (list.isEmpty()) { + return null; + } + return Collections.min(list, new Comparator() { + @Override + public int compare(NodeInfo o1, NodeInfo o2) { + return o1.getBoundsInScreen().width() * o1.getBoundsInScreen().height() - + o2.getBoundsInScreen().width() * o2.getBoundsInScreen().height(); + } + }); + } + + private void findNodeAt(NodeInfo node, int x, int y, List list) { for (NodeInfo child : node.getChildren()) { if (child != null && child.getBoundsInScreen().contains(x, y)) { @@ -126,4 +183,9 @@ public class LayoutBoundsView extends View { } } + public void setSelectedNode(NodeInfo selectedNode) { + mTouchedNode = selectedNode; + mTouchedNodeBounds = null; + invalidate(); + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutHierarchyView.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutHierarchyView.java index 012100bf..0da221ff 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutHierarchyView.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutHierarchyView.java @@ -19,8 +19,11 @@ import com.stardust.util.ViewUtil; import com.stardust.widget.LevelBeamView; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Set; +import java.util.Stack; import pl.openrnd.multilevellistview.ItemInfo; import pl.openrnd.multilevellistview.MultiLevelListAdapter; @@ -34,13 +37,17 @@ import pl.openrnd.multilevellistview.OnItemClickListener; public class LayoutHierarchyView extends MultiLevelListView { + public interface OnItemLongClickListener { + void onItemLongClick(View view, NodeInfo nodeInfo); + } + private Adapter mAdapter; - private OnNodeInfoSelectListener mOnNodeInfoSelectListener; + private OnItemLongClickListener mOnItemLongClickListener; private AdapterView.OnItemLongClickListener mOnItemLongClickListenerProxy = new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { - if (mOnNodeInfoSelectListener != null) { - mOnNodeInfoSelectListener.onNodeSelect(((ViewHolder) view.getTag()).nodeInfo); + if (mOnItemLongClickListener != null) { + mOnItemLongClickListener.onItemLongClick(view, ((ViewHolder) view.getTag()).nodeInfo); return true; } return false; @@ -55,7 +62,9 @@ public class LayoutHierarchyView extends MultiLevelListView { private Drawable mOriginalBackground; private boolean mShowClickedNodeBounds; - private int mClickedColor = 0x77c4c4c4; + private int mClickedColor = 0x99b2b3b7; + private NodeInfo mRootNode; + private Set mInitiallyExpandedNodes = new HashSet<>(); public LayoutHierarchyView(Context context) { super(context); @@ -80,6 +89,9 @@ public class LayoutHierarchyView extends MultiLevelListView { mClickedColor = clickedColor; } + public int getStatusBarHeight() { + return mStatusBarHeight; + } private void init() { mAdapter = new Adapter(); @@ -127,12 +139,14 @@ public class LayoutHierarchyView extends MultiLevelListView { } public void setRootNode(NodeInfo rootNodeInfo) { + mRootNode = rootNodeInfo; mAdapter.setDataItems(Collections.singletonList(rootNodeInfo)); mClickedNodeInfo = null; + mInitiallyExpandedNodes.clear(); } - public void setOnNodeInfoLongClickListener(final OnNodeInfoSelectListener onNodeInfoSelectListener) { - mOnNodeInfoSelectListener = onNodeInfoSelectListener; + public void setOnItemLongClickListener(final OnItemLongClickListener onNodeInfoSelectListener) { + mOnItemLongClickListener = onNodeInfoSelectListener; } @Override @@ -143,6 +157,35 @@ public class LayoutHierarchyView extends MultiLevelListView { } } + public void setSelectedNode(NodeInfo selectedNode) { + mInitiallyExpandedNodes.clear(); + Stack parents = new Stack<>(); + searchNodeParents(selectedNode, mRootNode, parents); + mClickedNodeInfo = parents.peek(); + for (NodeInfo nodeInfo : parents) { + mInitiallyExpandedNodes.add(nodeInfo); + } + mAdapter.reloadData(); + } + + private boolean searchNodeParents(NodeInfo nodeInfo, NodeInfo rootNode, Stack stack) { + stack.push(rootNode); + if (nodeInfo == rootNode) { + return true; + } + boolean found = false; + for (NodeInfo child : rootNode.getChildren()) { + if (searchNodeParents(nodeInfo, child, stack)) { + found = true; + break; + } + } + if (!found) { + stack.pop(); + } + return found; + } + private class ViewHolder { TextView nameView; TextView infoView; @@ -163,15 +206,20 @@ public class LayoutHierarchyView extends MultiLevelListView { @Override - public List getSubObjects(Object object) { + protected List getSubObjects(Object object) { return ((NodeInfo) object).getChildren(); } @Override - public boolean isExpandable(Object object) { + protected boolean isExpandable(Object object) { return !((NodeInfo) object).getChildren().isEmpty(); } + @Override + protected boolean isInitiallyExpanded(Object object) { + return mInitiallyExpandedNodes.contains((NodeInfo) object); + } + @Override public View getViewForObject(Object object, View convertView, ItemInfo itemInfo) { NodeInfo nodeInfo = (NodeInfo) object; @@ -199,6 +247,9 @@ public class LayoutHierarchyView extends MultiLevelListView { viewHolder.levelBeamView.setLevel(itemInfo.getLevel()); + if (nodeInfo == mClickedNodeInfo) { + setClickedItem(convertView, nodeInfo); + } return convertView; } diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutInspectView.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutInspectView.java deleted file mode 100644 index ed7af408..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/LayoutInspectView.java +++ /dev/null @@ -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; - } - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/NodeInfoView.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/NodeInfoView.java index b63bf272..22762a6c 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/NodeInfoView.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/NodeInfoView.java @@ -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,68 @@ 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", + "desc", + "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.getDeclaredField(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 +93,88 @@ public class NodeInfoView extends TableView { } public void setNodeInfo(NodeInfo nodeInfo) { - for (int i = 0; i < fields.length; i++) { + for (int i = 0; i < FIELDS.length; i++) { try { - Object value = fields[i].get(nodeInfo); - mData[i][1] = value == null ? "null" : value.toString(); + Object value = FIELDS[i].get(nodeInfo); + mData[i + 1][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(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 { + + 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(); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/view/FloatingLayoutBoundsView.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/view/FloatingLayoutBoundsView.java index cacbe015..100c3184 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/view/FloatingLayoutBoundsView.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/view/FloatingLayoutBoundsView.java @@ -1,17 +1,24 @@ package com.stardust.scriptdroid.external.floatingwindow.menu.view; import android.content.Context; +import android.content.Intent; import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; import android.view.WindowManager; import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; +import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.external.floatingwindow.menu.HoverMenuService; import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo; import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.LayoutBoundsView; import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.NodeInfoView; import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.OnNodeInfoSelectListener; -import com.stardust.util.MessageEvent; +import com.stardust.util.MessageIntent; +import com.stardust.widget.BubblePopupMenu; + +import java.util.Arrays; /** * Created by Stardust on 2017/3/12. @@ -20,7 +27,9 @@ import com.stardust.util.MessageEvent; public class FloatingLayoutBoundsView extends LayoutBoundsView { private MaterialDialog mNodeInfoDialog; + private BubblePopupMenu mBubblePopMenu; private NodeInfoView mNodeInfoView; + private NodeInfo mSelectedNode; public FloatingLayoutBoundsView(Context context) { super(context); @@ -31,21 +40,46 @@ public class FloatingLayoutBoundsView extends LayoutBoundsView { setOnNodeInfoSelectListener(new OnNodeInfoSelectListener() { @Override public void onNodeSelect(NodeInfo info) { - showNodeInfo(info); + mSelectedNode = info; + ensureOperationPopMenu(); + if (mBubblePopMenu.getContentView().getMeasuredWidth() <= 0) + mBubblePopMenu.preMeasure(); + mBubblePopMenu.showAsDropDownAtLocation(FloatingLayoutBoundsView.this, info.getBoundsInScreen().height(), info.getBoundsInScreen().centerX() - mBubblePopMenu.getContentView().getMeasuredWidth() / 2, info.getBoundsInScreen().bottom - getStatusBarHeight()); } }); setVisibility(GONE); - getPaint().setColor(0xFF222222); - getPaint().setStrokeWidth(2f); + getBoundsPaint().setStrokeWidth(2f); } - private void showNodeInfo(NodeInfo info) { + private void showNodeInfo() { ensureDialog(); - mNodeInfoView.setNodeInfo(info); + mNodeInfoView.setNodeInfo(mSelectedNode); mNodeInfoDialog.show(); } + private void ensureOperationPopMenu() { + if (mBubblePopMenu != null) + return; + mBubblePopMenu = new BubblePopupMenu(getContext(), Arrays.asList( + getResources().getString(R.string.text_show_widget_infomation), + getResources().getString(R.string.text_show_layout_hierarchy))); + mBubblePopMenu.setOnItemClickListener(new BubblePopupMenu.OnItemClickListener() { + @Override + public void onClick(View view, int position) { + mBubblePopMenu.dismiss(); + if (position == 0) { + showNodeInfo(); + } else { + HoverMenuService.postMessageIntent(new MessageIntent(HoverMenuService.ACTION_SHOW_NODE_LAYOUT_HIERARCHY) + .putExtra(HoverMenuService.EXTRA_NODE_INFO, mSelectedNode)); + } + } + }); + mBubblePopMenu.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); + mBubblePopMenu.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); + } + private void ensureDialog() { if (mNodeInfoDialog == null) { mNodeInfoView = new NodeInfoView(getContext()); @@ -53,14 +87,14 @@ public class FloatingLayoutBoundsView extends LayoutBoundsView { .customView(mNodeInfoView, false) .theme(Theme.LIGHT) .build(); - mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE); } } @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_SHOW_AND_EXPAND_MENU)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_SHOW_AND_EXPAND_MENU)); setVisibility(GONE); return true; } diff --git a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/view/FloatingLayoutHierarchyView.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/view/FloatingLayoutHierarchyView.java index 701ab41c..534154e6 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/view/FloatingLayoutHierarchyView.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/view/FloatingLayoutHierarchyView.java @@ -1,17 +1,23 @@ package com.stardust.scriptdroid.external.floatingwindow.menu.view; import android.content.Context; +import android.content.Intent; import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; import android.view.WindowManager; import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; +import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.external.floatingwindow.menu.HoverMenuService; import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo; import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.LayoutHierarchyView; import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.NodeInfoView; -import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.OnNodeInfoSelectListener; -import com.stardust.util.MessageEvent; +import com.stardust.util.MessageIntent; +import com.stardust.widget.BubblePopupMenu; + +import java.util.Arrays; /** * Created by Stardust on 2017/3/12. @@ -20,9 +26,12 @@ import com.stardust.util.MessageEvent; public class FloatingLayoutHierarchyView extends LayoutHierarchyView { private static final String TAG = "FloatingHierarchyView"; + private static final int COLOR_SHADOW = 0xddffffff; private MaterialDialog mNodeInfoDialog; + private BubblePopupMenu mBubblePopMenu; private NodeInfoView mNodeInfoView; + private NodeInfo mSelectedNodeInfo; public FloatingLayoutHierarchyView(Context context) { super(context); @@ -30,26 +39,53 @@ public class FloatingLayoutHierarchyView extends LayoutHierarchyView { } private void init() { - setBackgroundColor(0x99ffffff); + setBackgroundColor(COLOR_SHADOW); setVisibility(GONE); setShowClickedNodeBounds(true); getBoundsPaint().setStrokeWidth(3); getBoundsPaint().setColor(0xFFD32F2F); - setOnNodeInfoLongClickListener(new OnNodeInfoSelectListener() { + setOnItemLongClickListener(new OnItemLongClickListener() { @Override - public void onNodeSelect(NodeInfo info) { - showNodeInfo(info); + public void onItemLongClick(View view, NodeInfo nodeInfo) { + mSelectedNodeInfo = nodeInfo; + ensureOperationPopMenu(); + if (mBubblePopMenu.getContentView().getMeasuredWidth() <= 0) + mBubblePopMenu.preMeasure(); + mBubblePopMenu.showAsDropDown(view, view.getWidth() / 2 - mBubblePopMenu.getContentView().getMeasuredWidth() / 2, 0); } }); } - private void showNodeInfo(NodeInfo info) { - ensureDialog(); - mNodeInfoView.setNodeInfo(info); + private void ensureOperationPopMenu() { + if (mBubblePopMenu != null) + return; + mBubblePopMenu = new BubblePopupMenu(getContext(), Arrays.asList( + getResources().getString(R.string.text_show_widget_infomation), + getResources().getString(R.string.text_show_layout_bounds))); + mBubblePopMenu.setOnItemClickListener(new BubblePopupMenu.OnItemClickListener() { + @Override + public void onClick(View view, int position) { + mBubblePopMenu.dismiss(); + if (position == 0) { + showNodeInfo(); + } else { + HoverMenuService.postMessageIntent(new MessageIntent(HoverMenuService.ACTION_SHOW_NODE_LAYOUT_BOUNDS) + .putExtra(HoverMenuService.EXTRA_NODE_INFO, mSelectedNodeInfo)); + } + } + }); + mBubblePopMenu.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); + mBubblePopMenu.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); + } + + + void showNodeInfo() { + ensureNodeInfoDialog(); + mNodeInfoView.setNodeInfo(mSelectedNodeInfo); mNodeInfoDialog.show(); } - private void ensureDialog() { + private void ensureNodeInfoDialog() { if (mNodeInfoDialog == null) { mNodeInfoView = new NodeInfoView(getContext()); mNodeInfoDialog = new MaterialDialog.Builder(getContext()) @@ -57,18 +93,19 @@ 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); } } @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { - HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_SHOW_AND_EXPAND_MENU)); + HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_SHOW_AND_EXPAND_MENU)); setVisibility(GONE); return true; } return super.dispatchKeyEvent(event); } + } diff --git a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java b/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java index 2cac412b..a24768bd 100644 --- a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java +++ b/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java @@ -13,6 +13,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** @@ -39,7 +40,7 @@ public class SublimePluginClient { private String host; private int port; private OutputStream mOutputStream; - private Executor mExecutor; + private ExecutorService mExecutor; public SublimePluginClient(String host, int port) { this.host = host; @@ -105,8 +106,10 @@ public class SublimePluginClient { public void close() throws IOException { if (mSocket != null) { mSocket.close(); + mExecutor.shutdownNow(); mSocket = null; mOutputStream = null; + mExecutor = null; EventBus.getDefault().post(new ConnectionStateChangeEvent(false)); } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/script_list/MyScriptListFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/script_list/MyScriptListFragment.java index 75545632..88be08e0 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/script_list/MyScriptListFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/script_list/MyScriptListFragment.java @@ -1,5 +1,6 @@ package com.stardust.scriptdroid.ui.main.script_list; +import android.content.DialogInterface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -13,6 +14,7 @@ import android.widget.EditText; import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.MaterialDialog; import com.stardust.app.Fragment; +import com.stardust.app.OperationDialogBuilder; import com.stardust.scriptdroid.script.ScriptFile; import com.stardust.pio.PFile; import com.stardust.scriptdroid.R; @@ -20,6 +22,7 @@ import com.stardust.scriptdroid.script.Scripts; import com.stardust.scriptdroid.script.StorageScriptProvider; import com.stardust.scriptdroid.ui.edit.EditActivity; import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder; +import com.stardust.util.UnderuseExecutors; import com.stardust.view.ViewBinder; import com.stardust.view.ViewBinding; import com.stardust.widget.SimpleAdapterDataObserver; @@ -29,6 +32,9 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; +import butterknife.OnClick; +import butterknife.Optional; + /** * Created by Stardust on 2017/3/13. */ @@ -109,15 +115,17 @@ public class MyScriptListFragment extends Fragment { private void initDialogs() { - mScriptFileOperationDialog = buildDialog(R.layout.dialog_script_file_operations); - mDirectoryOperationDialog = buildDialog(R.layout.dialog_directory_operations); - } - - private MaterialDialog buildDialog(int layout) { - View view = View.inflate(getActivity(), layout, null); - ViewBinder.bind(this, view); - return new MaterialDialog.Builder(getActivity()) - .customView(view, false) + mScriptFileOperationDialog = new OperationDialogBuilder(getContext()) + .item(R.id.rename, R.drawable.ic_ali_rename, R.string.text_rename) + .item(R.id.open_by_other_apps, R.drawable.ic_ali_open, R.string.text_open_by_other_apps) + .item(R.id.create_shortcut, R.drawable.ic_ali_shortcut, R.string.text_send_shortcut) + .item(R.id.delete, R.drawable.ic_ali_delete, R.string.text_delete) + .bindItemClick(this) + .build(); + mDirectoryOperationDialog = new OperationDialogBuilder(getContext()) + .item(R.id.rename, R.drawable.ic_ali_rename, R.string.text_rename) + .item(R.id.delete, R.drawable.ic_ali_delete, R.string.text_delete) + .bindItemClick(this) .build(); } @@ -230,8 +238,9 @@ public class MyScriptListFragment extends Fragment { }); } - @ViewBinding.Click(R.id.rename) - private void renameScriptFile() { + @Optional + @OnClick(R.id.rename) + void renameScriptFile() { dismissDialogs(); String originalName = mSelectedScriptFile.getSimplifiedName(); showNameInputDialog(originalName, new InputCallback(mSelectedScriptFile.isDirectory(), originalName), new MaterialDialog.InputCallback() { @@ -252,8 +261,9 @@ public class MyScriptListFragment extends Fragment { } - @ViewBinding.Click(R.id.open_by_other_apps) - private void openByOtherApps() { + @Optional + @OnClick(R.id.open_by_other_apps) + void openByOtherApps() { dismissDialogs(); Scripts.openByOtherApps(mSelectedScriptFile); onScriptFileOperated(); @@ -269,16 +279,18 @@ public class MyScriptListFragment extends Fragment { }); } - @ViewBinding.Click(R.id.create_shortcut) - private void createShortcut() { + @Optional + @OnClick(R.id.create_shortcut) + void createShortcut() { dismissDialogs(); Scripts.createShortcut(mSelectedScriptFile); Snackbar.make(getView(), R.string.text_already_create, Snackbar.LENGTH_SHORT).show(); onScriptFileOperated(); } - @ViewBinding.Click(R.id.delete) - private void deleteScriptFile() { + @Optional + @OnClick(R.id.delete) + void deleteScriptFile() { dismissDialogs(); new MaterialDialog.Builder(getActivity()) .title(R.string.delete_confirm) @@ -295,7 +307,7 @@ public class MyScriptListFragment extends Fragment { private void doDeletingScriptFile() { mScriptListWithProgressBarView.showProgressBar(); - new Thread(new Runnable() { + UnderuseExecutors.execute(new Runnable() { @Override public void run() { if (PFile.deleteRecursively(mSelectedScriptFile)) { @@ -306,7 +318,7 @@ public class MyScriptListFragment extends Fragment { } onScriptFileOperated(); } - }).start(); + }); } private void showMessage(final int resId) { diff --git a/app/src/main/java/com/stardust/widget/BindableViewHolder.java b/app/src/main/java/com/stardust/widget/BindableViewHolder.java index 2f381472..308e3ca6 100644 --- a/app/src/main/java/com/stardust/widget/BindableViewHolder.java +++ b/app/src/main/java/com/stardust/widget/BindableViewHolder.java @@ -14,5 +14,5 @@ public abstract class BindableViewHolder extends RecyclerView.ViewHold super(itemView); } - public abstract void bind(DataType data); + public abstract void bind(DataType data, int position); } diff --git a/app/src/main/java/com/stardust/widget/BubblePopupMenu.java b/app/src/main/java/com/stardust/widget/BubblePopupMenu.java new file mode 100644 index 00000000..a3f98075 --- /dev/null +++ b/app/src/main/java/com/stardust/widget/BubblePopupMenu.java @@ -0,0 +1,109 @@ +package com.stardust.widget; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.support.v7.widget.RecyclerView; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import android.widget.TextView; + +import com.stardust.scriptdroid.R; + +import java.util.List; + +/** + * Created by Stardust on 2017/5/23. + */ + +public class BubblePopupMenu extends PopupWindow { + + + public interface OnItemClickListener { + void onClick(View view, int position); + } + + private RecyclerView mRecyclerView; + private OnItemClickListener mOnItemClickListener; + private View mLittleTriangle; + + public BubblePopupMenu(Context context, List options) { + super(context); + View view = View.inflate(context, R.layout.bubble_popup_menu, null); + mLittleTriangle = view.findViewById(R.id.little_triangle); + mRecyclerView = (RecyclerView) view.findViewById(R.id.list); + mRecyclerView.setAdapter(new SimpleRecyclerViewAdapter<>(R.layout.bubble_popup_menu_item, options, new SimpleRecyclerViewAdapter.ViewHolderFactory() { + @Override + public MenuItemViewHolder create(View itemView) { + return new MenuItemViewHolder(itemView); + } + })); + setContentView(view); + setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + setOutsideTouchable(true); + setFocusable(true); + } + + public void setOnItemClickListener(OnItemClickListener onItemClickListener) { + mOnItemClickListener = onItemClickListener; + } + + public void showAsDropDownAtLocation(View parent, int contentHeight, int x, int y) { + int screenWidth = getContentView().getResources().getDisplayMetrics().widthPixels; + int screenHeight = getContentView().getResources().getDisplayMetrics().heightPixels; + int width = getContentView().getWidth(); + int height = getContentView().getHeight(); + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mLittleTriangle.getLayoutParams(); + if (x + width > screenWidth) { + params.leftMargin = x + width - screenWidth; + } else if (x < 0) { + params.leftMargin = x; + } else { + params.leftMargin = 0; + } + if (y + height > screenHeight) { + getContentView().setRotation(180); + mRecyclerView.setRotation(180); + params.leftMargin = -params.leftMargin; + y -= contentHeight + height; + } else { + getContentView().setRotation(0); + mRecyclerView.setRotation(0); + } + mLittleTriangle.setLayoutParams(params); + super.showAtLocation(parent, Gravity.NO_GRAVITY, x, y); + } + + + public void preMeasure() { + getContentView().measure(getWidth(), getHeight()); + } + + + private class MenuItemViewHolder extends BindableViewHolder { + + private TextView mOption; + + public MenuItemViewHolder(View itemView) { + super(itemView); + mOption = (TextView) itemView.findViewById(R.id.option); + itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mOnItemClickListener != null) { + int i = mRecyclerView.getChildAdapterPosition(v); + mOnItemClickListener.onClick(v, i); + } + } + }); + } + + @Override + public void bind(String s, int position) { + mOption.setText(s); + } + } + +} diff --git a/app/src/main/java/com/stardust/widget/SimpleRecyclerViewAdapter.java b/app/src/main/java/com/stardust/widget/SimpleRecyclerViewAdapter.java new file mode 100644 index 00000000..87117611 --- /dev/null +++ b/app/src/main/java/com/stardust/widget/SimpleRecyclerViewAdapter.java @@ -0,0 +1,56 @@ +package com.stardust.widget; + +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Created by Stardust on 2017/5/24. + */ + +public class SimpleRecyclerViewAdapter> extends RecyclerView.Adapter { + + public interface ViewHolderFactory { + VH create(View itemView); + } + + private List mDataList = new ArrayList<>(); + private int mLayoutResource; + private ViewHolderFactory mVHViewHolderFactory; + + public SimpleRecyclerViewAdapter(int layoutResource, List dataList, ViewHolderFactory VHViewHolderFactory) { + mLayoutResource = layoutResource; + mVHViewHolderFactory = VHViewHolderFactory; + mDataList.addAll(dataList); + } + + public SimpleRecyclerViewAdapter(int layoutResource, ViewHolderFactory VHViewHolderFactory) { + this(layoutResource, Collections.emptyList(), VHViewHolderFactory); + } + + @Override + public VH onCreateViewHolder(ViewGroup parent, int viewType) { + return mVHViewHolderFactory.create(LayoutInflater.from(parent.getContext()).inflate(mLayoutResource, parent, false)); + } + + @Override + public void onBindViewHolder(VH holder, int position) { + M m = mDataList.get(position); + holder.bind(m, position); + } + + @Override + public int getItemCount() { + return mDataList.size(); + } + + public void add(M m) { + mDataList.add(m); + notifyItemInserted(mDataList.size() - 1); + } +} diff --git a/app/src/main/res/anim/item_hover.xml b/app/src/main/res/anim/item_hover.xml new file mode 100644 index 00000000..1110605d --- /dev/null +++ b/app/src/main/res/anim/item_hover.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bubble.xml b/app/src/main/res/drawable/bubble.xml new file mode 100644 index 00000000..f4e6edaa --- /dev/null +++ b/app/src/main/res/drawable/bubble.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/little_triangle.xml b/app/src/main/res/drawable/little_triangle.xml new file mode 100644 index 00000000..19650c1f --- /dev/null +++ b/app/src/main/res/drawable/little_triangle.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bubble_popup_menu.xml b/app/src/main/res/layout/bubble_popup_menu.xml new file mode 100644 index 00000000..55d605ca --- /dev/null +++ b/app/src/main/res/layout/bubble_popup_menu.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bubble_popup_menu_item.xml b/app/src/main/res/layout/bubble_popup_menu_item.xml new file mode 100644 index 00000000..3230c8b1 --- /dev/null +++ b/app/src/main/res/layout/bubble_popup_menu_item.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/floating_window_expand.xml b/app/src/main/res/layout/floating_window_expand.xml deleted file mode 100644 index b90bda5c..00000000 --- a/app/src/main/res/layout/floating_window_expand.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/node_info_view_header.xml b/app/src/main/res/layout/node_info_view_header.xml new file mode 100644 index 00000000..7a62c43c --- /dev/null +++ b/app/src/main/res/layout/node_info_view_header.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/node_info_view_item.xml b/app/src/main/res/layout/node_info_view_item.xml new file mode 100644 index 00000000..93231b84 --- /dev/null +++ b/app/src/main/res/layout/node_info_view_item.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/operation_dialog_item.xml b/app/src/main/res/layout/operation_dialog_item.xml new file mode 100644 index 00000000..f82975ac --- /dev/null +++ b/app/src/main/res/layout/operation_dialog_item.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 0764b0da..7f00b731 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -4,4 +4,5 @@ #00796B #536DFE #99444444 + #eef2f3f9 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a1b99127..258a1c59 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -184,6 +184,11 @@ 服务器地址 声明 关于项目与开发者 + 属性 + + 查看控件信息 + 在布局层次中查看 + 在布局范围中查看 diff --git a/app/src/main/res/xml/accessibility_service_config.xml b/app/src/main/res/xml/accessibility_service_config.xml index ea60b9a1..1dc081aa 100644 --- a/app/src/main/res/xml/accessibility_service_config.xml +++ b/app/src/main/res/xml/accessibility_service_config.xml @@ -1,8 +1,8 @@ mNotificationCallbacks = new CopyOnWriteArrayList<>(); private AccessibilityNodeInfo mRootInActiveWindow; @CallSuper @@ -32,7 +27,12 @@ public abstract class AccessibilityService extends android.accessibilityservice. @Override public AccessibilityNodeInfo getRootInActiveWindow() { - return mRootInActiveWindow; + try { + return super.getRootInActiveWindow(); + } catch (IllegalStateException ignored) { + return mRootInActiveWindow; + } } + } diff --git a/common/src/main/java/com/stardust/util/MessageIntent.java b/common/src/main/java/com/stardust/util/MessageIntent.java new file mode 100644 index 00000000..1d4e75ef --- /dev/null +++ b/common/src/main/java/com/stardust/util/MessageIntent.java @@ -0,0 +1,51 @@ +package com.stardust.util; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +import java.util.HashMap; + +/** + * Created by Stardust on 2017/6/27. + */ + +public class MessageIntent extends Intent { + + private HashMap mObjectExtras; + + public MessageIntent() { + } + + public MessageIntent(Intent o) { + super(o); + } + + public MessageIntent(String action) { + super(action); + } + + public MessageIntent(String action, Uri uri) { + super(action, uri); + } + + public MessageIntent(Context packageContext, Class cls) { + super(packageContext, cls); + } + + public MessageIntent(String action, Uri uri, Context packageContext, Class cls) { + super(action, uri, packageContext, cls); + } + + public MessageIntent putExtra(String key, Object value) { + if (mObjectExtras == null) { + mObjectExtras = new HashMap<>(); + } + mObjectExtras.put(key, value); + return this; + } + + public Object getObjectExtra(String key) { + return mObjectExtras.get(key); + } +}