fix: app memory leak; feat: app foreground service

This commit is contained in:
hyb1996
2018-09-19 14:40:05 +08:00
parent 44fe0079c3
commit 62aafaf06b
22 changed files with 167 additions and 305 deletions

Binary file not shown.

View File

@@ -8,8 +8,8 @@ android {
applicationId "org.autojs.autojs" applicationId "org.autojs.autojs"
minSdkVersion 17 minSdkVersion 17
targetSdkVersion 23 targetSdkVersion 23
versionCode 420 versionCode 421
versionName "4.0.3 Alpha" versionName "4.0.3 Alpha2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
ndk { ndk {
@@ -24,7 +24,7 @@ android {
} }
release { release {
shrinkResources false shrinkResources false
minifyEnabled false minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
@@ -83,10 +83,10 @@ dependencies {
}) })
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0' annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'
// Android supports // Android supports
compile 'com.android.support:appcompat-v7:25.4.0' compile 'com.android.support:appcompat-v7:27.1.1'
compile 'com.android.support:cardview-v7:25.4.0' compile 'com.android.support:cardview-v7:27.1.1'
compile 'com.android.support:design:25.4.0' compile 'com.android.support:design:27.1.1'
compile 'com.android.support:multidex:1.0.2' compile 'com.android.support:multidex:1.0.3'
// Personal libraries // Personal libraries
compile 'com.github.hyb1996:MutableTheme:0.2.2' compile 'com.github.hyb1996:MutableTheme:0.2.2'
// Material Dialogs // Material Dialogs
@@ -146,6 +146,10 @@ dependencies {
compile('com.afollestad.material-dialogs:commons:0.9.2.3', { compile('com.afollestad.material-dialogs:commons:0.9.2.3', {
exclude group: 'com.android.support' 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(':automator')
compile project(':common') compile project(':common')
compile project(':autojs') compile project(':autojs')

View File

@@ -116,6 +116,7 @@
android:theme="@style/IssueReporterTheme"/> android:theme="@style/IssueReporterTheme"/>
<service android:name=".external.foreground.ForegroundService"/>
<service android:name=".external.ScriptExecutionIntentService"/> <service android:name=".external.ScriptExecutionIntentService"/>
<activity android:name=".external.tasker.TaskPrefEditActivity_"/> <activity android:name=".external.tasker.TaskPrefEditActivity_"/>

View File

@@ -1,8 +1,11 @@
package org.autojs.autojs; package org.autojs.autojs;
import android.app.Application;
import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.support.multidex.MultiDex;
import android.support.multidex.MultiDexApplication; import android.support.multidex.MultiDexApplication;
import android.view.View; import android.view.View;
import android.widget.ImageView; 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.FlowConfig;
import com.raizlabs.android.dbflow.config.FlowManager; import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.runtime.DirectModelNotifier; import com.raizlabs.android.dbflow.runtime.DirectModelNotifier;
import com.squareup.leakcanary.LeakCanary;
import com.stardust.app.GlobalAppContext; import com.stardust.app.GlobalAppContext;
import com.stardust.autojs.core.ui.inflater.ImageLoader; import com.stardust.autojs.core.ui.inflater.ImageLoader;
import com.stardust.autojs.core.ui.inflater.util.Drawables; 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() { private void setUpDebugEnvironment() {
CrashHandler crashHandler = new CrashHandler(ErrorReportActivity.class); CrashHandler crashHandler = new CrashHandler(ErrorReportActivity.class);
@@ -77,6 +86,12 @@ public class App extends MultiDexApplication {
crashHandler.setBuglyHandler(Thread.getDefaultUncaughtExceptionHandler()); crashHandler.setBuglyHandler(Thread.getDefaultUncaughtExceptionHandler());
Thread.setDefaultUncaughtExceptionHandler(crashHandler); 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() { private void init() {

View File

@@ -201,4 +201,8 @@ public class Pref {
getString(R.string.default_value_script_dir_path)); getString(R.string.default_value_script_dir_path));
return new File(Environment.getExternalStorageDirectory(), dir).getPath(); return new File(Environment.getExternalStorageDirectory(), dir).getPath();
} }
public static boolean isForegroundServiceEnabled() {
return def().getBoolean(getString(R.string.key_foreground_servie), false);
}
} }

View File

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

View File

@@ -63,4 +63,9 @@ public class TaskerScriptEditActivity extends BaseActivity {
TaskerScriptEditActivity.super.finish(); TaskerScriptEditActivity.super.finish();
} }
@Override
protected void onDestroy() {
mEditorView.destroy();
super.onDestroy();
}
} }

View File

@@ -161,4 +161,7 @@ public class AutoCompletion {
} }
public void shutdown(){
mExecutorService.shutdownNow();
}
} }

View File

@@ -318,6 +318,7 @@ public class ScriptOperations {
String fileName = DownloadManager.parseFileNameLocally(url); String fileName = DownloadManager.parseFileNameLocally(url);
return new FileChooserDialogBuilder(mContext) return new FileChooserDialogBuilder(mContext)
.title(R.string.text_select_save_path) .title(R.string.text_select_save_path)
.dir(Pref.getScriptDirPath())
.chooseDir() .chooseDir()
.singleChoice() .singleChoice()
.map(saveDir -> new File(saveDir, fileName).getPath()) .map(saveDir -> new File(saveDir, fileName).getPath())

View File

@@ -180,6 +180,7 @@ EditActivity extends BaseActivity implements OnActivityResultDelegate.DelegateHo
@Override @Override
protected void onDestroy() { protected void onDestroy() {
mEditorView.destroy();
super.onDestroy(); super.onDestroy();
} }

View File

@@ -392,7 +392,7 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
Snackbar.make(this, R.string.text_start_running, Snackbar.LENGTH_SHORT).show(); Snackbar.make(this, R.string.text_start_running, Snackbar.LENGTH_SHORT).show();
} }
ScriptExecution execution = Scripts.runWithBroadcastSender(mFile); ScriptExecution execution = Scripts.runWithBroadcastSender(mFile);
if(execution == null){ if (execution == null) {
return null; return null;
} }
mScriptExecutionId = execution.getId(); mScriptExecutionId = execution.getId();
@@ -671,4 +671,9 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
super.onRestoreInstanceState(superData); super.onRestoreInstanceState(superData);
setMenuItemStatus(R.id.run, mScriptExecutionId == ScriptExecution.NO_ID); setMenuItemStatus(R.id.run, mScriptExecutionId == ScriptExecution.NO_ID);
} }
public void destroy() {
mEditor.destroy();
mAutoCompletion.shutdown();
}
} }

View File

@@ -373,6 +373,11 @@ public class CodeEditor extends HVScrollView {
mCodeEditText.removeAllBreakpoints(); mCodeEditText.removeAllBreakpoints();
} }
public void destroy(){
mJavaScriptHighlighter.shutdown();
mJsBeautifier.shutdown();
}
@Override @Override
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
int codeWidth = getWidth() - getPaddingLeft() - getPaddingRight(); int codeWidth = getWidth() - getPaddingLeft() - getPaddingRight();

View File

@@ -2,10 +2,12 @@ package org.autojs.autojs.ui.edit.editor;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher;
import android.util.TimingLogger; import android.util.TimingLogger;
import com.stardust.autojs.rhino.TokenStream; import com.stardust.autojs.rhino.TokenStream;
import com.stardust.pio.UncheckedIOException; import com.stardust.pio.UncheckedIOException;
import org.autojs.autojs.ui.edit.theme.Theme; import org.autojs.autojs.ui.edit.theme.Theme;
import org.autojs.autojs.ui.widget.SimpleTextWatcher; import org.autojs.autojs.ui.widget.SimpleTextWatcher;
@@ -46,7 +48,7 @@ public class JavaScriptHighlighter implements SimpleTextWatcher.AfterTextChanged
@Override @Override
public String toString() { public String toString() {
return super.toString() + "{count = " + mCount + ", length = " + mText.length() + "}"; return super.toString() + "{count = " + mCount + ", length = " + mText.length() + "}";
} }
public int getCharCount() { public int getCharCount() {
@@ -60,16 +62,18 @@ public class JavaScriptHighlighter implements SimpleTextWatcher.AfterTextChanged
private Theme mTheme; private Theme mTheme;
private CodeEditText mCodeEditText; private CodeEditText mCodeEditText;
private ThreadPoolExecutor mExecutorService = new ThreadPoolExecutor(3, 6, private ThreadPoolExecutor mExecutorService = new ThreadPoolExecutor(3, 6,
2L, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); 2L, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
private AtomicInteger mRunningHighlighterId = new AtomicInteger(); private AtomicInteger mRunningHighlighterId = new AtomicInteger();
private TimingLogger mLogger = new TimingLogger(CodeEditText.LOG_TAG, "highlight"); private TimingLogger mLogger = new TimingLogger(CodeEditText.LOG_TAG, "highlight");
private final TextWatcher mTextWatcher;
public JavaScriptHighlighter(Theme theme, CodeEditText codeEditText) { public JavaScriptHighlighter(Theme theme, CodeEditText codeEditText) {
mExecutorService.allowCoreThreadTimeOut(true); mExecutorService.allowCoreThreadTimeOut(true);
mTheme = theme; mTheme = theme;
mCodeEditText = codeEditText; mCodeEditText = codeEditText;
codeEditText.addTextChangedListener(new SimpleTextWatcher(this)); mTextWatcher = new SimpleTextWatcher(this);
codeEditText.addTextChangedListener(mTextWatcher);
} }
@Override @Override
@@ -112,5 +116,9 @@ public class JavaScriptHighlighter implements SimpleTextWatcher.AfterTextChanged
mCodeEditText.updateHighlightTokens(highlightTokens); mCodeEditText.updateHighlightTokens(highlightTokens);
} }
public void shutdown() {
mCodeEditText.removeTextChangedListener(mTextWatcher);
mExecutorService.shutdownNow();
}
} }

View File

@@ -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<Action> history = new Stack<>();
//恢复栈
Stack<Action> 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;
}
}
}

View File

@@ -9,6 +9,7 @@ import java.util.LinkedList;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.os.Handler;
import android.text.Editable; import android.text.Editable;
import android.text.Selection; import android.text.Selection;
import android.text.TextWatcher; import android.text.TextWatcher;
@@ -46,6 +47,10 @@ public class TextViewUndoRedo {
private int mInitialHistoryStackSize; 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) { if (mIsUndoOrRedo || !mEnabled) {
return; return;
} }
mBeforeChange = s.subSequence(start, start + count); mBeforeChange = s.subSequence(start, start + count);
} }
@@ -415,7 +419,10 @@ public class TextViewUndoRedo {
} }
mAfterChange = s.subSequence(start, start + count); mAfterChange = s.subSequence(start, start + count);
mTextChangeId++;
mEditHistory.add(new EditItem(start, mBeforeChange, mAfterChange)); mEditHistory.add(new EditItem(start, mBeforeChange, mAfterChange));
int textChangeId = mTextChangeId;
//TODO 增加连续输入文字当成一次撤销的功能
} }
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {

View File

@@ -1,5 +1,6 @@
package org.autojs.autojs.ui.main.drawer; package org.autojs.autojs.ui.main.drawer;
import android.annotation.SuppressLint;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
@@ -22,6 +23,7 @@ import com.stardust.notification.NotificationListenerService;
import org.autojs.autojs.Pref; import org.autojs.autojs.Pref;
import org.autojs.autojs.R; import org.autojs.autojs.R;
import org.autojs.autojs.external.foreground.ForegroundService;
import org.autojs.autojs.network.GlideApp; import org.autojs.autojs.network.GlideApp;
import org.autojs.autojs.network.UserService; import org.autojs.autojs.network.UserService;
import org.autojs.autojs.tool.EmptyObservers; 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 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 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); 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(mFloatingWindowItem, true);
} }
setChecked(mConnectionItem, DevPluginService.getInstance().isConnected()); setChecked(mConnectionItem, DevPluginService.getInstance().isConnected());
if(Pref.isForegroundServiceEnabled()){
GlobalAppContext.get().startService(new Intent(getContext(), ForegroundService.class));
setChecked(mForegroundServiceItem, true);
}
} }
private void initMenuItems() { private void initMenuItems() {
@@ -150,6 +158,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
mAccessibilityServiceItem, mAccessibilityServiceItem,
mStableModeItem, mStableModeItem,
mNotificationPermissionItem, mNotificationPermissionItem,
mForegroundServiceItem,
new DrawerMenuGroup(R.string.text_script_record), new DrawerMenuGroup(R.string.text_script_record),
mFloatingWindowItem, mFloatingWindowItem,
@@ -165,6 +174,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
} }
@SuppressLint("CheckResult")
@Click(R.id.avatar) @Click(R.id.avatar)
void loginOrShowUserInfo() { void loginOrShowUserInfo() {
UserService.getInstance() 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() { private void inputRemoteHost() {
String host = Pref.getServerAddressOrDefault(WifiTool.getRouterIp(getActivity())); String host = Pref.getServerAddressOrDefault(WifiTool.getRouterIp(getActivity()));
new MaterialDialog.Builder(getActivity()) new MaterialDialog.Builder(getActivity())

View File

@@ -398,4 +398,9 @@
<string name="text_new_project">新建项目</string> <string name="text_new_project">新建项目</string>
<string name="text_js_file">js文件</string> <string name="text_js_file">js文件</string>
<string name="text_invalid_project">无效项目</string> <string name="text_invalid_project">无效项目</string>
<string name="text_foreground_service">前台服务</string>
<string name="key_foreground_servie">key_foreground_service</string>
<string name="foreground_notification_channel_name">前台服务通知</string>
<string name="foreground_notification_title">Auto.js保持运行中</string>
<string name="foreground_notification_text">点击进入主界面</string>
</resources> </resources>

View File

@@ -6,6 +6,7 @@ import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.engine.ScriptEngineManager; import com.stardust.autojs.engine.ScriptEngineManager;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
import com.stardust.autojs.script.ScriptSource; import com.stardust.autojs.script.ScriptSource;
import com.stardust.lang.ThreadCompat;
/** /**
* Created by Stardust on 2017/5/1. * Created by Stardust on 2017/5/1.
@@ -24,6 +25,7 @@ public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecu
@Override @Override
public void run() { public void run() {
ThreadCompat.currentThread().setName("ScriptThread-" + getId() + "[" + getSource() + "]");
execute(); execute();
} }

View File

@@ -3,6 +3,7 @@ package com.stardust.autojs.rhino;
import android.util.Log; import android.util.Log;
import com.android.dx.command.dexer.Main; import com.android.dx.command.dexer.Main;
import com.android.dx.dex.file.DexFile;
import net.lingala.zip4j.core.ZipFile; import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.exception.ZipException;

View File

@@ -46,7 +46,7 @@ public class Threads {
TimerThread thread = createThread(runnable); TimerThread thread = createThread(runnable);
synchronized (mThreads) { synchronized (mThreads) {
mThreads.add(thread); mThreads.add(thread);
thread.setName(thread.getName() + " (Spawn-" + mSpawnCount + ")"); thread.setName(mMainThread.getName() + " (Spawn-" + mSpawnCount + ")");
mSpawnCount++; mSpawnCount++;
} }
thread.start(); thread.start();

View File

@@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
/** /**
@@ -35,7 +36,7 @@ public class JsBeautifier {
void onException(Exception e); void onException(Exception e);
} }
private Executor mExecutor = Executors.newSingleThreadExecutor(); private ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private Context mContext; private Context mContext;
private Function mJsBeautifyFunction; private Function mJsBeautifyFunction;
private org.mozilla.javascript.Context mScriptContext; private org.mozilla.javascript.Context mScriptContext;
@@ -122,4 +123,9 @@ public class JsBeautifier {
} }
} }
public void shutdown(){
mExecutor.shutdownNow();
mView = null;
}
} }

View File

@@ -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"}}] [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":421},"path":"commonRelease-4.0.3 Alpha2.apk","properties":{"packageId":"org.autojs.autojs","split":"","minSdkVersion":"17"}}]