rename dir

This commit is contained in:
pengfei.zhou
2019-12-21 20:17:45 +08:00
parent feb322ec8d
commit 1d98479c07
169 changed files with 0 additions and 0 deletions

1
doric-android/devkit/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,45 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "pub.doric:core:${rootProject.ext.Version}"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation "com.google.android.material:material:1.0.0"
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'cn.bingoogolapple:bga-qrcode-zbar:1.3.7'
implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
implementation "io.reactivex.rxjava2:rxjava:2.2.15"
api 'org.greenrobot:eventbus:3.1.1'
implementation 'com.lahm.library:easy-protector-release:1.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
apply from: rootProject.file('scripts/upload.gradle')

View File

View File

@@ -0,0 +1,3 @@
name=DoricDevKit
groupId=pub.doric
artifactId=devkit

21
doric-android/devkit/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,27 @@
package pub.doric.devkit;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("pub.doric.devkit.test", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="pub.doric.devkit">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<application>
<activity android:name=".ui.ScanQRCodeActivity" />
<activity
android:name=".ui.DemoDebugActivity"
android:theme="@style/Theme.Design.Light.NoActionBar" />
</application>
</manifest>

View File

@@ -0,0 +1,44 @@
package pub.doric.devkit;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
public class DevKit implements IDevKit {
public static boolean isRunningInEmulator = false;
public static String ip = "";
private static Gson gson = new Gson();
private static class Inner {
private static final DevKit sInstance = new DevKit();
}
private DevKit() {
}
public static DevKit getInstance() {
return Inner.sInstance;
}
private WSClient wsClient;
@Override
public void connectDevKit(String url) {
wsClient = new WSClient(url);
}
@Override
public void sendDevCommand(IDevKit.Command command, JsonObject jsonObject) {
JsonObject result = new JsonObject();
result.addProperty("cmd", command.toString());
result.add("data", jsonObject);
wsClient.send(gson.toJson(result));
}
@Override
public void disconnectDevKit() {
wsClient.close();
wsClient = null;
}
}

View File

@@ -0,0 +1,37 @@
package pub.doric.devkit;
import pub.doric.DoricContext;
import pub.doric.DoricContextManager;
import pub.doric.DoricNativeDriver;
public class DoricContextDebuggable {
private DoricContext doricContext;
private DoricDebugDriver doricDebugDriver;
public boolean isDebugging = false;
public DoricContextDebuggable(String contextId) {
this.doricContext = DoricContextManager.getContext(contextId);
isDebugging = true;
}
public void startDebug() {
doricDebugDriver = new DoricDebugDriver(new IStatusCallback() {
@Override
public void start() {
doricContext.setDriver(doricDebugDriver);
doricContext.reInit();
}
});
}
public void stopDebug() {
isDebugging = false;
doricDebugDriver.destroy();
doricContext.setDriver(DoricNativeDriver.getInstance());
doricContext.reInit();
}
public DoricContext getContext() {
return doricContext;
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package pub.doric.devkit;
import android.os.Handler;
import android.os.Looper;
import com.github.pengfeizhou.jscore.JSDecoder;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import pub.doric.DoricRegistry;
import pub.doric.IDoricDriver;
import pub.doric.async.AsyncCall;
import pub.doric.async.AsyncResult;
import pub.doric.engine.DoricJSEngine;
import pub.doric.utils.DoricConstant;
import pub.doric.utils.DoricLog;
import pub.doric.utils.ThreadMode;
/**
* @Description: Doric
* @Author: pengfei.zhou
* @CreateDate: 2019-07-18
*/
public class DoricDebugDriver implements IDoricDriver {
private final DoricJSEngine doricJSEngine;
private final ExecutorService mBridgeExecutor;
private final Handler mUIHandler;
private final Handler mJSHandler;
public DoricDebugDriver(IStatusCallback statusCallback) {
doricJSEngine = new DoricDebugJSEngine(statusCallback);
mBridgeExecutor = Executors.newCachedThreadPool();
mUIHandler = new Handler(Looper.getMainLooper());
mJSHandler = doricJSEngine.getJSHandler();
}
@Override
public AsyncResult<JSDecoder> invokeContextEntityMethod(final String contextId, final String method, final Object... args) {
final Object[] nArgs = new Object[args.length + 2];
nArgs[0] = contextId;
nArgs[1] = method;
if (args.length > 0) {
System.arraycopy(args, 0, nArgs, 2, args.length);
}
return invokeDoricMethod(DoricConstant.DORIC_CONTEXT_INVOKE, nArgs);
}
@Override
public AsyncResult<JSDecoder> invokeDoricMethod(final String method, final Object... args) {
return AsyncCall.ensureRunInHandler(mJSHandler, new Callable<JSDecoder>() {
@Override
public JSDecoder call() {
try {
return doricJSEngine.invokeDoricMethod(method, args);
} catch (Exception e) {
DoricLog.e("invokeDoricMethod(%s,...),error is %s", method, e.getLocalizedMessage());
return new JSDecoder(null);
}
}
});
}
@Override
public <T> AsyncResult<T> asyncCall(Callable<T> callable, ThreadMode threadMode) {
switch (threadMode) {
case JS:
return AsyncCall.ensureRunInHandler(mJSHandler, callable);
case UI:
return AsyncCall.ensureRunInHandler(mUIHandler, callable);
case INDEPENDENT:
default:
return AsyncCall.ensureRunInExecutor(mBridgeExecutor, callable);
}
}
@Override
public AsyncResult<Boolean> createContext(final String contextId, final String script, final String source) {
return AsyncCall.ensureRunInHandler(mJSHandler, new Callable<Boolean>() {
@Override
public Boolean call() {
try {
doricJSEngine.prepareContext(contextId, script, source);
return true;
} catch (Exception e) {
DoricLog.e("createContext %s error is %s", source, e.getLocalizedMessage());
return false;
}
}
});
}
@Override
public AsyncResult<Boolean> destroyContext(final String contextId) {
return AsyncCall.ensureRunInHandler(mJSHandler, new Callable<Boolean>() {
@Override
public Boolean call() {
try {
doricJSEngine.destroyContext(contextId);
return true;
} catch (Exception e) {
DoricLog.e("destroyContext %s error is %s", contextId, e.getLocalizedMessage());
return false;
}
}
});
}
@Override
public DoricRegistry getRegistry() {
return doricJSEngine.getRegistry();
}
public void destroy() {
doricJSEngine.teardown();
mBridgeExecutor.shutdown();
}
}

View File

@@ -0,0 +1,19 @@
package pub.doric.devkit;
import pub.doric.devkit.remote.DoricRemoteJSExecutor;
import pub.doric.engine.DoricJSEngine;
public class DoricDebugJSEngine extends DoricJSEngine {
private IStatusCallback statusCallback;
public DoricDebugJSEngine(IStatusCallback statusCallback) {
super();
this.statusCallback = statusCallback;
}
@Override
protected void initJSEngine() {
mDoricJSE = new DoricRemoteJSExecutor(statusCallback);
}
}

View File

@@ -0,0 +1,17 @@
package pub.doric.devkit;
import com.google.gson.JsonObject;
public class DoricDev {
public static void connectDevKit(String url) {
DevKit.getInstance().connectDevKit(url);
}
public static void sendDevCommand(IDevKit.Command command, JsonObject jsonObject) {
DevKit.getInstance().sendDevCommand(command, jsonObject);
}
public static void disconnectDevKit() {
DevKit.getInstance().disconnectDevKit();
}
}

View File

@@ -0,0 +1,16 @@
package pub.doric.devkit;
import com.google.gson.JsonObject;
public interface IDevKit {
enum Command {
DEBUG, HOT_RELOAD
}
void connectDevKit(String url);
void sendDevCommand(IDevKit.Command command, JsonObject jsonObject);
void disconnectDevKit();
}

View File

@@ -0,0 +1,5 @@
package pub.doric.devkit;
public interface IStatusCallback {
void start();
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package pub.doric.devkit;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.EOFException;
import java.net.ConnectException;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import pub.doric.devkit.event.ConnectExceptionEvent;
import pub.doric.devkit.event.EOFExceptionEvent;
import pub.doric.devkit.event.EnterDebugEvent;
import pub.doric.devkit.event.OpenEvent;
import pub.doric.devkit.event.ReloadEvent;
import pub.doric.devkit.ui.DevPanel;
/**
* @Description: com.github.penfeizhou.doric.dev
* @Author: pengfei.zhou
* @CreateDate: 2019-08-03
*/
public class WSClient extends WebSocketListener {
private final WebSocket webSocket;
public WSClient(String url) {
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder().url(url).build();
webSocket = okHttpClient.newWebSocket(request, this);
}
public void close() {
webSocket.close(-1, "Close");
}
@Override
public void onOpen(WebSocket webSocket, Response response) {
super.onOpen(webSocket, response);
DevPanel.isDevConnected = true;
EventBus.getDefault().post(new OpenEvent());
}
@Override
public void onMessage(WebSocket webSocket, String text) {
super.onMessage(webSocket, text);
try {
JSONObject jsonObject = new JSONObject(text);
String cmd = jsonObject.optString("cmd");
switch (cmd) {
case "RELOAD": {
String source = jsonObject.optString("source");
String script = jsonObject.optString("script");
EventBus.getDefault().post(new ReloadEvent(source, script));
}
break;
case "SWITCH_TO_DEBUG": {
String contextId = jsonObject.optString("contextId");
EventBus.getDefault().post(new EnterDebugEvent());
}
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
super.onClosing(webSocket, code, reason);
}
@Override
public void onClosed(WebSocket webSocket, int code, String reason) {
super.onClosed(webSocket, code, reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
super.onFailure(webSocket, t, response);
if (t instanceof EOFException) {
DevPanel.isDevConnected = false;
EventBus.getDefault().post(new EOFExceptionEvent());
} else if (t instanceof ConnectException) {
DevPanel.isDevConnected = false;
EventBus.getDefault().post(new ConnectExceptionEvent());
}
}
public void send(String command) {
webSocket.send(command);
}
}

View File

@@ -0,0 +1,4 @@
package pub.doric.devkit.event;
public class ConnectExceptionEvent {
}

View File

@@ -0,0 +1,4 @@
package pub.doric.devkit.event;
public class EOFExceptionEvent {
}

View File

@@ -0,0 +1,5 @@
package pub.doric.devkit.event;
public class EnterDebugEvent {
}

View File

@@ -0,0 +1,4 @@
package pub.doric.devkit.event;
public class OpenEvent {
}

View File

@@ -0,0 +1,11 @@
package pub.doric.devkit.event;
public class ReloadEvent {
public String source;
public String script;
public ReloadEvent(String source, String script) {
this.source = source;
this.script = script;
}
}

View File

@@ -0,0 +1,13 @@
package pub.doric.devkit.event;
public class StartDebugEvent {
private String contextId;
public StartDebugEvent(String contextId) {
this.contextId = contextId;
}
public String getContextId() {
return contextId;
}
}

View File

@@ -0,0 +1,5 @@
package pub.doric.devkit.event;
public class StopDebugEvent {
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package pub.doric.devkit.remote;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSRuntimeException;
import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
import pub.doric.devkit.IStatusCallback;
import pub.doric.engine.IDoricJSE;
public class DoricRemoteJSExecutor implements IDoricJSE {
private final RemoteJSExecutor mRemoteJSExecutor;
public DoricRemoteJSExecutor(IStatusCallback statusCallback) {
this.mRemoteJSExecutor = new RemoteJSExecutor(statusCallback);
}
@Override
public String loadJS(String script, String source) throws JSRuntimeException {
return mRemoteJSExecutor.loadJS(script, source);
}
@Override
public JSDecoder evaluateJS(String script, String source, boolean hashKey) throws JSRuntimeException {
return mRemoteJSExecutor.evaluateJS(script, source, hashKey);
}
@Override
public void injectGlobalJSFunction(String name, JavaFunction javaFunction) {
mRemoteJSExecutor.injectGlobalJSFunction(name, javaFunction);
}
@Override
public void injectGlobalJSObject(String name, JavaValue javaValue) {
mRemoteJSExecutor.injectGlobalJSObject(name, javaValue);
}
@Override
public JSDecoder invokeMethod(String objectName, String functionName, JavaValue[] javaValues, boolean hashKey) throws JSRuntimeException {
return mRemoteJSExecutor.invokeMethod(objectName, functionName, javaValues, hashKey);
}
@Override
public void teardown() {
mRemoteJSExecutor.destroy();
}
}

View File

@@ -0,0 +1,148 @@
package pub.doric.devkit.remote;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSONBuilder;
import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
import org.greenrobot.eventbus.EventBus;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.EOFException;
import java.net.ConnectException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import pub.doric.devkit.DevKit;
import pub.doric.devkit.IStatusCallback;
import pub.doric.devkit.event.StopDebugEvent;
public class RemoteJSExecutor {
private final WebSocket webSocket;
private final Map<String, JavaFunction> globalFunctions = new HashMap<>();
private JSDecoder temp;
public RemoteJSExecutor(final IStatusCallback statusCallback) {
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
final Request request = new Request.Builder().url("ws://" + DevKit.ip + ":2080").build();
final Thread current = Thread.currentThread();
webSocket = okHttpClient.newWebSocket(request, new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
LockSupport.unpark(current);
statusCallback.start();
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
if (t instanceof ConnectException) {
// 连接remote异常
LockSupport.unpark(current);
throw new RuntimeException("remote js executor cannot connect");
} else if (t instanceof EOFException) {
// 被远端强制断开
System.out.println("remote js executor eof");
LockSupport.unpark(current);
EventBus.getDefault().post(new StopDebugEvent());
}
}
@Override
public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {
try {
JSONObject jsonObject = new JSONObject(text);
String cmd = jsonObject.optString("cmd");
switch (cmd) {
case "injectGlobalJSFunction": {
String name = jsonObject.optString("name");
JSONArray arguments = jsonObject.optJSONArray("arguments");
assert arguments != null;
JSDecoder[] decoders = new JSDecoder[arguments.length()];
for (int i = 0; i < arguments.length(); i++) {
Object o = arguments.get(i);
decoders[i] = new JSDecoder(new ValueBuilder(o).build());
}
globalFunctions.get(name).exec(decoders);
}
break;
case "invokeMethod": {
try {
Object result = jsonObject.opt("result");
ValueBuilder vb = new ValueBuilder(result);
temp = new JSDecoder(vb.build());
System.out.println(result);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
LockSupport.unpark(current);
}
}
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
LockSupport.park(current);
}
public String loadJS(String script, String source) {
return null;
}
public JSDecoder evaluateJS(String script, String source, boolean hashKey) {
return null;
}
public void injectGlobalJSFunction(String name, JavaFunction javaFunction) {
globalFunctions.put(name, javaFunction);
webSocket.send(new JSONBuilder().put("cmd", "injectGlobalJSFunction")
.put("name", name).toString()
);
}
public void injectGlobalJSObject(String name, JavaValue javaValue) {
}
public JSDecoder invokeMethod(String objectName, String functionName, JavaValue[] javaValues, boolean hashKey) {
JSONArray jsonArray = new JSONArray();
for (JavaValue javaValue : javaValues) {
jsonArray.put(new JSONBuilder()
.put("type", javaValue.getType())
.put("value", javaValue.getValue())
.toJSONObject());
}
webSocket.send(new JSONBuilder()
.put("cmd", "invokeMethod")
.put("objectName", objectName)
.put("functionName", functionName)
.put("javaValues", jsonArray)
.put("hashKey", hashKey)
.toString());
LockSupport.park(Thread.currentThread());
return temp;
}
public void destroy() {
webSocket.close(1000, "destroy");
}
}

View File

@@ -0,0 +1,91 @@
package pub.doric.devkit.remote;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.util.Iterator;
/**
* Created by pengfei.zhou on 2018/4/17.
*/
public class ValueBuilder {
private final Object val;
private void writeBoolean(ByteArrayOutputStream output, boolean b) {
output.write((byte) (b ? 1 : 0));
}
private void writeInt(ByteArrayOutputStream output, int i) {
output.write((byte) (i >>> 24));
output.write((byte) (i >>> 16));
output.write((byte) (i >>> 8));
output.write((byte) i);
}
private void writeDouble(ByteArrayOutputStream output, double d) {
long l = Double.doubleToRawLongBits(d);
output.write((byte) (l >>> 56));
output.write((byte) (l >>> 48));
output.write((byte) (l >>> 40));
output.write((byte) (l >>> 32));
output.write((byte) (l >>> 24));
output.write((byte) (l >>> 16));
output.write((byte) (l >>> 8));
output.write((byte) l);
}
private void writeString(ByteArrayOutputStream output, String S) {
byte[] buf;
try {
buf = S.getBytes("UTF-8");
} catch (Exception e) {
buf = new byte[0];
}
int i = buf.length;
writeInt(output, i);
output.write(buf, 0, i);
}
private void write(ByteArrayOutputStream output, Object O) {
if (O instanceof Number) {
output.write((byte) 'D');
writeDouble(output, Double.valueOf(String.valueOf(O)));
} else if (O instanceof String) {
output.write((byte) 'S');
writeString(output, (String) O);
} else if (O instanceof Boolean) {
output.write((byte) 'B');
writeBoolean(output, (Boolean) O);
} else if (O instanceof JSONObject) {
output.write((byte) 'O');
//writeBoolean(output, (Boolean) O);
Iterator<String> iterator = ((JSONObject) O).keys();
while (iterator.hasNext()) {
String key = iterator.next();
write(output, key);
write(output, ((JSONObject) O).opt(key));
}
output.write((byte) 'N');
} else if (O instanceof JSONArray) {
output.write((byte) 'A');
writeInt(output, ((JSONArray) O).length());
for (int i = 0; i < ((JSONArray) O).length(); i++) {
write(output, ((JSONArray) O).opt(i));
}
} else {
output.write((byte) 'N');
}
}
public ValueBuilder(Object o) {
this.val = o;
}
public byte[] build() {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
write(outputStream, val);
return outputStream.toByteArray();
}
}

View File

@@ -0,0 +1,86 @@
package pub.doric.devkit.ui;
import android.app.Dialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import com.google.gson.JsonObject;
import org.greenrobot.eventbus.EventBus;
import pub.doric.DoricContext;
import pub.doric.DoricContextManager;
import pub.doric.devkit.DoricDev;
import pub.doric.devkit.IDevKit;
import pub.doric.devkit.R;
import pub.doric.devkit.event.StartDebugEvent;
public class DebugContextPanel extends DialogFragment {
public DebugContextPanel() {
}
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState
) {
return inflater.inflate(R.layout.layout_debug_context, container, false);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
return dialog;
}
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
LinearLayout container = getView().findViewById(R.id.container);
LayoutInflater inflater = LayoutInflater.from(getContext());
for (final DoricContext doricContext : DoricContextManager.aliveContexts()) {
View cell = inflater.inflate(R.layout.layout_debug_context_cell, container, false);
TextView contextIdTextView = cell.findViewById(R.id.context_id_text_view);
contextIdTextView.setText(doricContext.getContextId());
TextView sourceTextView = cell.findViewById(R.id.source_text_view);
sourceTextView.setText(doricContext.getSource());
cell.findViewById(R.id.debug_text_view).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post(new StartDebugEvent(doricContext.getContextId()));
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("contextId", doricContext.getContextId());
jsonObject.addProperty("source", doricContext.getSource().replace(".js", ".ts"));
DoricDev.sendDevCommand(IDevKit.Command.DEBUG, jsonObject);
dismissAllowingStateLoss();
}
});
container.addView(cell);
}
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package pub.doric.devkit.ui;
import android.os.Bundle;
import android.view.KeyEvent;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import pub.doric.DoricActivity;
import pub.doric.DoricContext;
import pub.doric.DoricContextManager;
import pub.doric.devkit.DoricContextDebuggable;
import pub.doric.devkit.event.EnterDebugEvent;
import pub.doric.devkit.event.ReloadEvent;
import pub.doric.devkit.event.StartDebugEvent;
import pub.doric.devkit.event.StopDebugEvent;
import pub.doric.devkit.util.SensorManagerHelper;
/**
* @Description: pub.doric.demo
* @Author: pengfei.zhou
* @CreateDate: 2019-11-19
*/
public class DemoDebugActivity extends DoricActivity {
private SensorManagerHelper sensorHelper;
private DoricContextDebuggable doricContextDebuggable;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sensorHelper = new SensorManagerHelper(this);
sensorHelper.setOnShakeListener(new SensorManagerHelper.OnShakeListener() {
@Override
public void onShake() {
Fragment devPanel = getSupportFragmentManager().findFragmentByTag("DevPanel");
if (devPanel != null && devPanel.isAdded()) {
return;
}
new DevPanel().show(getSupportFragmentManager(), "DevPanel");
}
});
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
EventBus.getDefault().register(this);
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
EventBus.getDefault().unregister(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
sensorHelper.stop();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onStartDebugEvent(StartDebugEvent startDebugEvent) {
doricContextDebuggable = new DoricContextDebuggable(startDebugEvent.getContextId());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEnterDebugEvent(EnterDebugEvent enterDebugEvent) {
doricContextDebuggable.startDebug();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onQuitDebugEvent(StopDebugEvent quitDebugEvent) {
doricContextDebuggable.stopDebug();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onReloadEvent(ReloadEvent reloadEvent) {
for (DoricContext context : DoricContextManager.aliveContexts()) {
if (reloadEvent.source.contains(context.getSource())) {
if (doricContextDebuggable != null &&
doricContextDebuggable.isDebugging &&
doricContextDebuggable.getContext().getContextId().equals(context.getContextId())) {
System.out.println("is debugging context id: " + context.getContextId());
} else {
context.reload(reloadEvent.script);
}
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (KeyEvent.KEYCODE_MENU == event.getKeyCode()) {
new DevPanel().show(getSupportFragmentManager(), "DevPanel");
}
return super.onKeyDown(keyCode, event);
}
}

View File

@@ -0,0 +1,136 @@
package pub.doric.devkit.ui;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.lahm.library.EasyProtectorLib;
import com.lahm.library.EmulatorCheckCallback;
import com.tbruyelle.rxpermissions2.RxPermissions;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import pub.doric.devkit.DevKit;
import pub.doric.devkit.DoricDev;
import pub.doric.devkit.R;
import pub.doric.devkit.event.ConnectExceptionEvent;
import pub.doric.devkit.event.EOFExceptionEvent;
import pub.doric.devkit.event.OpenEvent;
public class DevPanel extends BottomSheetDialogFragment {
public static boolean isDevConnected = false;
public DevPanel() {
}
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState
) {
return inflater.inflate(R.layout.layout_dev, container, false);
}
@Override
public void onStart() {
super.onStart();
updateUI();
getView().findViewById(R.id.connect_dev_kit_text_view).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (DevKit.isRunningInEmulator) {
DevKit.ip = "10.0.2.2";
DoricDev.connectDevKit("ws://" + DevKit.ip + ":7777");
} else {
final RxPermissions rxPermissions = new RxPermissions(DevPanel.this);
Disposable disposable = rxPermissions
.request(Manifest.permission.CAMERA)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean grant) throws Exception {
if (grant) {
Intent intent = new Intent(getContext(), ScanQRCodeActivity.class);
getContext().startActivity(intent);
}
}
});
}
}
});
getView().findViewById(R.id.debug_text_view).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DebugContextPanel debugContextPanel = new DebugContextPanel();
debugContextPanel.show(getActivity().getSupportFragmentManager(), "DebugContextPanel");
dismissAllowingStateLoss();
}
});
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
EventBus.getDefault().register(this);
DevKit.isRunningInEmulator = EasyProtectorLib.checkIsRunningInEmulator(context, new EmulatorCheckCallback() {
@Override
public void findEmulator(String emulatorInfo) {
System.out.println(emulatorInfo);
}
});
}
@Override
public void onDetach() {
super.onDetach();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onOpenEvent(OpenEvent openEvent) {
updateUI();
Toast.makeText(getContext(), "dev kit connected", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEOFEvent(EOFExceptionEvent eofExceptionEvent) {
updateUI();
Toast.makeText(getContext(), "dev kit eof exception", Toast.LENGTH_LONG).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onConnectExceptionEvent(ConnectExceptionEvent connectExceptionEvent) {
updateUI();
Toast.makeText(getContext(), "dev kit connection exception", Toast.LENGTH_LONG).show();
}
private void updateUI() {
if (isDevConnected) {
getView().findViewById(R.id.connect_dev_kit_text_view).setVisibility(View.GONE);
getView().findViewById(R.id.debug_text_view).setVisibility(View.VISIBLE);
getView().findViewById(R.id.hot_reload_text_view).setVisibility(View.VISIBLE);
} else {
getView().findViewById(R.id.connect_dev_kit_text_view).setVisibility(View.VISIBLE);
getView().findViewById(R.id.debug_text_view).setVisibility(View.GONE);
getView().findViewById(R.id.hot_reload_text_view).setVisibility(View.GONE);
}
}
}

View File

@@ -0,0 +1,79 @@
package pub.doric.devkit.ui;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import cn.bingoogolapple.qrcode.core.QRCodeView;
import cn.bingoogolapple.qrcode.zbar.ZBarView;
import pub.doric.devkit.DevKit;
import pub.doric.devkit.DoricDev;
import pub.doric.devkit.R;
public class ScanQRCodeActivity extends AppCompatActivity implements QRCodeView.Delegate {
private ZBarView mZbarView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_scan_qrcode);
mZbarView = findViewById(R.id.zbar_view);
mZbarView.setDelegate(this);
}
@Override
protected void onStart() {
super.onStart();
mZbarView.startCamera();
mZbarView.startSpotAndShowRect();
}
@Override
protected void onStop() {
super.onStop();
mZbarView.stopCamera();
super.onStop();
}
@Override
protected void onDestroy() {
mZbarView.onDestroy();
super.onDestroy();
}
@Override
public void onScanQRCodeSuccess(String result) {
setTitle("扫描结果为:" + result);
DevKit.ip = result;
Toast.makeText(this, "dev kit connecting to " + result, Toast.LENGTH_LONG).show();
DoricDev.connectDevKit("ws://" + result + ":7777");
finish();
}
@Override
public void onCameraAmbientBrightnessChanged(boolean isDark) {
String tipText = mZbarView.getScanBoxView().getTipText();
String ambientBrightnessTip = "\n环境过暗请打开闪光灯";
if (isDark) {
if (!tipText.contains(ambientBrightnessTip)) {
mZbarView.getScanBoxView().setTipText(tipText + ambientBrightnessTip);
}
} else {
if (tipText.contains(ambientBrightnessTip)) {
tipText = tipText.substring(0, tipText.indexOf(ambientBrightnessTip));
mZbarView.getScanBoxView().setTipText(tipText);
}
}
}
@Override
public void onScanQRCodeOpenCameraError() {
System.out.println();
}
}

View File

@@ -0,0 +1,113 @@
package pub.doric.devkit.util;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
public class SensorManagerHelper implements SensorEventListener {
// 速度阈值,当摇晃速度达到这值后产生作用
private final int SPEED_SHRESHOLD = 5000;
// 两次检测的时间间隔
private final int UPTATE_INTERVAL_TIME = 50;
// 传感器管理器
private SensorManager sensorManager;
// 传感器
private Sensor sensor;
// 重力感应监听器
private OnShakeListener onShakeListener;
// 上下文对象context
private Context context;
// 手机上一个位置时重力感应坐标
private float lastX;
private float lastY;
private float lastZ;
// 上次检测时间
private long lastUpdateTime;
public SensorManagerHelper(Context context) {
this.context = context;
start();
}
/**
* 开始检测
*/
public void start() {
// 获得传感器管理器
sensorManager = (SensorManager) context
.getSystemService(Context.SENSOR_SERVICE);
if (sensorManager != null) {
// 获得重力传感器
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
// 注册
if (sensor != null) {
sensorManager.registerListener(this, sensor,
SensorManager.SENSOR_DELAY_GAME);
}
}
/**
* 停止检测
*/
public void stop() {
sensorManager.unregisterListener(this);
}
/**
* 摇晃监听接口
*/
public interface OnShakeListener {
void onShake();
}
/**
* 设置重力感应监听器
*/
public void setOnShakeListener(OnShakeListener listener) {
onShakeListener = listener;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
/**
* 重力感应器感应获得变化数据
* android.hardware.SensorEventListener#onSensorChanged(android.hardware
* .SensorEvent)
*/
@Override
public void onSensorChanged(SensorEvent event) {
// 现在检测时间
long currentUpdateTime = System.currentTimeMillis();
// 两次检测的时间间隔
long timeInterval = currentUpdateTime - lastUpdateTime;
// 判断是否达到了检测时间间隔
if (timeInterval < UPTATE_INTERVAL_TIME) return;
// 现在的时间变成last时间
lastUpdateTime = currentUpdateTime;
// 获得x,y,z坐标
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
// 获得x,y,z的变化值
float deltaX = x - lastX;
float deltaY = y - lastY;
float deltaZ = z - lastZ;
// 将现在的坐标变成last坐标
lastX = x;
lastY = y;
lastZ = z;
double speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ
* deltaZ)
/ timeInterval * 10000;
// 达到速度阀值,发出提示
if (speed >= SPEED_SHRESHOLD) {
onShakeListener.onShake();
}
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/context_id_text_view"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="1"
android:gravity="center"
android:singleLine="true"
android:text="{Context Id}"
android:textSize="20sp" />
<TextView
android:id="@+id/source_text_view"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="3"
android:gravity="center"
android:singleLine="true"
android:text="{Source}"
android:textSize="20sp" />
<TextView
android:id="@+id/debug_text_view"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="1"
android:background="#ff0000"
android:gravity="center"
android:singleLine="true"
android:text="Debug"
android:textColor="#ffffff"
android:textSize="20sp" />
</LinearLayout>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@drawable/divider"
android:orientation="vertical"
android:showDividers="middle">
<TextView
android:id="@+id/connect_dev_kit_text_view"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:text="Dev Kit"
android:textSize="20sp" />
<TextView
android:id="@+id/debug_text_view"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:text="Debug via Visual Studio Code"
android:textSize="20sp"
android:visibility="gone" />
<TextView
android:id="@+id/hot_reload_text_view"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:text="Enable Hot Reload"
android:textSize="20sp"
android:visibility="gone" />
</LinearLayout>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<cn.bingoogolapple.qrcode.zbar.ZBarView
android:id="@+id/zbar_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:qrcv_animTime="1000"
app:qrcv_borderColor="@android:color/white"
app:qrcv_borderSize="1dp"
app:qrcv_cornerColor="@android:color/white"
app:qrcv_cornerLength="20dp"
app:qrcv_cornerSize="3dp"
app:qrcv_isShowDefaultScanLineDrawable="true"
app:qrcv_maskColor="#33FFFFFF"
app:qrcv_rectWidth="200dp"
app:qrcv_scanLineColor="@android:color/white"
app:qrcv_topOffset="90dp" />
</LinearLayout>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">devkit</string>
</resources>