From e33ce733d5f8d54531332bff532f58510dff6104 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 6 Dec 2017 13:18:36 +0800 Subject: [PATCH] add: module floaty; events.on('exit') --- autojs/src/main/assets/init.js | 2 +- autojs/src/main/assets/modules/__floaty__.js | 37 ++++ autojs/src/main/assets/modules/__ui__.js | 2 + .../autojs/core/console/StardustConsole.java | 17 +- .../autojs/core/floaty/FloatyWindow.java | 89 +++++++++- .../autojs/rhino/ProxyJavaObject.java | 70 ++++++++ .../autojs/runtime/ScriptRuntime.java | 37 ++-- .../stardust/autojs/runtime/api/Floaty.java | 159 ++++++++++++++++++ .../stardust/autojs/runtime/api/Loopers.java | 1 - .../com/stardust/autojs/runtime/api/UI.java | 6 + autojs/src/main/res/layout/floaty_window.xml | 42 +++++ autojs/src/main/res/values/styles.xml | 11 ++ 12 files changed, 448 insertions(+), 25 deletions(-) create mode 100644 autojs/src/main/assets/modules/__floaty__.js create mode 100644 autojs/src/main/java/com/stardust/autojs/rhino/ProxyJavaObject.java create mode 100644 autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java create mode 100644 autojs/src/main/res/layout/floaty_window.xml diff --git a/autojs/src/main/assets/init.js b/autojs/src/main/assets/init.js index c389de82..68cc23cb 100644 --- a/autojs/src/main/assets/init.js +++ b/autojs/src/main/assets/init.js @@ -65,7 +65,7 @@ require("__general__")(__runtime__, this); (function(scope){ var modules = ['app', 'automator', 'console', 'dialogs', 'io', 'selector', 'shell', 'web', 'ui', - "images", "timers", "events", "engines", "RootAutomator", "http", "storages"]; + "images", "timers", "events", "engines", "RootAutomator", "http", "storages", "floaty"]; var len = modules.length; for(var i = 0; i < len; i++) { var m = modules[i]; diff --git a/autojs/src/main/assets/modules/__floaty__.js b/autojs/src/main/assets/modules/__floaty__.js new file mode 100644 index 00000000..73db3382 --- /dev/null +++ b/autojs/src/main/assets/modules/__floaty__.js @@ -0,0 +1,37 @@ + +module.exports = function(__runtime__, scope){ + var floaty = {}; + + floaty.window = function(layout){ + if(typeof(layout) == 'xml'){ + layout = layout.toString(); + } + return wrap(__runtime__.floaty.window(layout)); + } + + function wrap(window){ + var proxyObject = new com.stardust.autojs.rhino.ProxyJavaObject(scope, window, window.getClass()); + proxyObject.__proxy__ = { + set: function(name, value){ + window[name] = value; + }, + get: function(name) { + var value = window[name]; + if(typeof(value) == 'undefined'){ + value = window.getView(name); + if(!value){ + value = undefined; + }else{ + value = scope.ui.__decorate__(value); + + } + } + return value; + } + }; + return proxyObject; + } + + return floaty; +} + diff --git a/autojs/src/main/assets/modules/__ui__.js b/autojs/src/main/assets/modules/__ui__.js index 91eb34a2..522b7864 100644 --- a/autojs/src/main/assets/modules/__ui__.js +++ b/autojs/src/main/assets/modules/__ui__.js @@ -83,6 +83,8 @@ module.exports = function(__runtime__, scope){ return view; } + ui.__decorate__ = decorate; + var proxy = __runtime__.ui; proxy.__proxy__ = { set: function(name, value){ diff --git a/autojs/src/main/java/com/stardust/autojs/core/console/StardustConsole.java b/autojs/src/main/java/com/stardust/autojs/core/console/StardustConsole.java index 34ebc957..a7ba8964 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/console/StardustConsole.java +++ b/autojs/src/main/java/com/stardust/autojs/core/console/StardustConsole.java @@ -148,16 +148,13 @@ public class StardustConsole extends AbstractConsole { return; } startFloatyService(); - mUiHandler.post(new Runnable() { - @Override - public void run() { - try { - FloatyService.addWindow(mFloatyWindow); - // SecurityException: https://github.com/hyb1996-guest/AutoJsIssueReport/issues/4781 - } catch (WindowManager.BadTokenException | SecurityException e) { - e.printStackTrace(); - mUiHandler.toast(R.string.text_no_floating_window_permission); - } + mUiHandler.post(() -> { + try { + FloatyService.addWindow(mFloatyWindow); + // SecurityException: https://github.com/hyb1996-guest/AutoJsIssueReport/issues/4781 + } catch (WindowManager.BadTokenException | SecurityException e) { + e.printStackTrace(); + mUiHandler.toast(R.string.text_no_floating_window_permission); } }); mShown = true; diff --git a/autojs/src/main/java/com/stardust/autojs/core/floaty/FloatyWindow.java b/autojs/src/main/java/com/stardust/autojs/core/floaty/FloatyWindow.java index 6fff1e64..604fac1a 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/floaty/FloatyWindow.java +++ b/autojs/src/main/java/com/stardust/autojs/core/floaty/FloatyWindow.java @@ -1,5 +1,13 @@ package com.stardust.autojs.core.floaty; +import android.content.Intent; +import android.support.annotation.Nullable; +import android.view.View; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import com.stardust.autojs.R; +import com.stardust.enhancedfloaty.FloatyService; import com.stardust.enhancedfloaty.ResizableFloaty; import com.stardust.enhancedfloaty.ResizableFloatyWindow; @@ -7,7 +15,86 @@ import com.stardust.enhancedfloaty.ResizableFloatyWindow; * Created by Stardust on 2017/12/5. */ -public class FloatyWindow { +public class FloatyWindow extends ResizableFloatyWindow { + + private static final Object LOCK = new Object(); + private View mView; + private boolean mCreated = false; + private View mMoveCursor; + private View mResizer; + public FloatyWindow(View view) { + super(new MyFloaty(view)); + mView = view; + } + + public void waitFor() { + synchronized (LOCK) { + if (mCreated) { + return; + } + try { + LOCK.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public void onCreate(FloatyService service, WindowManager manager) { + super.onCreate(service, manager); + synchronized (LOCK) { + mCreated = true; + LOCK.notify(); + } + View root = (View) mView.getParent().getParent(); + mMoveCursor = root.findViewById(R.id.move_cursor); + mResizer = root.findViewById(R.id.resizer); + } + + public void setAdjustEnabled(boolean enabled) { + if (!enabled) { + mMoveCursor.setVisibility(View.GONE); + mResizer.setVisibility(View.GONE); + } else { + mMoveCursor.setVisibility(View.VISIBLE); + mResizer.setVisibility(View.VISIBLE); + } + } + + public boolean isAdjustEnabled() { + return mMoveCursor.getVisibility() == View.VISIBLE; + } + + private static class MyFloaty implements ResizableFloaty { + + + private View mContentView; + + + public MyFloaty(View view) { + mContentView = view; + } + + @Override + public View inflateView(FloatyService floatyService, ResizableFloatyWindow resizableFloatyWindow) { + View view = View.inflate(mContentView.getContext(), R.layout.floaty_window, null); + ((FrameLayout) view.findViewById(R.id.container)).addView(mContentView); + return view; + } + + @Nullable + @Override + public View getResizerView(View view) { + return view.findViewById(R.id.resizer); + } + + @Nullable + @Override + public View getMoveCursorView(View view) { + return view.findViewById(R.id.move_cursor); + } + } } diff --git a/autojs/src/main/java/com/stardust/autojs/rhino/ProxyJavaObject.java b/autojs/src/main/java/com/stardust/autojs/rhino/ProxyJavaObject.java new file mode 100644 index 00000000..cb9bf9e3 --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/rhino/ProxyJavaObject.java @@ -0,0 +1,70 @@ +package com.stardust.autojs.rhino; + +import org.mozilla.javascript.Context; +import org.mozilla.javascript.NativeFunction; +import org.mozilla.javascript.NativeJavaObject; +import org.mozilla.javascript.NativeObject; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.UniqueTag; + +/** + * Created by Stardust on 2017/12/6. + */ + +public class ProxyJavaObject extends NativeJavaObject { + + private NativeFunction mGetter; + private NativeFunction mSetter; + + public ProxyJavaObject() { + } + + public ProxyJavaObject(Scriptable scope, Object javaObject, Class staticType) { + super(scope, javaObject, staticType); + } + + public ProxyJavaObject(Scriptable scope, Object javaObject, Class staticType, boolean isAdapter) { + super(scope, javaObject, staticType, isAdapter); + } + + @Override + public void put(String name, Scriptable start, Object value) { + if (name.equals("__proxy__")) { + NativeObject proxy = (NativeObject) value; + Object getter = proxy.get("get", start); + if (getter instanceof NativeFunction) { + mGetter = (NativeFunction) getter; + } + Object setter = proxy.get("set", start); + if (setter instanceof NativeFunction) { + mSetter = (NativeFunction) setter; + } + } else if (mSetter != null) { + mSetter.call(Context.getCurrentContext(), start, start, new Object[]{name, value}); + } else { + super.put(name, start, value); + } + } + + public Object getWithoutProxy(String name, Scriptable start) { + return super.get(name, start); + } + + @Override + public Object get(String name, Scriptable start) { + Object value = super.get(name, start); + if (value != null && value != UniqueTag.NOT_FOUND) { + return value; + } + if (mGetter != null) { + value = mGetter.call(Context.getCurrentContext(), start, start, new Object[]{name}); + } + return value; + } + + @Override + public Object getDefaultValue(Class typeHint) { + return toString(); + } +} + diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java index 134cf35b..bcc91e5e 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java @@ -16,6 +16,7 @@ import com.stardust.autojs.runtime.api.Console; import com.stardust.autojs.runtime.api.Device; import com.stardust.autojs.runtime.api.Engines; import com.stardust.autojs.runtime.api.Events; +import com.stardust.autojs.runtime.api.Floaty; import com.stardust.autojs.runtime.api.Loopers; import com.stardust.autojs.runtime.api.Threads; import com.stardust.autojs.runtime.api.Timers; @@ -154,6 +155,9 @@ public class ScriptRuntime { @ScriptVariable public final Threads threads; + @ScriptVariable + public final Floaty floaty; + private Images images; private static WeakReference applicationContext; @@ -182,6 +186,7 @@ public class ScriptRuntime { dialogs = new Dialogs(app, mUiHandler, bridges); threads = new Threads(this); device = new Device(mUiHandler.getContext()); + floaty = new Floaty(mUiHandler, ui); } public void init() { @@ -313,23 +318,31 @@ public class ScriptRuntime { } public void onExit() { + //悬浮窗需要第一时间关闭以免出现恶意脚本全屏悬浮窗屏蔽屏幕并且在exit中写死循环的问题 + ignoresException(floaty::closeAll); try { - threads.shutDownAll(); + events.emit("exit"); + } catch (Exception ignored) { + console.error("exception on exit: " + ignored); + } + ignoresException(threads::shutDownAll); + ignoresException(events::recycle); + ignoresException(loopers::quitAll); + ignoresException(() -> { + if (mRootShell != null) mRootShell.exitAndWaitFor(); + mRootShell = null; + mShellSupplier = null; + }); + ignoresException(() -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { images.releaseScreenCapturer(); } + }); + } - if (events != null) { - events.recycle(); - } - if (loopers != null) { - loopers.quitAll(); - } - if (mRootShell != null) { - mRootShell.exitAndWaitFor(); - } - mRootShell = null; - mShellSupplier = null; + private void ignoresException(Runnable r) { + try { + r.run(); } catch (Exception e) { e.printStackTrace(); } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java new file mode 100644 index 00000000..91f3030e --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java @@ -0,0 +1,159 @@ +package com.stardust.autojs.runtime.api; + +import android.content.Context; +import android.content.Intent; +import android.os.Looper; +import android.view.ContextThemeWrapper; +import android.view.View; + +import com.stardust.autojs.R; +import com.stardust.autojs.core.floaty.FloatyWindow; +import com.stardust.autojs.core.ui.JsLayoutInflater; +import com.stardust.autojs.core.ui.JsViewHelper; +import com.stardust.autojs.rhino.ProxyObject; +import com.stardust.enhancedfloaty.FloatyService; +import com.stardust.util.UiHandler; + +import org.mozilla.javascript.NativeJavaObject; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.UniqueTag; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * Created by Stardust on 2017/12/5. + */ + +public class Floaty { + + private JsLayoutInflater mJsLayoutInflater; + private Context mContext; + private UiHandler mUiHandler; + private Set mWindows = new HashSet<>(); + + public Floaty(UiHandler uiHandler, UI ui) { + mUiHandler = uiHandler; + mContext = new ContextThemeWrapper(mUiHandler.getContext(), R.style.AppTheme); + mJsLayoutInflater = ui.getJsLayoutInflater(); + } + + public JsFloatyWindow window(String xml) { + return window(inflate(xml)); + } + + public JsFloatyWindow window(View view) { + JsFloatyWindow window = new JsFloatyWindow(view); + mWindows.add(window); + return window; + } + + private View inflate(String xml) { + return mJsLayoutInflater.inflate(mContext, xml); + } + + public void closeAll() { + Iterator iterator = mWindows.iterator(); + while (iterator.hasNext()) { + JsFloatyWindow window = iterator.next(); + if (Looper.myLooper() == Looper.getMainLooper()) { + window.mWindow.close(); + } else { + mUiHandler.post(() -> window.mWindow.close()); + } + iterator.remove(); + } + } + + public class JsFloatyWindow { + + private Map mViewCache = new HashMap<>(); + private View mView; + private FloatyWindow mWindow; + + public JsFloatyWindow(View view) { + mWindow = new FloatyWindow(view); + mUiHandler.post(() -> { + mUiHandler.getContext().startService(new Intent(mUiHandler.getContext(), FloatyService.class)); + FloatyService.addWindow(mWindow); + }); + mWindow.waitFor(); + setSize(mWindow.getWindowBridge().getScreenWidth() / 2, mWindow.getWindowBridge().getScreenHeight() / 2); + mView = view; + } + + public View getView(String id) { + View v = mViewCache.get(id); + if (v != null) { + return v; + } + v = JsViewHelper.findViewByStringId(mView, id); + if (v != null) { + mViewCache.put(id, v); + return v; + } else { + return null; + } + } + public int getX() { + return mWindow.getWindowBridge().getX(); + } + + public int getY() { + return mWindow.getWindowBridge().getY(); + } + + public int getWidth() { + return mWindow.getWindowBridge().getWidth(); + } + + public int getHeight() { + return mWindow.getWindowBridge().getHeight(); + } + + public void setSize(int w, int h) { + if (Looper.myLooper() == Looper.getMainLooper()) { + mWindow.getWindowBridge().updateMeasure(w, h); + } else { + mUiHandler.post(() -> mWindow.getWindowBridge().updateMeasure(w, h)); + } + } + + public void setPosition(int x, int y) { + if (Looper.myLooper() == Looper.getMainLooper()) { + mWindow.getWindowBridge().updatePosition(x, y); + } else { + mUiHandler.post(() -> mWindow.getWindowBridge().updatePosition(x, y)); + } + } + + public void setAdjustEnabled(boolean enabled) { + if (Looper.myLooper() == Looper.getMainLooper()) { + mWindow.setAdjustEnabled(enabled); + } else { + mUiHandler.post(() -> mWindow.setAdjustEnabled(enabled)); + } + } + + public boolean isAdjustEnabled() { + return mWindow.isAdjustEnabled(); + } + + public void close() { + if (!mWindows.remove(this)) { + return; + } + if (Looper.myLooper() == Looper.getMainLooper()) { + mWindow.close(); + } else { + mUiHandler.post(() -> mWindow.close()); + } + } + } + + +} diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Loopers.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Loopers.java index 473c620e..b54f436e 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Loopers.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Loopers.java @@ -38,7 +38,6 @@ public class Loopers { Looper l = Looper.myLooper(); if (l != null && shouldQuitLooper()) { if (mLooperQuitHandler != null && mLooperQuitHandler.shouldQuit()) { - mScriptRuntime.events.emit("exit"); l.quit(); } } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java index 488d8648..8409e7b5 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java @@ -21,10 +21,12 @@ public class UI extends ProxyObject { private Context mContext; private Map mProperties = new ConcurrentHashMap<>(); + private JsLayoutInflater mJsLayoutInflater; public UI(Context context, JsLayoutInflater layoutInflater) { mContext = context; mProperties.put("layoutInflater", layoutInflater); + mJsLayoutInflater = layoutInflater; } public UI(Context context) { @@ -32,6 +34,10 @@ public class UI extends ProxyObject { } + public JsLayoutInflater getJsLayoutInflater() { + return mJsLayoutInflater; + } + @Override public String getClassName() { return UI.class.getSimpleName(); diff --git a/autojs/src/main/res/layout/floaty_window.xml b/autojs/src/main/res/layout/floaty_window.xml new file mode 100644 index 00000000..d62cbd71 --- /dev/null +++ b/autojs/src/main/res/layout/floaty_window.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/autojs/src/main/res/values/styles.xml b/autojs/src/main/res/values/styles.xml index a95206c6..b8fb963f 100644 --- a/autojs/src/main/res/values/styles.xml +++ b/autojs/src/main/res/values/styles.xml @@ -5,4 +5,15 @@ #cc181818 + + + + #009688 + #009688 + #03a9f4 \ No newline at end of file