Add: floating window, layout inspector
This commit is contained in:
@@ -2,20 +2,28 @@ package com.stardust.scriptdroid;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextPaint;
|
||||
import android.util.Log;
|
||||
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.scriptdroid.accessibility.AccessibilityInfoProvider;
|
||||
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
|
||||
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.tool.ViewTool;
|
||||
import com.stardust.scriptdroid.ui.error.ErrorReportActivity;
|
||||
import com.stardust.theme.ThemeColorManager;
|
||||
import com.stardust.util.CrashHandler;
|
||||
import com.stardust.util.StateObserver;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
@@ -23,6 +31,8 @@ import java.lang.ref.WeakReference;
|
||||
|
||||
public class App extends Application {
|
||||
|
||||
private static final String TAG = "App";
|
||||
|
||||
private static WeakReference<App> instance;
|
||||
private static StateObserver stateObserver;
|
||||
private static WeakReference<Activity> currentActivity;
|
||||
@@ -49,14 +59,15 @@ public class App extends Application {
|
||||
stateObserver = new StateObserver(PreferenceManager.getDefaultSharedPreferences(this));
|
||||
registerActivityLifecycleCallback();
|
||||
initAccessibilityServiceDelegates();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void initAccessibilityServiceDelegates() {
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(100, ActionPerformAccessibilityDelegate.class);
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(200, AccessibilityRecorderDelegate.getInstance());
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(300, BoundsAssistant.class);
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(300, AccessibilityEventCommandHost.instance);
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(400, AccessibilityInfoProvider.instance);
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(500, LayoutInspector.getInstance());
|
||||
|
||||
}
|
||||
|
||||
@@ -85,6 +96,10 @@ public class App extends Application {
|
||||
return currentActivity.get();
|
||||
}
|
||||
|
||||
public static String getResString(int id) {
|
||||
return getApp().getString(id);
|
||||
}
|
||||
|
||||
|
||||
private static class SimpleActivityLifecycleCallbacks implements ActivityLifecycleCallbacks {
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.stardust.scriptdroid.accessibility;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
public class AccessibilityInfoProvider implements AccessibilityDelegate {
|
||||
|
||||
public static AccessibilityInfoProvider instance = new AccessibilityInfoProvider();
|
||||
|
||||
private String mLatestPackage = "";
|
||||
private String mLatestActivity = "";
|
||||
|
||||
public synchronized String getLatestPackage() {
|
||||
return mLatestPackage;
|
||||
}
|
||||
|
||||
public synchronized String getLatestActivity() {
|
||||
return mLatestActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
setLatestComponent(event.getPackageName(), event.getClassName());
|
||||
return false;
|
||||
}
|
||||
|
||||
private synchronized void setLatestComponent(CharSequence latestPackage, CharSequence latestClass) {
|
||||
if (latestPackage == null)
|
||||
return;
|
||||
mLatestPackage = latestPackage.toString();
|
||||
if (latestClass == null)
|
||||
return;
|
||||
try {
|
||||
ComponentName componentName = new ComponentName(latestPackage.toString(), latestClass.toString());
|
||||
ActivityInfo activityInfo = App.getApp().getPackageManager().getActivityInfo(componentName, 0);
|
||||
mLatestActivity = activityInfo.name;
|
||||
} catch (PackageManager.NameNotFoundException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.stardust.scriptdroid.bounds_assist;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/4.
|
||||
*/
|
||||
|
||||
public interface BoundsAssistClipList {
|
||||
|
||||
interface OnClipChangedListener {
|
||||
void onClipRemove(int position);
|
||||
|
||||
void onClipInsert(int position);
|
||||
|
||||
void onChange();
|
||||
}
|
||||
|
||||
int size();
|
||||
|
||||
String get(int i);
|
||||
|
||||
void add(String clip);
|
||||
|
||||
void setOnClipChangedListener(OnClipChangedListener listener);
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package com.stardust.scriptdroid.bounds_assist;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.graphics.Rect;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.service.AccessibilityDelegate;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/4.
|
||||
*/
|
||||
|
||||
public class BoundsAssistant implements AccessibilityDelegate {
|
||||
|
||||
public static final String KEY_BOUNDS_ASSIST_ENABLE = "ASSIST_MODE_ENABLE";
|
||||
|
||||
private static boolean assistModeEnable;
|
||||
private static BoundsAssistClipList boundsAssistClipList = SharedPrefBoundsAssistClipList.getInstance();
|
||||
|
||||
public static boolean isAssistModeEnable() {
|
||||
return assistModeEnable;
|
||||
}
|
||||
|
||||
public static void setAssistModeEnable(boolean assistModeEnable) {
|
||||
if (assistModeEnable && Pref.isFirstEnableAssistMode()) {
|
||||
showAssistModeInfoDialog();
|
||||
}
|
||||
BoundsAssistant.assistModeEnable = assistModeEnable;
|
||||
App.getStateObserver().setState(KEY_BOUNDS_ASSIST_ENABLE, assistModeEnable);
|
||||
}
|
||||
|
||||
private static void showAssistModeInfoDialog() {
|
||||
new ThemeColorMaterialDialogBuilder(App.currentActivity())
|
||||
.title(R.string.text_alert)
|
||||
.content(R.string.assist_mode_notice)
|
||||
.positiveText(R.string.ok)
|
||||
.show();
|
||||
}
|
||||
|
||||
private static void performAssistance(AccessibilityEvent event) {
|
||||
if (!assistModeEnable) {
|
||||
return;
|
||||
}
|
||||
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED || event.getEventType() == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED) {
|
||||
AccessibilityNodeInfo nodeInfo = event.getSource();
|
||||
if (nodeInfo == null) {
|
||||
return;
|
||||
}
|
||||
nodeInfo.refresh();
|
||||
Rect rect = getBoundsInScreen(nodeInfo);
|
||||
saveAndAlertBounds(rect);
|
||||
nodeInfo.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
performAssistance(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Rect getBoundsInScreen(AccessibilityNodeInfo nodeInfo) {
|
||||
Rect rect = new Rect();
|
||||
nodeInfo.getBoundsInScreen(rect);
|
||||
return rect;
|
||||
}
|
||||
|
||||
private static void saveAndAlertBounds(Rect rect) {
|
||||
String str = boundsToString(rect);
|
||||
boundsAssistClipList.add(str);
|
||||
Toast.makeText(App.getApp(), str, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public static String boundsToString(Rect rect) {
|
||||
return rect.toString().replace('-', ',').replace(" ", "").substring(4);
|
||||
}
|
||||
|
||||
|
||||
static {
|
||||
assistModeEnable = PreferenceManager.getDefaultSharedPreferences(App.getApp()).getBoolean(KEY_BOUNDS_ASSIST_ENABLE, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package com.stardust.scriptdroid.bounds_assist;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.stardust.scriptdroid.App;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/4.
|
||||
*/
|
||||
|
||||
public class SharedPrefBoundsAssistClipList implements BoundsAssistClipList {
|
||||
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
|
||||
private static SharedPrefBoundsAssistClipList instance = new SharedPrefBoundsAssistClipList(App.getApp());
|
||||
private OnClipChangedListener mOnClipChangedListener;
|
||||
|
||||
public static SharedPrefBoundsAssistClipList getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static final int MAX_SIZE = 10;
|
||||
private static final String SHARED_PREF_NAME = "SharedPrefBoundsAssistClipList";
|
||||
private SharedPreferences mSharedPreferences;
|
||||
private List<String> mAssistClipList = new LinkedList<>();
|
||||
|
||||
public SharedPrefBoundsAssistClipList(Context context) {
|
||||
mSharedPreferences = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
|
||||
readFromSharedPref();
|
||||
}
|
||||
|
||||
private void readFromSharedPref() {
|
||||
Type type = new TypeToken<List<String>>() {
|
||||
}.getType();
|
||||
List<String> l = GSON.fromJson(mSharedPreferences.getString(SHARED_PREF_NAME, ""), type);
|
||||
if (l != null)
|
||||
mAssistClipList.addAll(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int size() {
|
||||
return mAssistClipList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String get(int i) {
|
||||
return mAssistClipList.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void add(String clip) {
|
||||
mAssistClipList.add(0, clip);
|
||||
notifyInsert();
|
||||
if (mAssistClipList.size() > MAX_SIZE) {
|
||||
mAssistClipList.remove(mAssistClipList.size() - 1);
|
||||
notifyRemove();
|
||||
}
|
||||
syncWithSharedPref();
|
||||
}
|
||||
|
||||
private void notifyRemove() {
|
||||
if (mOnClipChangedListener != null)
|
||||
mOnClipChangedListener.onClipRemove(mAssistClipList.size());
|
||||
}
|
||||
|
||||
private void notifyInsert() {
|
||||
if (mOnClipChangedListener != null) {
|
||||
mOnClipChangedListener.onClipInsert(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnClipChangedListener(OnClipChangedListener listener) {
|
||||
mOnClipChangedListener = listener;
|
||||
}
|
||||
|
||||
private void syncWithSharedPref() {
|
||||
mSharedPreferences.edit().putString(SHARED_PREF_NAME, GSON.toJson(mAssistClipList)).apply();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,21 +16,21 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionTarget;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.jraska.console.Console;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.Action;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionFactory;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionTarget;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.GetTextAction;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
import com.stardust.scriptdroid.service.AccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.tool.Shell;
|
||||
import com.stardust.scriptdroid.ui.console.ConsoleActivity;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import java.io.File;
|
||||
@@ -194,7 +194,7 @@ public class DroidRuntime {
|
||||
errorMessage = App.getApp().getString(R.string.text_auto_operate_service_enabled_but_not_running);
|
||||
} else {
|
||||
if (Pref.def().getBoolean(App.getApp().getString(R.string.key_enable_accessibility_service_by_root), false)) {
|
||||
if (!AccessibilityServiceUtils.enableAccessibilityServiceByRootAndWaitFor(App.getApp(), AccessibilityWatchDogService.class, 3000)) {
|
||||
if (!AccessibilityServiceTool.enableAccessibilityServiceByRootAndWaitFor(AccessibilityWatchDogService.class, 3000)) {
|
||||
errorMessage = App.getApp().getString(R.string.text_enable_accessibility_service_by_root_timeout);
|
||||
}
|
||||
} else {
|
||||
@@ -208,10 +208,6 @@ public class DroidRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getTexts() {
|
||||
return performAction(new GetTextAction());
|
||||
}
|
||||
|
||||
public void toast(final String text) {
|
||||
mUIHandler.post(new Runnable() {
|
||||
@Override
|
||||
@@ -229,16 +225,10 @@ public class DroidRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
public void addAccessibilityDelegate(final Object delegate) {
|
||||
public void addAccessibilityEventListener(final Object delegate) {
|
||||
if (delegate == null)
|
||||
return;
|
||||
AccessibilityWatchDogService.addDelegate(new AccessibilityDelegate() {
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
public Shell.CommandResult shell(String cmd, int root) {
|
||||
@@ -255,6 +245,10 @@ public class DroidRuntime {
|
||||
return ActionPerformAccessibilityDelegate.getLatestActivity();
|
||||
}
|
||||
|
||||
public UiSelector selector() {
|
||||
return new UiSelector();
|
||||
}
|
||||
|
||||
public boolean isStopped() {
|
||||
return Thread.currentThread().isInterrupted();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
package com.stardust.scriptdroid.droid.runtime;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.bezyapps.floatieslibrary.Floaty;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.automator.ActionArgument;
|
||||
import com.stardust.automator.UiGlobalSelector;
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.automator.UiObjectCollection;
|
||||
import com.stardust.automator.filter.DfsFilter;
|
||||
import com.stardust.scriptdroid.accessibility.AccessibilityInfoProvider;
|
||||
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLICK;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_COLLAPSE;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_COPY;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CUT;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_DISMISS;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_EXPAND;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_FOCUS;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_LONG_CLICK;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_PASTE;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SELECT;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SET_SELECTION;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SET_TEXT;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
public class UiSelector extends UiGlobalSelector {
|
||||
|
||||
private class FindCommand implements AccessibilityEventCommandHost.Command {
|
||||
|
||||
UiObjectCollection result;
|
||||
|
||||
@Override
|
||||
public void execute(AccessibilityService service, AccessibilityEvent event) {
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root != null) {
|
||||
result = findOf(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String TAG = "UiSelector";
|
||||
|
||||
public UiObjectCollection find() {
|
||||
FindCommand command = new FindCommand();
|
||||
AccessibilityEventCommandHost.instance.executeAndWaitForEvent(command);
|
||||
return command.result;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public UiObjectCollection untilFind() {
|
||||
UiObjectCollection uiObjectCollection;
|
||||
do {
|
||||
uiObjectCollection = find();
|
||||
} while (uiObjectCollection == null || uiObjectCollection.size() == 0);
|
||||
return uiObjectCollection;
|
||||
}
|
||||
|
||||
public UiObject findOne() {
|
||||
UiObjectCollection collection = find();
|
||||
if (collection == null || collection.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
return new UiObject(collection.get(0).getInfo());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public UiObject untilFindOne() {
|
||||
UiObjectCollection collection = untilFind();
|
||||
return new UiObject(collection.get(0).getInfo());
|
||||
}
|
||||
|
||||
public UiSelector id(final String id) {
|
||||
if (!id.contains(":")) {
|
||||
addFilter(new DfsFilter() {
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
String fullId = AccessibilityInfoProvider.instance.getLatestPackage() + ":id/" + id;
|
||||
return fullId.equals(nodeInfo.getViewIdResourceName());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
super.id(id);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public boolean performAction(int action, ActionArgument... arguments) {
|
||||
return untilFind().performAction(action, arguments);
|
||||
}
|
||||
|
||||
public boolean click() {
|
||||
return performAction(ACTION_CLICK);
|
||||
}
|
||||
|
||||
public boolean longClick() {
|
||||
return performAction(ACTION_LONG_CLICK);
|
||||
}
|
||||
|
||||
public boolean accessibilityFocus() {
|
||||
return performAction(ACTION_ACCESSIBILITY_FOCUS);
|
||||
}
|
||||
|
||||
public boolean clearAccessibilityFocus() {
|
||||
return performAction(ACTION_CLEAR_ACCESSIBILITY_FOCUS);
|
||||
}
|
||||
|
||||
public boolean focus() {
|
||||
return performAction(ACTION_FOCUS);
|
||||
}
|
||||
|
||||
public boolean clearFocus() {
|
||||
return performAction(ACTION_CLEAR_FOCUS);
|
||||
}
|
||||
|
||||
public boolean copy() {
|
||||
return performAction(ACTION_COPY);
|
||||
}
|
||||
|
||||
public boolean paste() {
|
||||
return performAction(ACTION_PASTE);
|
||||
}
|
||||
|
||||
public boolean select() {
|
||||
return performAction(ACTION_SELECT);
|
||||
}
|
||||
|
||||
public boolean cut() {
|
||||
return performAction(ACTION_CUT);
|
||||
}
|
||||
|
||||
public boolean collapse() {
|
||||
return performAction(ACTION_COLLAPSE);
|
||||
}
|
||||
|
||||
public boolean expand() {
|
||||
return performAction(ACTION_EXPAND);
|
||||
}
|
||||
|
||||
public boolean dismiss() {
|
||||
return performAction(ACTION_DISMISS);
|
||||
}
|
||||
|
||||
public boolean show() {
|
||||
return performAction(ACTION_SHOW_ON_SCREEN.getId());
|
||||
}
|
||||
|
||||
public boolean scrollForward() {
|
||||
return performAction(ACTION_SCROLL_FORWARD);
|
||||
}
|
||||
|
||||
public boolean scrollBackward() {
|
||||
return performAction(ACTION_SCROLL_BACKWARD);
|
||||
}
|
||||
|
||||
public boolean scrollUp() {
|
||||
return performAction(ACTION_SCROLL_UP.getId());
|
||||
}
|
||||
|
||||
public boolean scrollDown() {
|
||||
return performAction(ACTION_SCROLL_DOWN.getId());
|
||||
}
|
||||
|
||||
public boolean scrollLeft() {
|
||||
return performAction(ACTION_SCROLL_LEFT.getId());
|
||||
}
|
||||
|
||||
public boolean scrollRight() {
|
||||
return performAction(ACTION_SCROLL_RIGHT.getId());
|
||||
}
|
||||
|
||||
public boolean contextClick() {
|
||||
return performAction(ACTION_CONTEXT_CLICK.getId());
|
||||
}
|
||||
|
||||
public boolean setSelection(int s, int e) {
|
||||
return performAction(ACTION_SET_SELECTION,
|
||||
new ActionArgument.IntActionArgument(ACTION_ARGUMENT_SELECTION_START_INT, s),
|
||||
new ActionArgument.IntActionArgument(ACTION_ARGUMENT_SELECTION_END_INT, e));
|
||||
}
|
||||
|
||||
public boolean setText(String text) {
|
||||
return performAction(ACTION_SET_TEXT,
|
||||
new ActionArgument.CharSequenceActionArgument(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text));
|
||||
}
|
||||
|
||||
public boolean setProgress(float value) {
|
||||
return performAction(ACTION_SET_PROGRESS.getId(),
|
||||
new ActionArgument.FloatActionArgument(ACTION_ARGUMENT_PROGRESS_VALUE, value));
|
||||
}
|
||||
|
||||
public boolean scrollTo(int row, int column) {
|
||||
return performAction(ACTION_SCROLL_TO_POSITION.getId(),
|
||||
new ActionArgument.IntActionArgument(ACTION_ARGUMENT_ROW_INT, row),
|
||||
new ActionArgument.IntActionArgument(ACTION_ARGUMENT_COLUMN_INT, column));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import com.stardust.util.SparseArrayEntries;
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Able {
|
||||
|
||||
SparseArray<Able> ABLE_MAP = new SparseArrayEntries<Able>()
|
||||
|
||||
@@ -10,7 +10,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.service.AccessibilityDelegate;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
|
||||
/**
|
||||
@@ -50,6 +50,7 @@ public class ActionPerformAccessibilityDelegate implements AccessibilityDelegate
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root == null) {
|
||||
Log.v(TAG, "root = null");
|
||||
return false;
|
||||
}
|
||||
Log.i(TAG, "perform action:" + action);
|
||||
if (action.perform(root)) {
|
||||
|
||||
@@ -33,8 +33,7 @@ public abstract class JavaScriptEngine {
|
||||
try {
|
||||
return FileUtils.readString(App.getApp().getAssets().open("javasccript_engine_init.js"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return "Error: Unable to read init script.";
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.stardust.scriptdroid.droid.script;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.droid.runtime.ScriptStopException;
|
||||
|
||||
@@ -58,10 +58,10 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
||||
private void init(Context context, Scriptable scope) {
|
||||
ScriptableObject.putProperty(scope, "context", App.getApp());
|
||||
ScriptableObject.putProperty(scope, "__engine__", "rhino");
|
||||
context.evaluateString(scope, Init.getInitScript(), "<init>", 1, null);
|
||||
for (Map.Entry<String, Object> variable : mVariableMap.entrySet()) {
|
||||
ScriptableObject.putProperty(scope, variable.getKey(), variable.getValue());
|
||||
}
|
||||
context.evaluateString(scope, Init.getInitScript(), "<init>", 1, null);
|
||||
mThreads.add(Thread.currentThread());
|
||||
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.droid.RunningConfig;
|
||||
|
||||
import static com.stardust.scriptdroid.droid.Droid.JAVA_SCRIPT_ENGINE;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/5.
|
||||
*/
|
||||
@@ -43,9 +41,9 @@ public class ScriptExecuteActivity extends Activity {
|
||||
}
|
||||
|
||||
private void runScript() {
|
||||
JAVA_SCRIPT_ENGINE.set("activity", this);
|
||||
Droid.JAVA_SCRIPT_ENGINE.set("activity", this);
|
||||
try {
|
||||
mResult = JAVA_SCRIPT_ENGINE.execute(mScript);
|
||||
mResult = Droid.JAVA_SCRIPT_ENGINE.execute(mScript);
|
||||
} catch (Exception e) {
|
||||
mOnRunFinishedListener.onException(e);
|
||||
finish();
|
||||
@@ -61,7 +59,7 @@ public class ScriptExecuteActivity extends Activity {
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
JAVA_SCRIPT_ENGINE.set("activity", null);
|
||||
JAVA_SCRIPT_ENGINE.removeAndDestroy();
|
||||
Droid.JAVA_SCRIPT_ENGINE.set("activity", null);
|
||||
Droid.JAVA_SCRIPT_ENGINE.removeAndDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package com.stardust.scriptdroid.droid.script.file;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
32
app/src/main/java/com/stardust/scriptdroid/external/floating_window/FloatingWindowManger.java
vendored
Normal file
32
app/src/main/java/com/stardust/scriptdroid/external/floating_window/FloatingWindowManger.java
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package com.stardust.scriptdroid.external.floating_window;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.layout_inspector.view.LayoutInspectView;
|
||||
import com.stardust.view.Floaty;
|
||||
import com.stardust.view.ResizableFloaty;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class FloatingWindowManger {
|
||||
|
||||
public static void showFloatingWindow() {
|
||||
if (!HoverMenuService.isServiceRunning())
|
||||
App.getApp().startService(new Intent(App.getApp(), HoverMenuService.class));
|
||||
}
|
||||
|
||||
public static boolean isFloatingWindowShowing() {
|
||||
return HoverMenuService.isServiceRunning();
|
||||
}
|
||||
|
||||
|
||||
public static void hideFloatingWindow() {
|
||||
if (HoverMenuService.isServiceRunning())
|
||||
HoverMenuService.stopService();
|
||||
}
|
||||
}
|
||||
214
app/src/main/java/com/stardust/scriptdroid/external/floating_window/HoverMenuAdapter.java
vendored
Normal file
214
app/src/main/java/com/stardust/scriptdroid/external/floating_window/HoverMenuAdapter.java
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
package com.stardust.scriptdroid.external.floating_window;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floating_window.content.MainMenuNavigatorContent;
|
||||
import com.stardust.scriptdroid.external.floating_window.content.RecordNavigatorContent;
|
||||
import com.stardust.scriptdroid.external.floating_window.content.ScritpListNavigatorContent;
|
||||
import com.stardust.theme.ThemeColorManagerCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import io.mattcarroll.hover.NavigatorContent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/11.
|
||||
*/
|
||||
|
||||
public class HoverMenuAdapter implements io.mattcarroll.hover.HoverMenuAdapter {
|
||||
|
||||
|
||||
public static final String ID_MAIN = "intro";
|
||||
public static final String ID_RECORD = "record";
|
||||
public static final String ID_SCRIPT_LIST = "script_list";
|
||||
public static final String MENU_ID = "menu";
|
||||
public static final String PLACEHOLDER_ID = "placeholder";
|
||||
|
||||
private final Context mContext;
|
||||
private final List<String> mTabIds;
|
||||
private final Map<String, NavigatorContent> mData = new LinkedHashMap<>();
|
||||
private final Set<ContentChangeListener> mContentChangeListeners = new HashSet<>();
|
||||
private View[] mViews;
|
||||
|
||||
public HoverMenuAdapter(@NonNull Context context) {
|
||||
mContext = context;
|
||||
|
||||
mData.put(HoverMenuAdapter.ID_MAIN, new MainMenuNavigatorContent(context));
|
||||
mData.put(HoverMenuAdapter.ID_RECORD, new RecordNavigatorContent(context));
|
||||
mData.put(HoverMenuAdapter.ID_SCRIPT_LIST, new ScritpListNavigatorContent(context));
|
||||
|
||||
mTabIds = new ArrayList<>();
|
||||
for (String tabId : mData.keySet()) {
|
||||
mTabIds.add(tabId);
|
||||
}
|
||||
mViews = new View[mTabIds.size()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTabCount() {
|
||||
return mTabIds.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getTabView(int index) {
|
||||
mViews[index] = getTabViewInner(index);
|
||||
return mViews[index];
|
||||
}
|
||||
|
||||
private View getTabViewInner(int index) {
|
||||
String menuItemId = mTabIds.get(index);
|
||||
if (ID_MAIN.equals(menuItemId)) {
|
||||
return createTabView(R.drawable.ic_android_eat_js);
|
||||
} else if (ID_RECORD.equals(menuItemId)) {
|
||||
return createTabView(R.drawable.ic_video_record);
|
||||
} else if (ID_SCRIPT_LIST.equals(menuItemId)) {
|
||||
return createTabView(R.drawable.ic_menu);
|
||||
} else {
|
||||
throw new RuntimeException("Unknown tab selected: " + index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTabId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigatorContent getNavigatorContent(int index) {
|
||||
String tabId = mTabIds.get(index);
|
||||
return mData.get(tabId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addContentChangeListener(@NonNull ContentChangeListener listener) {
|
||||
mContentChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeContentChangeListener(@NonNull ContentChangeListener listener) {
|
||||
mContentChangeListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void selectTab(String id) {
|
||||
int i = mTabIds.indexOf(id);
|
||||
mViews[i].performClick();
|
||||
}
|
||||
|
||||
protected void notifyDataSetChanged() {
|
||||
for (ContentChangeListener listener : mContentChangeListeners) {
|
||||
listener.onContentChange(this);
|
||||
}
|
||||
}
|
||||
|
||||
private View createTabView(@DrawableRes int tabBitmapRes) {
|
||||
return createTabView(tabBitmapRes, ThemeColorManagerCompat.getColorPrimary(), Color.WHITE);
|
||||
}
|
||||
|
||||
private View createTabView(@DrawableRes int tabBitmapRes, @ColorInt int backgroundColor, @ColorInt Integer iconColor) {
|
||||
Resources resources = mContext.getResources();
|
||||
int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, resources.getDisplayMetrics());
|
||||
|
||||
DemoTabView view = new DemoTabView(mContext, resources.getDrawable(R.drawable.tab_background), resources.getDrawable(tabBitmapRes));
|
||||
view.setTabBackgroundColor(backgroundColor);
|
||||
view.setTabForegroundColor(iconColor);
|
||||
view.setPadding(padding, padding, padding, padding);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setElevation(padding);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
public class DemoTabView extends View {
|
||||
|
||||
private int mBackgroundColor;
|
||||
private Integer mForegroundColor;
|
||||
|
||||
private Drawable mCircleDrawable;
|
||||
private Drawable mIconDrawable;
|
||||
private int mIconInsetLeft, mIconInsetTop, mIconInsetRight, mIconInsetBottom;
|
||||
|
||||
public DemoTabView(Context context, Drawable backgroundDrawable, Drawable iconDrawable) {
|
||||
super(context);
|
||||
mCircleDrawable = backgroundDrawable;
|
||||
mIconDrawable = iconDrawable;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
int insetsDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getContext().getResources().getDisplayMetrics());
|
||||
mIconInsetLeft = mIconInsetTop = mIconInsetRight = mIconInsetBottom = insetsDp;
|
||||
}
|
||||
|
||||
public void setTabBackgroundColor(@ColorInt int backgroundColor) {
|
||||
mBackgroundColor = backgroundColor;
|
||||
mCircleDrawable.setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
public void setTabForegroundColor(@ColorInt Integer foregroundColor) {
|
||||
mForegroundColor = foregroundColor;
|
||||
if (null != mForegroundColor) {
|
||||
mIconDrawable.setColorFilter(mForegroundColor, PorterDuff.Mode.SRC_ATOP);
|
||||
} else {
|
||||
mIconDrawable.setColorFilter(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIcon(@Nullable Drawable icon) {
|
||||
mIconDrawable = icon;
|
||||
if (null != mForegroundColor && null != mIconDrawable) {
|
||||
mIconDrawable.setColorFilter(mForegroundColor, PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
updateIconBounds();
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
// Make circle as large as View minus padding.
|
||||
mCircleDrawable.setBounds(getPaddingLeft(), getPaddingTop(), w - getPaddingRight(), h - getPaddingBottom());
|
||||
|
||||
// Re-size the icon as necessary.
|
||||
updateIconBounds();
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void updateIconBounds() {
|
||||
if (null != mIconDrawable) {
|
||||
Rect bounds = new Rect(mCircleDrawable.getBounds());
|
||||
bounds.set(bounds.left + mIconInsetLeft, bounds.top + mIconInsetTop, bounds.right - mIconInsetRight, bounds.bottom - mIconInsetBottom);
|
||||
mIconDrawable.setBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
mCircleDrawable.draw(canvas);
|
||||
if (null != mIconDrawable) {
|
||||
mIconDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
191
app/src/main/java/com/stardust/scriptdroid/external/floating_window/HoverMenuService.java
vendored
Normal file
191
app/src/main/java/com/stardust/scriptdroid/external/floating_window/HoverMenuService.java
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
package com.stardust.scriptdroid.external.floating_window;
|
||||
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.stardust.hover.HoverMenuBuilder;
|
||||
import com.stardust.hover.SimpleHoverMenuTransitionListener;
|
||||
import com.stardust.hover.WindowHoverMenu;
|
||||
import com.stardust.scriptdroid.external.floating_window.view.FloatingLayoutBoundsView;
|
||||
import com.stardust.scriptdroid.external.floating_window.view.FloatingLayoutHierarchyView;
|
||||
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.theme.ThemeColorManagerCompat;
|
||||
import com.stardust.util.MessageEvent;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import io.mattcarroll.hover.HoverMenu;
|
||||
import io.mattcarroll.hover.defaulthovermenu.window.WindowViewController;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/11.
|
||||
*/
|
||||
|
||||
public class HoverMenuService extends Service {
|
||||
|
||||
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";
|
||||
|
||||
private static WeakReference<HoverMenuService> service;
|
||||
|
||||
public static boolean isServiceRunning() {
|
||||
return service != null && service.get() != null;
|
||||
}
|
||||
|
||||
public static void stopService() {
|
||||
if (isServiceRunning()) {
|
||||
service.get().stopSelf();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final String TAG = "HoverMenuService";
|
||||
|
||||
private static final String PREF_FILE = "hover_menu";
|
||||
private static final String PREF_HOVER_MENU_VISUAL_STATE = "hover_menu_visual_state";
|
||||
|
||||
private boolean mIsRunning;
|
||||
private SharedPreferences mPrefs;
|
||||
|
||||
private WindowViewController mWindowViewController;
|
||||
|
||||
private FloatingLayoutHierarchyView mFloatingLayoutHierarchyView;
|
||||
private FloatingLayoutBoundsView mFloatingLayoutBoundsView;
|
||||
|
||||
private WindowHoverMenu mWindowHoverMenu;
|
||||
private HoverMenu.OnExitListener mWindowHoverMenuMenuExitListener = new HoverMenu.OnExitListener() {
|
||||
@Override
|
||||
public void onExitByUserRequest() {
|
||||
savePreferredLocation();
|
||||
mWindowHoverMenu.hide();
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
if (isServiceRunning()) {
|
||||
stopSelf();
|
||||
} else {
|
||||
service = new WeakReference<>(this);
|
||||
}
|
||||
EventBus.getDefault().register(this);
|
||||
mPrefs = getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
|
||||
initViews();
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
mFloatingLayoutHierarchyView = new FloatingLayoutHierarchyView(this);
|
||||
mFloatingLayoutBoundsView = new FloatingLayoutBoundsView(this);
|
||||
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(this)
|
||||
.displayWithinWindow()
|
||||
.useAdapter(new HoverMenuAdapter(this))
|
||||
.restoreVisualState(loadPreferredLocation())
|
||||
.build();
|
||||
mWindowHoverMenu.getHoverMenuView().setContentBackgroundColor(ThemeColorManagerCompat.getColorPrimary());
|
||||
mWindowHoverMenu.addOnExitListener(mWindowHoverMenuMenuExitListener);
|
||||
mWindowViewController = mWindowHoverMenu.getWindowViewController();
|
||||
mWindowHoverMenu.setHoverMenuTransitionListener(new SimpleHoverMenuTransitionListener() {
|
||||
@Override
|
||||
public void onExpanding() {
|
||||
captureCurrentWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCollapsing() {
|
||||
LayoutInspector.getInstance().clearCapture();
|
||||
EventBus.getDefault().post(new MessageEvent(MESSAGE_MENU_COLLAPSING));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void captureCurrentWindow() {
|
||||
NodeInfo nodeInfo = LayoutInspector.getInstance().captureCurrentWindow();
|
||||
if (nodeInfo == null)
|
||||
return;
|
||||
mFloatingLayoutHierarchyView.setRootNode(nodeInfo);
|
||||
mFloatingLayoutBoundsView.setRootNode(nodeInfo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (!mIsRunning) {
|
||||
mIsRunning = true;
|
||||
mWindowHoverMenu.show();
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
mWindowHoverMenu.hide();
|
||||
mIsRunning = false;
|
||||
if (isServiceRunning() && service.get() == this)
|
||||
service.clear();
|
||||
}
|
||||
|
||||
|
||||
private void savePreferredLocation() {
|
||||
String memento = mWindowHoverMenu.getVisualState();
|
||||
mPrefs.edit().putString(PREF_HOVER_MENU_VISUAL_STATE, memento).apply();
|
||||
}
|
||||
|
||||
private String loadPreferredLocation() {
|
||||
return mPrefs.getString(PREF_HOVER_MENU_VISUAL_STATE, null);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMessageEvent(MessageEvent event) {
|
||||
switch (event.message) {
|
||||
case MESSAGE_SHOW_AND_EXPAND_MENU:
|
||||
mWindowHoverMenu.show();
|
||||
break;
|
||||
case MESSAGE_SHOW_LAYOUT_HIERARCHY:
|
||||
mWindowHoverMenu.hide();
|
||||
showView(mFloatingLayoutHierarchyView);
|
||||
break;
|
||||
case MESSAGE_SHOW_LAYOUT_BOUNDS:
|
||||
mWindowHoverMenu.hide();
|
||||
showView(mFloatingLayoutBoundsView);
|
||||
break;
|
||||
case MESSAGE_COLLAPSE_MENU:
|
||||
mWindowHoverMenu.collapseMenu();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void showView(View view) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
mWindowViewController.makeTouchable(view);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.stardust.scriptdroid.external.floating_window.content;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
|
||||
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
|
||||
import com.stardust.util.MessageEvent;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import io.mattcarroll.hover.Navigator;
|
||||
import io.mattcarroll.hover.NavigatorContent;
|
||||
import io.mattcarroll.hover.defaulthovermenu.menus.Menu;
|
||||
import io.mattcarroll.hover.defaulthovermenu.menus.MenuAction;
|
||||
import io.mattcarroll.hover.defaulthovermenu.menus.MenuItem;
|
||||
import io.mattcarroll.hover.defaulthovermenu.menus.MenuListNavigatorContent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/12.
|
||||
*/
|
||||
|
||||
public class MainMenuNavigatorContent implements NavigatorContent {
|
||||
|
||||
|
||||
private View mView;
|
||||
|
||||
|
||||
public MainMenuNavigatorContent(Context context) {
|
||||
mView = View.inflate(context, R.layout.floating_window_main_menu, null);
|
||||
ViewBinder.bind(this);
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.layout_hierarchy)
|
||||
private void showLayoutHierarchy() {
|
||||
if (LayoutInspector.getInstance().getCapture() == null) {
|
||||
Toast.makeText(mView.getContext(), R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_HIERARCHY));
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.layout_bounds)
|
||||
private void showLayoutBounds() {
|
||||
if (LayoutInspector.getInstance().getCapture() == null) {
|
||||
Toast.makeText(mView.getContext(), R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_BOUNDS));
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(@NonNull Navigator navigator) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHidden() {
|
||||
|
||||
}
|
||||
|
||||
public View findViewById(int id) {
|
||||
return mView.findViewById(id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.stardust.scriptdroid.external.floating_window.content;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
import io.mattcarroll.hover.Navigator;
|
||||
import io.mattcarroll.hover.NavigatorContent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/12.
|
||||
*/
|
||||
|
||||
public class RecordNavigatorContent implements NavigatorContent {
|
||||
|
||||
private View mView;
|
||||
|
||||
public RecordNavigatorContent(Context context) {
|
||||
mView = new View(context);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(@NonNull Navigator navigator) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHidden() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.stardust.scriptdroid.external.floating_window.content;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
|
||||
import com.stardust.scriptdroid.external.floating_window.view.FloatingScriptFileListView;
|
||||
|
||||
import io.mattcarroll.hover.Navigator;
|
||||
import io.mattcarroll.hover.NavigatorContent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/12.
|
||||
*/
|
||||
|
||||
public class ScritpListNavigatorContent implements NavigatorContent {
|
||||
|
||||
private FloatingScriptFileListView mFloatingScriptFileListView;
|
||||
|
||||
public ScritpListNavigatorContent(Context context) {
|
||||
mFloatingScriptFileListView = new FloatingScriptFileListView(new ContextThemeWrapper(context, R.style.AppTheme));
|
||||
mFloatingScriptFileListView.setScriptFileList(SharedPrefScriptFileList.getInstance());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView() {
|
||||
return mFloatingScriptFileListView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(@NonNull Navigator navigator) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHidden() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.stardust.scriptdroid.external.floating_window.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.Theme;
|
||||
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.scriptdroid.layout_inspector.view.LayoutBoundsView;
|
||||
import com.stardust.scriptdroid.layout_inspector.view.NodeInfoView;
|
||||
import com.stardust.scriptdroid.layout_inspector.view.OnNodeInfoSelectListener;
|
||||
import com.stardust.util.MessageEvent;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/12.
|
||||
*/
|
||||
|
||||
public class FloatingLayoutBoundsView extends LayoutBoundsView {
|
||||
|
||||
private MaterialDialog mNodeInfoDialog;
|
||||
private NodeInfoView mNodeInfoView;
|
||||
|
||||
public FloatingLayoutBoundsView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setOnNodeInfoSelectListener(new OnNodeInfoSelectListener() {
|
||||
@Override
|
||||
public void onNodeSelect(NodeInfo info) {
|
||||
showNodeInfo(info);
|
||||
}
|
||||
});
|
||||
setBackgroundColor(0x66000000);
|
||||
setVisibility(GONE);
|
||||
getPaint().setColor(0xFF222222);
|
||||
getPaint().setStrokeWidth(2f);
|
||||
}
|
||||
|
||||
|
||||
private void showNodeInfo(NodeInfo info) {
|
||||
ensureDialog();
|
||||
mNodeInfoView.setNodeInfo(info);
|
||||
mNodeInfoDialog.show();
|
||||
}
|
||||
|
||||
private void ensureDialog() {
|
||||
if (mNodeInfoDialog == null) {
|
||||
mNodeInfoView = new NodeInfoView(getContext());
|
||||
mNodeInfoDialog = new MaterialDialog.Builder(getContext())
|
||||
.customView(mNodeInfoView, false)
|
||||
.theme(Theme.LIGHT)
|
||||
.build();
|
||||
mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_SHOW_AND_EXPAND_MENU));
|
||||
setVisibility(GONE);
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.stardust.scriptdroid.external.floating_window.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.Theme;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.scriptdroid.layout_inspector.view.LayoutHierarchyView;
|
||||
import com.stardust.scriptdroid.layout_inspector.view.NodeInfoView;
|
||||
import com.stardust.scriptdroid.layout_inspector.view.OnNodeInfoSelectListener;
|
||||
import com.stardust.util.MessageEvent;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/12.
|
||||
*/
|
||||
|
||||
public class FloatingLayoutHierarchyView extends LayoutHierarchyView {
|
||||
|
||||
private static final String TAG = "FloatingHierarchyView";
|
||||
|
||||
private MaterialDialog mNodeInfoDialog;
|
||||
private NodeInfoView mNodeInfoView;
|
||||
|
||||
public FloatingLayoutHierarchyView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setBackgroundColor(0x99ffffff);
|
||||
setVisibility(GONE);
|
||||
setShowClickedNodeBounds(true);
|
||||
getBoundsPaint().setStrokeWidth(3);
|
||||
getBoundsPaint().setColor(0xFFD32F2F);
|
||||
setOnNodeInfoLongClickListener(new OnNodeInfoSelectListener() {
|
||||
@Override
|
||||
public void onNodeSelect(NodeInfo info) {
|
||||
showNodeInfo(info);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showNodeInfo(NodeInfo info) {
|
||||
ensureDialog();
|
||||
mNodeInfoView.setNodeInfo(info);
|
||||
mNodeInfoDialog.show();
|
||||
}
|
||||
|
||||
private void ensureDialog() {
|
||||
if (mNodeInfoDialog == null) {
|
||||
mNodeInfoView = new NodeInfoView(getContext());
|
||||
mNodeInfoDialog = new MaterialDialog.Builder(getContext())
|
||||
.customView(mNodeInfoView, false)
|
||||
.theme(Theme.LIGHT)
|
||||
.build();
|
||||
mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_SHOW_AND_EXPAND_MENU));
|
||||
setVisibility(GONE);
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
package com.stardust.scriptdroid.external.floating_window.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.DividerItemDecoration;
|
||||
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.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
|
||||
import com.stardust.scriptdroid.tool.ViewTool;
|
||||
import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperation;
|
||||
import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperationPopupMenu;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.util.MessageEvent;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/12.
|
||||
*/
|
||||
|
||||
public class FloatingScriptFileListView extends RecyclerView {
|
||||
|
||||
|
||||
private ScriptFileList mScriptFileList;
|
||||
|
||||
private final OnClickListener mOnItemClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
onItemClicked(v, position);
|
||||
}
|
||||
};
|
||||
|
||||
private final OnClickListener mOnEditIconClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder((View) v.getParent()).getAdapterPosition();
|
||||
onEditIconClick(v, position);
|
||||
}
|
||||
};
|
||||
|
||||
private final OnClickListener mOnMoreIconClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mOperateFileIndex = getChildViewHolder((View) v.getParent()).getAdapterPosition();
|
||||
showOrDismissOperationPopupMenu(v);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private ScriptFileOperationPopupMenu mScriptFileOperationPopupMenu;
|
||||
private int mOperateFileIndex;
|
||||
|
||||
public FloatingScriptFileListView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setAdapter(new Adapter());
|
||||
setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));
|
||||
initScriptFileOperationPopupMenu();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void showMessage(ScriptFileOperation.ShowMessageEvent event) {
|
||||
Toast.makeText(getContext(), event.messageResId, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private void initScriptFileOperationPopupMenu() {
|
||||
mScriptFileOperationPopupMenu = new ScriptFileOperationPopupMenu(getContext(), getScriptFileOperations());
|
||||
mScriptFileOperationPopupMenu.setOnItemClickListener(new ScriptFileOperationPopupMenu.OnItemClickListener() {
|
||||
@Override
|
||||
public void onClick(View view, int position, ScriptFileOperation operation) {
|
||||
operation.operate(FloatingScriptFileListView.this, mScriptFileList, mOperateFileIndex);
|
||||
mScriptFileOperationPopupMenu.dismiss();
|
||||
if (!(operation instanceof ScriptFileOperation.Rename))
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected List<ScriptFileOperation> getScriptFileOperations() {
|
||||
List<ScriptFileOperation> scriptFileOperations = new ArrayList<>();
|
||||
scriptFileOperations.add(new ScriptFileOperation.Run());
|
||||
scriptFileOperations.add(new ScriptFileOperation.Rename() {
|
||||
@Override
|
||||
public void operate(final RecyclerView recyclerView, final ScriptFileList scriptFileList, final int position) {
|
||||
String oldName = scriptFileList.get(position).name;
|
||||
MaterialDialog dialog = new ThemeColorMaterialDialogBuilder(recyclerView.getContext())
|
||||
.title(R.string.text_rename)
|
||||
.checkBoxPrompt(App.getApp().getString(R.string.text_rename_file_meanwhile), false, null)
|
||||
.input(App.getApp().getString(R.string.text_please_input_new_name), oldName, new MaterialDialog.InputCallback() {
|
||||
@Override
|
||||
public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {
|
||||
scriptFileList.rename(position, input.toString(), dialog.isPromptCheckBoxChecked());
|
||||
recyclerView.getAdapter().notifyItemChanged(position);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
scriptFileOperations.add(new ScriptFileOperation.OpenByOtherApp());
|
||||
scriptFileOperations.add(new ScriptFileOperation.CreateShortcut());
|
||||
scriptFileOperations.add(new ScriptFileOperation.Remove());
|
||||
scriptFileOperations.add(new ScriptFileOperation.Delete());
|
||||
return scriptFileOperations;
|
||||
}
|
||||
|
||||
protected void onItemClicked(View v, int position) {
|
||||
new ScriptFileOperation.Run().operate(this, mScriptFileList, position);
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
protected void onEditIconClick(View v, int position) {
|
||||
new ScriptFileOperation.Edit().operate(this, mScriptFileList, position);
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
public void setScriptFileList(ScriptFileList scriptFileList) {
|
||||
mScriptFileList = scriptFileList;
|
||||
getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void showOrDismissOperationPopupMenu(View v) {
|
||||
if (mScriptFileOperationPopupMenu.isShowing()) {
|
||||
mScriptFileOperationPopupMenu.dismiss();
|
||||
} else {
|
||||
mScriptFileOperationPopupMenu.show(v);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMenuCollapsing(MessageEvent event) {
|
||||
if (event.message.equals(HoverMenuService.MESSAGE_MENU_COLLAPSING) && mScriptFileOperationPopupMenu.isShowing()) {
|
||||
mScriptFileOperationPopupMenu.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(getContext()).inflate(R.layout.floating_script_list_recycler_view_item, parent, false);
|
||||
return new ViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
ScriptFile scriptFile = mScriptFileList.get(position);
|
||||
holder.name.setText(scriptFile.name);
|
||||
holder.path.setText(trimFilePath(scriptFile.path));
|
||||
}
|
||||
|
||||
private final String SD_CARD_PATH = Environment.getExternalStorageDirectory().toString();
|
||||
|
||||
private String trimFilePath(String path) {
|
||||
if (path.startsWith(SD_CARD_PATH)) {
|
||||
path = path.substring(SD_CARD_PATH.length());
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mScriptFileList.size();
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
TextView name, path;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
name = (TextView) itemView.findViewById(R.id.name);
|
||||
path = (TextView) itemView.findViewById(R.id.path);
|
||||
ViewTool.$(itemView, R.id.edit).setOnClickListener(mOnEditIconClickListener);
|
||||
ViewTool.$(itemView, R.id.more).setOnClickListener(mOnMoreIconClickListener);
|
||||
itemView.setOnClickListener(mOnItemClickListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.notification.bounds_assist;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
|
||||
import com.stardust.util.StateObserver;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/2.
|
||||
*/
|
||||
|
||||
public class BoundsAssistSwitchNotification {
|
||||
|
||||
private static final int NOTIFY_ID = 11126;
|
||||
public static final String KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE = "KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE";
|
||||
|
||||
private static boolean enable = false;
|
||||
|
||||
public static boolean isEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
||||
static {
|
||||
App.getStateObserver().register(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, new StateObserver.OnStateChangedListener() {
|
||||
@Override
|
||||
public void onStateChanged(boolean newState) {
|
||||
setEnable(newState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initState(boolean state) {
|
||||
enable = state;
|
||||
if (enable) {
|
||||
showNotification();
|
||||
}
|
||||
}
|
||||
});
|
||||
App.getStateObserver().register(BoundsAssistant.KEY_BOUNDS_ASSIST_ENABLE, new StateObserver.OnStateChangedListener() {
|
||||
@Override
|
||||
public void onStateChanged(boolean newState) {
|
||||
if (enable) {
|
||||
setEnable(false);
|
||||
setEnable(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initState(boolean state) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setEnable(boolean enable) {
|
||||
if (BoundsAssistSwitchNotification.enable == enable)
|
||||
return;
|
||||
BoundsAssistSwitchNotification.enable = enable;
|
||||
PreferenceManager.getDefaultSharedPreferences(App.getApp()).edit().putBoolean(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, enable).apply();
|
||||
if (enable) {
|
||||
showNotification();
|
||||
} else {
|
||||
hideNotification();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void showNotification() {
|
||||
Notification notification = new NotificationCompat.Builder(App.getApp())
|
||||
.setAutoCancel(false)
|
||||
.setSmallIcon(R.drawable.ic_robot_head)
|
||||
.setDeleteIntent(BoundsAssistSwitchNotificationHandleService.getDeletePendingIntent())
|
||||
.setContentText(BoundsAssistant.isAssistModeEnable() ?
|
||||
App.getApp().getString(R.string.text_assist_mode_enabled) :
|
||||
App.getApp().getString(R.string.text_assist_mode_disabled))
|
||||
.setContentIntent(BoundsAssistSwitchNotificationHandleService.getStartIntent())
|
||||
.build();
|
||||
showNotification(notification);
|
||||
}
|
||||
|
||||
private static void showNotification(Notification notification) {
|
||||
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(NOTIFY_ID, notification);
|
||||
}
|
||||
|
||||
private static void hideNotification() {
|
||||
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(NOTIFY_ID);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.notification.bounds_assist;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
|
||||
|
||||
import static com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification.KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/2.
|
||||
*/
|
||||
public class BoundsAssistSwitchNotificationHandleService extends Service {
|
||||
|
||||
|
||||
private static final String EXTRA_INTENT_VALID = "BoundsAssistSwitchNotificationHandleService.intentValid";
|
||||
private static final String EXTRA_ACTION = "action";
|
||||
|
||||
private static final int ACTION_TOGGLE_ASSIST_MODE = 1;
|
||||
private static final int ACTION_CANCEL_ASSIST_MODE_NOTIFICATION = 2;
|
||||
|
||||
|
||||
public static PendingIntent getStartIntent() {
|
||||
Intent intent = new Intent(App.getApp(), BoundsAssistSwitchNotificationHandleService.class)
|
||||
.putExtra(EXTRA_INTENT_VALID, true)
|
||||
.putExtra(EXTRA_ACTION, ACTION_TOGGLE_ASSIST_MODE);
|
||||
return PendingIntent.getService(App.getApp(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
boolean intentValid = intent.getBooleanExtra(EXTRA_INTENT_VALID, false);
|
||||
if (intentValid) {
|
||||
performAction(intent.getIntExtra(EXTRA_ACTION, 0));
|
||||
}
|
||||
stopSelf();
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
private void performAction(int action) {
|
||||
switch (action) {
|
||||
case ACTION_TOGGLE_ASSIST_MODE:
|
||||
BoundsAssistant.setAssistModeEnable(!BoundsAssistant.isAssistModeEnable());
|
||||
break;
|
||||
case ACTION_CANCEL_ASSIST_MODE_NOTIFICATION:
|
||||
App.getStateObserver().setState(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PendingIntent getDeletePendingIntent() {
|
||||
Intent deleteIntent = new Intent(App.getApp(), BoundsAssistSwitchNotificationHandleService.class)
|
||||
.putExtra(EXTRA_INTENT_VALID, true)
|
||||
.putExtra(EXTRA_ACTION, ACTION_CANCEL_ASSIST_MODE_NOTIFICATION);
|
||||
return PendingIntent.getService(App.getApp(), 0, deleteIntent, PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.service.VolumeChangeListenService;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
|
||||
@@ -7,8 +7,8 @@ import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.ui.edit.EditActivity;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/2.
|
||||
|
||||
@@ -8,12 +8,12 @@ import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.shortcut.ShortcutActivity;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/22.
|
||||
|
||||
@@ -6,8 +6,8 @@ import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.tile;
|
||||
|
||||
import android.os.Build;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/26.
|
||||
*/
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public class BoundsAssistEnableTileService extends TileService {
|
||||
|
||||
public void onClick() {
|
||||
BoundsAssistant.setAssistModeEnable(!BoundsAssistant.isAssistModeEnable());
|
||||
updateTile();
|
||||
}
|
||||
|
||||
private void updateTile() {
|
||||
getQsTile().setState(BoundsAssistant.isAssistModeEnable() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||
getQsTile().updateTile();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
updateTile();
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,13 @@ package com.stardust.scriptdroid.file;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
|
||||
import com.stardust.util.MapEntries;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.stardust.scriptdroid.layout_inspector;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class LayoutInspector implements AccessibilityDelegate {
|
||||
|
||||
|
||||
private static LayoutInspector instance = new LayoutInspector();
|
||||
|
||||
public static LayoutInspector getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private AccessibilityNodeInfo mRootInActiveWindow;
|
||||
private NodeInfo mCapture;
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
mRootInActiveWindow = service.getRootInActiveWindow();
|
||||
return false;
|
||||
}
|
||||
|
||||
public AccessibilityNodeInfo getRootInActiveWindow() {
|
||||
return mRootInActiveWindow;
|
||||
}
|
||||
|
||||
public NodeInfo captureCurrentWindow() {
|
||||
if (mRootInActiveWindow == null) {
|
||||
mCapture = null;
|
||||
} else {
|
||||
mCapture = NodeInfo.capture(mRootInActiveWindow);
|
||||
}
|
||||
return mCapture;
|
||||
}
|
||||
|
||||
|
||||
public void clearCapture() {
|
||||
mRootInActiveWindow = null;
|
||||
mCapture = null;
|
||||
}
|
||||
|
||||
public NodeInfo getCapture() {
|
||||
return mCapture;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.stardust.scriptdroid.layout_inspector;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class NodeInfo {
|
||||
|
||||
private List<NodeInfo> children = new ArrayList<>();
|
||||
|
||||
public String id;
|
||||
public CharSequence contentDesc, className, packageName, text;
|
||||
public int drawingOrder;
|
||||
public boolean accessibilityFocused, checked, clickable, contextClickable, dismissable, editable, enabled,
|
||||
focusable, longClickable, selected, scrollable, visibleToUser;
|
||||
public String bounds;
|
||||
|
||||
private Rect mBoundsInScreen;
|
||||
|
||||
public NodeInfo(AccessibilityNodeInfoCompat node) {
|
||||
id = simplifyId(node.getViewIdResourceName());
|
||||
contentDesc = node.getContentDescription();
|
||||
className = node.getClassName();
|
||||
packageName = node.getPackageName();
|
||||
text = node.getText();
|
||||
|
||||
drawingOrder = node.getDrawingOrder();
|
||||
|
||||
accessibilityFocused = node.isAccessibilityFocused();
|
||||
checked = node.isChecked();
|
||||
clickable = node.isClickable();
|
||||
contextClickable = node.isContextClickable();
|
||||
dismissable = node.isDismissable();
|
||||
enabled = node.isEnabled();
|
||||
editable = node.isEditable();
|
||||
focusable = node.isFocusable();
|
||||
longClickable = node.isLongClickable();
|
||||
selected = node.isSelected();
|
||||
scrollable = node.isScrollable();
|
||||
visibleToUser = node.isVisibleToUser();
|
||||
|
||||
mBoundsInScreen = new Rect();
|
||||
node.getBoundsInScreen(mBoundsInScreen);
|
||||
bounds = boundsToString(mBoundsInScreen);
|
||||
}
|
||||
|
||||
private String simplifyId(String idResourceName) {
|
||||
if(idResourceName == null)
|
||||
return null;
|
||||
int i = idResourceName.indexOf('/');
|
||||
return idResourceName.substring(i + 1);
|
||||
}
|
||||
|
||||
public Rect getBoundsInScreen() {
|
||||
return mBoundsInScreen;
|
||||
}
|
||||
|
||||
public static String boundsToString(Rect rect) {
|
||||
return rect.toString().replace('-', ',').replace(" ", "").substring(4);
|
||||
}
|
||||
|
||||
public NodeInfo(AccessibilityNodeInfo node) {
|
||||
this(new AccessibilityNodeInfoCompat(node));
|
||||
}
|
||||
|
||||
public static NodeInfo capture(@NonNull AccessibilityNodeInfo root) {
|
||||
NodeInfo nodeInfo = new NodeInfo(root);
|
||||
for (int i = 0; i < root.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = root.getChild(i);
|
||||
if (child != null) {
|
||||
nodeInfo.children.add(capture(child));
|
||||
}
|
||||
}
|
||||
return nodeInfo;
|
||||
}
|
||||
|
||||
public List<NodeInfo> getChildren() {
|
||||
return children;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.stardust.scriptdroid.layout_inspector.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.scriptdroid.tool.ViewTool;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class LayoutBoundsView extends View {
|
||||
|
||||
private NodeInfo mRootNode;
|
||||
|
||||
|
||||
private Paint mPaint;
|
||||
private int mStatusBarHeight;
|
||||
private OnNodeInfoSelectListener mOnNodeInfoSelectListener;
|
||||
|
||||
public LayoutBoundsView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public LayoutBoundsView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public LayoutBoundsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public LayoutBoundsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
public void setOnNodeInfoSelectListener(OnNodeInfoSelectListener onNodeInfoSelectListener) {
|
||||
mOnNodeInfoSelectListener = onNodeInfoSelectListener;
|
||||
}
|
||||
|
||||
public void setRootNode(NodeInfo rootNode) {
|
||||
mRootNode = rootNode;
|
||||
}
|
||||
|
||||
|
||||
private void init() {
|
||||
mPaint = new Paint();
|
||||
mPaint.setColor(Color.GREEN);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mStatusBarHeight = ViewTool.getStatusBarHeight(getContext());
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
draw(canvas, mRootNode);
|
||||
}
|
||||
|
||||
public Paint getPaint() {
|
||||
return mPaint;
|
||||
}
|
||||
|
||||
|
||||
private void draw(Canvas canvas, NodeInfo node) {
|
||||
if (node == null)
|
||||
return;
|
||||
drawRect(canvas, node.getBoundsInScreen(), mStatusBarHeight, mPaint);
|
||||
for (NodeInfo child : node.getChildren()) {
|
||||
draw(canvas, child);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawRect(Canvas canvas, Rect rect, int statusBarHeight, Paint paint) {
|
||||
Rect offsetRect = new Rect(rect);
|
||||
offsetRect.offset(0, -statusBarHeight);
|
||||
canvas.drawRect(offsetRect, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN && mRootNode != null) {
|
||||
NodeInfo nodeInfo = findNodeAt(mRootNode, (int) event.getRawX(), (int) event.getRawY());
|
||||
onNodeInfoClick(nodeInfo);
|
||||
}
|
||||
return super.onTouchEvent(event);
|
||||
|
||||
}
|
||||
|
||||
private void onNodeInfoClick(NodeInfo nodeInfo) {
|
||||
if (mOnNodeInfoSelectListener != null) {
|
||||
mOnNodeInfoSelectListener.onNodeSelect(nodeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private NodeInfo findNodeAt(NodeInfo node, int x, int y) {
|
||||
for (NodeInfo child : node.getChildren()) {
|
||||
if (child != null && child.getBoundsInScreen().contains(x, y)) {
|
||||
return findNodeAt(child, x, y);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package com.stardust.scriptdroid.layout_inspector.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.scriptdroid.tool.ViewTool;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import pl.openrnd.multilevellistview.ItemInfo;
|
||||
import pl.openrnd.multilevellistview.MultiLevelListAdapter;
|
||||
import pl.openrnd.multilevellistview.MultiLevelListView;
|
||||
import pl.openrnd.multilevellistview.NestType;
|
||||
import pl.openrnd.multilevellistview.OnItemClickListener;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class LayoutHierarchyView extends MultiLevelListView {
|
||||
|
||||
private Adapter mAdapter;
|
||||
private OnNodeInfoSelectListener mOnNodeInfoSelectListener;
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private Paint mPaint;
|
||||
private int mStatusBarHeight;
|
||||
private NodeInfo mClickedNodeInfo;
|
||||
|
||||
private boolean mShowClickedNodeBounds;
|
||||
|
||||
public LayoutHierarchyView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public LayoutHierarchyView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public LayoutHierarchyView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
public void setShowClickedNodeBounds(boolean showClickedNodeBounds) {
|
||||
mShowClickedNodeBounds = showClickedNodeBounds;
|
||||
}
|
||||
|
||||
|
||||
private void init() {
|
||||
mAdapter = new Adapter();
|
||||
setAdapter(mAdapter);
|
||||
setNestType(NestType.MULTIPLE);
|
||||
((ListView) getChildAt(0)).setOnItemLongClickListener(mOnItemLongClickListenerProxy);
|
||||
setWillNotDraw(false);
|
||||
initPaint();
|
||||
setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClicked(MultiLevelListView parent, View view, Object item, ItemInfo itemInfo) {
|
||||
mClickedNodeInfo = (NodeInfo) item;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGroupItemClicked(MultiLevelListView parent, View view, Object item, ItemInfo itemInfo) {
|
||||
mClickedNodeInfo = (NodeInfo) item;
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initPaint() {
|
||||
mPaint = new Paint();
|
||||
mPaint.setColor(Color.DKGRAY);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setStrokeWidth(3);
|
||||
mStatusBarHeight = ViewTool.getStatusBarHeight(getContext());
|
||||
}
|
||||
|
||||
public Paint getBoundsPaint() {
|
||||
return mPaint;
|
||||
}
|
||||
|
||||
public void setRootNode(NodeInfo rootNodeInfo) {
|
||||
mAdapter.setDataItems(Collections.singletonList(rootNodeInfo));
|
||||
mClickedNodeInfo = null;
|
||||
}
|
||||
|
||||
public void setOnNodeInfoLongClickListener(final OnNodeInfoSelectListener onNodeInfoSelectListener) {
|
||||
mOnNodeInfoSelectListener = onNodeInfoSelectListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
if (mShowClickedNodeBounds && mClickedNodeInfo != null) {
|
||||
LayoutBoundsView.drawRect(canvas, mClickedNodeInfo.getBoundsInScreen(), mStatusBarHeight, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewHolder {
|
||||
TextView nameView;
|
||||
TextView infoView;
|
||||
ImageView arrowView;
|
||||
LevelBeamView levelBeamView;
|
||||
NodeInfo nodeInfo;
|
||||
|
||||
ViewHolder(View view) {
|
||||
infoView = (TextView) view.findViewById(R.id.dataItemInfo);
|
||||
nameView = (TextView) view.findViewById(R.id.dataItemName);
|
||||
arrowView = (ImageView) view.findViewById(R.id.dataItemArrow);
|
||||
levelBeamView = (LevelBeamView) view.findViewById(R.id.dataItemLevelBeam);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class Adapter extends MultiLevelListAdapter {
|
||||
|
||||
|
||||
@Override
|
||||
public List<?> getSubObjects(Object object) {
|
||||
return ((NodeInfo) object).getChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpandable(Object object) {
|
||||
return !((NodeInfo) object).getChildren().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getViewForObject(Object object, View convertView, ItemInfo itemInfo) {
|
||||
NodeInfo nodeInfo = (NodeInfo) object;
|
||||
ViewHolder viewHolder;
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(getContext()).inflate(R.layout.layout_hierarchy_view_item, null);
|
||||
viewHolder = new ViewHolder(convertView);
|
||||
convertView.setTag(viewHolder);
|
||||
} else {
|
||||
viewHolder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
viewHolder.nameView.setText(simplifyClassName(nodeInfo.className));
|
||||
viewHolder.nodeInfo = nodeInfo;
|
||||
if (viewHolder.infoView.getVisibility() == VISIBLE)
|
||||
viewHolder.infoView.setText(getItemInfoDsc(itemInfo));
|
||||
|
||||
if (itemInfo.isExpandable() && !isAlwaysExpanded()) {
|
||||
viewHolder.arrowView.setVisibility(View.VISIBLE);
|
||||
viewHolder.arrowView.setImageResource(itemInfo.isExpanded() ?
|
||||
R.drawable.arrow_up : R.drawable.arrow_down);
|
||||
} else {
|
||||
viewHolder.arrowView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
viewHolder.levelBeamView.setLevel(itemInfo.getLevel());
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private String simplifyClassName(CharSequence className) {
|
||||
String s = className.toString();
|
||||
if (s.startsWith("android.widget.")) {
|
||||
s = s.substring(15);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
private String getItemInfoDsc(ItemInfo itemInfo) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append(String.format(Locale.getDefault(), "level[%d], idx in level[%d/%d]",
|
||||
itemInfo.getLevel() + 1, /*Indexing starts from 0*/
|
||||
itemInfo.getIdxInLevel() + 1 /*Indexing starts from 0*/,
|
||||
itemInfo.getLevelSize()));
|
||||
|
||||
if (itemInfo.isExpandable()) {
|
||||
builder.append(String.format(", expanded[%b]", itemInfo.isExpanded()));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.stardust.scriptdroid.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.layout_inspector.LayoutInspector;
|
||||
import com.stardust.scriptdroid.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 void showLayoutBoundsView() {
|
||||
mLayoutBoundsView.setRootNode(LayoutInspector.getInstance().captureCurrentWindow());
|
||||
backToLayoutBoundsView();
|
||||
}
|
||||
|
||||
public boolean isLayoutBoundsViewShowing() {
|
||||
return mCurrentView == mLayoutBoundsView;
|
||||
}
|
||||
|
||||
public boolean isNodeInfoViewShowing() {
|
||||
return mCurrentView == mNodeInfoView;
|
||||
}
|
||||
|
||||
public void backToLayoutBoundsView() {
|
||||
if (mCurrentView != mLayoutBoundsView) {
|
||||
mViewSwitcher.showNext();
|
||||
mCurrentView = mLayoutBoundsView;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.stardust.scriptdroid.layout_inspector.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class LevelBeamView extends View {
|
||||
|
||||
private static final String TAG = "LevelBeamView";
|
||||
|
||||
private static final int[] colors = {
|
||||
0xff1abc9c,
|
||||
0xff3498db,
|
||||
0xffe67e22,
|
||||
0xff8e44ad,
|
||||
0xfff1c40f,
|
||||
0xff2ecc71,
|
||||
};
|
||||
|
||||
private int mLevel;
|
||||
|
||||
private int mPaddingLeft, mPaddingRight;
|
||||
private int mLinesWidth;
|
||||
private int mLinesOffset;
|
||||
private Paint mLinePaint;
|
||||
|
||||
public LevelBeamView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public LevelBeamView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public LevelBeamView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
mLevel = level;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setWillNotDraw(false);
|
||||
mPaddingLeft = (int) getResources().getDimension(R.dimen.level_beam_view_padding_left);
|
||||
mPaddingRight = (int) getResources().getDimension(R.dimen.level_beam_view_padding_right);
|
||||
|
||||
mLinesWidth = (int) getResources().getDimension(R.dimen.level_beam_view_line_width);
|
||||
mLinesOffset = (int) getResources().getDimension(R.dimen.level_beam_view_line_offset);
|
||||
|
||||
mLinePaint = new Paint();
|
||||
mLinePaint.setAntiAlias(true);
|
||||
mLinePaint.setColor(Color.RED);
|
||||
mLinePaint.setStyle(Paint.Style.FILL);
|
||||
mLinePaint.setStrokeWidth(mLinesWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int width = mPaddingLeft + mPaddingRight + (mLevel + 1) * (mLinesWidth + mLinesOffset);
|
||||
int height = View.MeasureSpec.getSize(heightMeasureSpec);
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
Log.i(TAG, "onDraw");
|
||||
super.onDraw(canvas);
|
||||
for (int lvl = 0; lvl <= mLevel; lvl++) {
|
||||
float LINE_X = mPaddingLeft + lvl * mLinesWidth;
|
||||
if (lvl >= 1) {
|
||||
LINE_X += lvl * mLinesOffset;
|
||||
}
|
||||
mLinePaint.setColor(getColorForLevel(lvl));
|
||||
canvas.drawLine(LINE_X, 0, LINE_X, canvas.getHeight(), mLinePaint);
|
||||
}
|
||||
}
|
||||
|
||||
private int getColorForLevel(int level) {
|
||||
return colors[level % colors.length];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.stardust.scriptdroid.layout_inspector.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.scriptdroid.tool.ClipboardTool;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
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.SimpleTableHeaderAdapter;
|
||||
import de.codecrafters.tableview.toolkit.TableDataRowBackgroundProviders;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class NodeInfoView extends TableView {
|
||||
|
||||
private static final Field[] fields = NodeInfo.class.getFields();
|
||||
private String[][] mData = new String[fields.length][2];
|
||||
|
||||
public NodeInfoView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public NodeInfoView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public NodeInfoView(Context context, @Nullable AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
public void setNodeInfo(NodeInfo nodeInfo) {
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
try {
|
||||
Object value = fields[i].get(nodeInfo);
|
||||
mData[i][1] = value == null ? "null" : value.toString();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
getDataAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
initData();
|
||||
setUpTableConfig();
|
||||
setAdapter();
|
||||
setUpStyle();
|
||||
}
|
||||
|
||||
private void setAdapter() {
|
||||
setDataAdapter(new TableDataAdapter<String[]>(getContext(), mData) {
|
||||
SimpleTableDataAdapter mSimpleTableDataAdapter = new SimpleTableDataAdapter(getContext(), mData);
|
||||
|
||||
@Override
|
||||
public View getCellView(int rowIndex, int columnIndex, ViewGroup parentView) {
|
||||
final TextView textView = (TextView) mSimpleTableDataAdapter.getCellView(rowIndex, columnIndex, parentView);
|
||||
textView.setSingleLine(false);
|
||||
textView.setMaxLines(3);
|
||||
textView.setTextColor(0xcc000000);
|
||||
textView.setTextIsSelectable(true);
|
||||
textView.setOnLongClickListener(new OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
ClipboardTool.setClip(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));
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
for (int i = 0; i < mData.length; i++) {
|
||||
mData[i][0] = fields[i].getName();
|
||||
mData[i][1] = "";
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpStyle() {
|
||||
int colorEvenRows = Color.WHITE;
|
||||
int colorOddRows = 0xffe7e7e7;
|
||||
setDataRowBackgroundProvider(TableDataRowBackgroundProviders.alternatingRowColors(colorEvenRows, colorOddRows));
|
||||
getChildAt(0).setVisibility(GONE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.stardust.scriptdroid.layout_inspector.view;
|
||||
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public interface OnNodeInfoSelectListener {
|
||||
void onNodeSelect(NodeInfo info);
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package com.stardust.scriptdroid.record;
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.stardust.scriptdroid.service.AccessibilityDelegate;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
import static com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchView.PAUSED;
|
||||
import static com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchView.RECORDING;
|
||||
|
||||
@@ -7,13 +7,12 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.scriptdroid.droid.runtime.action.FilterAction;
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.stardust.scriptdroid.bounds_assist.BoundsAssistant.boundsToString;
|
||||
import static com.stardust.scriptdroid.bounds_assist.BoundsAssistant.getBoundsInScreen;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
@@ -69,7 +68,7 @@ public class ActionRecorder {
|
||||
AccessibilityNodeInfo source = event.getSource();
|
||||
if (source == null)
|
||||
return;
|
||||
String bounds = boundsToString(getBoundsInScreen(source));
|
||||
String bounds = NodeInfo.boundsToString(AccessibilityNodeInfoHelper.getBoundsInScreen(source));
|
||||
source.recycle();
|
||||
onAccessibilityEvent(event, bounds, sb);
|
||||
}
|
||||
@@ -130,7 +129,7 @@ public class ActionRecorder {
|
||||
private static int findInEditableList(List<AccessibilityNodeInfo> editableList, AccessibilityNodeInfo editable) {
|
||||
int i = 0;
|
||||
for (AccessibilityNodeInfo nodeInfo : editableList) {
|
||||
if (getBoundsInScreen(nodeInfo).equals(getBoundsInScreen(editable))) {
|
||||
if (AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo).equals(AccessibilityNodeInfoHelper.getBoundsInScreen(editable))) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.tool.Shell;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jackpal.androidterm.ShellTermSession;
|
||||
import jackpal.androidterm.emulatorview.TermSession;
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.util.MapEntries;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -3,8 +3,6 @@ package com.stardust.scriptdroid.record.inputevent;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.stardust.scriptdroid.service;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
|
||||
public interface AccessibilityDelegate {
|
||||
|
||||
boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event);
|
||||
|
||||
}
|
||||
@@ -5,7 +5,9 @@ import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
@@ -79,6 +81,7 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
Log.v(TAG, "onAccessibilityEvent: " + event);
|
||||
synchronized (mDelegates) {
|
||||
for (Map.Entry<Integer, AccessibilityDelegate> entry : mDelegates.entrySet()) {
|
||||
Log.v(TAG, "delegate: " + entry.getValue().getClass().getName());
|
||||
if (entry.getValue().onAccessibilityEvent(this, event))
|
||||
break;
|
||||
}
|
||||
@@ -101,7 +104,7 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
if (instance != null && instance.get() != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
instance.get().disableSelf();
|
||||
} else {
|
||||
AccessibilityServiceUtils.goToAccessibilitySetting(App.getApp());
|
||||
AccessibilityServiceTool.goToAccessibilitySetting();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ import android.content.IntentFilter;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchHandleService;
|
||||
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
package com.stardust.scriptdroid.tool;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import static com.stardust.view.accessibility.AccessibilityServiceUtils.isAccessibilityServiceEnabled;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/26.
|
||||
*/
|
||||
@@ -22,12 +19,37 @@ public class AccessibilityServiceTool {
|
||||
|
||||
public static void enableAccessibilityService() {
|
||||
if (Pref.def().getBoolean(App.getApp().getString(R.string.key_enable_accessibility_service_by_root), false)) {
|
||||
if (!AccessibilityServiceUtils.enableAccessibilityServiceByRootAndWaitFor(App.getApp(), AccessibilityWatchDogService.class, 3000)) {
|
||||
AccessibilityServiceUtils.goToAccessibilitySetting(App.getApp());
|
||||
if (!enableAccessibilityServiceByRootAndWaitFor(AccessibilityWatchDogService.class, 3000)) {
|
||||
goToAccessibilitySetting();
|
||||
}
|
||||
} else {
|
||||
AccessibilityServiceUtils.goToAccessibilitySetting(App.getApp());
|
||||
goToAccessibilitySetting();
|
||||
}
|
||||
}
|
||||
|
||||
public static void goToAccessibilitySetting() {
|
||||
Context context = App.getApp();
|
||||
if (Pref.isFirstGoToAccessibilitySetting()) {
|
||||
Toast.makeText(context, context.getString(R.string.text_please_choose) + context.getString(R.string._app_name), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
AccessibilityServiceUtils.goToAccessibilitySetting(context);
|
||||
}
|
||||
|
||||
public static boolean enableAccessibilityServiceByRootAndWaitFor(Class<AccessibilityWatchDogService> accessibilityService, int timeout) {
|
||||
Shell.execCommand("settings put secure enabled_accessibility_services %accessibility:"
|
||||
+ App.getApp().getPackageName() + "/" + accessibilityService.getName(), true);
|
||||
long millis = System.currentTimeMillis();
|
||||
while (true) {
|
||||
if (isAccessibilityServiceEnabled(App.getApp(), accessibilityService))
|
||||
return true;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (System.currentTimeMillis() - millis >= timeout) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.stardust.scriptdroid.tool;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class ClipboardTool {
|
||||
|
||||
|
||||
public static void setClip(CharSequence text) {
|
||||
((ClipboardManager) App.getApp().getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText("", text));
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,9 @@ package com.stardust.scriptdroid.tool;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.afollestad.materialdialogs.folderselector.FileChooserDialog;
|
||||
import com.stardust.app.OnActivityResultDelegate;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
|
||||
@@ -1,27 +1,17 @@
|
||||
package com.stardust.scriptdroid.tool;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stericson.RootShell.RootShell;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import jackpal.androidterm.ShellTermSession;
|
||||
import jackpal.androidterm.Term;
|
||||
import jackpal.androidterm.emulatorview.TermSession;
|
||||
import jackpal.androidterm.util.TermSettings;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package com.stardust.scriptdroid.tool;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/24.
|
||||
@@ -13,4 +17,13 @@ public class ViewTool {
|
||||
public static <V extends View> V $(View view, @IdRes int resId) {
|
||||
return (V) view.findViewById(resId);
|
||||
}
|
||||
|
||||
public static int getStatusBarHeight(Context context) {
|
||||
int result = 0;
|
||||
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
|
||||
if (resourceId > 0) {
|
||||
result = context.getResources().getDimensionPixelSize(resourceId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.View;
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.jraska.console.Console;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.jraska.console.Console;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,15 @@ import android.view.View;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.ui.edit.editor920.Editor920Activity;
|
||||
import com.stardust.scriptdroid.ui.edit.sidemenu.EditSideMenuFragment;
|
||||
import com.stardust.scriptdroid.ui.edit.sidemenu.FunctionListRecyclerView;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
import com.stardust.view.ViewBinding;
|
||||
import com.stardust.widget.ToolbarMenuItem;
|
||||
import com.jecelyin.editor.v2.common.Command;
|
||||
import com.jecelyin.editor.v2.common.SaveListener;
|
||||
import com.jecelyin.editor.v2.core.widget.TextView;
|
||||
@@ -22,20 +31,10 @@ import com.jecelyin.editor.v2.ui.EditorDelegate;
|
||||
import com.jecelyin.editor.v2.view.EditorView;
|
||||
import com.jecelyin.editor.v2.view.menu.MenuDef;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.ui.edit.completion.InputMethodEnhanceBar;
|
||||
import com.stardust.scriptdroid.ui.edit.editor920.Editor920Activity;
|
||||
import com.stardust.scriptdroid.ui.edit.sidemenu.AssistClipListRecyclerView;
|
||||
import com.stardust.scriptdroid.ui.edit.sidemenu.EditSideMenuFragment;
|
||||
import com.stardust.scriptdroid.ui.edit.sidemenu.FunctionListRecyclerView;
|
||||
import com.stardust.theme.ThemeColorManager;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
import com.stardust.widget.ToolbarMenuItem;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -154,15 +153,7 @@ public class EditActivity extends Editor920Activity {
|
||||
insertText(function.name);
|
||||
mDrawerLayout.closeDrawer(GravityCompat.END);
|
||||
}
|
||||
})
|
||||
.setOnClipClickListener(new AssistClipListRecyclerView.OnClipClickListener() {
|
||||
@Override
|
||||
public void onClick(String clip, int position) {
|
||||
insertText(clip);
|
||||
mDrawerLayout.closeDrawer(GravityCompat.END);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void setUpEditor() {
|
||||
|
||||
@@ -4,8 +4,8 @@ import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
|
||||
import com.jecelyin.editor.v2.core.widget.TextView;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.jecelyin.editor.v2.core.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
package com.stardust.scriptdroid.ui.edit.sidemenu;
|
||||
|
||||
import android.bug.WrapContentLinearLayoutManager;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
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;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.bounds_assist.BoundsAssistClipList;
|
||||
import com.stardust.scriptdroid.bounds_assist.SharedPrefBoundsAssistClipList;
|
||||
import com.stardust.widget.ExpandableRecyclerView;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/4.
|
||||
*/
|
||||
|
||||
public class AssistClipListRecyclerView extends ExpandableRecyclerView {
|
||||
|
||||
public interface OnClipClickListener {
|
||||
void onClick(String clip, int position);
|
||||
}
|
||||
|
||||
private BoundsAssistClipList mBoundsAssistClipList = SharedPrefBoundsAssistClipList.getInstance();
|
||||
private OnClipClickListener mOnClipClickListener;
|
||||
|
||||
public AssistClipListRecyclerView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public AssistClipListRecyclerView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public AssistClipListRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setLayoutManager(new WrapContentLinearLayoutManager(getContext()));
|
||||
setAdapter(new Adapter());
|
||||
setOnChildClickListener(new OnChildClickListener() {
|
||||
@Override
|
||||
public void onClick(View view, int position) {
|
||||
if (mOnClipClickListener != null) {
|
||||
String clip = (String) ((ChildViewHolder) getChildViewHolder(view)).mTextView.getText();
|
||||
mOnClipClickListener.onClick(clip, position);
|
||||
}
|
||||
}
|
||||
});
|
||||
mBoundsAssistClipList.setOnClipChangedListener(new BoundsAssistClipList.OnClipChangedListener() {
|
||||
@Override
|
||||
public void onClipRemove(int position) {
|
||||
if (isExpanded())
|
||||
getAdapter().notifyItemRemoved(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClipInsert(int position) {
|
||||
if (isExpanded())
|
||||
getAdapter().notifyItemInserted(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange() {
|
||||
getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setOnClipClickListener(OnClipClickListener onClipClickListener) {
|
||||
mOnClipClickListener = onClipClickListener;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
//防止因mAssistClipList持有OnClipChangedListener引用从而导致这个RecyclerView及其Context被引用,内存泄漏
|
||||
mBoundsAssistClipList.setOnClipChangedListener(null);
|
||||
}
|
||||
|
||||
private class Adapter extends ExpandableRecyclerView.DefaultTitleAdapter {
|
||||
|
||||
Adapter() {
|
||||
setIcon(R.drawable.ic_robot_head_green);
|
||||
setTitle(R.string.text_assist_clip);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecyclerView.ViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) {
|
||||
return new ChildViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.assist_clip_list_recycler_view_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBindChildViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
ChildViewHolder viewHolder = (ChildViewHolder) holder;
|
||||
viewHolder.mTextView.setText(mBoundsAssistClipList.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getChildItemCount() {
|
||||
return mBoundsAssistClipList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getChildItemViewType(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ChildViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
TextView mTextView;
|
||||
|
||||
ChildViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
mTextView = (TextView) itemView.findViewById(R.id.clip);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,27 +9,23 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.stardust.app.Fragment;
|
||||
import com.stardust.scriptdroid.external.floating_window.FloatingWindowManger;
|
||||
import com.stardust.view.ViewBinding;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.ui.help.DocumentationActivity;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.ui.console.ConsoleActivity;
|
||||
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
|
||||
import com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification;
|
||||
import com.stardust.scriptdroid.ui.help.HelpCatalogueActivity;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
|
||||
import static com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification.KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/4.
|
||||
*/
|
||||
|
||||
public class EditSideMenuFragment extends com.stardust.app.Fragment {
|
||||
public class EditSideMenuFragment extends Fragment {
|
||||
|
||||
|
||||
private FunctionListRecyclerView.OnFunctionClickListener mOnFunctionClickListener;
|
||||
private AssistClipListRecyclerView.OnClipClickListener mOnClipClickListener;
|
||||
|
||||
public static EditSideMenuFragment setFragment(AppCompatActivity activity, int viewId) {
|
||||
EditSideMenuFragment fragment = new EditSideMenuFragment();
|
||||
@@ -37,7 +33,7 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment {
|
||||
return fragment;
|
||||
}
|
||||
|
||||
private SwitchCompat mAssistServiceSwitch, mAssistServiceNotificationSwitch;
|
||||
private SwitchCompat mFloatingWindowSwitch;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@@ -48,7 +44,7 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment {
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
if (mAssistServiceSwitch == null) {
|
||||
if (mFloatingWindowSwitch == null) {
|
||||
setUpUI();
|
||||
}
|
||||
syncSwitchState();
|
||||
@@ -57,14 +53,9 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment {
|
||||
private void setUpUI() {
|
||||
setUpSwitchCompat();
|
||||
setUpFunctionList();
|
||||
setUpClipList();
|
||||
ViewBinder.bind(this);
|
||||
}
|
||||
|
||||
private void setUpClipList() {
|
||||
AssistClipListRecyclerView assistClipListRecyclerView = $(R.id.assist_clip_list);
|
||||
assistClipListRecyclerView.setOnClipClickListener(mOnClipClickListener);
|
||||
}
|
||||
|
||||
private void setUpFunctionList() {
|
||||
FunctionListRecyclerView functionListRecyclerView = $(R.id.function_list);
|
||||
@@ -73,15 +64,11 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment {
|
||||
}
|
||||
|
||||
private void syncSwitchState() {
|
||||
mAssistServiceSwitch.setChecked(BoundsAssistant.isAssistModeEnable());
|
||||
mAssistServiceNotificationSwitch.setChecked(BoundsAssistSwitchNotification.isEnable());
|
||||
mFloatingWindowSwitch.setChecked(FloatingWindowManger.isFloatingWindowShowing());
|
||||
}
|
||||
|
||||
private void setUpSwitchCompat() {
|
||||
mAssistServiceSwitch = $(R.id.sw_assist_service);
|
||||
mAssistServiceNotificationSwitch = $(R.id.sw_assist_service_notification);
|
||||
App.getStateObserver().register(BoundsAssistant.KEY_BOUNDS_ASSIST_ENABLE, mAssistServiceSwitch);
|
||||
App.getStateObserver().register(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, mAssistServiceNotificationSwitch);
|
||||
mFloatingWindowSwitch = $(R.id.sw_floating_window);
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.syntax_and_api)
|
||||
@@ -94,24 +81,18 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment {
|
||||
startActivity(new Intent(getContext(), ConsoleActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
|
||||
@ViewBinding.Check(R.id.sw_assist_service)
|
||||
private void setAssistServiceEnable(boolean enable) {
|
||||
BoundsAssistant.setAssistModeEnable(enable);
|
||||
@ViewBinding.Check(R.id.sw_floating_window)
|
||||
private void setFloatingWindowEnable(boolean enable) {
|
||||
if (enable && !FloatingWindowManger.isFloatingWindowShowing()) {
|
||||
FloatingWindowManger.showFloatingWindow();
|
||||
} else if (!enable && FloatingWindowManger.isFloatingWindowShowing()) {
|
||||
FloatingWindowManger.hideFloatingWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.assist_service)
|
||||
@ViewBinding.Click(R.id.floating_window)
|
||||
private void toggleAssistServiceSwitch() {
|
||||
mAssistServiceSwitch.toggle();
|
||||
}
|
||||
|
||||
@ViewBinding.Check(R.id.sw_assist_service_notification)
|
||||
private void setAssistServiceNotificationEnable(boolean enable) {
|
||||
BoundsAssistSwitchNotification.setEnable(enable);
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.assist_service_notification)
|
||||
private void toggleAssistServiceNotificationSwitch() {
|
||||
mAssistServiceNotificationSwitch.toggle();
|
||||
mFloatingWindowSwitch.toggle();
|
||||
}
|
||||
|
||||
public EditSideMenuFragment setOnFunctionClickListener(FunctionListRecyclerView.OnFunctionClickListener onFunctionClickListener) {
|
||||
@@ -119,8 +100,4 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment {
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSideMenuFragment setOnClipClickListener(AssistClipListRecyclerView.OnClipClickListener onClipClickListener) {
|
||||
mOnClipClickListener = onClipClickListener;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ import android.widget.Toast;
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
@@ -11,7 +11,6 @@ import android.widget.Toast;
|
||||
import com.heinrichreimersoftware.androidissuereporter.IssueReporterActivity;
|
||||
import com.heinrichreimersoftware.androidissuereporter.model.github.GithubTarget;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.theme.ThemeColorManager;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@@ -3,13 +3,11 @@ package com.stardust.scriptdroid.ui.help;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.widget.CommonMarkdownView;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
import com.stardust.widget.CommonMarkdownView;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
@@ -29,37 +28,31 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.folderselector.FileChooserDialog;
|
||||
import com.stardust.app.NotRemindAgainDialog;
|
||||
import com.stardust.app.OnActivityResultDelegate;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.BuildConfig;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
|
||||
import com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchNotification;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
import com.stardust.scriptdroid.file.SampleFileManager;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventRecorder;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventToJsConverter;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventToJsRecorder;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.scriptdroid.tool.BackPressedHandler;
|
||||
import com.stardust.scriptdroid.tool.ImageSelector;
|
||||
import com.stardust.scriptdroid.tool.Shell;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperation;
|
||||
import com.stardust.scriptdroid.ui.settings.SettingsActivity;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
import com.stardust.widget.SlidingUpPanel;
|
||||
import com.stardust.scriptdroid.BuildConfig;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
import com.stardust.scriptdroid.tool.BackPressedHandler;
|
||||
import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperation;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
|
||||
public class MainActivity extends BaseActivity implements FileChooserDialog.FileCallback {
|
||||
@@ -85,7 +78,6 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
checkPermissions();
|
||||
registerReceivers();
|
||||
handleIntent(getIntent());
|
||||
//Shell.test(this);
|
||||
}
|
||||
|
||||
private void registerReceivers() {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.stardust.scriptdroid.ui.main;
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.widget.DividerItemDecoration;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
@@ -14,17 +15,20 @@ import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.tool.ViewTool;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperation;
|
||||
import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperationPopupMenu;
|
||||
import com.stardust.scriptdroid.tool.ClassTool;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
|
||||
import static com.stardust.scriptdroid.tool.ViewTool.$;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
import static com.stardust.scriptdroid.ui.main.operation.ScriptFileOperation.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/23.
|
||||
@@ -38,16 +42,15 @@ public class ScriptListRecyclerView extends ThemeColorRecyclerView {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
new ScriptFileOperation.Run().operate(ScriptListRecyclerView.this, mScriptFileList, position);
|
||||
onItemClicked(v, position);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private final OnClickListener mOnEditIconClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder((View) v.getParent()).getAdapterPosition();
|
||||
new ScriptFileOperation.Edit().operate(ScriptListRecyclerView.this, mScriptFileList, position);
|
||||
onEditIconClick(v, position);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,7 +58,6 @@ public class ScriptListRecyclerView extends ThemeColorRecyclerView {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mOperateFileIndex = getChildViewHolder((View) v.getParent()).getAdapterPosition();
|
||||
//showOperationDialog(position);
|
||||
showOrDismissOperationPopupMenu(v);
|
||||
}
|
||||
|
||||
@@ -93,31 +95,40 @@ public class ScriptListRecyclerView extends ThemeColorRecyclerView {
|
||||
}
|
||||
|
||||
private void initScriptFileOperationPopupMenu() {
|
||||
mScriptFileOperationPopupMenu = new ScriptFileOperationPopupMenu(getContext());
|
||||
mScriptFileOperationPopupMenu = new ScriptFileOperationPopupMenu(getContext(), getScriptFileOperations());
|
||||
mScriptFileOperationPopupMenu.setOnItemClickListener(new ScriptFileOperationPopupMenu.OnItemClickListener() {
|
||||
@Override
|
||||
public void onClick(View view, int position) {
|
||||
ScriptFileOperation.getOperation(position).operate(ScriptListRecyclerView.this, mScriptFileList, mOperateFileIndex);
|
||||
public void onClick(View view, int position, ScriptFileOperation operation) {
|
||||
operation.operate(ScriptListRecyclerView.this, mScriptFileList, mOperateFileIndex);
|
||||
mScriptFileOperationPopupMenu.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected List<ScriptFileOperation> getScriptFileOperations() {
|
||||
List<ScriptFileOperation> scriptFileOperations = new ArrayList<>();
|
||||
scriptFileOperations.add(new ScriptFileOperation.Run());
|
||||
scriptFileOperations.add(new ScriptFileOperation.Rename());
|
||||
scriptFileOperations.add(new ScriptFileOperation.OpenByOtherApp());
|
||||
scriptFileOperations.add(new ScriptFileOperation.CreateShortcut());
|
||||
scriptFileOperations.add(new ScriptFileOperation.Remove());
|
||||
scriptFileOperations.add(new ScriptFileOperation.Delete());
|
||||
return scriptFileOperations;
|
||||
}
|
||||
|
||||
protected void onItemClicked(View v, int position) {
|
||||
new ScriptFileOperation.Run().operate(ScriptListRecyclerView.this, mScriptFileList, position);
|
||||
}
|
||||
|
||||
protected void onEditIconClick(View v, int position) {
|
||||
new ScriptFileOperation.Edit().operate(ScriptListRecyclerView.this, mScriptFileList, position);
|
||||
}
|
||||
|
||||
public void setScriptFileList(ScriptFileList scriptFileList) {
|
||||
mScriptFileList = scriptFileList;
|
||||
getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void showOperationDialog(final int position) {
|
||||
new ThemeColorMaterialDialogBuilder(getContext()).items(ScriptFileOperation.getOperationNames())
|
||||
.itemsCallback(new MaterialDialog.ListCallback() {
|
||||
@Override
|
||||
public void onSelection(MaterialDialog dialog, View itemView, int operation, CharSequence text) {
|
||||
ScriptFileOperation.getOperation(operation).operate(ScriptListRecyclerView.this, mScriptFileList, position);
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
private void showOrDismissOperationPopupMenu(View v) {
|
||||
if (mScriptFileOperationPopupMenu.isShowing()) {
|
||||
mScriptFileOperationPopupMenu.dismiss();
|
||||
@@ -126,6 +137,23 @@ public class ScriptListRecyclerView extends ThemeColorRecyclerView {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void showMessage(ScriptFileOperation.ShowMessageEvent event) {
|
||||
Snackbar.make(this, event.messageResId, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
@Override
|
||||
@@ -164,18 +192,10 @@ public class ScriptListRecyclerView extends ThemeColorRecyclerView {
|
||||
super(itemView);
|
||||
name = (TextView) itemView.findViewById(R.id.name);
|
||||
path = (TextView) itemView.findViewById(R.id.path);
|
||||
$(itemView, R.id.edit).setOnClickListener(mOnEditIconClickListener);
|
||||
$(itemView, R.id.more).setOnClickListener(mOnMoreIconClickListener);
|
||||
ViewTool.$(itemView, R.id.edit).setOnClickListener(mOnEditIconClickListener);
|
||||
ViewTool.$(itemView, R.id.more).setOnClickListener(mOnMoreIconClickListener);
|
||||
itemView.setOnClickListener(mOnItemClickListener);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
loadScriptFileOperations();
|
||||
}
|
||||
|
||||
private static void loadScriptFileOperations() {
|
||||
ClassTool.loadClasses(Run.class, Rename.class, OpenByOtherApp.class, CreateShortcut.class, Remove.class, Delete.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,18 +13,15 @@ import android.view.ViewGroup;
|
||||
import com.stardust.app.Fragment;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification;
|
||||
import com.stardust.scriptdroid.external.floating_window.FloatingWindowManger;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.scriptdroid.ui.console.ConsoleActivity;
|
||||
import com.stardust.scriptdroid.ui.help.HelpCatalogueActivity;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import static com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification.KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
@@ -38,7 +35,7 @@ public class SlideMenuFragment extends Fragment {
|
||||
activity.getSupportFragmentManager().beginTransaction().replace(viewId, fragment).commit();
|
||||
}
|
||||
|
||||
private SwitchCompat mAutoOperateServiceSwitch, mAssistServiceSwitch, mAssistServiceNotificationSwitch;
|
||||
private SwitchCompat mAutoOperateServiceSwitch, mAssistServiceSwitch;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@@ -64,16 +61,12 @@ public class SlideMenuFragment extends Fragment {
|
||||
mAutoOperateServiceSwitch.setChecked(AccessibilityWatchDogService.isEnable());
|
||||
}
|
||||
}, 450);
|
||||
mAssistServiceSwitch.setChecked(BoundsAssistant.isAssistModeEnable());
|
||||
mAssistServiceNotificationSwitch.setChecked(BoundsAssistSwitchNotification.isEnable());
|
||||
mAssistServiceSwitch.setChecked(FloatingWindowManger.isFloatingWindowShowing());
|
||||
}
|
||||
|
||||
private void setUpSwitchCompat() {
|
||||
mAutoOperateServiceSwitch = $(R.id.sw_auto_operate_service);
|
||||
mAssistServiceSwitch = $(R.id.sw_assist_service);
|
||||
mAssistServiceNotificationSwitch = $(R.id.sw_assist_service_notification);
|
||||
App.getStateObserver().register(BoundsAssistant.KEY_BOUNDS_ASSIST_ENABLE, mAssistServiceSwitch);
|
||||
App.getStateObserver().register(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, mAssistServiceNotificationSwitch);
|
||||
mAssistServiceSwitch = $(R.id.sw_floating_window);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,25 +94,20 @@ public class SlideMenuFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBinding.Check(R.id.sw_assist_service)
|
||||
private void setAssistServiceEnable(boolean enable) {
|
||||
BoundsAssistant.setAssistModeEnable(enable);
|
||||
@ViewBinding.Check(R.id.sw_floating_window)
|
||||
private void setFloatingWindowEnable(boolean enable) {
|
||||
if (enable && !FloatingWindowManger.isFloatingWindowShowing()) {
|
||||
FloatingWindowManger.showFloatingWindow();
|
||||
} else if (!enable && FloatingWindowManger.isFloatingWindowShowing()) {
|
||||
FloatingWindowManger.hideFloatingWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.assist_service)
|
||||
@ViewBinding.Click(R.id.floating_window)
|
||||
private void toggleAssistServiceSwitch() {
|
||||
mAssistServiceSwitch.toggle();
|
||||
}
|
||||
|
||||
@ViewBinding.Check(R.id.sw_assist_service_notification)
|
||||
private void setAssistServiceNotificationEnable(boolean enable) {
|
||||
BoundsAssistSwitchNotification.setEnable(enable);
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.assist_service_notification)
|
||||
private void toggleAssistServiceNotificationSwitch() {
|
||||
mAssistServiceNotificationSwitch.toggle();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.stop_all_running_scripts)
|
||||
private void stopAllRunningScripts() {
|
||||
|
||||
@@ -5,17 +5,20 @@ import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.ui.edit.EditActivity;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.shortcut.ShortcutActivity;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.external.shortcut.Shortcut;
|
||||
import com.stardust.scriptdroid.external.shortcut.ShortcutActivity;
|
||||
import com.stardust.scriptdroid.ui.edit.EditActivity;
|
||||
import com.stardust.scriptdroid.ui.main.ScriptListRecyclerView;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -26,27 +29,23 @@ import java.util.List;
|
||||
|
||||
public abstract class ScriptFileOperation {
|
||||
|
||||
private static List<String> operationNames = new ArrayList<>();
|
||||
private static List<ScriptFileOperation> operations = new ArrayList<>();
|
||||
public static class ShowMessageEvent {
|
||||
public int messageResId;
|
||||
|
||||
public static ScriptFileOperation getOperation(int index) {
|
||||
return operations.get(index);
|
||||
public ShowMessageEvent(int message) {
|
||||
this.messageResId = message;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getOperationNames() {
|
||||
return operationNames;
|
||||
}
|
||||
|
||||
public abstract void operate(ScriptListRecyclerView recyclerView, ScriptFileList scriptFileList, int position);
|
||||
|
||||
private static void addOperation(String name, int iconResId, ScriptFileOperation operation) {
|
||||
operation.mName = name;
|
||||
operation.mIconResId = iconResId;
|
||||
operationNames.add(name);
|
||||
operations.add(operation);
|
||||
}
|
||||
public abstract void operate(RecyclerView recyclerView, ScriptFileList scriptFileList, int position);
|
||||
|
||||
private String mName;
|
||||
|
||||
public ScriptFileOperation(String name, int iconResId) {
|
||||
mName = name;
|
||||
mIconResId = iconResId;
|
||||
}
|
||||
|
||||
private int mIconResId;
|
||||
|
||||
public String getName() {
|
||||
@@ -59,13 +58,13 @@ public abstract class ScriptFileOperation {
|
||||
|
||||
public static class Run extends ScriptFileOperation {
|
||||
|
||||
static {
|
||||
addOperation(App.getApp().getString(R.string.text_run), R.drawable.ic_play_green, new Run());
|
||||
public Run() {
|
||||
super(App.getApp().getString(R.string.text_run), R.drawable.ic_play_green);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate(ScriptListRecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
Snackbar.make(recyclerView, R.string.text_start_running, Snackbar.LENGTH_SHORT).show();
|
||||
public void operate(RecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
EventBus.getDefault().post(new ShowMessageEvent(R.string.text_start_running));
|
||||
ScriptFile scriptFile = scriptFileList.get(position);
|
||||
scriptFile.run();
|
||||
}
|
||||
@@ -73,12 +72,12 @@ public abstract class ScriptFileOperation {
|
||||
|
||||
public static class Edit extends ScriptFileOperation {
|
||||
|
||||
static {
|
||||
//addOperation(App.getApp().getString(R.string.text_edit)", R.drawable.ic_edit_green_48dp, new Edit());
|
||||
public Edit() {
|
||||
super(App.getApp().getString(R.string.text_edit), R.drawable.ic_edit_green_48dp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate(ScriptListRecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
public void operate(RecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
Context context = recyclerView.getContext();
|
||||
ScriptFile scriptFile = scriptFileList.get(position);
|
||||
EditActivity.editFile(context, scriptFile.name, scriptFile.path);
|
||||
@@ -87,12 +86,12 @@ public abstract class ScriptFileOperation {
|
||||
|
||||
public static class OpenByOtherApp extends ScriptFileOperation {
|
||||
|
||||
static {
|
||||
addOperation(App.getApp().getString(R.string.text_open_by_other_apps), R.drawable.ic_open_in_new_green_48dp, new OpenByOtherApp());
|
||||
public OpenByOtherApp() {
|
||||
super(App.getApp().getString(R.string.text_open_by_other_apps), R.drawable.ic_open_in_new_green_48dp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate(ScriptListRecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
public void operate(RecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
Context context = recyclerView.getContext();
|
||||
ScriptFile scriptFile = scriptFileList.get(position);
|
||||
Uri uri = Uri.parse("file://" + scriptFile.path);
|
||||
@@ -102,12 +101,12 @@ public abstract class ScriptFileOperation {
|
||||
|
||||
public static class Rename extends ScriptFileOperation {
|
||||
|
||||
static {
|
||||
addOperation(App.getApp().getString(R.string.text_rename), R.drawable.ic_rename_green, new Rename());
|
||||
public Rename() {
|
||||
super(App.getApp().getString(R.string.text_rename), R.drawable.ic_rename_green);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate(final ScriptListRecyclerView recyclerView, final ScriptFileList scriptFileList, final int position) {
|
||||
public void operate(final RecyclerView recyclerView, final ScriptFileList scriptFileList, final int position) {
|
||||
String oldName = scriptFileList.get(position).name;
|
||||
new ThemeColorMaterialDialogBuilder(recyclerView.getContext())
|
||||
.title(R.string.text_rename)
|
||||
@@ -125,13 +124,12 @@ public abstract class ScriptFileOperation {
|
||||
|
||||
public static class CreateShortcut extends ScriptFileOperation {
|
||||
|
||||
static {
|
||||
addOperation(App.getApp().getString(R.string.text_send_shortcut), R.drawable.ic_shortcut_green, new CreateShortcut());
|
||||
public CreateShortcut() {
|
||||
super(App.getApp().getString(R.string.text_send_shortcut), R.drawable.ic_shortcut_green);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void operate(ScriptListRecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
public void operate(RecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
Context context = recyclerView.getContext();
|
||||
ScriptFile scriptFile = scriptFileList.get(position);
|
||||
new Shortcut(context).name(scriptFile.name)
|
||||
@@ -139,18 +137,18 @@ public abstract class ScriptFileOperation {
|
||||
.icon(R.drawable.ic_robot_green)
|
||||
.extras(new Intent().putExtra("path", scriptFile.path))
|
||||
.send();
|
||||
Snackbar.make(recyclerView, R.string.text_already_create, Snackbar.LENGTH_SHORT).show();
|
||||
EventBus.getDefault().post(R.string.text_already_create);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Remove extends ScriptFileOperation {
|
||||
|
||||
static {
|
||||
addOperation(App.getApp().getString(R.string.text_delete), R.drawable.ic_delete_green_48dp, new Remove());
|
||||
public Remove() {
|
||||
super(App.getApp().getString(R.string.text_delete), R.drawable.ic_delete_green_48dp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate(ScriptListRecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
public void operate(RecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
scriptFileList.remove(position);
|
||||
recyclerView.getAdapter().notifyItemRemoved(position);
|
||||
}
|
||||
@@ -158,14 +156,14 @@ public abstract class ScriptFileOperation {
|
||||
|
||||
public static class Delete extends ScriptFileOperation {
|
||||
|
||||
static {
|
||||
addOperation(App.getApp().getString(R.string.text_delete_absolutly), R.drawable.ic_delete_forever_green_48dp, new Delete());
|
||||
public Delete() {
|
||||
super(App.getApp().getString(R.string.text_delete_absolutly), R.drawable.ic_delete_forever_green_48dp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate(ScriptListRecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
public void operate(RecyclerView recyclerView, ScriptFileList scriptFileList, int position) {
|
||||
boolean succeed = scriptFileList.deleteFromFileSystem(position);
|
||||
Snackbar.make(recyclerView, succeed ? R.string.text_already_delete : R.string.text_delete_failed, Snackbar.LENGTH_SHORT).show();
|
||||
EventBus.getDefault().post(new ShowMessageEvent(succeed ? R.string.text_already_delete : R.string.text_delete_failed));
|
||||
recyclerView.getAdapter().notifyItemRemoved(position);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,10 @@ import android.widget.ImageView;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.stardust.scriptdroid.tool.ViewTool;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
import static com.stardust.scriptdroid.tool.ViewTool.$;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/24.
|
||||
@@ -30,26 +31,31 @@ public class ScriptFileOperationPopupMenu extends PopupWindow {
|
||||
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onClick(View view, int position);
|
||||
void onClick(View view, int position, ScriptFileOperation operation);
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
private ScriptFileOperationListRecyclerView mOperationListRecyclerView;
|
||||
private OnItemClickListener mOnItemClickListener;
|
||||
|
||||
|
||||
private List<ScriptFileOperation> mScriptFileOperationList;
|
||||
|
||||
private final View.OnClickListener mOnItemClickRealListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mOnItemClickListener != null) {
|
||||
int position = mOperationListRecyclerView.getChildViewHolder(v).getAdapterPosition();
|
||||
mOnItemClickListener.onClick(v, position);
|
||||
mOnItemClickListener.onClick(v, position, mScriptFileOperationList.get(position));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public ScriptFileOperationPopupMenu(Context context) {
|
||||
super();
|
||||
|
||||
public ScriptFileOperationPopupMenu(Context context, List<ScriptFileOperation> scriptFileOperationList) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
mScriptFileOperationList = scriptFileOperationList;
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -77,7 +83,7 @@ public class ScriptFileOperationPopupMenu extends PopupWindow {
|
||||
|
||||
private float getScreenHeight() {
|
||||
DisplayMetrics displaymetrics = new DisplayMetrics();
|
||||
((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
|
||||
((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displaymetrics);
|
||||
return displaymetrics.heightPixels;
|
||||
}
|
||||
|
||||
@@ -93,8 +99,9 @@ public class ScriptFileOperationPopupMenu extends PopupWindow {
|
||||
private void initContentView() {
|
||||
View contentView = View.inflate(mContext, R.layout.script_file_operation_popup_menu_content, null);
|
||||
setContentView(contentView);
|
||||
mOperationListRecyclerView = $(contentView, R.id.operation_list);
|
||||
mOperationListRecyclerView = ViewTool.$(contentView, R.id.operation_list);
|
||||
mOperationListRecyclerView.setOnItemClickListener(mOnItemClickRealListener);
|
||||
mOperationListRecyclerView.setScriptFileOperationList(mScriptFileOperationList);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +109,8 @@ public class ScriptFileOperationPopupMenu extends PopupWindow {
|
||||
|
||||
private OnClickListener mOnItemClickListener;
|
||||
|
||||
private List<ScriptFileOperation> mScriptFileOperationList;
|
||||
|
||||
public ScriptFileOperationListRecyclerView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
@@ -117,6 +126,10 @@ public class ScriptFileOperationPopupMenu extends PopupWindow {
|
||||
init();
|
||||
}
|
||||
|
||||
public void setScriptFileOperationList(List<ScriptFileOperation> scriptFileOperationList) {
|
||||
mScriptFileOperationList = scriptFileOperationList;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
setAdapter(new Adapter<ViewHolder>() {
|
||||
@@ -128,14 +141,14 @@ public class ScriptFileOperationPopupMenu extends PopupWindow {
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
ScriptFileOperation operation = ScriptFileOperation.getOperation(position);
|
||||
ScriptFileOperation operation = mScriptFileOperationList.get(position);
|
||||
holder.operationName.setText(operation.getName());
|
||||
holder.icon.setImageResource(operation.getIconResId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return ScriptFileOperation.getOperationNames().size();
|
||||
return mScriptFileOperationList.size();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -152,8 +165,8 @@ public class ScriptFileOperationPopupMenu extends PopupWindow {
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
itemView.setOnClickListener(mOnItemClickListener);
|
||||
operationName = $(itemView, R.id.name);
|
||||
icon = $(itemView, R.id.icon);
|
||||
operationName = ViewTool.$(itemView, R.id.name);
|
||||
icon = ViewTool.$(itemView, R.id.icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,20 +6,19 @@ import android.content.ClipboardManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.tool.IntentTool;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
import com.stardust.scriptdroid.BuildConfig;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.tool.IntentTool;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
|
||||
import moe.feng.alipay.zerosdk.AlipayZeroSdk;
|
||||
|
||||
|
||||
@@ -10,15 +10,15 @@ import android.support.v7.widget.Toolbar;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.file.SampleFileManager;
|
||||
import com.stardust.scriptdroid.tool.IntentTool;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.ui.error.IssueReportActivity;
|
||||
import com.stardust.util.MapEntries;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
import com.stardust.theme.app.ColorSelectActivity;
|
||||
import com.stardust.theme.util.ListBuilder;
|
||||
import com.stardust.util.MapEntries;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -26,7 +26,6 @@ import java.util.Map;
|
||||
import de.psdev.licensesdialog.LicenseResolver;
|
||||
import de.psdev.licensesdialog.LicensesDialog;
|
||||
import de.psdev.licensesdialog.licenses.License;
|
||||
import de.psdev.licensesdialog.licenses.MozillaPublicLicense11;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/2.
|
||||
|
||||
Reference in New Issue
Block a user