diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
index 259a89dc..4c2daf66 100644
Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ
diff --git a/app/build.gradle b/app/build.gradle
index 41d8fa47..7c4f2275 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "org.autojs.autojs"
minSdkVersion 17
targetSdkVersion 23
- versionCode 420
- versionName "4.0.3 Alpha"
+ versionCode 421
+ versionName "4.0.3 Alpha2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
ndk {
@@ -24,7 +24,7 @@ android {
}
release {
shrinkResources false
- minifyEnabled false
+ minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -83,10 +83,10 @@ dependencies {
})
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'
// Android supports
- compile 'com.android.support:appcompat-v7:25.4.0'
- compile 'com.android.support:cardview-v7:25.4.0'
- compile 'com.android.support:design:25.4.0'
- compile 'com.android.support:multidex:1.0.2'
+ compile 'com.android.support:appcompat-v7:27.1.1'
+ compile 'com.android.support:cardview-v7:27.1.1'
+ compile 'com.android.support:design:27.1.1'
+ compile 'com.android.support:multidex:1.0.3'
// Personal libraries
compile 'com.github.hyb1996:MutableTheme:0.2.2'
// Material Dialogs
@@ -146,6 +146,10 @@ dependencies {
compile('com.afollestad.material-dialogs:commons:0.9.2.3', {
exclude group: 'com.android.support'
})
+ debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
+ releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
+ // Optional, if you use support library fragments:
+ debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.1'
compile project(':automator')
compile project(':common')
compile project(':autojs')
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ef88f4bd..c0c87487 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -116,6 +116,7 @@
android:theme="@style/IssueReporterTheme"/>
+
diff --git a/app/src/main/java/org/autojs/autojs/App.java b/app/src/main/java/org/autojs/autojs/App.java
index d8f07b60..dabe48ab 100644
--- a/app/src/main/java/org/autojs/autojs/App.java
+++ b/app/src/main/java/org/autojs/autojs/App.java
@@ -1,8 +1,11 @@
package org.autojs.autojs;
+import android.app.Application;
+import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.support.multidex.MultiDex;
import android.support.multidex.MultiDexApplication;
import android.view.View;
import android.widget.ImageView;
@@ -14,6 +17,7 @@ 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.app.GlobalAppContext;
import com.stardust.autojs.core.ui.inflater.ImageLoader;
import com.stardust.autojs.core.ui.inflater.util.Drawables;
@@ -67,6 +71,11 @@ public class App extends MultiDexApplication {
}
+ @Override
+ protected void attachBaseContext(Context base) {
+ super.attachBaseContext(base);
+ }
+
private void setUpDebugEnvironment() {
CrashHandler crashHandler = new CrashHandler(ErrorReportActivity.class);
@@ -77,6 +86,12 @@ public class App extends MultiDexApplication {
crashHandler.setBuglyHandler(Thread.getDefaultUncaughtExceptionHandler());
Thread.setDefaultUncaughtExceptionHandler(crashHandler);
+ if (LeakCanary.isInAnalyzerProcess(this)) {
+ // This process is dedicated to LeakCanary for heap analysis.
+ // You should not init your app in this process.
+ return;
+ }
+ LeakCanary.install(this);
}
private void init() {
diff --git a/app/src/main/java/org/autojs/autojs/Pref.java b/app/src/main/java/org/autojs/autojs/Pref.java
index e63bc533..90a2c01f 100644
--- a/app/src/main/java/org/autojs/autojs/Pref.java
+++ b/app/src/main/java/org/autojs/autojs/Pref.java
@@ -201,4 +201,8 @@ public class Pref {
getString(R.string.default_value_script_dir_path));
return new File(Environment.getExternalStorageDirectory(), dir).getPath();
}
+
+ public static boolean isForegroundServiceEnabled() {
+ return def().getBoolean(getString(R.string.key_foreground_servie), false);
+ }
}
diff --git a/app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java b/app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java
new file mode 100644
index 00000000..563f2e8b
--- /dev/null
+++ b/app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java
@@ -0,0 +1,58 @@
+package org.autojs.autojs.external.foreground;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.IBinder;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
+import android.support.v4.app.NotificationCompat;
+
+import org.autojs.autojs.R;
+
+public class ForegroundService extends Service {
+ private static final int NOTIFICATION_ID = 117;
+ private static final String CHANEL_ID = "foreground";
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ startForeground();
+ return START_STICKY;
+ }
+
+ private void startForeground(){
+ startForeground(NOTIFICATION_ID, buildNotification());
+ }
+
+ private Notification buildNotification() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ createNotificationChannel();
+ }
+ return new NotificationCompat.Builder(this, CHANEL_ID)
+ .setContentTitle(getString(R.string.foreground_notification_title))
+ .setContentText(getString(R.string.foreground_notification_text))
+ .setSmallIcon(R.drawable.autojs_material)
+ .build();
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.O)
+ private void createNotificationChannel(){
+ NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ assert manager != null;
+ CharSequence name = getString(R.string.foreground_notification_channel_name);
+ String description = getString(R.string.foreground_notification_channel_name);
+ NotificationChannel channel = new NotificationChannel(CHANEL_ID, name, NotificationManager.IMPORTANCE_HIGH);
+ channel.setDescription(description);
+ manager.createNotificationChannel(channel);
+ }
+}
diff --git a/app/src/main/java/org/autojs/autojs/external/tasker/TaskerScriptEditActivity.java b/app/src/main/java/org/autojs/autojs/external/tasker/TaskerScriptEditActivity.java
index 0b5afb01..4c0de0a1 100644
--- a/app/src/main/java/org/autojs/autojs/external/tasker/TaskerScriptEditActivity.java
+++ b/app/src/main/java/org/autojs/autojs/external/tasker/TaskerScriptEditActivity.java
@@ -63,4 +63,9 @@ public class TaskerScriptEditActivity extends BaseActivity {
TaskerScriptEditActivity.super.finish();
}
+ @Override
+ protected void onDestroy() {
+ mEditorView.destroy();
+ super.onDestroy();
+ }
}
diff --git a/app/src/main/java/org/autojs/autojs/model/autocomplete/AutoCompletion.java b/app/src/main/java/org/autojs/autojs/model/autocomplete/AutoCompletion.java
index 7bbbb675..ca95c75f 100644
--- a/app/src/main/java/org/autojs/autojs/model/autocomplete/AutoCompletion.java
+++ b/app/src/main/java/org/autojs/autojs/model/autocomplete/AutoCompletion.java
@@ -161,4 +161,7 @@ public class AutoCompletion {
}
+ public void shutdown(){
+ mExecutorService.shutdownNow();
+ }
}
diff --git a/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java b/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java
index 535d4bbb..cf18a459 100644
--- a/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java
+++ b/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java
@@ -318,6 +318,7 @@ public class ScriptOperations {
String fileName = DownloadManager.parseFileNameLocally(url);
return new FileChooserDialogBuilder(mContext)
.title(R.string.text_select_save_path)
+ .dir(Pref.getScriptDirPath())
.chooseDir()
.singleChoice()
.map(saveDir -> new File(saveDir, fileName).getPath())
diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.java b/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.java
index d293c100..0ec43fef 100644
--- a/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.java
+++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.java
@@ -180,6 +180,7 @@ EditActivity extends BaseActivity implements OnActivityResultDelegate.DelegateHo
@Override
protected void onDestroy() {
+ mEditorView.destroy();
super.onDestroy();
}
diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java
index 3ba09bdb..3f9b827c 100644
--- a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java
+++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java
@@ -392,7 +392,7 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
Snackbar.make(this, R.string.text_start_running, Snackbar.LENGTH_SHORT).show();
}
ScriptExecution execution = Scripts.runWithBroadcastSender(mFile);
- if(execution == null){
+ if (execution == null) {
return null;
}
mScriptExecutionId = execution.getId();
@@ -671,4 +671,9 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
super.onRestoreInstanceState(superData);
setMenuItemStatus(R.id.run, mScriptExecutionId == ScriptExecution.NO_ID);
}
+
+ public void destroy() {
+ mEditor.destroy();
+ mAutoCompletion.shutdown();
+ }
}
diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditor.java b/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditor.java
index 83b3db16..0c6eeceb 100644
--- a/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditor.java
+++ b/app/src/main/java/org/autojs/autojs/ui/edit/editor/CodeEditor.java
@@ -373,6 +373,11 @@ public class CodeEditor extends HVScrollView {
mCodeEditText.removeAllBreakpoints();
}
+ public void destroy(){
+ mJavaScriptHighlighter.shutdown();
+ mJsBeautifier.shutdown();
+ }
+
@Override
protected void onDraw(Canvas canvas) {
int codeWidth = getWidth() - getPaddingLeft() - getPaddingRight();
diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/editor/JavaScriptHighlighter.java b/app/src/main/java/org/autojs/autojs/ui/edit/editor/JavaScriptHighlighter.java
index 20752a55..7037a3ff 100644
--- a/app/src/main/java/org/autojs/autojs/ui/edit/editor/JavaScriptHighlighter.java
+++ b/app/src/main/java/org/autojs/autojs/ui/edit/editor/JavaScriptHighlighter.java
@@ -2,10 +2,12 @@ package org.autojs.autojs.ui.edit.editor;
import android.text.Editable;
+import android.text.TextWatcher;
import android.util.TimingLogger;
import com.stardust.autojs.rhino.TokenStream;
import com.stardust.pio.UncheckedIOException;
+
import org.autojs.autojs.ui.edit.theme.Theme;
import org.autojs.autojs.ui.widget.SimpleTextWatcher;
@@ -46,7 +48,7 @@ public class JavaScriptHighlighter implements SimpleTextWatcher.AfterTextChanged
@Override
public String toString() {
- return super.toString() + "{count = " + mCount + ", length = " + mText.length() + "}";
+ return super.toString() + "{count = " + mCount + ", length = " + mText.length() + "}";
}
public int getCharCount() {
@@ -60,16 +62,18 @@ public class JavaScriptHighlighter implements SimpleTextWatcher.AfterTextChanged
private Theme mTheme;
private CodeEditText mCodeEditText;
- private ThreadPoolExecutor mExecutorService = new ThreadPoolExecutor(3, 6,
+ private ThreadPoolExecutor mExecutorService = new ThreadPoolExecutor(3, 6,
2L, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
private AtomicInteger mRunningHighlighterId = new AtomicInteger();
private TimingLogger mLogger = new TimingLogger(CodeEditText.LOG_TAG, "highlight");
+ private final TextWatcher mTextWatcher;
public JavaScriptHighlighter(Theme theme, CodeEditText codeEditText) {
mExecutorService.allowCoreThreadTimeOut(true);
mTheme = theme;
mCodeEditText = codeEditText;
- codeEditText.addTextChangedListener(new SimpleTextWatcher(this));
+ mTextWatcher = new SimpleTextWatcher(this);
+ codeEditText.addTextChangedListener(mTextWatcher);
}
@Override
@@ -112,5 +116,9 @@ public class JavaScriptHighlighter implements SimpleTextWatcher.AfterTextChanged
mCodeEditText.updateHighlightTokens(highlightTokens);
}
+ public void shutdown() {
+ mCodeEditText.removeTextChangedListener(mTextWatcher);
+ mExecutorService.shutdownNow();
+ }
}
diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewRedoUndoer.java b/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewRedoUndoer.java
deleted file mode 100644
index 06144eb0..00000000
--- a/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewRedoUndoer.java
+++ /dev/null
@@ -1,290 +0,0 @@
-package org.autojs.autojs.ui.edit.editor;
-/*
- * Copyright 2016. SHENQINCI(沈钦赐)<946736079@qq.com>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import android.support.annotation.NonNull;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.widget.EditText;
-
-import java.util.Stack;
-
-/**
- * 撤销和恢复撤销
- * Created by 沈钦赐 on 16/6/23.
- */
-public class TextViewRedoUndoer {
- //操作序号(一次编辑可能对应多个操作,如替换文字,就是删除+插入)
- int index;
- //撤销栈
- Stack history = new Stack<>();
- //恢复栈
- Stack historyBack = new Stack<>();
-
- private Editable editable;
- private EditText editText;
- //自动操作标志,防止重复回调,导致无限撤销
- private boolean flag = false;
-
- private int mInitialHistoryStackSize;
- private boolean mEnabled = true;
-
- public TextViewRedoUndoer(@NonNull EditText editText) {
- this.editable = editText.getText();
- this.editText = editText;
- editText.addTextChangedListener(new Watcher());
- }
-
- protected void onEditableChanged(Editable s) {
-
- }
-
- protected void onTextChanged(Editable s) {
- if (history.size() < mInitialHistoryStackSize) {
- mInitialHistoryStackSize = 0;
- }
- }
-
-
- /**
- * 清理记录
- * Clear history.
- */
- public final void clearHistory() {
- history.clear();
- historyBack.clear();
- mInitialHistoryStackSize = 0;
- }
-
- public boolean canUndo() {
- return !history.empty();
- }
-
- /**
- * 撤销
- * Undo.
- */
- public final void undo() {
- if (history.empty()) return;
- //锁定操作
- flag = true;
- Action action = history.pop();
- historyBack.push(action);
- if (action.isAdd) {
- //撤销添加
- editable.delete(action.startCursor, action.startCursor + action.actionTarget.length());
- editText.setSelection(action.startCursor, action.startCursor);
- } else {
- //插销删除
- editable.insert(action.startCursor, action.actionTarget);
- if (action.endCursor == action.startCursor) {
- editText.setSelection(action.startCursor + action.actionTarget.length());
- } else {
- editText.setSelection(action.startCursor, action.endCursor);
- }
- }
- //释放操作
- flag = false;
- //判断是否是下一个动作是否和本动作是同一个操作,直到不同为止
- if (!history.empty() && history.peek().index == action.index) {
- undo();
- }
- }
-
- public boolean canRedo() {
- return !historyBack.empty();
- }
-
- /**
- * 恢复
- * Redo.
- */
- public final void redo() {
- if (historyBack.empty()) return;
- flag = true;
- Action action = historyBack.pop();
- history.push(action);
- if (action.isAdd) {
- //恢复添加
- editable.insert(action.startCursor, action.actionTarget);
- if (action.endCursor == action.startCursor) {
- editText.setSelection(action.startCursor + action.actionTarget.length());
- } else {
- editText.setSelection(action.startCursor, action.endCursor);
- }
- } else {
- //恢复删除
- editable.delete(action.startCursor, action.startCursor + action.actionTarget.length());
- editText.setSelection(action.startCursor, action.startCursor);
- }
- flag = false;
- //判断是否是下一个动作是否和本动作是同一个操作
- if (!historyBack.empty() && historyBack.peek().index == action.index)
- redo();
- }
-
- /**
- * 首次设置文本
- * Set default text.
- */
- public final void setDefaultText(CharSequence text) {
- clearHistory();
- flag = true;
- editable.replace(0, editable.length(), text);
- flag = false;
- }
-
- public boolean isTextChanged() {
- return history.size() != mInitialHistoryStackSize;
- }
-
- public void markTextAsUnchanged() {
- mInitialHistoryStackSize = history.size();
- }
-
- public void setEnabled(boolean enabled) {
- mEnabled = enabled;
- }
-
- public boolean isEnabled() {
- return mEnabled;
- }
-
- private class Watcher implements TextWatcher {
-
- /**
- * Before text changed.
- *
- * @param s the s
- * @param start the start 起始光标
- * @param count the endCursor 选择数量
- * @param after the after 替换增加的文字数
- */
- @Override
- public final void beforeTextChanged(CharSequence s, int start, int count, int after) {
- if (!editText.isEnabled() || !mEnabled) {
- return;
- }
- if (flag) return;
- int end = start + count;
- if (end > start && end <= s.length()) {
- CharSequence charSequence = s.subSequence(start, end);
- //删除了文字
- if (charSequence.length() > 0) {
- Action action = new Action(charSequence, start, false);
- if (count > 1) {
- //如果一次超过一个字符,说名用户选择了,然后替换或者删除操作
- action.setSelectCount(count);
- } else if (count == 1 && count == after) {
- //一个字符替换
- action.setSelectCount(count);
- }
- //还有一种情况:选择一个字符,然后删除(暂时没有考虑这种情况)
-
- history.push(action);
- historyBack.clear();
- action.setIndex(++index);
- }
- }
- }
-
- /**
- * On text changed.
- *
- * @param s the s
- * @param start the start 起始光标
- * @param before the before 选择数量
- * @param count the endCursor 添加的数量
- */
- @Override
- public final void onTextChanged(CharSequence s, int start, int before, int count) {
- if (!editText.isEnabled() || !mEnabled) {
- return;
- }
- if (flag) return;
- int end = start + count;
- if (end > start) {
- CharSequence charSequence = s.subSequence(start, end);
- //添加文字
- if (charSequence.length() > 0) {
- Action action = new Action(charSequence, start, true);
-
- history.push(action);
- historyBack.clear();
- if (before > 0) {
- //文字替换(先删除再增加),删除和增加是同一个操作,所以不需要增加序号
- action.setIndex(index);
- } else {
- action.setIndex(++index);
- }
- }
- }
- }
-
- @Override
- public final void afterTextChanged(Editable s) {
- if (!editText.isEnabled() || !mEnabled) {
- return;
- }
- if (flag) return;
- if (s != editable) {
- editable = s;
- onEditableChanged(s);
- }
- TextViewRedoUndoer.this.onTextChanged(s);
- }
-
- }
-
- private class Action {
- /**
- * 改变字符.
- */
- CharSequence actionTarget;
- /**
- * 光标位置.
- */
- int startCursor;
- int endCursor;
- /**
- * 标志增加操作.
- */
- boolean isAdd;
- /**
- * 操作序号.
- */
- int index;
-
-
- public Action(CharSequence actionTag, int startCursor, boolean add) {
- this.actionTarget = actionTag;
- this.startCursor = startCursor;
- this.endCursor = startCursor;
- this.isAdd = add;
- }
-
- public void setSelectCount(int count) {
- this.endCursor = endCursor + count;
- }
-
- public void setIndex(int index) {
- this.index = index;
- }
- }
-
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewUndoRedo.java b/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewUndoRedo.java
index 01b6a173..c9c54751 100644
--- a/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewUndoRedo.java
+++ b/app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewUndoRedo.java
@@ -9,6 +9,7 @@ import java.util.LinkedList;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
+import android.os.Handler;
import android.text.Editable;
import android.text.Selection;
import android.text.TextWatcher;
@@ -46,6 +47,10 @@ public class TextViewUndoRedo {
private int mInitialHistoryStackSize;
+ private Handler mHandler = new Handler();
+ private int mTextChangeId = 0;
+ private boolean mTextChanging = false;
+
// =================================================================== //
/**
@@ -404,7 +409,6 @@ public class TextViewUndoRedo {
if (mIsUndoOrRedo || !mEnabled) {
return;
}
-
mBeforeChange = s.subSequence(start, start + count);
}
@@ -415,7 +419,10 @@ public class TextViewUndoRedo {
}
mAfterChange = s.subSequence(start, start + count);
+ mTextChangeId++;
mEditHistory.add(new EditItem(start, mBeforeChange, mAfterChange));
+ int textChangeId = mTextChangeId;
+ //TODO 增加连续输入文字当成一次撤销的功能
}
public void afterTextChanged(Editable s) {
diff --git a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java
index 5d7ccae0..65b09364 100644
--- a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java
+++ b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java
@@ -1,5 +1,6 @@
package org.autojs.autojs.ui.main.drawer;
+import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -22,6 +23,7 @@ import com.stardust.notification.NotificationListenerService;
import org.autojs.autojs.Pref;
import org.autojs.autojs.R;
+import org.autojs.autojs.external.foreground.ForegroundService;
import org.autojs.autojs.network.GlideApp;
import org.autojs.autojs.network.UserService;
import org.autojs.autojs.tool.EmptyObservers;
@@ -107,6 +109,8 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
};
private DrawerMenuItem mNotificationPermissionItem = new DrawerMenuItem(R.drawable.ic_ali_notification, R.string.text_notification_permission, 0, this::goToNotificationServiceSettings);
+ private DrawerMenuItem mForegroundServiceItem = new DrawerMenuItem(R.drawable.ic_service_green, R.string.text_foreground_service, R.string.key_foreground_servie, this::toggleForegroundService);
+
private DrawerMenuItem mFloatingWindowItem = new DrawerMenuItem(R.drawable.ic_robot_64, R.string.text_floating_window, 0, this::showOrDismissFloatingWindow);
private DrawerMenuItem mCheckForUpdatesItem = new DrawerMenuItem(R.drawable.ic_check_for_updates, R.string.text_check_for_updates, this::checkForUpdates);
@@ -142,6 +146,10 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
setChecked(mFloatingWindowItem, true);
}
setChecked(mConnectionItem, DevPluginService.getInstance().isConnected());
+ if(Pref.isForegroundServiceEnabled()){
+ GlobalAppContext.get().startService(new Intent(getContext(), ForegroundService.class));
+ setChecked(mForegroundServiceItem, true);
+ }
}
private void initMenuItems() {
@@ -150,6 +158,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
mAccessibilityServiceItem,
mStableModeItem,
mNotificationPermissionItem,
+ mForegroundServiceItem,
new DrawerMenuGroup(R.string.text_script_record),
mFloatingWindowItem,
@@ -165,6 +174,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
}
+ @SuppressLint("CheckResult")
@Click(R.id.avatar)
void loginOrShowUserInfo() {
UserService.getInstance()
@@ -251,6 +261,17 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
}
}
+
+ private void toggleForegroundService(DrawerMenuItemViewHolder holder) {
+ boolean checked = holder.getSwitchCompat().isChecked();
+ if(checked){
+ GlobalAppContext.get().startService(new Intent(getContext(), ForegroundService.class));
+ }else {
+ GlobalAppContext.get().stopService(new Intent(getContext(), ForegroundService.class));
+ }
+ }
+
+
private void inputRemoteHost() {
String host = Pref.getServerAddressOrDefault(WifiTool.getRouterIp(getActivity()));
new MaterialDialog.Builder(getActivity())
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4e89bd90..0bebb257 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -398,4 +398,9 @@
新建项目
js文件
无效项目
+ 前台服务
+ key_foreground_service
+ 前台服务通知
+ Auto.js保持运行中
+ 点击进入主界面
diff --git a/autojs/src/main/java/com/stardust/autojs/execution/RunnableScriptExecution.java b/autojs/src/main/java/com/stardust/autojs/execution/RunnableScriptExecution.java
index 5073803b..ce87eebc 100644
--- a/autojs/src/main/java/com/stardust/autojs/execution/RunnableScriptExecution.java
+++ b/autojs/src/main/java/com/stardust/autojs/execution/RunnableScriptExecution.java
@@ -6,6 +6,7 @@ import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.engine.ScriptEngineManager;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
import com.stardust.autojs.script.ScriptSource;
+import com.stardust.lang.ThreadCompat;
/**
* Created by Stardust on 2017/5/1.
@@ -24,6 +25,7 @@ public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecu
@Override
public void run() {
+ ThreadCompat.currentThread().setName("ScriptThread-" + getId() + "[" + getSource() + "]");
execute();
}
diff --git a/autojs/src/main/java/com/stardust/autojs/rhino/AndroidClassLoader.java b/autojs/src/main/java/com/stardust/autojs/rhino/AndroidClassLoader.java
index 0e9363bc..4538c348 100644
--- a/autojs/src/main/java/com/stardust/autojs/rhino/AndroidClassLoader.java
+++ b/autojs/src/main/java/com/stardust/autojs/rhino/AndroidClassLoader.java
@@ -3,6 +3,7 @@ package com.stardust.autojs.rhino;
import android.util.Log;
import com.android.dx.command.dexer.Main;
+import com.android.dx.dex.file.DexFile;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Threads.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Threads.java
index abb91107..d1a1428c 100644
--- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Threads.java
+++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Threads.java
@@ -46,7 +46,7 @@ public class Threads {
TimerThread thread = createThread(runnable);
synchronized (mThreads) {
mThreads.add(thread);
- thread.setName(thread.getName() + " (Spawn-" + mSpawnCount + ")");
+ thread.setName(mMainThread.getName() + " (Spawn-" + mSpawnCount + ")");
mSpawnCount++;
}
thread.start();
diff --git a/autojs/src/main/java/com/stardust/autojs/script/JsBeautifier.java b/autojs/src/main/java/com/stardust/autojs/script/JsBeautifier.java
index 15b02ffa..5b114468 100644
--- a/autojs/src/main/java/com/stardust/autojs/script/JsBeautifier.java
+++ b/autojs/src/main/java/com/stardust/autojs/script/JsBeautifier.java
@@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
@@ -35,7 +36,7 @@ public class JsBeautifier {
void onException(Exception e);
}
- private Executor mExecutor = Executors.newSingleThreadExecutor();
+ private ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private Context mContext;
private Function mJsBeautifyFunction;
private org.mozilla.javascript.Context mScriptContext;
@@ -122,4 +123,9 @@ public class JsBeautifier {
}
}
+ public void shutdown(){
+ mExecutor.shutdownNow();
+ mView = null;
+ }
+
}
diff --git a/common/release/output.json b/common/release/output.json
index 9b80d418..25bb428d 100644
--- a/common/release/output.json
+++ b/common/release/output.json
@@ -1 +1 @@
-[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":416},"path":"commonRelease-4.0.2 Alpha11.apk","properties":{"packageId":"org.autojs.autojs","split":"","minSdkVersion":"17"}}]
\ No newline at end of file
+[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":421},"path":"commonRelease-4.0.3 Alpha2.apk","properties":{"packageId":"org.autojs.autojs","split":"","minSdkVersion":"17"}}]
\ No newline at end of file