add: slide menu

This commit is contained in:
hyb1996 2017-01-31 22:41:04 +08:00
parent b47eaf9d5e
commit 853a518d97
51 changed files with 1214 additions and 299 deletions

View File

@ -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" />

View File

@ -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'

View File

@ -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>

View File

@ -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));
}

View 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();
}

View File

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

View File

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

View File

@ -1,3 +0,0 @@
droid.toast("略略略");
droid.click(droid.text("哈哈哈"));

View 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();
}
}

View 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);
}

View 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()));
}
}
}

View File

@ -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) {

View File

@ -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) {
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View 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());
}
}

View File

@ -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");

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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");
}

View File

@ -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));
}
}

View File

@ -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();

View File

@ -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) {
}
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}

View 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);
}
}
}

View 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();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -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>

View 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>

View 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>

View File

@ -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>

View 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>

View 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();
}

View File

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

View File

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

View File

@ -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>

View File

@ -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>

View File

@ -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"/>