diff --git a/app/src/main/java/com/stardust/scriptdroid/autojs/AutoJs.java b/app/src/main/java/com/stardust/scriptdroid/autojs/AutoJs.java index ba93485a..5fe8743c 100644 --- a/app/src/main/java/com/stardust/scriptdroid/autojs/AutoJs.java +++ b/app/src/main/java/com/stardust/scriptdroid/autojs/AutoJs.java @@ -32,7 +32,7 @@ import com.stardust.scriptdroid.R; import com.stardust.autojs.core.image.ScreenCaptureRequestActivity; import com.stardust.autojs.core.util.Shell; import com.stardust.autojs.core.console.StardustConsole; -import com.stardust.scriptdroid.sublime.SublimePluginService; +import com.stardust.scriptdroid.pluginclient.DevPluginService; import com.stardust.util.ScreenMetrics; import com.stardust.util.Supplier; import com.stardust.util.UiHandler; @@ -81,7 +81,7 @@ public class AutoJs { @Override public String println(int level, CharSequence charSequence) { String log = super.println(level, charSequence); - SublimePluginService.log(log); + DevPluginService.getInstance().log(log); return log; } }; diff --git a/app/src/main/java/com/stardust/scriptdroid/pluginclient/DevPluginClient.java b/app/src/main/java/com/stardust/scriptdroid/pluginclient/DevPluginClient.java new file mode 100644 index 00000000..32429fe4 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/pluginclient/DevPluginClient.java @@ -0,0 +1,187 @@ +package com.stardust.scriptdroid.pluginclient; + +import android.os.Build; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.stardust.scriptdroid.tool.SimpleObserver; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Map; + +import io.reactivex.Observable; +import io.reactivex.subjects.PublishSubject; + +/** + * Created by Stardust on 2017/5/10. + */ + +public class DevPluginClient { + + public static class State { + + public static final int DISCONNECTED = 0; + public static final int CONNECTING = 1; + public static final int CONNECTED = 2; + + private final int mState; + private final Throwable mException; + + public State(int state, Throwable exception) { + mState = state; + mException = exception; + } + + public State(int state) { + this(state, null); + } + + public int getState() { + return mState; + } + + public Throwable getException() { + return mException; + } + } + + private static final State STATE_CONNECTED = new State(State.CONNECTED); + private static final State STATE_CONNECTING = new State(State.CONNECTING); + + private volatile Socket mSocket; + private Handler mResponseHandler; + private String host; + private int port; + private OutputStream mOutputStream; + private final PublishSubject mConnection; + private int mState; + + public DevPluginClient(String host, int port, PublishSubject connection) { + this.host = host; + this.port = port; + mConnection = connection; + mConnection.subscribe(state -> mState = state.getState()); + } + + public int getState() { + return mState; + } + + public void setResponseHandler(Handler handler) { + mResponseHandler = handler; + } + + public void connectToServer() { + if (mState != State.DISCONNECTED) { + throw new IllegalStateException("Connecting or Connected!"); + } + new Thread(() -> { + if (mState != State.DISCONNECTED) { + return; + } + mConnection.onNext(STATE_CONNECTING); + try { + connect(); + if (mSocket != null) + readDataFromSocket(); + close(); + } catch (Exception e) { + e.printStackTrace(); + close(); + mConnection.onNext(new State(State.DISCONNECTED, e)); + } + }).start(); + } + + + private void readDataFromSocket() throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(mSocket.getInputStream())); + JsonParser parser = new JsonParser(); + while (!Thread.currentThread().isInterrupted()) { + String line = reader.readLine(); + if (line == null) { + return; + } + if (mResponseHandler != null) { + handleData(parser, line); + + } + } + } + + private void handleData(JsonParser parser, String line) { + try { + JsonElement jsonElement = parser.parse(line); + JsonObject jsonObject = jsonElement.getAsJsonObject(); + mResponseHandler.handle(jsonObject); + } catch (Exception e) { + e.printStackTrace(); + //ignore exception thrown by data handler + } + } + + private void connect() throws IOException { + mSocket = new Socket(host, port); + mConnection.onNext(STATE_CONNECTED); + mOutputStream = mSocket.getOutputStream(); + sendDeviceName(); + } + + private void sendDeviceName() { + JsonObject object = new JsonObject(); + object.addProperty("type", "device_name"); + object.addProperty("device_name", Build.BRAND + " " + Build.MODEL); + send(object).subscribe(); + } + + + public Observable send(final JsonObject object) { + if (mState != State.CONNECTED) { + throw new IllegalStateException("Not connected!"); + } + return Observable.fromCallable(() -> { + mOutputStream.write(object.toString().getBytes()); + mOutputStream.write("\n".getBytes()); + mOutputStream.flush(); + return object; + }); + } + + public Observable send(Map data) { + JsonObject object = new JsonObject(); + for (Map.Entry entry : data.entrySet()) { + Object value = entry.getValue(); + if (value instanceof Number) { + object.addProperty(entry.getKey(), (Number) value); + } else if (value instanceof Boolean) { + object.addProperty(entry.getKey(), (Boolean) value); + } else if (value instanceof Character) { + object.addProperty(entry.getKey(), (Character) value); + } else { + object.addProperty(entry.getKey(), value.toString()); + } + } + return send(object); + } + + public boolean close() { + if (mSocket != null) { + try { + mSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + mSocket = null; + mOutputStream = null; + return true; + } + return false; + } + + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimeResponseHandler.java b/app/src/main/java/com/stardust/scriptdroid/pluginclient/DevPluginResponseHandler.java similarity index 50% rename from app/src/main/java/com/stardust/scriptdroid/sublime/SublimeResponseHandler.java rename to app/src/main/java/com/stardust/scriptdroid/pluginclient/DevPluginResponseHandler.java index 34c528c7..6580bd4e 100644 --- a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimeResponseHandler.java +++ b/app/src/main/java/com/stardust/scriptdroid/pluginclient/DevPluginResponseHandler.java @@ -1,7 +1,6 @@ -package com.stardust.scriptdroid.sublime; +package com.stardust.scriptdroid.pluginclient; import android.text.TextUtils; -import android.util.SparseArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; @@ -21,56 +20,40 @@ import java.util.HashMap; * Created by Stardust on 2017/5/11. */ -public class SublimeResponseHandler implements Handler { +public class DevPluginResponseHandler implements Handler { private Router mRouter = new Router("type") .handler("command", new Router("command") - .handler("run", new Handler() { - @Override - public boolean handle(JsonObject data) { - String script = data.get("script").getAsString(); - String name = getName(data); - String viewId = data.get("view_id").getAsString(); - runScript(viewId, name, script); - return false; - } + .handler("run", data -> { + String script = data.get("script").getAsString(); + String name = getName(data); + String viewId = data.get("view_id").getAsString(); + runScript(viewId, name, script); + return false; }) - .handler("stop", new Handler() { - @Override - public boolean handle(JsonObject data) { - String viewId = data.get("view_id").getAsString(); - stopScript(viewId); - return true; - } + .handler("stop", data -> { + String viewId = data.get("view_id").getAsString(); + stopScript(viewId); + return true; }) - .handler("save", new Handler() { - @Override - public boolean handle(JsonObject data) { - String script = data.get("script").getAsString(); - String name = getName(data); - saveScript(name, script); - return false; - } + .handler("save", data -> { + String script = data.get("script").getAsString(); + String name = getName(data); + saveScript(name, script); + return false; }) - .handler("rerun", new Handler() { - - @Override - public boolean handle(JsonObject data) { - String viewId = data.get("view_id").getAsString(); - String script = data.get("script").getAsString(); - String name = getName(data); - stopScript(viewId); - runScript(viewId, name, script); - return false; - } + .handler("rerun", data -> { + String viewId = data.get("view_id").getAsString(); + String script = data.get("script").getAsString(); + String name = getName(data); + stopScript(viewId); + runScript(viewId, name, script); + return false; }) - .handler("stopAll", new Handler() { - @Override - public boolean handle(JsonObject data) { - AutoJs.getInstance().getScriptEngineService().stopAllAndToast(); - return false; - } + .handler("stopAll", data -> { + AutoJs.getInstance().getScriptEngineService().stopAllAndToast(); + return false; })); diff --git a/app/src/main/java/com/stardust/scriptdroid/pluginclient/DevPluginService.java b/app/src/main/java/com/stardust/scriptdroid/pluginclient/DevPluginService.java new file mode 100644 index 00000000..82936678 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/pluginclient/DevPluginService.java @@ -0,0 +1,63 @@ +package com.stardust.scriptdroid.pluginclient; + +import com.google.gson.JsonObject; + +import io.reactivex.schedulers.Schedulers; +import io.reactivex.subjects.PublishSubject; + +/** + * Created by Stardust on 2017/5/11. + */ + +public class DevPluginService { + + private static DevPluginService sInstance = new DevPluginService(); + private DevPluginClient mClient; + private final PublishSubject mConnection = PublishSubject.create(); + + public static DevPluginService getInstance() { + return sInstance; + } + + public boolean isConnected() { + return mClient != null && mClient.getState() == DevPluginClient.State.CONNECTED; + } + + public boolean isDisconnected(){ + return mClient == null || mClient.getState() == DevPluginClient.State.DISCONNECTED; + } + + public void disconnectIfNeeded() { + if (isDisconnected()) + return; + disconnect(); + } + + public void disconnect() { + mClient.close(); + mClient = null; + mConnection.onNext(new DevPluginClient.State(DevPluginClient.State.DISCONNECTED)); + } + + public PublishSubject getConnection() { + return mConnection; + } + + public void connectToServer(String host) { + mClient = new DevPluginClient(host, 1209, mConnection); + mClient.setResponseHandler(new DevPluginResponseHandler()); + mClient.connectToServer(); + } + + public void log(String log) { + if (!isConnected()) + return; + JsonObject object = new JsonObject(); + object.addProperty("type", "log"); + object.addProperty("log", log); + mClient.send(object) + .subscribeOn(Schedulers.io()) + .subscribe(ignored -> { + }, Throwable::printStackTrace); + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/sublime/Handler.java b/app/src/main/java/com/stardust/scriptdroid/pluginclient/Handler.java similarity index 76% rename from app/src/main/java/com/stardust/scriptdroid/sublime/Handler.java rename to app/src/main/java/com/stardust/scriptdroid/pluginclient/Handler.java index 87acd293..b00615c7 100644 --- a/app/src/main/java/com/stardust/scriptdroid/sublime/Handler.java +++ b/app/src/main/java/com/stardust/scriptdroid/pluginclient/Handler.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.sublime; +package com.stardust.scriptdroid.pluginclient; import com.google.gson.JsonObject; diff --git a/app/src/main/java/com/stardust/scriptdroid/sublime/Router.java b/app/src/main/java/com/stardust/scriptdroid/pluginclient/Router.java similarity index 93% rename from app/src/main/java/com/stardust/scriptdroid/sublime/Router.java rename to app/src/main/java/com/stardust/scriptdroid/pluginclient/Router.java index 754f3eaa..57d8ea7e 100644 --- a/app/src/main/java/com/stardust/scriptdroid/sublime/Router.java +++ b/app/src/main/java/com/stardust/scriptdroid/pluginclient/Router.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.sublime; +package com.stardust.scriptdroid.pluginclient; import com.google.gson.JsonObject; diff --git a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java b/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java deleted file mode 100644 index ec34fed0..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.stardust.scriptdroid.sublime; - -import android.os.Build; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import org.reactivestreams.Publisher; -import org.reactivestreams.Subscriber; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.Socket; -import java.util.concurrent.Callable; - -import io.reactivex.Observable; -import io.reactivex.subjects.PublishSubject; - -/** - * Created by Stardust on 2017/5/10. - */ - -public class SublimePluginClient { - - - private volatile Socket mSocket; - private Handler mResponseHandler; - private String host; - private int port; - private OutputStream mOutputStream; - private final PublishSubject mConnectionState; - - public SublimePluginClient(String host, int port, PublishSubject connectionState) { - this.host = host; - this.port = port; - mConnectionState = connectionState; - } - - public void setResponseHandler(Handler handler) { - mResponseHandler = handler; - } - - public Observable listen() { - if (mSocket != null) { - throw new IllegalStateException("Socket listening "); - } - return Observable.fromPublisher(new Publisher() { - - @Override - public void subscribe(Subscriber s) { - if (mSocket != null) { - s.onError(new IllegalStateException("Socket listening ")); - return; - } - listenInternal(s); - } - }); - - } - - private void listenInternal(final Subscriber s) { - try { - mSocket = new Socket(host, port); - mConnectionState.onNext(true); - mSocket.setTcpNoDelay(true); - mOutputStream = mSocket.getOutputStream(); - s.onComplete(); - sendDeviceName(); - } catch (IOException e) { - s.onError(e); - tryClose(); - return; - } - try { - readLoop(mSocket.getInputStream()); - } catch (IOException e) { - e.printStackTrace(); - }finally { - tryClose(); - } - - } - - private void sendDeviceName() { - JsonObject object = new JsonObject(); - object.addProperty("type", "device_name"); - object.addProperty("device_name", Build.MODEL); - send(object).subscribe(); - } - - public PublishSubject getConnectionState() { - return mConnectionState; - } - - public boolean isListening() { - return mSocket != null; - } - - private void tryClose() { - try { - close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public Observable send(final JsonObject object) { - if (mSocket == null) { - throw new IllegalStateException("Socket is not listening "); - } - return Observable.fromCallable(() -> { - mOutputStream.write(object.toString().getBytes()); - mOutputStream.write("\n".getBytes()); - mOutputStream.flush(); - return object; - }); - } - - public void close() throws IOException { - if (mSocket != null) { - mSocket.close(); - mSocket = null; - mOutputStream = null; - mConnectionState.onNext(false); - } - } - - private void readLoop(InputStream stream) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); - JsonParser parser = new JsonParser(); - while (!Thread.currentThread().isInterrupted()) { - String line = reader.readLine(); - if (line == null) { - return; - } - if (mResponseHandler != null) { - JsonElement jsonElement = parser.parse(line); - JsonObject jsonObject = jsonElement.getAsJsonObject(); - mResponseHandler.handle(jsonObject); - } - } - } - - -} diff --git a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginService.java b/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginService.java deleted file mode 100644 index e5657519..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginService.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.stardust.scriptdroid.sublime; - -import com.google.gson.JsonObject; - -import io.reactivex.Observable; -import io.reactivex.Scheduler; -import io.reactivex.schedulers.Schedulers; -import io.reactivex.subjects.PublishSubject; - -/** - * Created by Stardust on 2017/5/11. - */ - -public class SublimePluginService { - - private static SublimePluginClient client; - private static final PublishSubject CONNECTION_STATE = PublishSubject.create(); - - public static boolean isConnected() { - return client != null && client.isListening(); - } - - public static void disconnectIfNeeded() { - if (!isConnected()) - return; - disconnect(); - } - - public static void disconnect() { - try { - client.close(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - client = null; - } - } - - public static PublishSubject getConnectionState() { - return CONNECTION_STATE; - } - - public static Observable connect(String host) { - client = new SublimePluginClient(host, 1209, CONNECTION_STATE); - client.setResponseHandler(new SublimeResponseHandler()); - return client.listen(); - } - - public static void log(String log) { - if (!isConnected()) - return; - JsonObject object = new JsonObject(); - object.addProperty("type", "log"); - object.addProperty("log", log); - client.send(object) - .subscribeOn(Schedulers.io()) - .subscribe(ignored -> { - }, Throwable::printStackTrace); - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java index 0388faa1..a71382e6 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java @@ -10,7 +10,6 @@ import android.widget.TextView; import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; -import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.target.SimpleTarget; import com.bumptech.glide.request.transition.Transition; @@ -18,7 +17,7 @@ import com.stardust.scriptdroid.App; import com.stardust.scriptdroid.Pref; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.network.GlideApp; -import com.stardust.scriptdroid.network.UserService; +import com.stardust.scriptdroid.pluginclient.DevPluginClient; import com.stardust.scriptdroid.ui.floating.CircularMenu; import com.stardust.scriptdroid.ui.floating.FloatyWindowManger; import com.stardust.scriptdroid.network.NodeBB; @@ -36,7 +35,7 @@ import com.stardust.scriptdroid.ui.widget.AvatarView; import com.stardust.theme.ThemeColorManager; import com.stardust.theme.ThemeColorManagerCompat; import com.stardust.view.accessibility.AccessibilityService; -import com.stardust.scriptdroid.sublime.SublimePluginService; +import com.stardust.scriptdroid.pluginclient.DevPluginService; import com.stardust.scriptdroid.tool.AccessibilityServiceTool; import com.stardust.scriptdroid.tool.WifiTool; import com.stardust.util.IntentUtil; @@ -95,23 +94,25 @@ public class DrawerFragment extends android.support.v4.app.Fragment { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mConnectionStateDisposable = SublimePluginService.getConnectionState() + mConnectionStateDisposable = DevPluginService.getInstance().getConnection() .observeOn(AndroidSchedulers.mainThread()) - .doOnNext(connected -> mConnectionItem.getSwitchCompat().setChecked(connected)) - .subscribe(); + .subscribe(state -> { + if (mConnectionItem != null) { + mConnectionItem.getSwitchCompat().setChecked(state.getState() == DevPluginClient.State.CONNECTED, false); + mConnectionItem.setProgress(state.getState() == DevPluginClient.State.CONNECTING); + } + if (state.getException() != null) { + showMessage(state.getException().getMessage()); + } + }); EventBus.getDefault().register(this); } - @Override - public void onStart() { - super.onStart(); - syncSwitchState(); - } - @Override public void onResume() { super.onResume(); + syncSwitchState(); syncUserInfo(); } @@ -121,6 +122,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment { if (Pref.isFloatingMenuShown()) { mFloatingWindowItem.getSwitchCompat().setChecked(true); } + mConnectionItem.getSwitchCompat().setChecked(DevPluginService.getInstance().isConnected(), false); } private void syncUserInfo() { @@ -238,11 +240,11 @@ public class DrawerFragment extends android.support.v4.app.Fragment { @Click(R.id.debug) void connectOrDisconnectToRemote() { boolean checked = mConnectionItem.getSwitchCompat().isChecked(); - boolean connected = SublimePluginService.isConnected(); + boolean connected = DevPluginService.getInstance().isConnected(); if (checked && !connected) { inputRemoteHost(); } else if (!checked && connected) { - SublimePluginService.disconnectIfNeeded(); + DevPluginService.getInstance().disconnectIfNeeded(); } } @@ -264,28 +266,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment { } private void connectToRemote(String host) { - mConnectionItem.setProgress(true); - Toast.makeText(App.getApp(), R.string.text_connecting, Toast.LENGTH_SHORT).show(); - SublimePluginService.connect(host) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new SimpleObserver() { - - @Override - public void onError(@io.reactivex.annotations.NonNull Throwable e) { - if (isHidden()) { - return; - } - Toast.makeText(App.getApp(), e.getMessage(), Toast.LENGTH_SHORT).show(); - mConnectionItem.getSwitchCompat().setChecked(false, false); - mConnectionItem.setProgress(false); - } - - @Override - public void onComplete() { - mConnectionItem.setProgress(false); - } - }); + DevPluginService.getInstance().connectToServer(host); } @Click(R.id.check_for_updates) @@ -350,6 +331,13 @@ public class DrawerFragment extends android.support.v4.app.Fragment { }); } + + private void showMessage(CharSequence text) { + if (getContext() == null) + return; + Toast.makeText(getContext(), text, Toast.LENGTH_SHORT).show(); + } + @Override public void onDestroy() { super.onDestroy(); diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/widget/PrefSwitch.java b/app/src/main/java/com/stardust/scriptdroid/ui/widget/PrefSwitch.java index f71901dc..902af283 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/widget/PrefSwitch.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/widget/PrefSwitch.java @@ -73,12 +73,12 @@ public class PrefSwitch extends SwitchCompat implements SharedPreferences.OnShar @Override public void setChecked(boolean checked) { - setChecked(checked, true); - + super.setChecked(checked); + notifyPrefChanged(checked); } public void setChecked(boolean checked, boolean notifyChange) { - super.setChecked(checked); + super.setChecked(checked, notifyChange); if (notifyChange) { notifyPrefChanged(checked); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cd6a5973..def955ea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -281,6 +281,7 @@ 重置失败 重置成功 无法读取文件: %s + 已连接 diff --git a/autojs/src/main/res/layout/console_view_item.xml b/autojs/src/main/res/layout/console_view_item.xml index e7624c7d..7e341b9a 100644 --- a/autojs/src/main/res/layout/console_view_item.xml +++ b/autojs/src/main/res/layout/console_view_item.xml @@ -2,6 +2,7 @@ \ No newline at end of file