add: slide menu
@ -2,6 +2,10 @@
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
<list size="2">
|
||||
<item index="0" class="java.lang.String" itemvalue="com.stardust.view.ViewBind.Click" />
|
||||
<item index="1" class="java.lang.String" itemvalue="com.stardust.view.ViewBinding.Click" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
||||
|
||||
@ -37,16 +37,14 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
|
||||
compile 'com.android.support:appcompat-v7:25.0.0'
|
||||
compile 'com.android.support:design:25.0.0'
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'com.afollestad.material-dialogs:core:0.9.2.3'
|
||||
compile 'com.google.code.gson:gson:2.8.0'
|
||||
compile 'com.sothree.slidinguppanel:library:3.3.1'
|
||||
|
||||
compile('de.psdev.licensesdialog:licensesdialog:1.8.1')
|
||||
compile 'com.squareup.duktape:duktape-android:1.1.0'
|
||||
compile 'com.furture.react:DuktapeJava:1.1.0'
|
||||
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
|
||||
<activity
|
||||
android:name=".ShortcutActivity"
|
||||
android:label="脚本执行机器人"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
|
||||
<intent-filter>
|
||||
@ -40,7 +39,7 @@
|
||||
android:name=".droid.runtime.action.ActionPerformService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:label="脚本执行机器人"
|
||||
android:label="@string/app_name"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.accessibilityservice.AccessibilityService"/>
|
||||
@ -74,7 +73,6 @@
|
||||
|
||||
<activity android:name=".EditActivity"/>
|
||||
|
||||
<activity android:name="com.jecelyin.editor.v2.ui.MainActivity"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -109,4 +109,11 @@ var input = function(a, b){
|
||||
|
||||
var sleep = function(millis){
|
||||
droid.sleep(millis);
|
||||
}
|
||||
|
||||
|
||||
importClass("java.lang.Runnable");
|
||||
|
||||
var ui = function(action){
|
||||
droid.ui(new Runnable(action));
|
||||
}
|
||||
23
app/src/main/assets/sample_open_running_services.js
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
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();
|
||||
}
|
||||
5
app/src/main/assets/sample_open_wechat_moment.js
Normal file
@ -0,0 +1,5 @@
|
||||
launchApp("微信");
|
||||
sleep(500);
|
||||
click("发现");
|
||||
sleep(500);
|
||||
click("朋友圈");
|
||||
7
app/src/main/assets/sample_simple_calculator.js
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
importClass("com.afollestad.materialdialogs.MaterialDialog.Builder");
|
||||
|
||||
new Builder(context)
|
||||
.title("请输入算式")
|
||||
.content("测试")
|
||||
.show();
|
||||
@ -1,3 +0,0 @@
|
||||
|
||||
droid.toast("略略略");
|
||||
droid.click(droid.text("哈哈哈"));
|
||||
39
app/src/main/java/com/stardust/UIActionPerformActivity.java
Normal file
@ -0,0 +1,39 @@
|
||||
package com.stardust;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/31.
|
||||
*/
|
||||
|
||||
public class UIActionPerformActivity extends AppCompatActivity {
|
||||
|
||||
|
||||
private static volatile Runnable action;
|
||||
|
||||
public static void performAction(Runnable action) {
|
||||
if (UIActionPerformActivity.action != null) {
|
||||
return;
|
||||
}
|
||||
UIActionPerformActivity.action = action;
|
||||
App.getApp().startActivity(new Intent(App.getApp(), UIActionPerformActivity.class));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
DroidRuntime.setContext(this);
|
||||
action.run();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
45
app/src/main/java/com/stardust/app/Fragment.java
Normal file
@ -0,0 +1,45 @@
|
||||
package com.stardust.app;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.stardust.scriptdroid.tool.ViewTool;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
*/
|
||||
|
||||
public abstract class Fragment extends android.support.v4.app.Fragment {
|
||||
|
||||
private View mView;
|
||||
|
||||
public View getView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
public <T extends View> T $(int id) {
|
||||
return ViewTool.$(mView, id);
|
||||
}
|
||||
|
||||
public View findViewById(int id) {
|
||||
return mView.findViewById(id);
|
||||
}
|
||||
|
||||
public View getActivityContentView() {
|
||||
return getActivity().getWindow().getDecorView();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
mView = createView(inflater, container, savedInstanceState);
|
||||
return mView;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract View createView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState);
|
||||
|
||||
}
|
||||
63
app/src/main/java/com/stardust/app/NotRemindAgainDialog.java
Normal file
@ -0,0 +1,63 @@
|
||||
package com.stardust.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.CompoundButton;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
import static com.jecelyin.common.utils.StringUtils.md5;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
*/
|
||||
|
||||
public class NotRemindAgainDialog extends MaterialDialog {
|
||||
|
||||
protected NotRemindAgainDialog(Builder builder) {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
|
||||
public static class Builder extends MaterialDialog.Builder {
|
||||
|
||||
private String mKeyRemind;
|
||||
private boolean mRemind;
|
||||
|
||||
public Builder(@NonNull Context context) {
|
||||
super(context);
|
||||
readRemindStatus();
|
||||
checkBoxPrompt(context.getString(R.string.text_do_not_remind_again), false, new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
setRemindState(!isChecked);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MaterialDialog show() {
|
||||
if (mRemind) {
|
||||
return super.show();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setRemindState(boolean remind) {
|
||||
mRemind = remind;
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext()).edit()
|
||||
.putBoolean(mKeyRemind, remind).apply();
|
||||
}
|
||||
|
||||
private void readRemindStatus() {
|
||||
generatePreferenceKey();
|
||||
mRemind = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean(mKeyRemind, true);
|
||||
}
|
||||
|
||||
private void generatePreferenceKey() {
|
||||
mKeyRemind = md5(TextUtils.join("", Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.stardust.scriptdroid;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.View;
|
||||
|
||||
@ -17,6 +18,8 @@ import static android.content.pm.PackageManager.PERMISSION_DENIED;
|
||||
public class BaseActivity extends AppCompatActivity {
|
||||
|
||||
|
||||
protected static final int PERMISSION_REQUEST_CODE = 11186;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends View> T $(int resId) {
|
||||
return (T) findViewById(resId);
|
||||
@ -26,10 +29,11 @@ public class BaseActivity extends AppCompatActivity {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
String[] requestPermissions = getRequestPermissions(permissions);
|
||||
if (requestPermissions.length > 0)
|
||||
requestPermissions(requestPermissions, 0);
|
||||
requestPermissions(requestPermissions, PERMISSION_REQUEST_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private String[] getRequestPermissions(String[] permissions) {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String permission : permissions) {
|
||||
|
||||
@ -11,18 +11,19 @@ import android.view.View;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.folderselector.FolderChooserDialog;
|
||||
import com.jecelyin.editor.v2.Pref;
|
||||
import com.jecelyin.editor.v2.common.Command;
|
||||
import com.jecelyin.editor.v2.common.SaveListener;
|
||||
import com.jecelyin.editor.v2.ui.EditorDelegate;
|
||||
import com.jecelyin.editor.v2.ui.IActivity;
|
||||
import com.jecelyin.editor.v2.ui.TabManager;
|
||||
import com.jecelyin.editor.v2.view.EditorView;
|
||||
import com.jecelyin.editor.v2.view.menu.MenuDef;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.editor920.Editor920Activity;
|
||||
import com.stardust.scriptdroid.widget.ToolbarMenuItem;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@ -30,8 +31,7 @@ import java.io.File;
|
||||
* Created by Stardust on 2017/1/29.
|
||||
*/
|
||||
|
||||
public class EditActivity extends IActivity {
|
||||
|
||||
public class EditActivity extends Editor920Activity {
|
||||
|
||||
public static void editFile(Context context, String path) {
|
||||
editFile(context, null, path);
|
||||
@ -47,16 +47,38 @@ public class EditActivity extends IActivity {
|
||||
private File mFile;
|
||||
private View mView;
|
||||
private EditorDelegate mEditorDelegate;
|
||||
private ToolbarMenuItem mSaveMenuItem, mRedoMenuItem, mUndoMenuItem, mRunMenuItem;
|
||||
private SparseArray<ToolbarMenuItem> mMenuMap;
|
||||
|
||||
public void onCreate(Bundle b) {
|
||||
super.onCreate(b);
|
||||
DroidRuntime.setContext(this);
|
||||
handleIntent();
|
||||
setUpUI();
|
||||
setUpEditor();
|
||||
}
|
||||
|
||||
private void handleIntent() {
|
||||
String path = getIntent().getStringExtra("path");
|
||||
mName = getIntent().getStringExtra("name");
|
||||
if (path == null) {
|
||||
finish();
|
||||
} else {
|
||||
mFile = new File(path);
|
||||
if (mName == null) {
|
||||
mName = mFile.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpUI() {
|
||||
setTheme(R.style.EditorTheme);
|
||||
mView = View.inflate(this, R.layout.activity_edit, null);
|
||||
setContentView(mView);
|
||||
initMenuItem();
|
||||
setUpToolbar();
|
||||
ViewBinder.bind(this);
|
||||
}
|
||||
|
||||
private void setUpEditor() {
|
||||
if (mFile != null) {
|
||||
Pref.getInstance(this).setReadOnly(false);
|
||||
@ -66,63 +88,42 @@ public class EditActivity extends IActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpUI() {
|
||||
setTheme(R.style.EditorTheme);
|
||||
mView = View.inflate(this, R.layout.activity_edit, null);
|
||||
setContentView(mView);
|
||||
initMenuItem();
|
||||
setUpToolbar();
|
||||
setUpListener();
|
||||
|
||||
private void setUpToolbar() {
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(mName);
|
||||
setSupportActionBar(toolbar);
|
||||
if (getSupportActionBar() != null) {
|
||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initMenuItem() {
|
||||
mRedoMenuItem = (ToolbarMenuItem) findViewById(R.id.redo);
|
||||
mUndoMenuItem = (ToolbarMenuItem) findViewById(R.id.undo);
|
||||
mSaveMenuItem = (ToolbarMenuItem) findViewById(R.id.save);
|
||||
mRunMenuItem = (ToolbarMenuItem) findViewById(R.id.run);
|
||||
mMenuMap = new SparseArrayEntries<ToolbarMenuItem>()
|
||||
.entry(com.jecelyin.editor.v2.R.id.m_redo, mRedoMenuItem)
|
||||
.entry(com.jecelyin.editor.v2.R.id.m_undo, mUndoMenuItem)
|
||||
.entry(com.jecelyin.editor.v2.R.id.m_save, mSaveMenuItem)
|
||||
.entry(R.id.run, mRunMenuItem)
|
||||
.sparseArray();
|
||||
}
|
||||
|
||||
private void setUpListener() {
|
||||
mUndoMenuItem.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
undo();
|
||||
}
|
||||
});
|
||||
mRedoMenuItem.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
redo();
|
||||
}
|
||||
});
|
||||
mSaveMenuItem.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
saveFile(false, null);
|
||||
}
|
||||
});
|
||||
mRunMenuItem.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mEditorDelegate.isChanged()) {
|
||||
saveFile(false, new SaveListener() {
|
||||
@Override
|
||||
public void onSaved() {
|
||||
run();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ViewBinding.Click(R.id.run)
|
||||
private void runAndSaveFileIFNeeded() {
|
||||
if (mEditorDelegate.isChanged()) {
|
||||
saveFile(false, new SaveListener() {
|
||||
@Override
|
||||
public void onSaved() {
|
||||
run();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
private void saveFile(boolean toast, SaveListener listener) {
|
||||
Command command = new Command(Command.CommandEnum.SAVE);
|
||||
command.args = new Bundle();
|
||||
command.args.putBoolean("is_cluster", !toast);
|
||||
command.object = listener;
|
||||
mEditorDelegate.doCommand(command);
|
||||
}
|
||||
|
||||
private void run() {
|
||||
@ -143,55 +144,39 @@ public class EditActivity extends IActivity {
|
||||
});
|
||||
}
|
||||
|
||||
private void handleIntent() {
|
||||
String path = getIntent().getStringExtra("path");
|
||||
mName = getIntent().getStringExtra("name");
|
||||
if (path == null) {
|
||||
finish();
|
||||
} else {
|
||||
mFile = new File(path);
|
||||
if (mName == null) {
|
||||
mName = mFile.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(mName);
|
||||
setSupportActionBar(toolbar);
|
||||
if (getSupportActionBar() != null) {
|
||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveFile(boolean toast, SaveListener listener) {
|
||||
Command command = new Command(Command.CommandEnum.SAVE);
|
||||
command.args = new Bundle();
|
||||
command.args.putBoolean("is_cluster", !toast);
|
||||
command.object = listener;
|
||||
mEditorDelegate.doCommand(command);
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.undo)
|
||||
private void undo() {
|
||||
Command command = new Command(Command.CommandEnum.UNDO);
|
||||
mEditorDelegate.doCommand(command);
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.redo)
|
||||
private void redo() {
|
||||
Command command = new Command(Command.CommandEnum.REDO);
|
||||
mEditorDelegate.doCommand(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPickPathActivity(String s, String s1) {
|
||||
|
||||
@ViewBinding.Click(R.id.save)
|
||||
private void saveFile() {
|
||||
saveFile(false, null);
|
||||
}
|
||||
|
||||
private void initMenuItem() {
|
||||
mMenuMap = new SparseArrayEntries<ToolbarMenuItem>()
|
||||
.entry(com.jecelyin.editor.v2.R.id.m_redo, (ToolbarMenuItem) findViewById(R.id.redo))
|
||||
.entry(com.jecelyin.editor.v2.R.id.m_undo, (ToolbarMenuItem) findViewById(R.id.undo))
|
||||
.entry(com.jecelyin.editor.v2.R.id.m_save, (ToolbarMenuItem) findViewById(R.id.save))
|
||||
.entry(R.id.run, (ToolbarMenuItem) findViewById(R.id.run))
|
||||
.sparseArray();
|
||||
}
|
||||
|
||||
public void setMenuStatus(int menuResId, int status) {
|
||||
ToolbarMenuItem menuItem = mMenuMap.get(menuResId);
|
||||
if (menuItem == null)
|
||||
return;
|
||||
boolean disabled = status == MenuDef.STATUS_DISABLED;
|
||||
menuItem.setEnabled(!disabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -209,7 +194,7 @@ public class EditActivity extends IActivity {
|
||||
.content(R.string.edit_exit_without_save_warn)
|
||||
.positiveText(R.string.text_cancel)
|
||||
.negativeText(R.string.text_save_and_exit)
|
||||
.neutralText(R.string.text_exit_directly )
|
||||
.neutralText(R.string.text_exit_directly)
|
||||
.onNegative(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
|
||||
@ -226,62 +211,4 @@ public class EditActivity extends IActivity {
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doNextCommand() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setMenuStatus(int menuResId, int status) {
|
||||
ToolbarMenuItem menuItem = mMenuMap.get(menuResId);
|
||||
if (menuItem == null)
|
||||
return;
|
||||
boolean disabled = status == MenuDef.STATUS_DISABLED;
|
||||
menuItem.setEnabled(!disabled);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDocumentChanged(int i) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCommand(Command command) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openFile(String s, String s1, int i) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFindFolderCallback(FolderChooserDialog.FolderCallback folderCallback) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabManager getTabManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertText(CharSequence charSequence) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFolderSelection(@NonNull FolderChooserDialog dialog, @NonNull File folder) {
|
||||
|
||||
}
|
||||
|
||||
protected void onDestroy() {
|
||||
try {
|
||||
super.onDestroy();
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ package com.stardust.scriptdroid;
|
||||
import android.Manifest;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
@ -11,12 +11,12 @@ import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.text.InputType;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.app.NotRemindAgainDialog;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
@ -25,18 +25,19 @@ import com.stardust.scriptdroid.file.FileChooser;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
import com.stardust.scriptdroid.ui.ScriptFileOperation;
|
||||
import com.stardust.scriptdroid.ui.ScriptListRecyclerView;
|
||||
import com.stardust.scriptdroid.ui.SlideMenuFragment;
|
||||
import com.stardust.scriptdroid.ui.SlidingUpPanel;
|
||||
import com.stardust.util.MapEntries;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class MainActivity extends BaseActivity {
|
||||
|
||||
private View mView;
|
||||
private SlidingUpPanel mSlidingUpPanel;
|
||||
private SlidingUpPanel mAddFilePanel;
|
||||
private ScriptListRecyclerView mScriptListRecyclerView;
|
||||
private ScriptFileList mScriptFileList;
|
||||
private FileChooser mFileChooser;
|
||||
@ -45,11 +46,8 @@ public class MainActivity extends BaseActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setUpUI();
|
||||
|
||||
setUpFileChooser();
|
||||
|
||||
checkPermissions();
|
||||
}
|
||||
|
||||
@ -60,7 +58,7 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
private void goToAccessibilityPermissionSettingIfDisabled() {
|
||||
if (!AccessibilityServiceUtils.isAccessibilityServiceEnabled(this, ActionPerformService.class)) {
|
||||
new MaterialDialog.Builder(this)
|
||||
new NotRemindAgainDialog.Builder(this)
|
||||
.title(R.string.text_alert)
|
||||
.content(R.string.explain_accessibility_permission)
|
||||
.positiveText(R.string.text_go_to_setting)
|
||||
@ -90,7 +88,7 @@ public class MainActivity extends BaseActivity {
|
||||
private void addScriptFile(final String path) {
|
||||
new MaterialDialog.Builder(this).title(R.string.text_name)
|
||||
.inputType(InputType.TYPE_CLASS_TEXT)
|
||||
.input(getString(R.string.text_please_input_name), "", new MaterialDialog.InputCallback() {
|
||||
.input(getString(R.string.text_please_input_name), new File(path).getName(), new MaterialDialog.InputCallback() {
|
||||
@Override
|
||||
public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {
|
||||
MainActivity.this.addScriptFile(input.toString(), path);
|
||||
@ -105,14 +103,14 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
|
||||
private void setUpUI() {
|
||||
mView = View.inflate(this, R.layout.activity_main, null);
|
||||
setContentView(mView);
|
||||
mSlidingUpPanel = $(R.id.bottom_menu);
|
||||
mDrawerLayout = $(R.id.drawer_layout);
|
||||
mDrawerLayout = (DrawerLayout) View.inflate(this, R.layout.activity_main, null);
|
||||
setContentView(mDrawerLayout);
|
||||
SlideMenuFragment.init(this, R.id.fragment_slide_menu);
|
||||
mAddFilePanel = $(R.id.bottom_menu);
|
||||
|
||||
setUpToolbar();
|
||||
setUpScriptList();
|
||||
setUpListener();
|
||||
ViewBinder.bind(this);
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
@ -128,31 +126,16 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
private void setUpScriptList() {
|
||||
mScriptListRecyclerView = $(R.id.script_list);
|
||||
mScriptFileList = new SharedPrefScriptFileList(this);
|
||||
mScriptFileList = SharedPrefScriptFileList.getInstance();
|
||||
mScriptListRecyclerView.setScriptFileList(mScriptFileList);
|
||||
}
|
||||
|
||||
private void setUpListener() {
|
||||
$(R.id.fab).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
mSlidingUpPanel.show();
|
||||
}
|
||||
});
|
||||
$(R.id.import_from_file).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
MainActivity.this.showFileChooser();
|
||||
}
|
||||
});
|
||||
$(R.id.create_new_file).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
MainActivity.this.createScriptFile();
|
||||
}
|
||||
});
|
||||
@ViewBinding.Click(R.id.fab)
|
||||
private void showAddFilePanel() {
|
||||
mAddFilePanel.show();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.create_new_file)
|
||||
private void createScriptFile() {
|
||||
new MaterialDialog.Builder(this).title(R.string.text_name)
|
||||
.inputType(InputType.TYPE_CLASS_TEXT)
|
||||
@ -170,73 +153,42 @@ public class MainActivity extends BaseActivity {
|
||||
addScriptFile(name, path);
|
||||
new ScriptFileOperation.Edit().operate(mScriptListRecyclerView, mScriptFileList, mScriptFileList.size() - 1);
|
||||
} else {
|
||||
Snackbar.make(mView, R.string.text_file_create_fail, Snackbar.LENGTH_LONG).show();
|
||||
Snackbar.make(mDrawerLayout, R.string.text_file_create_fail, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.import_from_file)
|
||||
private void showFileChooser() {
|
||||
mFileChooser.startFileManagerToChoose("*/*", new FileChooser.FileManagerNotFoundHandler() {
|
||||
@Override
|
||||
public void handle(ActivityNotFoundException exception, String mimeType) {
|
||||
exception.printStackTrace();
|
||||
Snackbar.make(mView, R.string.text_file_manager_not_found, Snackbar.LENGTH_SHORT).show();
|
||||
Snackbar.make(mDrawerLayout, R.string.text_file_manager_not_found, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private final Map<Integer, Runnable> mOptionActionMap = new MapEntries<Integer, Runnable>()
|
||||
.entry(R.id.action_exit, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MainActivity.this.finish();
|
||||
}
|
||||
})
|
||||
.entry(R.id.action_disable_service, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MainActivity.this.disableAccessibilityService();
|
||||
}
|
||||
})
|
||||
.entry(R.id.action_test, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startActivity(new Intent(MainActivity.this, EditActivity.class));
|
||||
}
|
||||
})
|
||||
.map();
|
||||
|
||||
|
||||
@ViewBinding.Click(R.id.setting)
|
||||
private void startSettingActivity() {
|
||||
//TODO create Setting Activity
|
||||
startActivity(new Intent(this, MainActivity.class));
|
||||
Toast.makeText(this, "暂无", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private void disableAccessibilityService() {
|
||||
if (ActionPerformService.getInstance() != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
ActionPerformService.getInstance().disableSelf();
|
||||
}
|
||||
Snackbar.make(mView, R.string.text_service_disabled, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
Runnable action = mOptionActionMap.get(item.getItemId());
|
||||
if (action != null) {
|
||||
action.run();
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
@ViewBinding.Click(R.id.exit)
|
||||
public void finish() {
|
||||
super.finish();
|
||||
}
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
mFileChooser.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
@NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
if (requestCode == PERMISSION_REQUEST_CODE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
NonUiInitializer.getInstance().copySampleScriptFileIfNeeded();
|
||||
mScriptListRecyclerView.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package com.stardust.scriptdroid;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
import com.stardust.util.MapEntries;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
*/
|
||||
public class NonUiInitializer {
|
||||
|
||||
private static final Map<String, Integer> SAMPLES = new MapEntries<String, Integer>()
|
||||
.entry("sample_open_wechat_moment.js", R.string.text_sample_open_what_moment)
|
||||
.entry("sample_open_running_services.js", R.string.text_sample_open_running_services)
|
||||
.entry("sample_simple_calculator.js", R.string.text_sample_simple_calculator)
|
||||
.map();
|
||||
|
||||
private static NonUiInitializer instance = new NonUiInitializer();
|
||||
|
||||
public static NonUiInitializer getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Context getContext() {
|
||||
return App.getApp();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
|
||||
}
|
||||
|
||||
public void copySampleScriptFileIfNeeded(){
|
||||
if (!Pref.def().getBoolean(Pref.SAMPLE_SCRIPTS_COPIED, false)) {
|
||||
copySampleScriptFile();
|
||||
}
|
||||
}
|
||||
|
||||
private void copySampleScriptFile() {
|
||||
ScriptFileList list = SharedPrefScriptFileList.getInstance();
|
||||
int succeedCount = 0;
|
||||
for (Map.Entry<String, Integer> entry : SAMPLES.entrySet()) {
|
||||
String assetFile = entry.getKey();
|
||||
String name = getContext().getString(entry.getValue());
|
||||
String path = ScriptFile.DEFAULT_FOLDER + name + ".js";
|
||||
if (FileUtils.copyAsset(assetFile, path)) {
|
||||
list.add(new ScriptFile(name, path));
|
||||
succeedCount++;
|
||||
}
|
||||
}
|
||||
if (succeedCount > 0) {
|
||||
Pref.def().edit().putBoolean(Pref.SAMPLE_SCRIPTS_COPIED, true).apply();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
17
app/src/main/java/com/stardust/scriptdroid/Pref.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.stardust.scriptdroid;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/31.
|
||||
*/
|
||||
public class Pref {
|
||||
|
||||
public static final String SAMPLE_SCRIPTS_COPIED = "SAMPLE_SCRIPTS_COPIED";
|
||||
|
||||
public static SharedPreferences def() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(App.getApp());
|
||||
}
|
||||
|
||||
}
|
||||
@ -72,6 +72,11 @@ public class Droid {
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
public int stopAll() {
|
||||
return JAVA_SCRIPT_ENGINE.stopAll();
|
||||
}
|
||||
|
||||
private void checkFile(File file) {
|
||||
if (file == null) {
|
||||
throw new NullPointerException("file = null");
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.stardust.scriptdroid.droid.runtime;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -8,6 +9,8 @@ import android.os.Handler;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.UIActionPerformActivity;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.Action;
|
||||
@ -25,9 +28,10 @@ import java.util.List;
|
||||
public class DroidRuntime implements IDroidRuntime {
|
||||
|
||||
private static final String TAG = "DroidRuntime";
|
||||
private static DroidRuntime runtime = new DroidRuntime();
|
||||
private static Context context;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private static DroidRuntime runtime = new DroidRuntime();
|
||||
private boolean mActionPerformResult;
|
||||
private Handler mUIHandler;
|
||||
|
||||
@ -35,6 +39,10 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
return runtime;
|
||||
}
|
||||
|
||||
public static void setContext(Context context) {
|
||||
DroidRuntime.context = context;
|
||||
}
|
||||
|
||||
protected DroidRuntime() {
|
||||
mUIHandler = new Handler(App.getApp().getMainLooper());
|
||||
}
|
||||
@ -167,6 +175,10 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialDialog.Builder dialog() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public void notifyActionPerformed(boolean succeed) {
|
||||
mActionPerformResult = succeed;
|
||||
@ -174,4 +186,22 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
mLock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public class Builder extends MaterialDialog.Builder {
|
||||
|
||||
public Builder() {
|
||||
super(DroidRuntime.context);
|
||||
}
|
||||
|
||||
public MaterialDialog show(final MaterialDialog.Builder dialog) {
|
||||
UIActionPerformActivity.performAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import android.accessibilityservice.AccessibilityService;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
@ -12,6 +13,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -114,7 +116,8 @@ public class ActionPerformService extends AccessibilityService {
|
||||
AccessibilityNodeInfo nodeInfo = event.getSource();
|
||||
if (nodeInfo == null) {
|
||||
return;
|
||||
}nodeInfo.refresh();
|
||||
}
|
||||
nodeInfo.refresh();
|
||||
Log.v(TAG, "click: " + nodeInfo);
|
||||
Rect rect = new Rect();
|
||||
nodeInfo.getBoundsInScreen(rect);
|
||||
@ -141,4 +144,13 @@ public class ActionPerformService extends AccessibilityService {
|
||||
assistModeEnable = PreferenceManager.getDefaultSharedPreferences(App.getApp()).getBoolean(KEY_ASSIST_MODE_ENABLE, false);
|
||||
}
|
||||
|
||||
public static void disable() {
|
||||
if (instance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
instance.disableSelf();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isEnable() {
|
||||
return AccessibilityServiceUtils.isAccessibilityServiceEnabled(App.getApp(), ActionPerformService.class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.stardust.scriptdroid.droid.runtime.api;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionTarget;
|
||||
|
||||
/**
|
||||
@ -41,4 +42,5 @@ public interface IDroidRuntime {
|
||||
|
||||
void sleep(long millis);
|
||||
|
||||
MaterialDialog.Builder dialog();
|
||||
}
|
||||
|
||||
@ -38,6 +38,12 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine {
|
||||
mDuktape.set(varName, c, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int stopAll() {
|
||||
mDuktape.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void recycle() {
|
||||
if (!mRecycled) {
|
||||
mDuktape.close();
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.stardust.scriptdroid.droid.script;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import com.efurture.script.JSTransformer;
|
||||
import com.furture.react.DuktapeEngine;
|
||||
import com.stardust.scriptdroid.App;
|
||||
@ -7,6 +9,11 @@ import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
@ -15,18 +22,22 @@ import java.io.StringReader;
|
||||
public class GBJDuktapeJavaScriptEngine implements JavaScriptEngine {
|
||||
|
||||
|
||||
private DuktapeEngine mDuktapeEngine = new DuktapeEngine();
|
||||
private boolean mRecycled = false;
|
||||
private String init = Init.readInitScript();
|
||||
private final List<Pair<DuktapeEngine, Thread>> mDuktapeEngineList = new ArrayList<>();
|
||||
private static final String INIT_SCRIPT;
|
||||
private Map<String, Object> mVariableMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
try {
|
||||
INIT_SCRIPT = JSTransformer.parse(new StringReader(Init.INIT_SCRIPT));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public GBJDuktapeJavaScriptEngine(IDroidRuntime runtime) {
|
||||
setRuntime(runtime);
|
||||
mDuktapeEngine.put("context", App.getApp());
|
||||
try {
|
||||
execute(init);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setRuntime(IDroidRuntime runtime) {
|
||||
@ -35,12 +46,75 @@ public class GBJDuktapeJavaScriptEngine implements JavaScriptEngine {
|
||||
|
||||
@Override
|
||||
public Object execute(String script) throws IOException {
|
||||
return mDuktapeEngine.execute(JSTransformer.parse(new StringReader(script)));
|
||||
DuktapeEngine duktapeEngine = new DuktapeEngine();
|
||||
init(duktapeEngine);
|
||||
add(duktapeEngine, Thread.currentThread());
|
||||
Object result;
|
||||
try {
|
||||
result = duktapeEngine.execute(JSTransformer.parse(new StringReader(script)));
|
||||
} catch (IOException e) {
|
||||
remove(duktapeEngine);
|
||||
throw e;
|
||||
}
|
||||
remove(duktapeEngine);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void init(DuktapeEngine duktapeEngine) {
|
||||
duktapeEngine.put("context", App.getApp());
|
||||
duktapeEngine.execute(INIT_SCRIPT);
|
||||
for (Map.Entry<String, Object> variable : mVariableMap.entrySet()) {
|
||||
duktapeEngine.put(variable.getKey(), variable.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void remove(DuktapeEngine duktapeEngine) {
|
||||
duktapeEngine.destory();
|
||||
synchronized (mDuktapeEngineList) {
|
||||
Iterator<Pair<DuktapeEngine, Thread>> iterator = mDuktapeEngineList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Pair<DuktapeEngine, Thread> pair = iterator.next();
|
||||
if (pair.first == duktapeEngine) {
|
||||
stop(pair.first, pair.second);
|
||||
}
|
||||
iterator.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stop(DuktapeEngine engine, Thread thread) {
|
||||
try {
|
||||
thread.interrupt();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
engine.destory();
|
||||
}
|
||||
|
||||
private void add(DuktapeEngine duktapeEngine, Thread thread) {
|
||||
synchronized (mDuktapeEngineList) {
|
||||
mDuktapeEngineList.add(0, new Pair<>(duktapeEngine, thread));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void set(String varName, Class<T> c, T value) {
|
||||
mDuktapeEngine.put(varName, value);
|
||||
mVariableMap.put(varName, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int stopAll() {
|
||||
int n;
|
||||
synchronized (mDuktapeEngineList) {
|
||||
for (Pair<DuktapeEngine, Thread> pair : mDuktapeEngineList) {
|
||||
stop(pair.first, pair.second);
|
||||
}
|
||||
n = mDuktapeEngineList.size();
|
||||
mDuktapeEngineList.clear();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,7 +15,11 @@ public interface JavaScriptEngine {
|
||||
|
||||
<T> void set(String varName, Class<T> c, T value);
|
||||
|
||||
int stopAll();
|
||||
|
||||
class Init {
|
||||
public static final String INIT_SCRIPT = readInitScript();
|
||||
|
||||
static String readInitScript() {
|
||||
return AssetScript.read(App.getApp(), "javasccript_engine_init.js");
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.stardust.scriptdroid.droid.script.file;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
@ -31,4 +30,8 @@ public class ScriptFile {
|
||||
return new File(path);
|
||||
}
|
||||
|
||||
public void rename(String newName) {
|
||||
File file = toFile();
|
||||
file.renameTo(new File(file.getParent(), newName));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import android.content.SharedPreferences;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.stardust.scriptdroid.App;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
@ -21,16 +22,23 @@ public class SharedPrefScriptFileList extends ScriptFileList {
|
||||
private static final String SP_KEY_SCRIPT_NAME = "script_name";
|
||||
private static final String SP_KEY_SCRIPT_PATH = "script_path";
|
||||
|
||||
private static ScriptFileList instance = new SharedPrefScriptFileList(App.getApp());
|
||||
|
||||
private SharedPreferences mSharedPreferences;
|
||||
private List<String> mScriptPath;
|
||||
private List<String> mScriptName;
|
||||
|
||||
public static ScriptFileList getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public SharedPrefScriptFileList(Context context) {
|
||||
mSharedPreferences = context.getSharedPreferences("SharedPrefScriptFileList", Context.MODE_PRIVATE);
|
||||
readFromSharedPref();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void readFromSharedPref() {
|
||||
Type type = new TypeToken<List<String>>() {
|
||||
}.getType();
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
package com.stardust.scriptdroid.editor920;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.afollestad.materialdialogs.folderselector.FolderChooserDialog;
|
||||
import com.jecelyin.editor.v2.common.Command;
|
||||
import com.jecelyin.editor.v2.ui.IActivity;
|
||||
import com.jecelyin.editor.v2.ui.TabManager;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
*/
|
||||
public class Editor920Activity extends IActivity {
|
||||
@Override
|
||||
public void startPickPathActivity(String s, String s1) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doNextCommand() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMenuStatus(int i, int i1) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDocumentChanged(int i) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCommand(Command command) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openFile(String s, String s1, int i) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFindFolderCallback(FolderChooserDialog.FolderCallback folderCallback) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabManager getTabManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertText(CharSequence charSequence) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFolderSelection(@NonNull FolderChooserDialog dialog, @NonNull File folder) {
|
||||
|
||||
}
|
||||
|
||||
protected void onDestroy() {
|
||||
try {
|
||||
super.onDestroy();
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,10 +4,14 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
@ -17,6 +21,8 @@ import java.net.URISyntaxException;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
private static final int BUFFER_SIZE = 1024 * 100;
|
||||
|
||||
public static String getPath(Context context, Uri uri) throws URISyntaxException {
|
||||
if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||
String[] projection = {"_data"};
|
||||
@ -70,8 +76,11 @@ public class FileUtils {
|
||||
if (i < 0)
|
||||
i = path.lastIndexOf("/");
|
||||
if (i >= 0) {
|
||||
String folder = path.substring(i);
|
||||
return new File(folder).mkdirs();
|
||||
String folder = path.substring(0, i);
|
||||
File file = new File(folder);
|
||||
if(file.exists())
|
||||
return true;
|
||||
return file.mkdirs();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -92,4 +101,50 @@ public class FileUtils {
|
||||
public static String readString(File file) {
|
||||
return readString(file, "utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean copy(int rawId, String path) {
|
||||
InputStream is = App.getApp().getResources().openRawResource(rawId);
|
||||
return copy(is, path);
|
||||
}
|
||||
|
||||
public static boolean copy(InputStream is, String path) {
|
||||
if (!ensureFolder(path))
|
||||
return false;
|
||||
File file = new File(path);
|
||||
try {
|
||||
if (!file.exists())
|
||||
if (!file.createNewFile())
|
||||
return false;
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
return copy(is, fos);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean copy(InputStream is, OutputStream os) {
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
try {
|
||||
while (is.available() > 0) {
|
||||
int n = is.read(buffer);
|
||||
os.write(buffer, 0, n);
|
||||
}
|
||||
is.close();
|
||||
os.close();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean copyAsset(String assetFile, String path) {
|
||||
try {
|
||||
return copy(App.getApp().getAssets().open(assetFile), path);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -106,14 +106,20 @@ public abstract class ScriptFileOperation {
|
||||
@Override
|
||||
public void operate(final ScriptListRecyclerView recyclerView, final ScriptFileList scriptFileList, final int position) {
|
||||
String oldName = scriptFileList.get(position).name;
|
||||
new MaterialDialog.Builder(recyclerView.getContext()).title("重命名")
|
||||
new MaterialDialog.Builder(recyclerView.getContext())
|
||||
.title("重命名")
|
||||
.checkBoxPrompt("同时重命名原文件", false, null)
|
||||
.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);
|
||||
}
|
||||
recyclerView.getAdapter().notifyItemChanged(position);
|
||||
}
|
||||
}).show();
|
||||
})
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
package com.stardust.scriptdroid.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.SwitchCompat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.app.Fragment;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import de.psdev.licensesdialog.LicensesDialog;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
*/
|
||||
|
||||
public class SlideMenuFragment extends Fragment {
|
||||
|
||||
|
||||
public static void init(AppCompatActivity activity, int viewId) {
|
||||
SlideMenuFragment fragment = new SlideMenuFragment();
|
||||
activity.getSupportFragmentManager().beginTransaction().replace(viewId, fragment).commit();
|
||||
}
|
||||
|
||||
private SwitchCompat mAutoOperateServiceSwitch;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View createView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_slide_menu, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
if (mAutoOperateServiceSwitch == null) {
|
||||
setUpSwitchCompat();
|
||||
ViewBinder.bind(this);
|
||||
}
|
||||
syncSwitchStatus();
|
||||
}
|
||||
|
||||
private void syncSwitchStatus() {
|
||||
mAutoOperateServiceSwitch.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mAutoOperateServiceSwitch.setChecked(ActionPerformService.isEnable());
|
||||
}
|
||||
}, 450);
|
||||
}
|
||||
|
||||
private void setUpSwitchCompat() {
|
||||
mAutoOperateServiceSwitch = $(R.id.sw_auto_operate_service);
|
||||
mAutoOperateServiceSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked && !ActionPerformService.isEnable()) {
|
||||
AccessibilityServiceUtils.goToPermissionSetting(getContext());
|
||||
} else if (!isChecked && ActionPerformService.isEnable()) {
|
||||
ActionPerformService.disable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.licenses)
|
||||
private void showLicenseDialog() {
|
||||
new LicensesDialog.Builder(getActivity())
|
||||
.setNotices(R.raw.licenses)
|
||||
.setIncludeOwnLicense(true)
|
||||
.build()
|
||||
.showAppCompat();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.stop_all_running_scripts)
|
||||
private void stopAllRunningScripts() {
|
||||
int n = Droid.getInstance().stopAll();
|
||||
if (n > 0)
|
||||
Snackbar.make(getActivityContentView(), "已停止" + n + "个正在运行的脚本", Snackbar.LENGTH_SHORT).show();
|
||||
else
|
||||
Snackbar.make(getActivityContentView(), "没有正在运行的脚本", Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.syntax_and_api)
|
||||
private void startSyntaxHelpActivity() {
|
||||
// TODO: 2017/1/30 startSyntaxHelpActivity
|
||||
Toast.makeText(getContext(), "暂无", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.about_app)
|
||||
private void startAboutActivity() {
|
||||
// TODO: 2017/1/30 startAboutActivity
|
||||
Toast.makeText(getContext(), "暂无", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.auto_operate_service)
|
||||
private void clickAutoOperateServiceSwitch() {
|
||||
mAutoOperateServiceSwitch.setChecked(!mAutoOperateServiceSwitch.isChecked());
|
||||
}
|
||||
}
|
||||
54
app/src/main/java/com/stardust/view/ViewBinder.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.stardust.view;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
*/
|
||||
|
||||
public class ViewBinder {
|
||||
|
||||
public static void bind(Object o) {
|
||||
Method findViewById;
|
||||
try {
|
||||
findViewById = o.getClass().getMethod("findViewById", int.class);
|
||||
findViewById.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("You must implement findViewById to use view binding", e);
|
||||
}
|
||||
Method[] methods = o.getClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
bindClick(o, method, findViewById);
|
||||
}
|
||||
}
|
||||
|
||||
private static void bindClick(final Object o, final Method method, Method findViewById) {
|
||||
ViewBinding.Click annotation = method.getAnnotation(ViewBinding.Click.class);
|
||||
if (annotation == null || annotation.value() == 0)
|
||||
return;
|
||||
int id = annotation.value();
|
||||
try {
|
||||
View view = (View) findViewById.invoke(o, id);
|
||||
view.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
invokeMethod(o, method);
|
||||
}
|
||||
});
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void invokeMethod(Object o, Method method) {
|
||||
try {
|
||||
method.setAccessible(true);
|
||||
method.invoke(o);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
app/src/main/java/com/stardust/view/ViewBinding.java
Normal file
@ -0,0 +1,29 @@
|
||||
package com.stardust.view;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
*/
|
||||
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ViewBinding {
|
||||
|
||||
@interface Multi {
|
||||
ViewBinding[] value();
|
||||
}
|
||||
|
||||
String click() default "";
|
||||
|
||||
int id();
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Click {
|
||||
int value();
|
||||
}
|
||||
}
|
||||
BIN
app/src/main/res/drawable/ic_about_us_green_100px.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/drawable/ic_add_file_green.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/drawable/ic_close_green_48dp.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable/ic_exit_to_app_green_48dp.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable/ic_folder_open_outline_green.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
app/src/main/res/drawable/ic_js.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
app/src/main/res/drawable/ic_license_green.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/drawable/ic_service_green.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
@ -5,13 +5,13 @@
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context="com.stardust.scriptdroid.MainActivity">
|
||||
|
||||
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -55,16 +55,17 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="600dp"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:src="@drawable/ic_create_new_folder_black_48dp"/>
|
||||
android:padding="10dp"
|
||||
android:src="@drawable/ic_add_file_green"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_new_file"
|
||||
android:textColor="@android:color/secondary_text_light"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
@ -83,14 +84,14 @@
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:padding="10dp"
|
||||
android:src="@drawable/ic_sdcard_black"/>
|
||||
android:src="@drawable/ic_folder_open_outline_green"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_import_from_file"
|
||||
android:textColor="@android:color/secondary_text_light"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
@ -102,9 +103,10 @@
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
<include
|
||||
layout="@layout/slide_menu"
|
||||
android:layout_width="280dp"
|
||||
layout="@layout/drawer"
|
||||
android:layout_width="304dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"/>
|
||||
android:layout_gravity="start"
|
||||
/>
|
||||
</android.support.v4.widget.DrawerLayout>
|
||||
|
||||
|
||||
117
app/src/main/res/layout/drawer.xml
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white"
|
||||
android:clickable="true"
|
||||
android:fitsSystemWindows="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="180dp"
|
||||
android:layout_marginBottom="5dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/slide_menu_img"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/version"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@id/version"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="28sp"/>
|
||||
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_slide_menu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="bottom">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/setting"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="6dp"
|
||||
android:src="@drawable/ic_settings_applications_green_48dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_setting"
|
||||
android:textSize="15sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/exit"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="6dp"
|
||||
android:src="@drawable/ic_exit_to_app_green_48dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_exit"
|
||||
android:textSize="15sp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
129
app/src/main/res/layout/fragment_slide_menu.xml
Normal file
@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/auto_operate_service"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="52dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_service"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_margin="16dp"
|
||||
android:src="@drawable/ic_service_green"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_toRightOf="@id/icon_service"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_auto_operate_service"
|
||||
android:textColor="@android:color/primary_text_light"/>
|
||||
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:id="@+id/sw_auto_operate_service"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="16dp"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/syntax_and_api"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="52dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_margin="16dp"
|
||||
android:src="@drawable/ic_js"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_syntax_and_api"
|
||||
android:textColor="@android:color/primary_text_light"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/stop_all_running_scripts"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="52dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_margin="16dp"
|
||||
android:src="@drawable/ic_close_green_48dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_close_all_running_scripts"
|
||||
android:textColor="@android:color/primary_text_light"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/about_app"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="52dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_margin="16dp"
|
||||
android:src="@drawable/ic_about_us_green_100px"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_about"
|
||||
android:textColor="@android:color/primary_text_light"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/licenses"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="52dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_margin="16dp"
|
||||
android:src="@drawable/ic_license_green"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_licenses"
|
||||
android:textColor="@android:color/primary_text_light"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@ -1,14 +0,0 @@
|
||||
<?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:background="@android:color/white"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="156dp"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/slide_menu_img"/>
|
||||
|
||||
</LinearLayout>
|
||||
15
app/src/main/res/raw/licenses.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<notices>
|
||||
<notice>
|
||||
<name>Material Dialogs</name>
|
||||
<url>https://github.com/afollestad/material-dialogs</url>
|
||||
<copyright>Copyright (c) 2014-2016 Aidan Michael Follestad</copyright>
|
||||
<license>MIT License</license>
|
||||
</notice>
|
||||
<notice>
|
||||
<name>Gson</name>
|
||||
<url>https://github.com/google/gson</url>
|
||||
<copyright>Copyright 2008 Google Inc.</copyright>
|
||||
<license>Apache Software License 2.0</license>
|
||||
</notice>
|
||||
</notices>
|
||||
23
app/src/main/res/raw/sample_open_running_services.js
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
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();
|
||||
}
|
||||
5
app/src/main/res/raw/sample_open_wechat_moment.js
Normal file
@ -0,0 +1,5 @@
|
||||
launchApp("微信");
|
||||
sleep(500);
|
||||
click("发现");
|
||||
sleep(500);
|
||||
click("朋友圈");
|
||||
7
app/src/main/res/raw/sample_simple_calculator.js
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
importClass("com.afollestad.materialdialogs.MaterialDialog");
|
||||
|
||||
new MaterialDialog.Builder(context)
|
||||
.title("请输入算式")
|
||||
.contenet("测试")
|
||||
.show();
|
||||
@ -2,7 +2,7 @@
|
||||
<string name="app_name">免Root脚本机器人</string>
|
||||
<string name="action_settings">设置</string>
|
||||
<string name="action_disable_service">关闭服务</string>
|
||||
<string name="text_accesibility_service_description">略略略</string>
|
||||
<string name="text_accessibility_service_description">使脚本自动操作(点击、长按、滑动等)所需,若关闭则只能执行不涉及自动操作的脚本。</string>
|
||||
<string name="text_new_file">新建文件</string>
|
||||
<string name="text_import_from_file">从文件导入</string>
|
||||
<string name="action_exit">退出</string>
|
||||
@ -12,13 +12,13 @@
|
||||
<string name="text_please_input_name">请输入名称</string>
|
||||
<string name="text_name">名称</string>
|
||||
<string name="text_go_to_setting">去设置</string>
|
||||
<string name="explain_accessibility_permission">软件需要权限才能运行 ~ 请在随后的设置中选择”脚本执行机器人\"并开启权限</string>
|
||||
<string name="explain_accessibility_permission">软件需要打开\"自动操作服务\"才能运行,请在随后的设置中选择\"免Root脚本机器人\"并开启服务。\n您也可以稍后在侧拉菜单中设置。</string>
|
||||
<string name="text_cancel">取消</string>
|
||||
<string name="text_path_is_empty">路径为空</string>
|
||||
<string name="text_file_not_exists">文件不存在</string>
|
||||
<string name="text_no_file_rw_permission">无文件读写权限</string>
|
||||
<string name="action_test">内嵌920测试</string>
|
||||
<string name="text_no_accessibility_permission">辅助性服务未启动</string>
|
||||
<string name="text_no_accessibility_permission">自动操作服务未启动,脚本已停止运行</string>
|
||||
<string name="text_drawer_close">关闭侧拉菜单</string>
|
||||
<string name="text_drawer_open">打开侧拉菜单</string>
|
||||
<string name="text_undo">撤销</string>
|
||||
@ -29,4 +29,16 @@
|
||||
<string name="edit_exit_without_save_warn">内容尚未保存,您确定要退出吗?</string>
|
||||
<string name="text_save_and_exit">保存并退出</string>
|
||||
<string name="text_exit_directly">直接退出</string>
|
||||
<string name="text_setting">设置</string>
|
||||
<string name="text_exit">退出</string>
|
||||
<string name="text_auto_operate_service">自动操作服务</string>
|
||||
<string name="version">Version 1.17.0130</string>
|
||||
<string name="text_syntax_and_api">语法与API</string>
|
||||
<string name="text_close_all_running_scripts">关闭所有正在运行的脚本</string>
|
||||
<string name="text_about">关于</string>
|
||||
<string name="text_licenses">开放源代码许可</string>
|
||||
<string name="text_do_not_remind_again">不再提示</string>
|
||||
<string name="text_sample_open_what_moment">示例:打开朋友圈</string>
|
||||
<string name="text_sample_open_running_services">示例:打开正在运行的服务(安卓6.0+)</string>
|
||||
<string name="text_sample_simple_calculator">示例:简单计算器</string>
|
||||
</resources>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
|
||||
@ -4,5 +4,5 @@
|
||||
android:accessibilityFeedbackType="feedbackGeneric"
|
||||
android:accessibilityFlags="flagIncludeNotImportantViews|flagReportViewIds|flagRetrieveInteractiveWindows"
|
||||
android:canRetrieveWindowContent="true"
|
||||
android:description="@string/text_accesibility_service_description"
|
||||
android:description="@string/text_accessibility_service_description"
|
||||
android:notificationTimeout="100"/>
|
||||