This commit is contained in:
hyb1996 2017-10-29 12:39:13 +08:00
commit 2e41de5679
37 changed files with 693 additions and 255 deletions

View File

@ -9,8 +9,8 @@ android {
applicationId "com.stardust.scriptdroid"
minSdkVersion 17
targetSdkVersion 23
versionCode 214
versionName "3.0.0 Alpha15"
versionCode 215
versionName "3.0.0 Alpha16"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
ndk {

View File

@ -18,6 +18,7 @@ public class Pref {
private static final String KEY_SHOULD_SHOW_ANNUNCIATION = "Sing about all the things you forgot, things you are not";
private static final String KEY_FIRST_SHOW_AD = "En, Today is 17.7.7, but, I'm still love you so....";
private static final String KEY_LAST_SHOW_AD_MILLIS = "But... it seems that...you will not come back any more...";
private static final String KEY_FLOATING_MENU_SHOWN = "17.10.28 I have idea of what you think...maybe...I'm overthinking...";
private static SharedPreferences.OnSharedPreferenceChangeListener onSharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
@ -147,4 +148,12 @@ public class Pref {
public static String getDocumentationUrl() {
return "file:///android_asset/docs/";
}
public static boolean isFloatingMenuShown() {
return def().getBoolean(KEY_FLOATING_MENU_SHOWN, false);
}
public static void setFloatingMenuShown(boolean checked) {
def().edit().putBoolean(KEY_FLOATING_MENU_SHOWN, checked).apply();
}
}

View File

@ -0,0 +1,74 @@
package com.stardust.scriptdroid.io;
import android.content.Context;
import android.content.res.AssetManager;
import android.support.annotation.NonNull;
import com.stardust.pio.PFile;
import com.stardust.pio.PFiles;
import com.stardust.scriptdroid.model.script.ScriptFile;
import java.io.File;
import io.reactivex.Observable;
/**
* Created by Stardust on 2017/10/28.
*/
public class SampleFileProvider extends StorageFileProvider {
private AssetManager mAssetManager;
private Context mContext;
public SampleFileProvider(String path, Context context) {
super(path, 10);
mContext = context;
mAssetManager = context.getAssets();
}
public SampleFileProvider(Context context) {
this("sample/", context);
}
@Override
protected Observable<PFile> listFiles(PFile directory) {
return Observable.just(directory)
.flatMap(dir -> Observable.fromArray(mAssetManager.list(directory.getPath())))
.map(path -> {
String absPath = new File(directory, path).getPath();
if (!absPath.endsWith(".js")) {
return new AssetDirectory(absPath);
}
PFile file = new PFile(mContext.getFilesDir(), absPath);
if (!file.exists()) {
copySample(mContext, absPath, file.getPath());
}
return file;
});
}
public static boolean copySample(Context context, String samplePath, String pathTo) {
PFiles.ensureDir(pathTo);
return PFiles.copyAsset(context, samplePath, pathTo);
}
public static class AssetDirectory extends ScriptFile {
public AssetDirectory(@NonNull String pathname) {
super(pathname);
}
@Override
public boolean isDirectory() {
return true;
}
@Override
public boolean isFile() {
return false;
}
}
}

View File

@ -16,9 +16,6 @@ import java.util.List;
import java.util.Map;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Function;
/**
* Created by Stardust on 2017/3/31.
@ -82,6 +79,7 @@ public class StorageFileProvider {
private EventBus mDirectoryEventBus = new EventBus();
private LimitedHashMap<String, List<PFile>> mPFileCache;
private PFile mInitialDirectory;
private FileFilter mFileFilter;
public StorageFileProvider(PFile initialDirectory, int cacheSize, FileFilter fileFilter) {
mInitialDirectory = initialDirectory;
@ -89,7 +87,6 @@ public class StorageFileProvider {
mPFileCache = new LimitedHashMap<>(cacheSize);
}
private FileFilter mFileFilter;
public StorageFileProvider(String path, int cacheSize) {
this(new PFile(path), cacheSize);
@ -185,23 +182,20 @@ public class StorageFileProvider {
}
private Observable<PFile> listFiles(PFile directory) {
protected Observable<PFile> listFiles(PFile directory) {
return Observable.just(directory)
.flatMap(new Function<PFile, ObservableSource<PFile>>() {
@Override
public ObservableSource<PFile> apply(@NonNull PFile dir) throws Exception {
PFile[] files;
if (mFileFilter == null) {
files = dir.listFiles();
} else {
files = dir.listFiles(mFileFilter);
}
if (files == null) {
return Observable.empty();
}
mPFileCache.put(dir.getPath(), new ArrayList<>(Arrays.asList(files)));
return Observable.fromArray(files);
.flatMap(dir -> {
PFile[] files;
if (mFileFilter == null) {
files = dir.listFiles();
} else {
files = dir.listFiles(mFileFilter);
}
if (files == null) {
return Observable.empty();
}
mPFileCache.put(dir.getPath(), new ArrayList<>(Arrays.asList(files)));
return Observable.fromArray(files);
});
}

View File

@ -1,18 +0,0 @@
package com.stardust.scriptdroid.model.sample;
import java.io.Serializable;
/**
* Created by Stardust on 2017/3/13.
*/
public class Sample implements Serializable {
public String name;
public String path;
public Sample(String name, String path) {
this.name = name;
this.path = path;
}
}

View File

@ -0,0 +1,112 @@
package com.stardust.scriptdroid.model.sample;
import android.content.res.AssetManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.stardust.autojs.script.JavaScriptSource;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.pio.PFiles;
import com.stardust.pio.UncheckedIOException;
import com.stardust.scriptdroid.model.script.ScriptFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
/**
* Created by Stardust on 2017/10/28.
*/
public class SampleFile extends ScriptFile {
private long mLength;
private AssetManager mAssetManager;
public SampleFile(@NonNull String pathname, AssetManager assetManager) {
super(pathname);
mAssetManager = assetManager;
init();
}
private void init() {
if (isDirectory()) {
mLength = 0;
return;
}
try {
InputStream inputStream = openInputStream();
mLength = inputStream.available();
inputStream.close();
} catch (IOException e) {
mLength = 0;
}
}
public SampleFile(String parent, @NonNull String child, AssetManager assetManager) {
super(parent, child);
mAssetManager = assetManager;
init();
}
public SampleFile(File parent, @NonNull String child, AssetManager assetManager) {
super(parent, child);
mAssetManager = assetManager;
init();
}
@Override
public boolean isFile() {
return getName().endsWith(".js");
}
@Override
public boolean isDirectory() {
return !isFile();
}
@Override
public long length() {
return mLength;
}
@Override
public String[] list() {
try {
return mAssetManager.list(getPath());
} catch (IOException e) {
return null;
}
}
@Override
public ScriptSource toSource() {
return new JavaScriptSource(getSimplifiedName()) {
@NonNull
@Override
public String getScript() {
try {
return PFiles.read(openInputStream());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Nullable
@Override
public Reader getScriptReader() {
try {
return new InputStreamReader(openInputStream());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
};
}
public InputStream openInputStream() throws IOException {
return mAssetManager.open(getPath());
}
}

View File

@ -1,53 +0,0 @@
package com.stardust.scriptdroid.model.sample;
import android.content.Context;
import android.content.res.AssetManager;
import com.stardust.pio.PFiles;
import com.stardust.scriptdroid.App;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Stardust on 2017/1/30.
*/
public class SampleFileManager {
private static SampleFileManager instance = new SampleFileManager();
public static SampleFileManager getInstance() {
return instance;
}
private Context getContext() {
return App.getApp();
}
public List<SampleGroup> getSamplesFromAssets(AssetManager assets, String path) {
List<SampleGroup> sampleGroups = new ArrayList<>();
try {
String[] groups = assets.list(path);
for (String groupName : groups) {
sampleGroups.add(getSampleGroupFromAssets(assets, groupName, path + "/" + groupName));
}
return sampleGroups;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private SampleGroup getSampleGroupFromAssets(AssetManager assets, String groupName, String path) {
SampleGroup group = new SampleGroup(groupName);
try {
String[] samples = assets.list(path);
for (String sample : samples) {
group.add(new Sample(PFiles.getNameWithoutExtension(sample), path + "/" + sample));
}
return group;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,28 +0,0 @@
package com.stardust.scriptdroid.model.sample;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Stardust on 2017/3/13.
*/
public class SampleGroup {
public String name;
public List<Sample> sampleList;
public SampleGroup(String name) {
this(name, new ArrayList<Sample>());
}
public SampleGroup(String name, List<Sample> samples) {
this.name = name;
sampleList = samples;
}
public void add(Sample sample){
sampleList.add(sample);
}
}

View File

@ -34,7 +34,7 @@ public class ScriptFile extends PFile {
super(parent, name);
}
public ScriptFile(ScriptFile parent, String child) {
public ScriptFile(File parent, String child) {
super(parent, child);
}

View File

@ -1,6 +1,5 @@
package com.stardust.scriptdroid.model.script;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.Nullable;
@ -11,7 +10,6 @@ import com.stardust.autojs.execution.ScriptExecutionListener;
import com.stardust.autojs.execution.SimpleScriptExecutionListener;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.autojs.script.StringScriptSource;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
@ -19,9 +17,7 @@ import com.stardust.scriptdroid.external.CommonUtils;
import com.stardust.scriptdroid.external.shortcut.Shortcut;
import com.stardust.scriptdroid.external.shortcut.ShortcutActivity;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.model.sample.Sample;
import com.stardust.scriptdroid.ui.edit.EditActivity;
import com.stardust.util.AssetsCache;
import org.mozilla.javascript.RhinoException;
@ -113,10 +109,6 @@ public class Scripts {
new ExecutionConfig().path(directoryPath, StorageFileProvider.DEFAULT_DIRECTORY_PATH));
}
public static ScriptExecution run(Context context, Sample file) {
ScriptSource source = new StringScriptSource(file.name, AssetsCache.get(context.getAssets(), file.path));
return AutoJs.getInstance().getScriptEngineService().execute(source);
}
public static ScriptExecution runWithBroadcastSender(ScriptSource source) {
return AutoJs.getInstance().getScriptEngineService().execute(source, BROADCAST_SENDER_SCRIPT_EXECUTION_LISTENER,

View File

@ -22,10 +22,10 @@ import com.stardust.pio.UncheckedIOException;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.io.TmpScriptFiles;
import com.stardust.scriptdroid.model.sample.SampleFile;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.model.script.Scripts;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.model.sample.Sample;
import com.stardust.scriptdroid.network.download.DownloadManager;
import com.stardust.scriptdroid.ui.filechooser.FileChooserDialogBuilder;
import com.stardust.scriptdroid.ui.shortcut.ShortcutCreateActivity;
@ -110,51 +110,43 @@ public class ScriptOperations {
public Observable<String> importFile(final String pathFrom) {
return showFileNameInputDialog(PFiles.getNameWithoutExtension(pathFrom), PFiles.getExtension(pathFrom))
.observeOn(Schedulers.io())
.map(new Function<String, String>() {
@Override
public String apply(@io.reactivex.annotations.NonNull String s) throws Exception {
final String pathTo = getCurrentDirectoryPath() + s + "." + PFiles.getExtension(pathFrom);
if (PFiles.copy(pathFrom, pathTo)) {
showMessage(R.string.text_import_succeed);
} else {
showMessage(R.string.text_import_fail);
}
mStorageFileProvider.notifyFileCreated(mCurrentDirectory, new ScriptFile(pathTo));
return pathTo;
.map(input -> {
final String pathTo = getCurrentDirectoryPath() + input + "." + PFiles.getExtension(pathFrom);
if (PFiles.copy(pathFrom, pathTo)) {
showMessage(R.string.text_import_succeed);
} else {
showMessage(R.string.text_import_fail);
}
mStorageFileProvider.notifyFileCreated(mCurrentDirectory, new ScriptFile(pathTo));
return pathTo;
});
}
public Observable<String> importFile(String prefix, final InputStream inputStream, final String ext) {
return showFileNameInputDialog(PFiles.getNameWithoutExtension(prefix), ext)
.observeOn(Schedulers.io())
.map(new Function<String, String>() {
@Override
public String apply(@io.reactivex.annotations.NonNull String s) throws Exception {
final String pathTo = getCurrentDirectoryPath() + s + "." + ext;
if (PFiles.copyStream(inputStream, pathTo)) {
showMessage(R.string.text_import_succeed);
} else {
showMessage(R.string.text_import_fail);
}
mStorageFileProvider.notifyFileCreated(mCurrentDirectory, new ScriptFile(pathTo));
return pathTo;
.map(input -> {
final String pathTo = getCurrentDirectoryPath() + input + "." + ext;
if (PFiles.copyStream(inputStream, pathTo)) {
showMessage(R.string.text_import_succeed);
} else {
showMessage(R.string.text_import_fail);
}
mStorageFileProvider.notifyFileCreated(mCurrentDirectory, new ScriptFile(pathTo));
return pathTo;
});
}
public void newDirectory() {
showNameInputDialog("", new InputCallback())
.subscribe(new Consumer<String>() {
@Override
public void accept(@io.reactivex.annotations.NonNull String path) throws Exception {
if (new ScriptFile(getCurrentDirectory(), path).mkdirs()) {
showMessage(R.string.text_already_create);
mStorageFileProvider.notifyFileCreated(mCurrentDirectory, new ScriptFile(path));
} else {
showMessage(R.string.text_create_fail);
}
.subscribe(path -> {
ScriptFile newDir = new ScriptFile(getCurrentDirectory(), path);
if (newDir.mkdirs()) {
showMessage(R.string.text_already_create);
mStorageFileProvider.notifyFileCreated(mCurrentDirectory, new ScriptFile(newDir));
} else {
showMessage(R.string.text_create_fail);
}
});
}
@ -164,12 +156,7 @@ public class ScriptOperations {
showMessageWithoutThreadSwitch(resId);
}
//switch to ui thread to show message
App.getApp().getUiHandler().post(new Runnable() {
@Override
public void run() {
showMessageWithoutThreadSwitch(resId);
}
});
App.getApp().getUiHandler().post(() -> showMessageWithoutThreadSwitch(resId));
}
private void showMessageWithoutThreadSwitch(int resId) {
@ -191,12 +178,9 @@ public class ScriptOperations {
.inputType(InputType.TYPE_CLASS_TEXT)
.alwaysCallInputCallback()
.input(getString(R.string.text_please_input_name), prefix, false, textWatcher)
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
input.onNext(dialog.getInputEditText().getText().toString());
input.onComplete();
}
.onPositive((dialog, which) -> {
input.onNext(dialog.getInputEditText().getText().toString());
input.onComplete();
})
.build());
return input;
@ -207,9 +191,9 @@ public class ScriptOperations {
return mContext.getString(resId);
}
public Observable<String> importSample(Sample sample) {
public Observable<String> importSample(SampleFile sample) {
try {
return importFile(sample.name, mContext.getAssets().open(sample.path), PFiles.getExtension(sample.path));
return importFile(sample.getSimplifiedName(), sample.openInputStream(), sample.getExtension());
} catch (IOException e) {
e.printStackTrace();
showMessage(R.string.text_import_fail);

View File

@ -17,6 +17,7 @@ import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
@ -172,46 +173,36 @@ public class CodeMirrorEditor extends FrameLayout {
mWebView.setWebChromeClient(new MyWebChromeClient());
}
public void setReadOnly(boolean readOnly) {
evalJavaScript(String.format("editor.setOption('readOnly', %b);", readOnly));
}
public void setProgress(boolean onProgress) {
mProgressBarContainer.setVisibility(onProgress ? VISIBLE : GONE);
}
public void setText(final String text) {
mTextFromAndroid = text;
mPageFinished.promise().done(new DoneCallback<Void>() {
@Override
public void onDone(Void result) {
evalJavaScript("editor.setValue(__bridge__.getStringFromAndroid());");
}
});
mPageFinished.promise().done(result -> evalJavaScript("editor.setValue(__bridge__.getStringFromAndroid());"));
}
public void insert(String text) {
mTextFromAndroid = text;
mPageFinished.promise().done(new DoneCallback<Void>() {
@Override
public void onDone(Void result) {
evalJavaScript("editor.replaceSelection(__bridge__.getStringFromAndroid());");
}
});
mPageFinished.promise().done(result -> evalJavaScript("editor.replaceSelection(__bridge__.getStringFromAndroid());"));
}
public void loadFile(final File file) {
setProgress(true);
// TODO: 2017/9/29 handle error
Observable.fromCallable(new Callable<String>() {
@Override
public String call() throws Exception {
return PFiles.read(file);
}
}).subscribeOn(Schedulers.io())
Observable.fromCallable(() -> PFiles.read(file))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
setText(s);
setProgress(false);
}
.subscribe(s -> {
setText(s);
setProgress(false);
}, err -> {
err.printStackTrace();
Toast.makeText(getContext(), getContext().getString(R.string.text_cannot_read_file, file.getPath()),
Toast.LENGTH_SHORT).show();
});
}

View File

@ -14,8 +14,10 @@ import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ViewById;
import static com.stardust.scriptdroid.ui.edit.EditorView.EXTRA_CONTENT;
import static com.stardust.scriptdroid.ui.edit.EditorView.EXTRA_NAME;
import static com.stardust.scriptdroid.ui.edit.EditorView.EXTRA_PATH;
import static com.stardust.scriptdroid.ui.edit.EditorView.EXTRA_READ_ONLY;
/**
* Created by Stardust on 2017/1/29.
@ -41,8 +43,12 @@ public class EditActivity extends BaseActivity {
.putExtra(EXTRA_NAME, name));
}
public static void editFile(Context context, ScriptFile file) {
editFile(context, file.getSimplifiedName(), file.getPath());
public static void viewContent(Context context, String name, String content) {
context.startActivity(new Intent(context, EditActivity_.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(EXTRA_CONTENT, content)
.putExtra(EXTRA_NAME, name)
.putExtra(EXTRA_READ_ONLY, true));
}
@AfterViews

View File

@ -151,6 +151,9 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
if (!intent.getBooleanExtra(EXTRA_RUN_ENABLED, true)) {
findViewById(R.id.run).setVisibility(GONE);
}
if(mReadOnly){
mEditor.setReadOnly(true);
}
}

View File

@ -17,7 +17,7 @@ import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.execution.ScriptExecution;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.model.sample.Sample;
import com.stardust.scriptdroid.model.sample.SampleFile;
import com.stardust.scriptdroid.ui.BaseActivity;
import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.theme.ThemeColorManager;
@ -41,14 +41,14 @@ import static com.stardust.scriptdroid.model.script.Scripts.EXTRA_EXCEPTION_MESS
public class ViewSampleActivity extends AppCompatActivity implements OnActivityResultDelegate.DelegateHost {
public static void view(Context context, Sample sample) {
public static void view(Context context, SampleFile sample) {
context.startActivity(new Intent(context, ViewSampleActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra("sample", sample));
.putExtra("sample_path", sample.getPath()));
}
private View mView;
private Sample mSample;
private SampleFile mSample;
private ScriptExecution mScriptExecution;
private SparseArray<ToolbarMenuItem> mMenuMap;
private OnActivityResultDelegate.Mediator mMediator = new OnActivityResultDelegate.Mediator();
@ -76,8 +76,7 @@ public class ViewSampleActivity extends AppCompatActivity implements OnActivityR
}
private void handleIntent(Intent intent) {
mSample = (Sample) intent.getSerializableExtra("sample");
String content = AssetsCache.get(this, mSample.path);
mSample = new SampleFile(intent.getStringExtra("sample_path"), getAssets());
}
private void setUpUI() {
@ -92,7 +91,7 @@ public class ViewSampleActivity extends AppCompatActivity implements OnActivityR
}
private void setUpToolbar() {
BaseActivity.setToolbarAsBack(this, R.id.toolbar, mSample.name);
BaseActivity.setToolbarAsBack(this, R.id.toolbar, mSample.getSimplifiedName());
}
@OnClick(R.id.run)

View File

@ -246,7 +246,7 @@ public class CircularMenu implements Recorder.OnStateChangedListener {
}
@Optional
@OnClick(R.id.package_name)
@OnClick(R.id.class_name)
void copyActivityName() {
dismissSettingsDialog();
if (TextUtils.isEmpty(mRunningActivity))

View File

@ -162,9 +162,7 @@ public class LayoutHierarchyView extends MultiLevelListView {
Stack<NodeInfo> parents = new Stack<>();
searchNodeParents(selectedNode, mRootNode, parents);
mClickedNodeInfo = parents.peek();
for (NodeInfo nodeInfo : parents) {
mInitiallyExpandedNodes.add(nodeInfo);
}
mInitiallyExpandedNodes.addAll(parents);
mAdapter.reloadData();
}
@ -225,7 +223,7 @@ public class LayoutHierarchyView extends MultiLevelListView {
NodeInfo nodeInfo = (NodeInfo) object;
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.layout_hierarchy_view_item, LayoutHierarchyView.this, false);
convertView = LayoutInflater.from(getContext()).inflate(R.layout.layout_hierarchy_view_item, null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {

View File

@ -31,6 +31,8 @@ import com.stardust.scriptdroid.ui.doc.OnlineDocsFragment_;
import com.stardust.scriptdroid.ui.floating.FloatyWindowManger;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.ui.main.community.CommunityFragment_;
import com.stardust.scriptdroid.ui.main.sample.SampleListFragment;
import com.stardust.scriptdroid.ui.main.sample.SampleListFragment_;
import com.stardust.scriptdroid.ui.main.scripts.MyScriptListFragment_;
import com.stardust.scriptdroid.ui.main.task.TaskManagerFragment_;
import com.stardust.theme.ThemeColorManager;
@ -145,6 +147,7 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega
.add(new MyScriptListFragment_(), R.string.text_script)
.add(new OnlineDocsFragment_(), R.string.text_tutorial)
.add(new CommunityFragment_(), R.string.text_community)
.add(new SampleListFragment_(), R.string.text_sample)
.add(new TaskManagerFragment_(), R.string.text_manage)
.build();
mViewPager.setAdapter(mPagerAdapter);
@ -184,10 +187,10 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega
@Click(R.id.exit)
public void exitCompletely() {
finish();
FloatyWindowManger.hideCircularMenu();
stopService(new Intent(this, FloatyService.class));
AutoJs.getInstance().getScriptEngineService().stopAll();
finish();
}
@Override

View File

@ -89,7 +89,6 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
@ViewById(R.id.default_cover)
View mDefaultCover;
private Disposable mConnectionStateDisposable;
@ -101,6 +100,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
.doOnNext(connected -> mConnectionItem.getSwitchCompat().setChecked(connected))
.subscribe();
EventBus.getDefault().register(this);
}
@Override
@ -118,6 +118,9 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
@AfterViews
void setUpViews() {
ThemeColorManager.addViewBackground(mHeaderView);
if (Pref.isFloatingMenuShown()) {
mFloatingWindowItem.getSwitchCompat().setChecked(true);
}
}
private void syncUserInfo() {
@ -204,6 +207,9 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
void showOrDismissFloatingWindow() {
boolean isFloatingWindowShowing = FloatyWindowManger.isCircularMenuShowing();
boolean checked = mFloatingWindowItem.getSwitchCompat().isChecked();
if (getActivity() != null && !getActivity().isFinishing()) {
Pref.setFloatingMenuShown(checked);
}
if (checked && !isFloatingWindowShowing) {
FloatyWindowManger.showCircularMenu();
enableAccessibilityServiceByRootIfNeeded();

View File

@ -0,0 +1,108 @@
package com.stardust.scriptdroid.ui.main.sample;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.io.SampleFileProvider;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.model.script.Scripts;
import com.stardust.scriptdroid.tool.SimpleObserver;
import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.scriptdroid.ui.main.FloatingActionMenu;
import com.stardust.scriptdroid.ui.main.QueryEvent;
import com.stardust.scriptdroid.ui.main.ViewPagerFragment;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListView;
import com.stardust.util.BackPressedHandler;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.ViewById;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
/**
* Created by Stardust on 2017/10/28.
*/
@EFragment(R.layout.fragment_sample_list)
public class SampleListFragment extends ViewPagerFragment implements BackPressedHandler {
public SampleListFragment() {
super(ROTATION_GONE);
}
@ViewById(R.id.sample_list)
ScriptListView mScriptFileList;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventBus.getDefault().register(this);
}
@AfterViews
void setUpViews() {
mScriptFileList.setDirectorySpanSize(2);
mScriptFileList.setStorageFileProvider(new SampleFileProvider(getContext()));
mScriptFileList.setOnScriptFileClickListener((view, file) -> Scripts.edit(file));
}
@Override
public void onResume() {
super.onResume();
((BackPressedHandler.HostActivity) getActivity())
.getBackPressedObserver()
.registerHandlerAtFront(this);
}
@Override
public void onPause() {
super.onPause();
((BackPressedHandler.HostActivity) getActivity())
.getBackPressedObserver()
.unregisterHandler(this);
}
@Override
protected void onFabClick(FloatingActionButton fab) {
}
@Override
public boolean onBackPressed(Activity activity) {
if (mScriptFileList.canGoBack()) {
mScriptFileList.goBack();
return true;
}
return false;
}
@Subscribe
public void onQuerySummit(QueryEvent event) {
if (!isShown()) {
return;
}
if (event == QueryEvent.CLEAR) {
mScriptFileList.setFilter(null);
return;
}
String query = event.getQuery();
mScriptFileList.setFilter((file -> file.getSimplifiedName().contains(query)));
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}

View File

@ -0,0 +1,149 @@
package com.stardust.scriptdroid.ui.main.sample;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.content.res.ResourcesCompat;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.stardust.pio.PFiles;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.io.SampleFileProvider;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.model.script.Scripts;
import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListView;
import com.stardust.scriptdroid.ui.widget.BindableViewHolder;
import java.io.File;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
/**
* Created by Stardust on 2017/10/28.
*/
public class SampleListView extends ScriptListView {
public SampleListView(Context context) {
super(context);
}
public SampleListView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.copy_to_my_script:
new ScriptOperations(getContext(), this)
.importFile(mSelectedScriptFile.getPath())
.subscribe();
return true;
case R.id.reset:
resetSample();
return true;
default:
return super.onMenuItemClick(item);
}
}
private void resetSample() {
String samplePath = new File(getCurrentDirectory(), mSelectedScriptFile.getName()).getPath();
if (SampleFileProvider.copySample(getContext(), samplePath, mSelectedScriptFile.getPath())) {
Snackbar.make(this, R.string.text_reset_succeed, Snackbar.LENGTH_SHORT).show();
} else {
Snackbar.make(this, R.string.text_reset_fail, Snackbar.LENGTH_SHORT).show();
}
}
@Override
protected BindableViewHolder<?> onCreateViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_FILE) {
return new SampleFileViewHolder(inflater.inflate(R.layout.script_file_list_file, parent, false));
} else if (viewType == VIEW_TYPE_DIRECTORY) {
DirectoryViewHolder viewHolder = (DirectoryViewHolder) super.onCreateViewHolder(inflater, parent, viewType);
viewHolder.mOptions.setVisibility(GONE);
return viewHolder;
}
return super.onCreateViewHolder(inflater, parent, viewType);
}
class SampleFileViewHolder extends BindableViewHolder<ScriptFile> {
@BindView(R.id.name)
TextView mName;
@BindView(R.id.first_char)
TextView mFirstChar;
@BindView(R.id.desc)
TextView mDesc;
@BindView(R.id.more)
View mOptions;
@BindView(R.id.edit)
View mEdit;
GradientDrawable mFirstCharBackground;
private ScriptFile mScriptFile;
SampleFileViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
mFirstCharBackground = (GradientDrawable) mFirstChar.getBackground();
}
@Override
public void bind(ScriptFile file, int position) {
mScriptFile = file;
mName.setText(file.getSimplifiedName());
mDesc.setText(PFiles.getHumanReadableSize(file.length()));
if (file.getType() == ScriptFile.TYPE_JAVA_SCRIPT) {
mFirstChar.setText("J");
mFirstCharBackground.setColor(ResourcesCompat.getColor(getResources(), R.color.color_j, getContext().getTheme()));
mEdit.setVisibility(VISIBLE);
} else {
mFirstChar.setText("R");
mFirstCharBackground.setColor(ResourcesCompat.getColor(getResources(), R.color.color_r, getContext().getTheme()));
mEdit.setVisibility(GONE);
}
}
@OnClick(R.id.item)
void onItemClick() {
if (mOnScriptFileClickListener != null) {
mOnScriptFileClickListener.onScriptFileClick(itemView, mScriptFile);
}
notifyOperated();
}
@OnClick(R.id.run)
void run() {
Scripts.run(mScriptFile);
notifyOperated();
}
@OnClick(R.id.edit)
void edit() {
Scripts.edit(mScriptFile);
notifyOperated();
}
@OnClick(R.id.more)
void showOptionMenu() {
mSelectedScriptFile = mScriptFile;
PopupMenu popupMenu = new PopupMenu(getContext(), mOptions);
popupMenu.inflate(R.menu.menu_sample_options);
popupMenu.setOnMenuItemClickListener(SampleListView.this);
popupMenu.show();
}
}
}

View File

@ -66,10 +66,10 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
private RecyclerView mScriptListView;
private ScriptListAdapter mScriptListAdapter = new ScriptListAdapter();
private ScriptFile mCurrentDirectory;
private OnScriptFileClickListener mOnScriptFileClickListener;
protected OnScriptFileClickListener mOnScriptFileClickListener;
private Function<PFile, Boolean> mFilter;
private OnItemOperatedListener mOnItemOperatedListener;
private ScriptFile mSelectedScriptFile;
protected ScriptFile mSelectedScriptFile;
private StorageFileProvider mStorageFileProvider;
private boolean mDirSortMenuShowing = false;
private boolean mDirsCollapsed;
@ -174,9 +174,13 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
mStorageFileProvider.getDirectoryFiles(mCurrentDirectory)
.subscribeOn(Schedulers.io())
.filter(f -> mFilter == null ? true : mFilter.apply(f))
.collectInto(mScriptList.cloneConfig(), (list, file) ->
list.add(new ScriptFile(file))
)
.collectInto(mScriptList.cloneConfig(), (list, file) -> {
if (file instanceof ScriptFile) {
list.add((ScriptFile) file);
} else {
list.add(new ScriptFile(file));
}
})
.observeOn(Schedulers.computation())
.doOnSuccess(ScriptList::sort)
.observeOn(AndroidSchedulers.mainThread())
@ -248,7 +252,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
return true;
}
private void notifyOperated() {
protected void notifyOperated() {
if (mOnItemOperatedListener != null) {
mOnItemOperatedListener.OnItemOperated(mSelectedScriptFile);
}
@ -345,7 +349,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
}
}
class ScriptFileViewHolder extends BindableViewHolder<ScriptFile> {
protected class ScriptFileViewHolder extends BindableViewHolder<ScriptFile> {
@BindView(R.id.name)
@ -413,12 +417,12 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
}
}
class DirectoryViewHolder extends BindableViewHolder<ScriptFile> {
protected class DirectoryViewHolder extends BindableViewHolder<ScriptFile> {
@BindView(R.id.name)
TextView mName;
public TextView mName;
@BindView(R.id.more)
View mOptions;
public View mOptions;
private ScriptFile mScriptFile;

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.stardust.scriptdroid.ui.main.sample.SampleListView
android:id="@+id/sample_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>

View File

@ -5,12 +5,12 @@
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:clickable="true"
android:foreground="?selectableItemBackground"
app:cardBackgroundColor="#ffffff"
app:cardElevation="1dp"
app:cardElevation="0.5dp"
app:cardUseCompatPadding="true">
<LinearLayout

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/run_repeatedly"
android:title="@string/text_run_repeatedly"/>
<item
android:id="@+id/floating_edit"
android:title="@string/text_floating_edit"/>
<item
android:id="@+id/create_shortcut"
android:title="@string/text_send_shortcut"/>
<item
android:id="@+id/copy_to_my_script"
android:title="@string/text_copy_to_my_script"/>
<item
android:id="@+id/reset"
android:title="@string/text_reset_to_initial_content"/>
</menu>

View File

@ -275,6 +275,12 @@
<string name="text_registering">注册中</string>
<string name="text_register_fail">注册失败</string>
<string name="text_register_succeed">注册成功</string>
<string name="text_sample">示例</string>
<string name="text_copy_to_my_script">导入到我的脚本</string>
<string name="text_reset_to_initial_content">重置为初始内容</string>
<string name="text_reset_fail">重置失败</string>
<string name="text_reset_succeed">重置成功</string>
<string name="text_cannot_read_file" formatted="true">无法读取文件: %s</string>
<string-array name="ad_showing_mode_keys">

View File

@ -27,6 +27,7 @@ repositories {
flatDir {
dirs 'libs'
}
google()
}
dependencies {
@ -41,8 +42,8 @@ dependencies {
compile('com.afollestad.material-dialogs:core:0.9.2.3', {
exclude group: 'com.android.support'
})
compile 'com.android.support:design:25.3.1'
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:design:25.4.0'
compile 'com.android.support:appcompat-v7:25.4.0'
compile 'com.github.hyb1996:EnhancedFloaty:0.17'
// Terminal emulator
compile(name: 'libtermexec-release', ext: 'aar')

View File

@ -98,4 +98,4 @@ module.exports = function(__runtime__, scope){
}
};
return proxy;
}
}

View File

@ -65,7 +65,7 @@ public class StardustConsole extends AbstractConsole {
private AtomicInteger mIdCounter = new AtomicInteger(0);
private ResizableExpandableFloatyWindow mFloatyWindow;
private ConsoleFloaty mConsoleFloaty;
private LogListener mLogListener;
private WeakReference<LogListener> mLogListener;
private UiHandler mUiHandler;
private BlockingQueue<String> mInput = new ArrayBlockingQueue<>(1);
private WeakReference<ConsoleView> mConsoleView;
@ -96,8 +96,9 @@ public class StardustConsole extends AbstractConsole {
}
}
public void setLogListener(LogListener logListener) {
mLogListener = logListener;
mLogListener = new WeakReference<>(logListener);
}
public ArrayList<Log> getAllLogs() {
@ -111,8 +112,8 @@ public class StardustConsole extends AbstractConsole {
if (mGlobalConsole != null) {
mGlobalConsole.println(level, charSequence);
}
if (mLogListener != null) {
mLogListener.onNewLog(log);
if (mLogListener != null && mLogListener.get() != null) {
mLogListener.get().onNewLog(log);
}
}
@ -124,8 +125,8 @@ public class StardustConsole extends AbstractConsole {
if (mGlobalConsole != null) {
mGlobalConsole.print(level, charSequence);
}
if (mLogListener != null) {
mLogListener.onNewLog(log);
if (mLogListener != null && mLogListener.get() != null) {
mLogListener.get().onNewLog(log);
}
}
@ -133,8 +134,8 @@ public class StardustConsole extends AbstractConsole {
@Override
public void clear() {
mLogs.clear();
if (mLogListener != null) {
mLogListener.onLogClear();
if (mLogListener != null && mLogListener.get() != null) {
mLogListener.get().onLogClear();
}
}

View File

@ -1,5 +1,12 @@
package com.stardust.autojs.core.ui.xml;
import com.stardust.autojs.core.ui.widget.JsButton;
import com.stardust.autojs.core.ui.widget.JsEditText;
import com.stardust.autojs.core.ui.widget.JsFrameLayout;
import com.stardust.autojs.core.ui.widget.JsLinearLayout;
import com.stardust.autojs.core.ui.widget.JsRelativeLayout;
import com.stardust.autojs.core.ui.widget.JsTextView;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
@ -21,14 +28,14 @@ import javax.xml.parsers.ParserConfigurationException;
public class XmlConverter {
private static final NodeHandler NODE_HANDLER = new NodeHandler.NameRouter()
.handler("vertical", new NodeHandler.VerticalHandler("com.stardust.autojs.runtime.api.ui.widget.JsLinearLayout"))
.handler("vertical", new NodeHandler.VerticalHandler(JsLinearLayout.class.getName()))
.defaultHandler(new NodeHandler.MapNameHandler()
.map("frame", "com.stardust.autojs.runtime.api.ui.widget.JsFrameLayout")
.map("linear", "com.stardust.autojs.runtime.api.ui.widget.JsLinearLayout")
.map("relative", "com.stardust.autojs.runtime.api.ui.widget.JsRelativeLayout")
.map("button", "com.stardust.autojs.runtime.api.ui.widget.JsButton")
.map("text", "com.stardust.autojs.runtime.api.ui.widget.JsTextView")
.map("input", "com.stardust.autojs.runtime.api.ui.widget.JsEditText")
.map("frame", JsFrameLayout.class.getName())
.map("linear", JsLinearLayout.class.getName())
.map("relative", JsRelativeLayout.class.getName())
.map("button", JsButton.class.getName())
.map("text", JsTextView.class.getName())
.map("input", JsEditText.class.getName())
.map("image", "ImageView")
);

View File

@ -44,9 +44,7 @@ public class LoopedBasedJavaScriptExecution extends RunnableScriptExecution {
return true;
}
});
javaScriptEngine.execute(
getSource());
javaScriptEngine.execute(getSource());
return null;
}

View File

@ -39,7 +39,7 @@ public class ScriptExecuteActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentExtras extras = IntentExtras.fromIntent(getIntent());
if (extras == null || extras.get(EXTRA_EXECUTION) == null) {
if (extras.get(EXTRA_EXECUTION) == null) {
finish();
return;
}

View File

@ -27,6 +27,7 @@ import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
import com.stardust.autojs.core.accessibility.SimpleActionAutomator;
import com.stardust.concurrent.VolatileBox;
import com.stardust.autojs.runtime.api.UI;
import com.stardust.concurrent.VolatileDispose;
import com.stardust.pio.UncheckedIOException;
import com.stardust.util.ClipboardUtil;
import com.stardust.autojs.core.util.ProcessShell;
@ -237,7 +238,7 @@ public class ScriptRuntime {
if (Looper.myLooper() == Looper.getMainLooper()) {
return ClipboardUtil.getClipOrEmpty(mUiHandler.getContext()).toString();
}
final VolatileBox<String> clip = new VolatileBox<>("");
final VolatileDispose<String> clip = new VolatileDispose<>();
mUiHandler.post(new Runnable() {
@Override
public void run() {

View File

@ -25,6 +25,7 @@ repositories {
flatDir {
dirs 'libs'
}
google()
}
dependencies {
@ -32,6 +33,6 @@ dependencies {
exclude group: 'com.android.support', module: 'support-annotations'
})
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:appcompat-v7:25.4.0'
compile project(path: ':common')
}

View File

@ -11,6 +11,7 @@ import android.support.annotation.RequiresApi;
import android.view.ViewConfiguration;
import com.stardust.concurrent.VolatileBox;
import com.stardust.concurrent.VolatileDispose;
import com.stardust.util.ScreenMetrics;
/**
@ -110,7 +111,7 @@ public class GlobalActionAutomator {
@RequiresApi(api = Build.VERSION_CODES.N)
private boolean gesturesWithHandler(GestureDescription description) {
final VolatileBox<Boolean> result = new VolatileBox<>(false);
final VolatileDispose<Boolean> result = new VolatileDispose<>();
mService.dispatchGesture(description, new AccessibilityService.GestureResultCallback() {
@Override
public void onCompleted(GestureDescription gestureDescription) {

View File

@ -0,0 +1,52 @@
package com.stardust.concurrent;
/**
* Created by Stardust on 2017/10/28.
*/
public class VolatileDispose<T> {
private volatile T mValue;
public T blockedGet() {
synchronized (this) {
if (mValue != null) {
return mValue;
}
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return mValue;
}
public T blockedGetOrThrow(Class<? extends RuntimeException> exception) {
synchronized (this) {
if (mValue != null) {
return mValue;
}
try {
this.wait();
} catch (InterruptedException e) {
try {
throw exception.newInstance();
} catch (InstantiationException e1) {
throw new RuntimeException(e1);
} catch (IllegalAccessException e1) {
throw new RuntimeException(e1);
}
}
}
return mValue;
}
public void setAndNotify(T value) {
synchronized (this) {
mValue = value;
notify();
}
}
}

View File

@ -36,6 +36,7 @@ repositories {
flatDir {
dirs 'libs'
}
google()
}
dependencies {
@ -43,7 +44,7 @@ dependencies {
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.3.1'
compile 'com.android.support:appcompat-v7:25.4.0'
testCompile 'junit:junit:4.12'
compile project(':automator')
compile project(':common')