add: syntax and api document

This commit is contained in:
hyb1996
2017-02-01 21:36:10 +08:00
parent 853a518d97
commit 636ce6d889
19 changed files with 369 additions and 92 deletions

View File

@@ -1,26 +0,0 @@
package com.stardust.scriptdroid;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation 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() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.stardust.scriptdroid", appContext.getPackageName());
}
}

View File

@@ -73,6 +73,8 @@
<activity android:name=".EditActivity"/>
<activity android:name=".DocumentActivity"/>
</application>
</manifest>

View File

@@ -0,0 +1,50 @@
package com.stardust.scriptdroid;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import com.stardust.scriptdroid.file.FileUtils;
import com.stardust.view.MarkdownView;
/**
* Created by Stardust on 2017/2/1.
*/
public class DocumentActivity extends BaseActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setUpUI();
}
private void setUpUI() {
setContentView(R.layout.activity_document);
setUpToolbar();
loadDocument();
}
private void loadDocument() {
MarkdownView markdownView = $(R.id.markdown);
try {
markdownView.loadMarkdown(FileUtils.readString(getResources().openRawResource(R.raw.document)));
} catch (Exception e) {
e.printStackTrace();
markdownView.setText("文档加载失败/(ㄒoㄒ)/~~");
}
}
private void setUpToolbar() {
Toolbar toolbar = $(R.id.toolbar);
toolbar.setTitle(R.string.text_syntax_and_api);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
}

View File

@@ -45,31 +45,24 @@ public class Droid {
public void runScriptFile(File file, OnRunFinishedListener listener) {
checkFile(file);
runScript(FileUtils.readString(file), listener);
runScript(FileUtils.readString(file), listener, RunningConfig.getDefault());
}
private void runScript(String script) {
runScript(script, null);
runScript(script, null, RunningConfig.getDefault());
}
public void runScriptFile(String path) {
runScriptFile(new File(path));
}
public void runScript(final String script, OnRunFinishedListener listener) {
if (listener == null)
listener = DEFAULT_LISTENER;
final OnRunFinishedListener finalListener = listener;
new Thread(new Runnable() {
@Override
public void run() {
try {
finalListener.onRunFinished(JAVA_SCRIPT_ENGINE.execute(script), null);
} catch (Exception e) {
finalListener.onRunFinished(null, e);
}
}
}).start();
public void runScript(final String script, OnRunFinishedListener listener, RunningConfig config) {
if (config.runInNewThread) {
new Thread(new RunScriptRunnable(script, listener, config)).start();
}else {
new RunScriptRunnable(script, listener, config).run();
}
}
@@ -90,4 +83,23 @@ public class Droid {
}
private static class RunScriptRunnable implements Runnable {
private final String mScript;
private OnRunFinishedListener mOnRunFinishedListener;
public RunScriptRunnable(String script, OnRunFinishedListener listener, RunningConfig config) {
mOnRunFinishedListener = listener == null ? DEFAULT_LISTENER : listener;
mScript = script;
}
@Override
public void run() {
try {
mOnRunFinishedListener.onRunFinished(JAVA_SCRIPT_ENGINE.execute(mScript), null);
} catch (Exception e) {
mOnRunFinishedListener.onRunFinished(null, e);
}
}
}
}

View File

@@ -0,0 +1,38 @@
package com.stardust.scriptdroid.droid;
import android.app.Activity;
import android.content.Context;
/**
* Created by Stardust on 2017/2/1.
*/
public class RunningConfig {
private static final RunningConfig RUNNING_CONFIG = new RunningConfig();
public static RunningConfig getDefault() {
return RUNNING_CONFIG;
}
public boolean runInNewThread = true;
public Activity activity;
public Context context;
public RunningConfig runInNewThread(boolean runInNewThread) {
this.runInNewThread = runInNewThread;
return this;
}
public RunningConfig activity(Activity activity) {
this.activity = activity;
this.context = activity;
return this;
}
public RunningConfig context(Context context) {
this.context = context;
return this;
}
}

View File

@@ -14,7 +14,7 @@ public abstract class ScriptFileList {
public abstract void remove(int i);
public abstract void rename(int position, String newName);
public abstract void rename(int position, String newName, boolean renameFile);
public abstract int size();

View File

@@ -6,6 +6,7 @@ import android.content.SharedPreferences;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.file.FileUtils;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -38,7 +39,6 @@ public class SharedPrefScriptFileList extends ScriptFileList {
}
private void readFromSharedPref() {
Type type = new TypeToken<List<String>>() {
}.getType();
@@ -75,8 +75,12 @@ public class SharedPrefScriptFileList extends ScriptFileList {
}
@Override
public void rename(int position, String newName) {
public void rename(int position, String newName, boolean renameFile) {
mScriptName.set(position, newName);
if (renameFile) {
String newPath = FileUtils.renameWithoutExtension(mScriptPath.get(position), newName);
mScriptPath.set(position, newPath);
}
syncWithSharedPref();
}

View File

@@ -8,6 +8,7 @@ import com.stardust.scriptdroid.App;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -78,7 +79,7 @@ public class FileUtils {
if (i >= 0) {
String folder = path.substring(0, i);
File file = new File(folder);
if(file.exists())
if (file.exists())
return true;
return file.mkdirs();
} else {
@@ -88,11 +89,8 @@ public class FileUtils {
public static String readString(File file, String encoding) {
try {
FileInputStream fis = new FileInputStream(file);
byte[] bytes = new byte[fis.available()];
fis.read(bytes);
return new String(bytes, encoding);
} catch (IOException e) {
return readString(new FileInputStream(file), encoding);
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
@@ -102,6 +100,21 @@ public class FileUtils {
return readString(file, "utf-8");
}
public static String readString(InputStream is, String encoding) {
try {
byte[] bytes = new byte[is.available()];
is.read(bytes);
return new String(bytes, encoding);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static String readString(InputStream inputStream) {
return readString(inputStream, "utf-8");
}
public static boolean copy(int rawId, String path) {
InputStream is = App.getApp().getResources().openRawResource(rawId);
return copy(is, path);
@@ -147,4 +160,20 @@ public class FileUtils {
return false;
}
}
public static String renameWithoutExtension(String path, String newName) {
File file = new File(path);
File newFile = new File(file.getParent(), newName + "." + getExtension(file.getName()));
file.renameTo(newFile);
return newFile.getAbsolutePath();
}
public static String getExtension(String fileName) {
int i = fileName.lastIndexOf('.');
if (i < 0)
return "";
return fileName.substring(i + 1);
}
}

View File

@@ -112,10 +112,7 @@ public abstract class ScriptFileOperation {
.input("输入新名称", oldName, new MaterialDialog.InputCallback() {
@Override
public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {
scriptFileList.rename(position, input.toString());
if(dialog.isPromptCheckBoxChecked()){
scriptFileList.get(position).rename(input);
}
scriptFileList.rename(position, input.toString(), dialog.isPromptCheckBoxChecked());
recyclerView.getAdapter().notifyItemChanged(position);
}
})

View File

@@ -1,5 +1,6 @@
package com.stardust.scriptdroid.ui;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
@@ -12,6 +13,7 @@ import android.widget.CompoundButton;
import android.widget.Toast;
import com.stardust.app.Fragment;
import com.stardust.scriptdroid.DocumentActivity;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.Droid;
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService;
@@ -94,8 +96,7 @@ public class SlideMenuFragment extends Fragment {
@ViewBinding.Click(R.id.syntax_and_api)
private void startSyntaxHelpActivity() {
// TODO: 2017/1/30 startSyntaxHelpActivity
Toast.makeText(getContext(), "暂无", Toast.LENGTH_LONG).show();
startActivity(new Intent(getContext(), DocumentActivity.class));
}
@ViewBinding.Click(R.id.about_app)

View File

@@ -0,0 +1,61 @@
package com.stardust.view;
import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.text.Html;
import android.text.Spanned;
import android.text.method.ScrollingMovementMethod;
import android.util.AttributeSet;
import android.widget.TextView;
import com.zzhoujay.markdown.MarkDown;
/**
* Created by Stardust on 2017/2/1.
*/
public class MarkdownView extends TextView {
public MarkdownView(Context context) {
super(context);
init();
}
public MarkdownView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MarkdownView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MarkdownView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
setMovementMethod(ScrollingMovementMethod.getInstance());
setVerticalScrollBarEnabled(true);
setTextIsSelectable(true);
setClickable(true);
}
public void loadMarkdown(final String text, final Html.ImageGetter imageGetter) {
post(new Runnable() {
@Override
public void run() {
Spanned spanned = MarkDown.fromMarkdown(text, imageGetter, MarkdownView.this);
setText(spanned);
}
});
}
public void loadMarkdown(final String text) {
loadMarkdown(text, null);
}
}

View File

@@ -0,0 +1,35 @@
<?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"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
<com.stardust.view.MarkdownView
android:id="@+id/markdown"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:textColor="@android:color/secondary_text_light"/>
</LinearLayout>

View File

@@ -0,0 +1,37 @@
###一、语法
本软件使用JavaScript语言([ECMAscript E5/E5.1](http://www.ecma-international.org/ecma-262/5.1/)),基于[Duktape](http://www.duktape.org/)引擎拓展一些自动操作(点击、长按、滑动等)函数。因而语法参见JavaScript(例如[w3cschool教程](http://www.w3school.com.cn/js/))。
###二、自动操作函数
**自动操作的函数都需要开启"自动操作服务"才能执行,否则执行到相应函数时脚本会停止运行。**
* `click(text)` 点击文本text所在的区域并返回是否点击成功。当前界面没有出现该文本或者该文本所在区域不可点击时返回false。例如`click("发现")`,是点击"发现"。如果要点击"发现"直至点击成功可以用`while(!click("发现"))`
> 文本所在区域指的是,从文本处向上寻找,直至发现一个可点击的部件为止。
* `click(left, top, bottom, right)` 点击与长方形范围严格匹配的区域并返回是否点击成功。其中left为长方形左边与屏幕左边的像素距离top为上边与屏幕上边的像素距离right为右边与**屏幕左边**的像素距离, bottom为下边与**屏幕下边**的距离。区域严格匹配,至于要确定要点击的区域在屏幕上的左边位置,可以在侧拉菜单开启"脚本辅助"或者安卓7.0以上在通知栏点击"修改"添加脚本辅助快捷设定图标),之后每次点击或长按事件都会提示这次点击或长按的区域并自动保存,可以在编辑器中插入。
> 以下的longClick、select、scrollUp、scrollDown的参数均与click类似不再赘述。
* `longClick` 长按
* `select` 选择
* `scrollUp` 上滑。不加参数时会寻找"最大"的可滑动的控件下滑,例如微信消息列表等。
* `scrollDown` 下滑。不加参数时与scrollUp类似。
* `input(string)` 把所有输入框的文本都置为string。
###三、其他函数
* `sleep(n)` 暂停执行n**毫秒**时间。
* `toast(string)` 显示提示文本。
* `launch(packageName)` 运行包名为packageName的应用。例如launch("com.tencent.mm")是运行微信应用包名可以通过一些工具获取获取通过函数launchApp代替
* `launch(packageName, className)` 运行包名为packageName类名(Activity)为className的应用。
* `launchApp(appName)` 运存应用名称为appName的应用。例如launchApp("QQ")。不同应用名称可能相同,这时只运行其中某一个应用。
###四、在脚本中调用安卓
使用importClass来引入要使用的库例如:
```javascript
importClass("android.view.View.OnClickListener")
view.setOnClickListener(new OnClickListener(function(){
Toast.makeText(activity, "Button1 Clicked", Toast.LENGTH_SHORT).show();
var intent = new Intent(activity, "com.furture.react.activity.DetailActivity");
activity.startActivity(intent);
}));
view2.setOnClickListener(new OnClickListener({
onClick: function(){
Toast.makeText(activity, "Button2 Clicked", Toast.LENGTH_SHORT).show();
}
}));
```
详细文档参见[DuktapeJava Java Docs](http://gubaojian.github.io/DuktapeJava/javadoc/)。

View File

@@ -1,23 +0,0 @@
function openRunningServices(){
launch("com.android.settings");
var i = 0;
while(!click("开发者选项")){
i++;
if(i == 10){
toast("开发者选项未开启");
return;
}
scrollDown();
}
while(!click("正在运行的服务"));
}
importClass("android.os.Build.VERSION");
if(VERSION.SDK_INT < 23){
toast("本代码只适用于Android6.0以上");
}else{
openRunningServices();
}

View File

@@ -1,5 +0,0 @@
launchApp("微信");
sleep(500);
click("发现");
sleep(500);
click("朋友圈");

View File

@@ -1,7 +0,0 @@
importClass("com.afollestad.materialdialogs.MaterialDialog");
new MaterialDialog.Builder(context)
.title("请输入算式")
.contenet("测试")
.show();