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 2913178e..c0598ce2 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 139 + versionName "2.0.13 Alpha2" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { @@ -111,7 +111,7 @@ dependencies { // Android issue reporter (a github issue reporter) compile 'com.heinrichreimersoftware:android-issue-reporter:1.3.1' // - 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' @@ -129,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 51b863b2..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); } @@ -96,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(); @@ -142,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)); } }); } @@ -197,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 8577e02a..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 @@ -21,7 +21,7 @@ public class NodeInfo { private Rect mBoundsInScreen; public String id; - public CharSequence contentDesc; + public CharSequence desc; public CharSequence className; public CharSequence packageName; public CharSequence text; @@ -42,7 +42,7 @@ public class NodeInfo { public NodeInfo(AccessibilityNodeInfoCompat node) { id = simplifyId(node.getViewIdResourceName()); - contentDesc = node.getContentDescription(); + desc = node.getContentDescription(); className = node.getClassName(); packageName = node.getPackageName(); text = node.getText(); @@ -102,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/NodeInfoView.java b/app/src/main/java/com/stardust/scriptdroid/external/floatingwindow/menu/layout_inspector/view/NodeInfoView.java index de39a963..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 @@ -31,9 +31,10 @@ import butterknife.Optional; public class NodeInfoView extends RecyclerView { - private static final String[] FIELD_NAMES = {"id", + private static final String[] FIELD_NAMES = { + "id", "bounds", - "contentDesc", + "desc", "className", "packageName", "text", @@ -56,7 +57,7 @@ public class NodeInfoView extends RecyclerView { Arrays.sort(FIELD_NAMES); for (int i = 0; i < FIELD_NAMES.length; i++) { try { - FIELDS[i] = NodeInfo.class.getField(FIELD_NAMES[i]); + FIELDS[i] = NodeInfo.class.getDeclaredField(FIELD_NAMES[i]); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } @@ -92,10 +93,10 @@ public class NodeInfoView extends RecyclerView { } public void setNodeInfo(NodeInfo nodeInfo) { - for (int i = 1; i < FIELD_NAMES.length; i++) { + for (int i = 0; i < FIELDS.length; i++) { try { - Object value = FIELDS[i - 1].get(nodeInfo); - mData[i][1] = value == null ? "" : value.toString(); + Object value = FIELDS[i].get(nodeInfo); + mData[i + 1][1] = value == null ? "" : value.toString(); } catch (Exception e) { throw new RuntimeException(e); } 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 21cbe5ec..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,27 +40,51 @@ 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()); mNodeInfoDialog = new MaterialDialog.Builder(getContext()) .customView(mNodeInfoView, false) - .backgroundColor(0xddffffff) .theme(Theme.LIGHT) .build(); mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE); @@ -61,7 +94,7 @@ public class FloatingLayoutBoundsView extends LayoutBoundsView { @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 a0fd5294..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()) @@ -64,11 +100,12 @@ public class FloatingLayoutHierarchyView extends LayoutHierarchyView { @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/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/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/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 f8adc9fa..258a1c59 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -186,6 +186,9 @@ 关于项目与开发者 属性 + 查看控件信息 + 在布局层次中查看 + 在布局范围中查看 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); + } +}