add: supports for daily task and disposable task

This commit is contained in:
hyb1996
2017-11-28 20:59:29 +08:00
parent e8bab643af
commit 97382965da
51 changed files with 1106 additions and 171 deletions

View File

@@ -86,6 +86,7 @@
<activity android:name=".ui.log.LogActivity_"/>
<activity android:name=".ui.doc.DocumentationActivity_"/>
<activity android:name=".ui.shortcut.ShortcutIconSelectActivity_"/>
<activity android:name=".ui.timing.TimedTaskSettingActivity_"/>
<activity
android:name=".ui.shortcut.ShortcutCreateActivity"
android:theme="@style/AppTheme.Transparent"/>
@@ -102,6 +103,7 @@
android:name=".ui.error.IssueReporterActivity"
android:theme="@style/IssueReporterTheme"/>
<service android:name=".external.ScriptExecutionIntentService"/>
<activity android:name=".external.tasker.TaskPrefEditActivity_"/>

View File

@@ -234,14 +234,14 @@ exports.puts = util.deprecate(function() {
<p>When called, <code>util.deprecate()</code> will return a function that will emit a
<code>DeprecationWarning</code> using the <code>process.on(&#39;warning&#39;)</code> event. By default,
this warning will be emitted and printed to <code>stderr</code> exactly once, the first
time it is called. After the warning is emitted, the wrapped <code>function</code>
timeFlag it is called. After the warning is emitted, the wrapped <code>function</code>
is called.</p>
<p>If either the <code>--no-deprecation</code> or <code>--no-warnings</code> command line flags are
used, or if the <code>process.noDeprecation</code> property is set to <code>true</code> <em>prior</em> to
the first deprecation warning, the <code>util.deprecate()</code> method does nothing.</p>
<p>If the <code>--trace-deprecation</code> or <code>--trace-warnings</code> command line flags are set,
or the <code>process.traceDeprecation</code> property is set to <code>true</code>, a warning and a
stack trace are printed to <code>stderr</code> the first time the deprecated function is
stack trace are printed to <code>stderr</code> the first timeFlag the deprecated function is
called.</p>
<p>If the <code>--throw-deprecation</code> command line flag is set, or the
<code>process.throwDeprecation</code> property is set to <code>true</code>, then an exception will be
@@ -447,7 +447,7 @@ via the <code>util.inspect.styles</code> and <code>util.inspect.colors</code> pr
<li><code>regexp</code> - <code>red</code></li>
<li><code>null</code> - <code>bold</code></li>
<li><code>undefined</code> - <code>grey</code></li>
<li><code>special</code> - <code>cyan</code> (only applied to functions at this time)</li>
<li><code>special</code> - <code>cyan</code> (only applied to functions at this timeFlag)</li>
<li><code>name</code> - (no styling)</li>
</ul>
<p>The predefined color codes are: <code>white</code>, <code>grey</code>, <code>black</code>, <code>blue</code>, <code>cyan</code>,

View File

@@ -643,7 +643,7 @@ Fix a [bug](https://github.com/codemirror/CodeMirror/issues/3834) that caused ph
* The editor and theme CSS was cleaned up. Some selectors are now less specific than before
* New theme: [abcdef](http://codemirror.net/demo/theme.html#abcdef)
* Lines longer than [`maxHighlightLength`](http://codemirror.net/doc/manual.html#option_maxHighlightLength) are now less likely to mess up indentation
* New addons: [`autorefresh`](http://codemirror.net/doc/manual.html#addon_autorefresh) for refreshing an editor the first time it becomes visible, and `html-lint` for using [HTMLHint](http://htmlhint.com/)
* New addons: [`autorefresh`](http://codemirror.net/doc/manual.html#addon_autorefresh) for refreshing an editor the first timeFlag it becomes visible, and `html-lint` for using [HTMLHint](http://htmlhint.com/)
* The [`search`](http://codemirror.net/doc/manual.html#addon_search) addon now recognizes `\r` and `\n` in pattern and replacement input
## 5.5.0 (2015-07-20)
@@ -774,7 +774,7 @@ Emergency single-patch update to 4.9\. Fixes Firefox-specific problem where the
## 4.4.0 (2014-07-21)
* **Note:** Some events might now fire in slightly different order (`"change"` is still guaranteed to fire before `"cursorActivity"`)
* Nested operations in multiple editors are now synced (complete at same time, reducing DOM reflows)
* Nested operations in multiple editors are now synced (complete at same timeFlag, reducing DOM reflows)
* Visual block mode for [vim](http://codemirror.net/demo/vim.html) (<C-v>) is nearly complete
* New mode: [Kotlin](http://codemirror.net/mode/kotlin/index.html)
* Better multi-selection paste for text copied from multiple CodeMirror selections
@@ -804,7 +804,7 @@ Emergency single-patch update to 4.9\. Fixes Firefox-specific problem where the
## 4.1.0 (2014-04-22)
* _Slightly incompatible_: The [`"cursorActivity"`](http://codemirror.net/doc/manual.html#event_cursorActivity) event now fires after all other events for the operation (and only for handlers that were actually registered at the time the activity happened).
* _Slightly incompatible_: The [`"cursorActivity"`](http://codemirror.net/doc/manual.html#event_cursorActivity) event now fires after all other events for the operation (and only for handlers that were actually registered at the timeFlag the activity happened).
* New command: [`insertSoftTab`](http://codemirror.net/doc/manual.html#command_insertSoftTab).
* New mode: [Django](http://codemirror.net/mode/django/index.html).
* Improved modes: [Verilog](http://codemirror.net/mode/verilog/index.html) (rewritten), [Jinja2](http://codemirror.net/mode/jinja2/index.html), [Haxe](http://codemirror.net/mode/haxe/index.html), [PHP](http://codemirror.net/mode/php/index.html) (string interpolation highlighted), [JavaScript](http://codemirror.net/mode/javascript/index.html) (indentation of trailing else, template strings), [LiveScript](http://codemirror.net/mode/livescript/index.html) (multi-line strings).

View File

@@ -12,12 +12,16 @@ import com.bumptech.glide.request.transition.Transition;
import com.flurry.android.FlurryAgent;
import com.nickandjerry.dynamiclayoutinflator.lib.ImageLoader;
import com.nickandjerry.dynamiclayoutinflator.lib.util.Drawables;
import com.raizlabs.android.dbflow.config.DatabaseConfig;
import com.raizlabs.android.dbflow.config.FlowConfig;
import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.runtime.DirectModelNotifier;
import com.squareup.leakcanary.LeakCanary;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.autojs.key.GlobalKeyObserver;
import com.stardust.scriptdroid.autojs.record.GlobalRecorder;
import com.stardust.scriptdroid.network.GlideApp;
import com.stardust.scriptdroid.storage.database.TimedTaskDatabase;
import com.stardust.scriptdroid.timing.TimedTaskScheduler;
import com.stardust.scriptdroid.tool.CrashHandler;
import com.stardust.scriptdroid.ui.error.ErrorReportActivity;
@@ -68,7 +72,11 @@ public class App extends MultiDexApplication {
}
private void init() {
FlowManager.init(this);
FlowManager.init(FlowConfig.builder(this)
.addDatabaseConfig(DatabaseConfig.builder(TimedTaskDatabase.class)
.modelNotifier(DirectModelNotifier.get())
.build())
.build());
ThemeColorManager.setDefaultThemeColor(new ThemeColor(getResources().getColor(R.color.colorPrimary), getResources().getColor(R.color.colorPrimaryDark), getResources().getColor(R.color.colorAccent)));
ThemeColorManager.init(this);
AutoJs.initInstance(this);

View File

@@ -10,7 +10,7 @@ import com.stardust.autojs.script.ScriptSource;
import com.stardust.autojs.script.SequenceScriptSource;
import com.stardust.autojs.script.StringScriptSource;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.model.script.PathChecker;
import java.io.File;

View File

@@ -11,7 +11,7 @@ import android.view.MenuItem;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.ScriptIntents;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.ui.BaseActivity;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListView;
import com.twofortyfouram.locale.sdk.client.ui.activity.AbstractAppCompatPluginActivity;

View File

@@ -9,7 +9,7 @@ import android.view.MenuItem;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.ui.BaseActivity;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListView;

View File

@@ -16,7 +16,7 @@ import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.external.ScriptIntents;
import com.stardust.scriptdroid.external.shortcut.Shortcut;
import com.stardust.scriptdroid.external.shortcut.ShortcutActivity;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.ui.edit.EditActivity;
import org.mozilla.javascript.RhinoException;

View File

@@ -12,7 +12,7 @@ import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.model.script.Scripts;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import java.util.HashMap;

View File

@@ -0,0 +1,34 @@
package com.stardust.scriptdroid.storage.database;
import com.raizlabs.android.dbflow.structure.BaseModel;
/**
* Created by Stardust on 2017/11/28.
*/
public class ModelChange<M> {
private final M mData;
private final BaseModel.Action mAction;
public ModelChange(M data, BaseModel.Action action) {
mData = data;
mAction = action;
}
public M getData() {
return mData;
}
public BaseModel.Action getAction() {
return mAction;
}
@Override
public String toString() {
return "ModelChange{" +
"mData=" + mData +
", mAction=" + mAction +
'}';
}
}

View File

@@ -1,4 +1,4 @@
package com.stardust.scriptdroid.timing;
package com.stardust.scriptdroid.storage.database;
import com.raizlabs.android.dbflow.annotation.Database;

View File

@@ -1,4 +1,4 @@
package com.stardust.scriptdroid.io;
package com.stardust.scriptdroid.storage.file;
import android.content.Context;
import android.content.res.AssetManager;

View File

@@ -1,4 +1,4 @@
package com.stardust.scriptdroid.io;
package com.stardust.scriptdroid.storage.file;
import android.os.Environment;

View File

@@ -1,9 +1,8 @@
package com.stardust.scriptdroid.io;
package com.stardust.scriptdroid.storage.file;
import android.content.Context;
import com.stardust.pio.PFiles;
import com.stardust.scriptdroid.model.script.ScriptFile;
import java.io.File;
import java.io.IOException;

View File

@@ -5,6 +5,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.external.ScriptIntents;
/**

View File

@@ -1,20 +1,19 @@
package com.stardust.scriptdroid.timing;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.text.format.Time;
import com.raizlabs.android.dbflow.annotation.Column;
import com.raizlabs.android.dbflow.annotation.PrimaryKey;
import com.raizlabs.android.dbflow.annotation.Table;
import com.stardust.autojs.execution.ExecutionConfig;
import com.stardust.scriptdroid.external.ScriptIntents;
import com.stardust.scriptdroid.storage.database.TimedTaskDatabase;
import org.joda.time.Instant;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
@@ -33,39 +32,40 @@ public class TimedTask {
public final static int FLAG_FRIDAY = 0x20;
public final static int FLAG_SATURDAY = 0x40;
private static final int FLAG_EVERYDAY = 0x7F;
private static final int REQUEST_CODE = 2000;
@PrimaryKey(autoincrement = true)
@PrimaryKey(autoincrement = true, quickCheckAutoIncrement = true)
@Column(name = "id")
int mId;
int mId = -1;
@Column(name = "days_of_week")
int mDaysOfWeek;
@Column(name = "time")
long mTimeFlag;
@Column(name = "scheduled")
boolean mScheduled;
@Column(name = "delay")
private long mDelay = 0;
long mDelay = 0;
@Column(name = "interval")
private long mInterval = 0;
long mInterval = 0;
@Column(name = "loop_times")
private int mLoopTimes = 1;
int mLoopTimes = 1;
@Column(name = "millis")
private long mMillis;
long mMillis;
@Column(name = "script_path")
private String mScriptPath;
String mScriptPath;
public TimedTask() {
}
public TimedTask(long millis, int daysOfWeek, String scriptPath, ExecutionConfig config) {
public TimedTask(long millis, int timeFlag, String scriptPath, ExecutionConfig config) {
mMillis = millis;
mDaysOfWeek = daysOfWeek;
mTimeFlag = timeFlag;
mScriptPath = scriptPath;
mDelay = config.delay;
mLoopTimes = config.loopTimes;
@@ -73,7 +73,7 @@ public class TimedTask {
}
public boolean isDisposable() {
return mDaysOfWeek == FLAG_DISPOSABLE;
return mTimeFlag == FLAG_DISPOSABLE;
}
public boolean isScheduled() {
@@ -97,10 +97,67 @@ public class TimedTask {
return nextTimeMillis;
}
public long getMillis() {
return mMillis;
}
public int getId() {
return mId;
}
public String getScriptPath() {
return mScriptPath;
}
public void setId(int id) {
mId = id;
}
public long getTimeFlag() {
return mTimeFlag;
}
public void setTimeFlag(long time) {
mTimeFlag = time;
}
public long getDelay() {
return mDelay;
}
public void setDelay(long delay) {
mDelay = delay;
}
public long getInterval() {
return mInterval;
}
public void setInterval(long interval) {
mInterval = interval;
}
public int getLoopTimes() {
return mLoopTimes;
}
public void setLoopTimes(int loopTimes) {
mLoopTimes = loopTimes;
}
public void setMillis(long millis) {
mMillis = millis;
}
public void setScriptPath(String scriptPath) {
mScriptPath = scriptPath;
}
public boolean isDaily() {
return mTimeFlag == FLAG_EVERYDAY;
}
public Intent createIntent() {
return new Intent(TaskReceiver.ACTION_TASK)
.putExtra(TaskReceiver.EXTRA_TASK_ID, mId)
@@ -110,12 +167,47 @@ public class TimedTask {
.putExtra(ScriptIntents.EXTRA_KEY_LOOP_INTERVAL, mInterval);
}
public PendingIntent createPendingIntent(Context context) {
return PendingIntent.getBroadcast(context, REQUEST_CODE + 1 + getId(),
createIntent(), PendingIntent.FLAG_UPDATE_CURRENT);
}
@Override
public String toString() {
return "TimedTask{" +
"mId=" + mId +
", mTimeFlag=" + mTimeFlag +
", mScheduled=" + mScheduled +
", mDelay=" + mDelay +
", mInterval=" + mInterval +
", mLoopTimes=" + mLoopTimes +
", mMillis=" + mMillis +
", mScriptPath='" + mScriptPath + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TimedTask timedTask = (TimedTask) o;
return mId == timedTask.mId;
}
@Override
public int hashCode() {
return mId;
}
public static TimedTask dailyTask(LocalTime time, String scriptPath, ExecutionConfig config) {
return new TimedTask(time.getMillisOfDay(), FLAG_EVERYDAY, scriptPath, config);
}
public static TimedTask disposableTask(long millis, String scriptPath, ExecutionConfig config) {
return new TimedTask(millis, FLAG_EVERYDAY, scriptPath, config);
public static TimedTask disposableTask(LocalDateTime dateTime, String scriptPath, ExecutionConfig config) {
return new TimedTask(dateTime.toDateTime().getMillis(), FLAG_DISPOSABLE, scriptPath, config);
}
}

View File

@@ -2,17 +2,26 @@ package com.stardust.scriptdroid.timing;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.runtime.DirectModelNotifier;
import com.raizlabs.android.dbflow.rx2.language.RXSQLite;
import com.raizlabs.android.dbflow.sql.language.SQLite;
import com.raizlabs.android.dbflow.structure.BaseModel;
import com.raizlabs.android.dbflow.structure.ModelAdapter;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.storage.database.ModelChange;
import com.stardust.scriptdroid.storage.database.TimedTaskDatabase;
import java.util.List;
import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject;
/**
* Created by Stardust on 2017/11/27.
@@ -20,31 +29,48 @@ import io.reactivex.schedulers.Schedulers;
public class TimedTaskManager {
private static TimedTaskManager sInstance;
private ModelAdapter<TimedTask> mTimedTaskModelAdapter;
private Context mContext;
private PublishSubject<ModelChange<TimedTask>> mTimedTaskChanges = PublishSubject.create();
public static TimedTaskManager getInstance() {
if (sInstance == null) {
sInstance = new TimedTaskManager();
sInstance = new TimedTaskManager(App.getApp());
}
return sInstance;
}
public TimedTaskManager() {
public TimedTaskManager(Context context) {
mContext = context;
mTimedTaskModelAdapter = FlowManager.getModelAdapter(TimedTask.class);
}
DirectModelNotifier.get().registerForModelChanges(TimedTask.class, new DirectModelNotifier.ModelChangedListener<TimedTask>() {
@Override
public void onModelChanged(@NonNull TimedTask model, @NonNull BaseModel.Action action) {
mTimedTaskChanges.onNext(new ModelChange<>(model, action));
}
@Override
public void onTableChanged(@Nullable Class<?> tableChanged, @NonNull BaseModel.Action action) {
public void notifyTaskFinished(int id) {
getTaskById(id).subscribe(timedTask -> {
if (timedTask.isDisposable()) {
removeTask(id).subscribe();
} else {
timedTask.setScheduled(false);
mTimedTaskModelAdapter.update(timedTask);
}
});
}
public void notifyTaskFinished(int id) {
TimedTask task = getTimedTask(id);
if (task == null)
return;
if (task.isDisposable()) {
mTimedTaskModelAdapter.delete(task);
} else {
task.setScheduled(false);
mTimedTaskModelAdapter.update(task);
}
}
private Flowable<TimedTask> getTaskById(int id) {
return RXSQLite.rx(SQLite.select()
.from(TimedTask.class)
@@ -61,6 +87,16 @@ public class TimedTaskManager {
}
public void cancelTask(TimedTask timedTask) {
TimedTaskScheduler.cancel(mContext, timedTask);
mTimedTaskModelAdapter.delete(timedTask);
}
public void addTask(TimedTask timedTask) {
mTimedTaskModelAdapter.insert(timedTask);
TimedTaskScheduler.scheduleTaskIfNeeded(mContext, timedTask);
}
public Flowable<TimedTask> getAllTasks() {
return RXSQLite.rx(SQLite.select().from(TimedTask.class))
@@ -69,10 +105,31 @@ public class TimedTaskManager {
}
public Observable<ModelChange<TimedTask>> getTimeTaskChanges() {
return mTimedTaskChanges;
}
public void notifyTaskScheduled(TimedTask timedTask) {
timedTask.setScheduled(true);
mTimedTaskModelAdapter.update(timedTask);
}
public List<TimedTask> getAllTasksAsList() {
return SQLite.select().from(TimedTask.class)
.queryList();
}
public TimedTask getTimedTask(int taskId) {
return SQLite.select()
.from(TimedTask.class)
.where(TimedTask_Table.id.is(taskId))
.querySingle();
}
public void updateTask(TimedTask task) {
mTimedTaskModelAdapter.update(task);
TimedTaskScheduler.cancel(mContext, task);
TimedTaskScheduler.scheduleTaskIfNeeded(mContext, task);
}
}

View File

@@ -61,8 +61,7 @@ public class TimedTaskScheduler extends BroadcastReceiver {
return;
}
// FIXME: 2017/11/28 requestCode may > 65535
PendingIntent op = PendingIntent.getBroadcast(context, REQUEST_CODE + 1 + timedTask.getId(),
timedTask.createIntent(), PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent op = timedTask.createPendingIntent(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, millis, op);
} else {
@@ -76,4 +75,9 @@ public class TimedTaskScheduler extends BroadcastReceiver {
INTERVAL, PendingIntent.getBroadcast(context, REQUEST_CODE,
new Intent(TimedTaskScheduler.ACTION_CHECK_TASK), PendingIntent.FLAG_UPDATE_CURRENT));
}
public static void cancel(Context context, TimedTask timedTask) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(timedTask.createPendingIntent(context));
}
}

View File

@@ -1,23 +1,17 @@
package com.stardust.scriptdroid.ui.build;
import android.annotation.SuppressLint;
import android.app.ListActivity;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.autojs.apkbuilder.ApkBuilder;
import com.stardust.pio.PFiles;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.build.AutoJsApkBuilder;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.ui.BaseActivity;
import com.stardust.scriptdroid.ui.filechooser.FileChooserDialogBuilder;
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
import com.stardust.util.IntentUtil;
import org.androidannotations.annotations.AfterViews;
@@ -26,10 +20,7 @@ import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ViewById;
import java.io.File;
import java.io.FileOutputStream;
import java.util.concurrent.Callable;
import butterknife.OnClick;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;

View File

@@ -21,14 +21,16 @@ import com.stardust.pio.PFiles;
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.external.ScriptIntents;
import com.stardust.scriptdroid.storage.file.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.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.network.download.DownloadManager;
import com.stardust.scriptdroid.ui.filechooser.FileChooserDialogBuilder;
import com.stardust.scriptdroid.ui.shortcut.ShortcutCreateActivity;
import com.stardust.scriptdroid.ui.timing.TimedTaskSettingActivity_;
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
import org.reactivestreams.Publisher;
@@ -40,8 +42,6 @@ import java.io.InputStream;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject;
@@ -307,7 +307,9 @@ public class ScriptOperations {
}
public void timedTask(ScriptFile scriptFile) {
TimedTaskSettingActivity_.intent(mContext)
.extra(ScriptIntents.EXTRA_KEY_PATH, scriptFile.getPath())
.start();
}

View File

@@ -7,7 +7,7 @@ import android.support.annotation.StringRes;
import com.stardust.pio.PFile;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
import java.io.File;

View File

@@ -9,7 +9,6 @@ import android.widget.ImageView;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.google.gson.Gson;
import com.stardust.app.DialogUtils;
import com.stardust.app.OperationDialogBuilder;
import com.stardust.autojs.core.record.Recorder;
@@ -21,10 +20,8 @@ import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.accessibility.AccessibilityService;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.autojs.record.GlobalRecorder;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
import com.stardust.scriptdroid.tool.GsonUtils;
import com.stardust.scriptdroid.ui.floating.layoutinspector.LayoutBoundsFloatyWindow;
import com.stardust.scriptdroid.ui.floating.layoutinspector.LayoutHierarchyFloatyWindow;
import com.stardust.scriptdroid.ui.main.MainActivity_;

View File

@@ -29,7 +29,7 @@ import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.ui.common.NotAskAgainDialog;
import com.stardust.scriptdroid.ui.doc.OnlineDocsFragment_;
import com.stardust.scriptdroid.ui.floating.FloatyWindowManger;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.ui.main.community.CommunityFragment_;
import com.stardust.scriptdroid.ui.log.LogActivity_;
import com.stardust.scriptdroid.ui.main.sample.SampleListFragment_;

View File

@@ -9,7 +9,7 @@ import android.webkit.ValueCallback;
import android.webkit.WebView;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.model.script.Scripts;
import com.stardust.scriptdroid.network.download.DownloadManager;
import com.stardust.scriptdroid.ui.common.OptionListView;

View File

@@ -6,12 +6,8 @@ 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.storage.file.SampleFileProvider;
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;
@@ -23,8 +19,6 @@ 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.
*/

View File

@@ -15,8 +15,7 @@ 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.storage.file.SampleFileProvider;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.model.script.Scripts;
import com.stardust.scriptdroid.ui.common.ScriptOperations;

View File

@@ -4,12 +4,10 @@ import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.view.View;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.model.script.Scripts;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.tool.SimpleObserver;
import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.scriptdroid.ui.main.FloatingActionMenu;

View File

@@ -8,7 +8,6 @@ import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -22,7 +21,7 @@ import com.stardust.pio.PFiles;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.model.script.Scripts;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.ui.common.ScriptLoopDialog;
import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.scriptdroid.ui.floating.EditorFloaty;

View File

@@ -0,0 +1,119 @@
package com.stardust.scriptdroid.ui.main.task;
import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.engine.ScriptEngineFactory;
import com.stardust.autojs.script.AutoFileSource;
import com.stardust.autojs.script.JavaScriptSource;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.pio.PFile;
import com.stardust.pio.PFiles;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.timing.TimedTask;
import com.stardust.scriptdroid.timing.TimedTaskManager;
import org.joda.time.format.DateTimeFormat;
/**
* Created by Stardust on 2017/11/28.
*/
public abstract class Task {
public abstract String getName();
public abstract String getDesc();
public abstract void cancel();
public abstract String getEngineName();
public static class PendingTask extends Task {
private TimedTask mTimedTask;
public PendingTask(TimedTask timedTask) {
mTimedTask = timedTask;
}
public TimedTask getTimedTask() {
return mTimedTask;
}
@Override
public String getName() {
return PFiles.getSimplifiedPath(mTimedTask.getScriptPath());
}
@Override
public String getDesc() {
long nextTime = mTimedTask.getNextTime();
return App.getApp().getString(R.string.text_next_run_time) + ": " +
DateTimeFormat.shortDateTime().print(nextTime);
}
@Override
public void cancel() {
TimedTaskManager.getInstance().cancelTask(mTimedTask);
}
@Override
public String getEngineName() {
if (mTimedTask.getScriptPath().endsWith(".js")) {
return JavaScriptSource.ENGINE;
} else {
return AutoFileSource.ENGINE;
}
}
public void setTimedTask(TimedTask timedTask) {
mTimedTask = timedTask;
}
}
public static class RunningTask extends Task {
private final ScriptEngine mScriptEngine;
public RunningTask(ScriptEngine scriptEngine) {
mScriptEngine = scriptEngine;
}
public ScriptEngine getScriptEngine() {
return mScriptEngine;
}
@Override
public String getName() {
ScriptSource source = (ScriptSource) mScriptEngine.getTag(ScriptEngine.TAG_SOURCE);
if (source == null) {
return null;
}
return source.getName();
}
@Override
public String getDesc() {
ScriptSource source = (ScriptSource) mScriptEngine.getTag(ScriptEngine.TAG_SOURCE);
if (source == null) {
return null;
}
return source.toString();
}
@Override
public void cancel() {
mScriptEngine.forceStop();
}
@Override
public String getEngineName() {
ScriptSource source = (ScriptSource) mScriptEngine.getTag(ScriptEngine.TAG_SOURCE);
if (source == null) {
return null;
}
return source.getEngineName();
}
}
}

View File

@@ -0,0 +1,131 @@
package com.stardust.scriptdroid.ui.main.task;
import android.content.Context;
import com.bignerdranch.expandablerecyclerview.model.Parent;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.timing.TimedTask;
import com.stardust.scriptdroid.timing.TimedTaskManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Created by Stardust on 2017/11/28.
*/
public abstract class TaskGroup implements Parent<Task> {
protected List<Task> mTasks = new ArrayList<>();
private String mTitle;
protected TaskGroup(String title) {
mTitle = title;
}
@Override
public List<Task> getChildList() {
return mTasks;
}
@Override
public boolean isInitiallyExpanded() {
return true;
}
public String getTitle() {
return mTitle;
}
public abstract void refresh();
public static class PendingTaskGroup extends TaskGroup {
public PendingTaskGroup(Context context) {
super(context.getString(R.string.text_timed_task));
refresh();
}
@Override
public void refresh() {
List<TimedTask> timedTasks = TimedTaskManager.getInstance().getAllTasksAsList();
mTasks.clear();
for (TimedTask timedTask : timedTasks) {
mTasks.add(new Task.PendingTask(timedTask));
}
}
public int addTask(TimedTask timedTask) {
int pos = mTasks.size();
mTasks.add(new Task.PendingTask(timedTask));
return pos;
}
public int removeTask(TimedTask data) {
int i = indexOf(data);
if (i >= 0)
mTasks.remove(i);
return i;
}
private int indexOf(TimedTask data) {
for (int i = 0; i < mTasks.size(); i++) {
if (((Task.PendingTask) mTasks.get(i)).getTimedTask().equals(data)) {
return i;
}
}
return -1;
}
public int updateTask(TimedTask task) {
int i = indexOf(task);
if (i >= 0)
((Task.PendingTask) mTasks.get(i)).setTimedTask(task);
return i;
}
}
public static class RunningTaskGroup extends TaskGroup {
public RunningTaskGroup(Context context) {
super(context.getString(R.string.text_running_task));
refresh();
}
@Override
public void refresh() {
Set<ScriptEngine> scriptEngines = AutoJs.getInstance().getScriptEngineService().getEngines();
mTasks.clear();
for (ScriptEngine engine : scriptEngines) {
mTasks.add(new Task.RunningTask(engine));
}
}
public int addTask(ScriptEngine engine) {
int pos = mTasks.size();
mTasks.add(new Task.RunningTask(engine));
return pos;
}
public int removeTask(ScriptEngine engine) {
int i = indexOf(engine);
if (i >= 0) {
mTasks.remove(i);
}
return i;
}
public int indexOf(ScriptEngine engine) {
for (int i = 0; i < mTasks.size(); i++) {
if (((Task.RunningTask) mTasks.get(i)).getScriptEngine().equals(engine)) {
return i;
}
}
return -1;
}
}
}

View File

@@ -2,16 +2,22 @@ package com.stardust.scriptdroid.ui.main.task;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.ThemeColorRecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.workground.WrapContentLinearLayoutManager;
import com.bignerdranch.expandablerecyclerview.ChildViewHolder;
import com.bignerdranch.expandablerecyclerview.ExpandableRecyclerAdapter;
import com.bignerdranch.expandablerecyclerview.ParentViewHolder;
import com.raizlabs.android.dbflow.structure.BaseModel;
import com.stardust.autojs.ScriptEngineService;
import com.stardust.autojs.engine.ScriptEngineManager;
import com.stardust.autojs.execution.ScriptExecution;
@@ -19,9 +25,13 @@ import com.stardust.autojs.execution.ScriptExecutionListener;
import com.stardust.autojs.execution.SimpleScriptExecutionListener;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.script.AutoFileSource;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.storage.database.ModelChange;
import com.stardust.scriptdroid.timing.TaskReceiver;
import com.stardust.scriptdroid.timing.TimedTask;
import com.stardust.scriptdroid.timing.TimedTaskManager;
import com.stardust.scriptdroid.ui.timing.TimedTaskSettingActivity_;
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
import java.util.ArrayList;
@@ -30,6 +40,8 @@ import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
/**
* Created by Stardust on 2017/3/24.
@@ -38,28 +50,23 @@ import butterknife.OnClick;
public class TaskListRecyclerView extends ThemeColorRecyclerView implements ScriptEngineManager.EngineLifecycleCallback {
private final OnClickListener mOnItemClickListenerProxy = new OnClickListener() {
@Override
public void onClick(View v) {
private static final String LOG_TAG = "TaskListRecyclerView";
}
};
private final List<ScriptEngine> mScriptEngines = new ArrayList<>();
private final List<TaskGroup> mTaskGroups = new ArrayList<>();
private TaskGroup.RunningTaskGroup mRunningTaskGroup;
private TaskGroup.PendingTaskGroup mPendingTaskGroup;
private Adapter mAdapter;
private Disposable mTimedTaskChangeDisposable;
private final ScriptEngineService mScriptEngineService = AutoJs.getInstance().getScriptEngineService();
private ScriptExecutionListener mScriptExecutionListener = new SimpleScriptExecutionListener() {
@Override
public void onStart(final ScriptExecution execution) {
post(new Runnable() {
@Override
public void run() {
int position = mScriptEngines.indexOf(execution.getEngine());
if (position >= 0) {
mAdapter.notifyItemChanged(position);
} else {
updateEngineList();
}
post(() -> {
int position = mRunningTaskGroup.indexOf(execution.getEngine());
if (position >= 0) {
mAdapter.notifyChildChanged(0, position);
} else {
refresh();
}
});
@@ -89,14 +96,21 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Scri
.marginResId(R.dimen.script_and_folder_list_divider_left_margin, R.dimen.script_and_folder_list_divider_right_margin)
.showLastDivider()
.build());
mAdapter = new Adapter();
mRunningTaskGroup = new TaskGroup.RunningTaskGroup(getContext());
mTaskGroups.add(mRunningTaskGroup);
mPendingTaskGroup = new TaskGroup.PendingTaskGroup(getContext());
mTaskGroups.add(mPendingTaskGroup);
mAdapter = new Adapter(mTaskGroups);
setAdapter(mAdapter);
}
public void updateEngineList() {
mScriptEngines.clear();
mScriptEngines.addAll(mScriptEngineService.getEngines());
mAdapter.notifyDataSetChanged();
public void refresh() {
for (TaskGroup group : mTaskGroups) {
group.refresh();
}
mAdapter.notifyParentChanged(0);
mAdapter.notifyParentChanged(1);
//notifyDataSetChanged not working...
}
@Override
@@ -104,13 +118,16 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Scri
super.onAttachedToWindow();
mScriptEngineService.registerEngineLifecycleCallback(this);
AutoJs.getInstance().getScriptEngineService().registerGlobalScriptExecutionListener(mScriptExecutionListener);
mTimedTaskChangeDisposable = TimedTaskManager.getInstance().getTimeTaskChanges()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onTimedTaskChange);
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
if (visibility == VISIBLE) {
updateEngineList();
refresh();
}
}
@@ -119,63 +136,84 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Scri
super.onDetachedFromWindow();
mScriptEngineService.unregisterEngineLifecycleCallback(this);
AutoJs.getInstance().getScriptEngineService().unregisterGlobalScriptExecutionListener(mScriptExecutionListener);
mTimedTaskChangeDisposable.dispose();
}
private void onScriptANR(final ScriptEngine engine) {
// TODO: 2017/7/19 强制停止aq1sws2
void onTimedTaskChange(ModelChange<TimedTask> taskChange) {
if (taskChange.getAction() == BaseModel.Action.INSERT) {
mAdapter.notifyChildInserted(1, mPendingTaskGroup.addTask(taskChange.getData()));
} else if (taskChange.getAction() == BaseModel.Action.DELETE) {
final int i = mPendingTaskGroup.removeTask(taskChange.getData());
// FIXME: 2017/11/28 task id is always 0
if (i >= 0) {
mAdapter.notifyChildRemoved(1, i);
} else {
Log.w(LOG_TAG, "data inconsistent on change: " + taskChange);
refresh();
}
} else if (taskChange.getAction() == BaseModel.Action.UPDATE) {
final int i = mPendingTaskGroup.updateTask(taskChange.getData());
if (i >= 0) {
mAdapter.notifyChildChanged(1, i);
} else {
Log.w(LOG_TAG, "data inconsistent on change: " + taskChange);
refresh();
}
}
}
@Override
public void onEngineCreate(final ScriptEngine engine) {
synchronized (mScriptEngines) {
post(new Runnable() {
@Override
public void run() {
mScriptEngines.add(engine);
getAdapter().notifyItemInserted(mScriptEngines.size() - 1);
}
});
}
post(() ->
mAdapter.notifyChildInserted(0, mRunningTaskGroup.addTask(engine))
);
}
@Override
public void onEngineRemove(final ScriptEngine engine) {
post(new Runnable() {
@Override
public void run() {
final int i = mScriptEngines.indexOf(engine);
if (i >= 0) {
mScriptEngines.remove(i);
mAdapter.notifyItemRemoved(i);
} else {
updateEngineList();
}
post(() -> {
final int i = mRunningTaskGroup.removeTask(engine);
if (i >= 0) {
mAdapter.notifyChildRemoved(0, i);
} else {
refresh();
}
});
}
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
private class Adapter extends ExpandableRecyclerAdapter<TaskGroup, Task, TaskGroupViewHolder, TaskViewHolder> {
public Adapter(@NonNull List<TaskGroup> parentList) {
super(parentList);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.task_list_recycler_view_item, parent, false));
public TaskGroupViewHolder onCreateParentViewHolder(@NonNull ViewGroup parentViewGroup, int viewType) {
return new TaskGroupViewHolder(LayoutInflater.from(parentViewGroup.getContext())
.inflate(R.layout.dialog_code_generate_option_group, parentViewGroup, false));
}
@NonNull
@Override
public TaskViewHolder onCreateChildViewHolder(@NonNull ViewGroup parent, int viewType) {
return new TaskViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.task_list_recycler_view_item, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ScriptEngine engine = mScriptEngines.get(position);
ScriptSource source = (ScriptSource) mScriptEngines.get(position).getTag(ScriptEngine.TAG_SOURCE);
holder.bind(source, engine);
public void onBindParentViewHolder(@NonNull TaskGroupViewHolder viewHolder, int parentPosition, @NonNull TaskGroup taskGroup) {
viewHolder.title.setText(taskGroup.getTitle());
}
@Override
public int getItemCount() {
return mScriptEngines.size();
public void onBindChildViewHolder(@NonNull TaskViewHolder viewHolder, int parentPosition, int childPosition, @NonNull Task task) {
viewHolder.bind(task);
}
}
class ViewHolder extends RecyclerView.ViewHolder {
class TaskViewHolder extends ChildViewHolder<Task> {
@BindView(R.id.first_char)
TextView mFirstChar;
@@ -184,24 +222,21 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Scri
@BindView(R.id.desc)
TextView mDesc;
private ScriptEngine mScriptEngine;
private Task mTask;
private GradientDrawable mFirstCharBackground;
ViewHolder(View itemView) {
TaskViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(mOnItemClickListenerProxy);
itemView.setOnClickListener(this::onItemClick);
ButterKnife.bind(this, itemView);
mFirstCharBackground = (GradientDrawable) mFirstChar.getBackground();
}
public void bind(ScriptSource source, ScriptEngine engine) {
mScriptEngine = engine;
if (source == null)
return;
mName.setText(source.getName());
mDesc.setText(source.toString());
//ignore android studio warning: use equals to compare string
if (source.getEngineName() == AutoFileSource.ENGINE) {
public void bind(Task task) {
mTask = task;
mName.setText(task.getName());
mDesc.setText(task.getDesc());
if (AutoFileSource.ENGINE.equals(mTask.getEngineName())) {
mFirstChar.setText("R");
mFirstCharBackground.setColor(getResources().getColor(R.color.color_r));
} else {
@@ -210,12 +245,45 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Scri
}
}
@OnClick(R.id.stop)
void stop() {
if (mScriptEngine != null) {
mScriptEngine.forceStop();
if (mTask != null) {
mTask.cancel();
}
}
void onItemClick(View view) {
if (mTask instanceof Task.PendingTask) {
TimedTaskSettingActivity_.intent(getContext())
.extra(TaskReceiver.EXTRA_TASK_ID, ((Task.PendingTask) mTask).getTimedTask().getId())
.start();
}
}
}
private class TaskGroupViewHolder extends ParentViewHolder<TaskGroup, Task> {
TextView title;
ImageView icon;
TaskGroupViewHolder(@NonNull View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
icon = (ImageView) itemView.findViewById(R.id.icon);
itemView.setOnClickListener(view -> {
if (isExpanded()) {
collapseView();
} else {
expandView();
}
});
}
@Override
public void onExpansionToggled(boolean expanded) {
icon.setRotation(expanded ? -90 : 0);
}
}
}

View File

@@ -3,20 +3,14 @@ package com.stardust.scriptdroid.ui.main.task;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.MenuItem;
import android.view.View;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.stardust.autojs.core.console.ConsoleView;
import com.stardust.autojs.core.console.StardustConsole;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.ui.main.ViewPagerFragment;
import com.stardust.scriptdroid.ui.widget.SimpleAdapterDataObserver;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.ViewById;
@@ -63,7 +57,7 @@ public class TaskManagerFragment extends ViewPagerFragment {
});
mSwipeRefreshLayout.setOnRefreshListener(() -> {
mTaskListRecyclerView.updateEngineList();
mTaskListRecyclerView.refresh();
mTaskListRecyclerView.postDelayed(() -> {
if (mSwipeRefreshLayout != null)
mSwipeRefreshLayout.setRefreshing(false);

View File

@@ -0,0 +1,232 @@
package com.stardust.scriptdroid.ui.timing;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import com.github.aakira.expandablelayout.ExpandableRelativeLayout;
import com.stardust.autojs.execution.ExecutionConfig;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.ScriptIntents;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.timing.TaskReceiver;
import com.stardust.scriptdroid.timing.TimedTask;
import com.stardust.scriptdroid.timing.TimedTaskManager;
import com.stardust.scriptdroid.ui.BaseActivity;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.CheckedChange;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ViewById;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
/**
* Created by Stardust on 2017/11/28.
*/
@EActivity(R.layout.activity_timed_task_setting)
public class TimedTaskSettingActivity extends BaseActivity {
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormat.forPattern("HH:mm");
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormat.forPattern("yy-MM-dd");
@ViewById(R.id.toolbar)
Toolbar mToolbar;
@ViewById(R.id.timing_group)
RadioGroup mTimingGroup;
@ViewById(R.id.disposable_task_radio)
RadioButton mDisposableTaskRadio;
@ViewById(R.id.daily_task_radio)
RadioButton mDailyTaskRadio;
@ViewById(R.id.weekly_task_radio)
RadioButton mWeeklyTaskRadio;
@ViewById(R.id.disposable_task_time)
TextView mDisposableTaskTime;
@ViewById(R.id.disposable_task_date)
TextView mDisposableTaskDate;
@ViewById(R.id.daily_task_time_picker)
TimePicker mDailyTaskTimePicker;
@ViewById(R.id.weekly_task_time_picker)
TimePicker mWWeeklyTaskTimePicker;
private ScriptFile mScriptFile;
private TimedTask mTimedTask;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int taskId = getIntent().getIntExtra(TaskReceiver.EXTRA_TASK_ID, -1);
if (taskId != -1) {
mTimedTask = TimedTaskManager.getInstance().getTimedTask(taskId);
if (mTimedTask != null) {
mScriptFile = new ScriptFile(mTimedTask.getScriptPath());
}
} else {
String path = getIntent().getStringExtra(ScriptIntents.EXTRA_KEY_PATH);
if (TextUtils.isEmpty(path)) {
finish();
}
mScriptFile = new ScriptFile(path);
}
}
@AfterViews
void setupViews() {
setToolbarAsBack(getString(R.string.text_timed_task));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mToolbar.setSubtitle(mScriptFile.getName());
}
setUpTime();
}
private void setUpTime() {
mDisposableTaskDate.setText(DATE_FORMATTER.print(LocalDate.now()));
mDisposableTaskTime.setText(TIME_FORMATTER.print(LocalTime.now()));
if (mTimedTask == null) {
mDailyTaskRadio.setChecked(true);
return;
}
if (mTimedTask.isDisposable()) {
mDisposableTaskRadio.setChecked(true);
mDisposableTaskTime.setText(TIME_FORMATTER.print(mTimedTask.getMillis()));
mDisposableTaskDate.setText(DATE_FORMATTER.print(mTimedTask.getMillis()));
return;
}
if (mTimedTask.isDaily()) {
mDailyTaskRadio.setChecked(true);
LocalTime time = LocalTime.fromMillisOfDay(mTimedTask.getMillis());
mDailyTaskTimePicker.setCurrentHour(time.getHourOfDay());
mDailyTaskTimePicker.setCurrentMinute(time.getMinuteOfHour());
return;
}
// TODO: 2017/11/28 Weekly
}
@CheckedChange({R.id.daily_task_radio, R.id.weekly_task_radio, R.id.disposable_task_radio})
void onCheckedChanged(CompoundButton button) {
ExpandableRelativeLayout relativeLayout = findExpandableLayoutOf(button);
if (button.isChecked()) {
relativeLayout.post(relativeLayout::expand);
} else {
relativeLayout.collapse();
}
}
private ExpandableRelativeLayout findExpandableLayoutOf(CompoundButton button) {
ViewGroup parent = (ViewGroup) button.getParent();
for (int i = 0; i < parent.getChildCount(); i++) {
if (parent.getChildAt(i) == button) {
return ((ExpandableRelativeLayout) parent.getChildAt(i + 1));
}
}
throw new IllegalStateException("findExpandableLayout: button = " + button + ", parent = " + parent + ", childCount = " + parent.getChildCount());
}
@Click(R.id.disposable_task_time_container)
void showDisposableTaskTimePicker() {
LocalTime time = TIME_FORMATTER.parseLocalTime(mDisposableTaskTime.getText().toString());
new TimePickerDialog(this, (view, hourOfDay, minute) -> mDisposableTaskTime.setText(TIME_FORMATTER.print(new LocalTime(hourOfDay, minute))), time.getHourOfDay(), time.getMinuteOfHour(), true)
.show();
}
@Click(R.id.disposable_task_date_container)
void showDisposableTaskDatePicker() {
LocalDate date = DATE_FORMATTER.parseLocalDate(mDisposableTaskDate.getText().toString());
new DatePickerDialog(this, (view, year, month, dayOfMonth) ->
mDisposableTaskDate.setText(DATE_FORMATTER.print(new LocalDate(year, month, dayOfMonth)))
, date.getYear(), date.getMonthOfYear(), date.getDayOfMonth())
.show();
}
TimedTask createTimedTask() {
if (mDisposableTaskRadio.isChecked()) {
return createDisposableTask();
} else if (mDailyTaskRadio.isChecked()) {
return createDailyTask();
} else {
return createWeeklyTask();
}
}
private TimedTask createWeeklyTask() {
// TODO: 2017/11/28 Weekly
return null;
}
private TimedTask createDailyTask() {
LocalTime time = new LocalTime(mDailyTaskTimePicker.getCurrentHour(), mDailyTaskTimePicker.getCurrentMinute());
return TimedTask.dailyTask(time, mScriptFile.getPath(), new ExecutionConfig());
}
private TimedTask createDisposableTask() {
LocalTime time = TIME_FORMATTER.parseLocalTime(mDisposableTaskTime.getText().toString());
LocalDate date = DATE_FORMATTER.parseLocalDate(mDisposableTaskDate.getText().toString());
LocalDateTime dateTime = new LocalDateTime(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth(),
time.getHourOfDay(), time.getMinuteOfHour());
if (dateTime.isBefore(LocalDateTime.now())) {
Toast.makeText(this, R.string.text_disposable_task_time_before_now, Toast.LENGTH_SHORT).show();
return null;
}
return TimedTask.disposableTask(dateTime, mScriptFile.getPath(), ExecutionConfig.getDefault());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_timed_task_setting, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_done) {
createOrUpdateTimedTask();
return true;
}
return super.onOptionsItemSelected(item);
}
private void createOrUpdateTimedTask() {
TimedTask task = createTimedTask();
if (task == null)
return;
if (mTimedTask == null) {
TimedTaskManager.getInstance().addTask(task);
Toast.makeText(this, R.string.text_already_create, Toast.LENGTH_SHORT).show();
} else {
task.setId(mTimedTask.getId());
TimedTaskManager.getInstance().updateTask(task);
}
finish();
}
}

View File

@@ -17,7 +17,7 @@ import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.scriptdroid.BuildConfig;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.network.entity.VersionInfo;
import com.stardust.scriptdroid.io.StorageFileProvider;
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
import com.stardust.scriptdroid.tool.IntentTool;
import com.stardust.util.DownloadTask;
import com.stardust.util.IntentUtil;

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.stardust.theme.widget.ThemeColorToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="12dp"
app:cardBackgroundColor="@android:color/white"
app:cardCornerRadius="2dp"
app:cardElevation="1dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/text_timing"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="?android:textColorSecondary"/>
<RadioGroup
android:id="@+id/timing_group"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton
android:id="@+id/daily_task_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:paddingLeft="16dp"
android:text="@string/text_daily_task"/>
<com.github.aakira.expandablelayout.ExpandableRelativeLayout
android:id="@+id/daily_task_relative_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:ael_expanded="false"
app:ael_interpolator="fastOutSlowIn"
app:ael_orientation="vertical">
<TimePicker
android:id="@+id/daily_task_time_picker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:timePickerMode="spinner"/>
</com.github.aakira.expandablelayout.ExpandableRelativeLayout>
<RadioButton
android:id="@+id/disposable_task_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:paddingLeft="16dp"
android:text="@string/text_disposable_task"/>
<com.github.aakira.expandablelayout.ExpandableRelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="36dp"
app:ael_expanded="false"
app:ael_interpolator="fastOutSlowIn"
app:ael_orientation="vertical">
<LinearLayout
android:id="@+id/disposable_task_time_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="6dp"
android:paddingTop="6dp">
<com.stardust.theme.widget.ThemeColorImageViewCompat
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:gravity="center"
android:src="@drawable/ic_schedule_black_48dp"/>
<TextView
android:id="@+id/disposable_task_time"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginLeft="12dp"
android:gravity="center_vertical"
android:textColor="#202020"
android:textSize="16sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/disposable_task_date_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="@+id/disposable_task_time_container"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="6dp">
<com.stardust.theme.widget.ThemeColorImageViewCompat
android:id="@+id/disposable_task_date_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:gravity="center"
android:src="@drawable/ic_date_range_black_48dp"/>
<TextView
android:id="@+id/disposable_task_date"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginLeft="12dp"
android:gravity="center_vertical"
android:textColor="#202020"
android:textSize="16sp"/>
</LinearLayout>
</com.github.aakira.expandablelayout.ExpandableRelativeLayout>
<RadioButton
android:id="@+id/weekly_task_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:paddingLeft="16dp"
android:text="@string/text_weekly_task"/>
<com.github.aakira.expandablelayout.ExpandableRelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:ael_expanded="false"
app:ael_interpolator="fastOutSlowIn"
app:ael_orientation="vertical">
<TimePicker
android:id="@+id/weekly_task_time_picker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:timePickerMode="spinner"/>
</com.github.aakira.expandablelayout.ExpandableRelativeLayout>
</RadioGroup>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_done"
android:icon="@drawable/ic_done_white_48dp"
android:title="@string/text_done"
app:showAsAction="always"/>
</menu>

View File

@@ -32,7 +32,7 @@ means a work that combines Covered Software with other material, in a separate f
means this document.
1.9. “Licensable”
means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License.
means having the right to grant, to the maximum extent possible, whether at the timeFlag of the initial grant or subsequently, any and all of the rights conveyed by this License.
1.10. “Modifications”
means any of the following:
@@ -127,7 +127,7 @@ If it is impossible for You to comply with any of the terms of this License with
5. Termination
5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received toast of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the toast.
5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first timeFlag You have received toast of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the toast.
5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.

View File

@@ -313,5 +313,13 @@
<string name="key_documentation_source">key_documentation_source</string>
<string name="text_documentation_source">文档源</string>
<string name="text_send">发送</string>
<string name="text_timed_task">定时运行</string>
<string name="text_timed_task">定时任务</string>
<string name="text_running_task">运行中脚本</string>
<string name="text_done">完成</string>
<string name="text_disposable_task">只运行一次</string>
<string name="text_daily_task">每天运行</string>
<string name="text_weekly_task">按星期运行</string>
<string name="text_timing">定时</string>
<string name="text_disposable_task_time_before_now">任务时间小于当前时间</string>
<string name="text_next_run_time">下次运行</string>
</resources>