From 8259a12e1248cf688b5fda05f9e138a490a0b3c4 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Tue, 18 Sep 2018 20:01:24 +0800 Subject: [PATCH 01/14] fix: invalid project cause ProjectConfigActivity and ExplorerToolbar crash --- .gitignore | 3 ++- .../ui/explorer/ExplorerProjectToolbar.java | 16 ++++++++-------- .../autojs/autojs/ui/explorer/ExplorerView.java | 2 +- .../autojs/ui/project/ProjectConfigActivity.java | 12 ++++++++++++ app/src/main/res/values/strings.xml | 1 + 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 50688619..c2d30342 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ /captures .externalNativeBuild *.apk -*.exe \ No newline at end of file +*.exe +.idea/caches/build_file_checksums.ser diff --git a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerProjectToolbar.java b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerProjectToolbar.java index 1a1650e0..2f01565e 100644 --- a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerProjectToolbar.java +++ b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerProjectToolbar.java @@ -4,9 +4,6 @@ import android.content.Context; import android.support.annotation.Nullable; import android.support.v7.widget.CardView; import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; @@ -14,7 +11,6 @@ import com.stardust.autojs.project.ProjectConfig; import com.stardust.autojs.project.ProjectLauncher; import com.stardust.pio.PFile; -import org.androidannotations.annotations.Click; import org.autojs.autojs.R; import org.autojs.autojs.autojs.AutoJs; import org.autojs.autojs.model.explorer.ExplorerChangeEvent; @@ -59,15 +55,19 @@ public class ExplorerProjectToolbar extends CardView { setOnClickListener(view -> edit()); } - public void setProject(PFile dir, ProjectConfig config) { + public void setProject(PFile dir) { + mProjectConfig = ProjectConfig.fromProjectDir(dir.getPath()); + if(mProjectConfig == null){ + setVisibility(GONE); + return; + } mDirectory = dir; - mProjectConfig = config; - mProjectName.setText(config.getName()); + mProjectName.setText(mProjectConfig.getName()); } public void refresh() { if (mDirectory != null) { - setProject(mDirectory, ProjectConfig.fromProjectDir(mDirectory.getPath())); + setProject(mDirectory); } } diff --git a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java index f4956775..e250921c 100644 --- a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java +++ b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java @@ -111,7 +111,7 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR mCurrentPageState = currentPageState; if (mCurrentPageState.page instanceof ExplorerProjectPage) { mProjectToolbar.setVisibility(VISIBLE); - mProjectToolbar.setProject(currentPageState.page.toScriptFile(), ((ExplorerProjectPage) currentPageState.page).getProjectConfig()); + mProjectToolbar.setProject(currentPageState.page.toScriptFile()); } else { mProjectToolbar.setVisibility(GONE); } diff --git a/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.java b/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.java index 6351663b..3950d0f6 100644 --- a/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.java @@ -12,6 +12,7 @@ import android.widget.ImageView; import android.widget.Toast; import com.stardust.autojs.project.ProjectConfig; +import com.stardust.autojs.runtime.api.Dialogs; import com.stardust.pio.PFiles; import org.androidannotations.annotations.AfterViews; @@ -24,6 +25,7 @@ import org.autojs.autojs.model.explorer.ExplorerFileItem; import org.autojs.autojs.model.explorer.ExplorerItem; import org.autojs.autojs.model.explorer.Explorers; import org.autojs.autojs.model.project.ProjectTemplate; +import org.autojs.autojs.theme.dialog.ThemeColorMaterialDialogBuilder; import org.autojs.autojs.ui.BaseActivity; import org.autojs.autojs.ui.widget.SimpleTextWatcher; @@ -89,11 +91,21 @@ public class ProjectConfigActivity extends BaseActivity { } mDirectory = new File(dir); mProjectConfig = ProjectConfig.fromProjectDir(dir); + if (mProjectConfig == null) { + new ThemeColorMaterialDialogBuilder(this) + .title(R.string.text_invalid_project) + .positiveText(R.string.ok) + .dismissListener(dialogInterface -> finish()) + .show(); + } } } @AfterViews void setupViews() { + if (mProjectConfig == null) { + return; + } setToolbarAsBack(mNewProject ? getString(R.string.text_new_project) : mProjectConfig.getName()); if (mNewProject) { mAppName.addTextChangedListener(new SimpleTextWatcher(s -> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b06d2b6a..4e89bd90 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -397,4 +397,5 @@ 项目位置 新建项目 js文件 + 无效项目 From a01fdbc131aa56f7d323478be0fbe53e1f367ed7 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Tue, 18 Sep 2018 20:20:35 +0800 Subject: [PATCH 02/14] fix: forget to set package name to apk builder --- .../java/org/autojs/autojs/autojs/build/AutoJsApkBuilder.java | 1 + .../main/java/org/autojs/autojs/ui/project/BuildActivity.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/autojs/autojs/autojs/build/AutoJsApkBuilder.java b/app/src/main/java/org/autojs/autojs/autojs/build/AutoJsApkBuilder.java index 7c0b8dd3..419ce82c 100644 --- a/app/src/main/java/org/autojs/autojs/autojs/build/AutoJsApkBuilder.java +++ b/app/src/main/java/org/autojs/autojs/autojs/build/AutoJsApkBuilder.java @@ -50,6 +50,7 @@ public class AutoJsApkBuilder extends ApkBuilder { public static AppConfig fromProjectConfig(String projectDir, ProjectConfig projectConfig) { return new AppConfig() .setAppName(projectConfig.getName()) + .setPackageName(projectConfig.getPackageName()) .ignoreDir(new File(projectDir, projectConfig.getBuildDir())) .setVersionCode(projectConfig.getVersionCode()) .setVersionName(projectConfig.getVersionName()) diff --git a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java index e338bd49..2eadd7f1 100644 --- a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java @@ -39,6 +39,7 @@ import org.autojs.autojs.ui.shortcut.ShortcutIconSelectActivity_; import java.io.File; import java.io.InputStream; +import java.security.KeyStore; import java.util.Locale; import java.util.concurrent.Callable; @@ -116,7 +117,6 @@ public class BuildActivity extends BaseActivity implements AutoJsApkBuilder.Prog if (version < ApkBuilderPluginHelper.getSuitablePluginVersion()) { showPluginDownloadDialog(R.string.apk_builder_plugin_version_too_low, false); } - } private void showPluginDownloadDialog(int msgRes, boolean finishIfCanceled) { From 44fe0079c3587fdfc55bd898083c0a5dbd986139 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Tue, 18 Sep 2018 21:12:27 +0800 Subject: [PATCH 03/14] =?UTF-8?q?fix:=20https://docs.qq.com/doc/Bx01Pn3Vcg?= =?UTF-8?q?Tn1sMR4T3EkjgU0LuPI60KdqgC2ETyTC4KNvuh39MYhP0gVL1S3wtZlQ2SUh123?= =?UTF-8?q?=20:=20"=E6=82=AC=E6=B5=AE=E7=AA=97=E9=80=89=E6=8B=A9=E5=99=A8?= =?UTF-8?q?=E5=95=8F=E9=A1=8C=EF=BC=8C=E5=A6=82=E6=9E=9C=E9=BB=9E=E6=93=8A?= =?UTF-8?q?=E4=BD=88=E5=B1=80=E5=9B=BE=E5=B1=82=E5=88=86=E6=9E=90=EF=BC=8C?= =?UTF-8?q?=E7=84=B6=E5=BE=8C=E6=89=BE=E5=88=B0=E6=9C=80=E4=B8=8B=E9=9D=A2?= =?UTF-8?q?=E4=B8=80=E5=80=8B=E9=95=B7=E6=8C=89=EF=BC=8C=E6=9C=83=E5=87=BA?= =?UTF-8?q?=E7=8F=BE=E7=84=A1=E6=B3=95=E9=A1=AF=E7=A4=BA=E6=9F=A5=E7=9C=8B?= =?UTF-8?q?=E6=8E=A7=E4=BB=B6=E4=BF=A1=E6=81=AF=E5=95=8F=E9=A1=8C"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../autojs/ui/floating/CircularMenu.java | 2 +- .../ui/floating/CircularMenuWindow.java | 19 ++++++++++++++----- .../autojs/ui/widget/BubblePopupMenu.java | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java index aaa95359..ffc5e0de 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java @@ -115,7 +115,7 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp @Override public View inflateActionView(FloatyService service, CircularMenuWindow window) { View actionView = View.inflate(service, R.layout.circular_action_view, null); - mActionViewIcon = (RoundedImageView) actionView.findViewById(R.id.icon); + mActionViewIcon = actionView.findViewById(R.id.icon); return actionView; } diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuWindow.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuWindow.java index ee0f170b..8f57a5e6 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuWindow.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuWindow.java @@ -1,11 +1,8 @@ package org.autojs.autojs.ui.floating; -import android.app.Activity; import android.content.Context; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.util.Log; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; import android.view.OrientationEventListener; import android.view.View; import android.view.WindowManager; @@ -15,9 +12,13 @@ import com.stardust.enhancedfloaty.FloatyWindow; import com.stardust.enhancedfloaty.WindowBridge; import com.stardust.floatingcircularactionmenu.CircularActionMenu; import com.stardust.floatingcircularactionmenu.gesture.BounceDragGesture; +import com.stardust.util.ScreenMetrics; public class CircularMenuWindow implements FloatyWindow { + private static final String KEY_POSITION_X = CircularMenuWindow.class.getName() + ".position.x"; + private static final String KEY_POSITION_Y = CircularMenuWindow.class.getName() + ".position.y"; + protected CircularMenuFloaty mFloaty; protected WindowManager mWindowManager; protected CircularActionMenu mCircularActionMenu; @@ -66,6 +67,9 @@ public class CircularMenuWindow implements FloatyWindow { } private void setInitialState() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext); + int y = preferences.getInt(KEY_POSITION_Y, ScreenMetrics.getDeviceScreenHeight() / 2); + mActionViewWindowBridge.updatePosition(mActionViewWindowBridge.getX(), y); keepToSide(); } @@ -190,6 +194,11 @@ public class CircularMenuWindow implements FloatyWindow { } public void close() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext); + preferences.edit() + .putInt(KEY_POSITION_X, mActionViewWindowBridge.getX()) + .putInt(KEY_POSITION_Y, mActionViewWindowBridge.getY()) + .apply(); mOrientationEventListener.disable(); this.mWindowManager.removeView(this.mCircularActionMenu); this.mWindowManager.removeView(this.mCircularActionView); diff --git a/app/src/main/java/org/autojs/autojs/ui/widget/BubblePopupMenu.java b/app/src/main/java/org/autojs/autojs/ui/widget/BubblePopupMenu.java index a65d392e..74c5f448 100644 --- a/app/src/main/java/org/autojs/autojs/ui/widget/BubblePopupMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/widget/BubblePopupMenu.java @@ -58,7 +58,7 @@ public class BubblePopupMenu extends PopupWindow { } else { params.leftMargin = 0; } - if (y + height > screenHeight) { + if (y > screenHeight / 2) { getContentView().setRotation(180); mRecyclerView.setRotation(180); params.leftMargin = -params.leftMargin; From 62aafaf06b36e4cb9a38c56bffb7f607ee77c077 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 19 Sep 2018 14:40:05 +0800 Subject: [PATCH 04/14] fix: app memory leak; feat: app foreground service --- .idea/caches/build_file_checksums.ser | Bin 733 -> 733 bytes app/build.gradle | 18 +- app/src/main/AndroidManifest.xml | 1 + app/src/main/java/org/autojs/autojs/App.java | 15 + app/src/main/java/org/autojs/autojs/Pref.java | 4 + .../foreground/ForegroundService.java | 58 ++++ .../tasker/TaskerScriptEditActivity.java | 5 + .../model/autocomplete/AutoCompletion.java | 3 + .../autojs/ui/common/ScriptOperations.java | 1 + .../autojs/autojs/ui/edit/EditActivity.java | 1 + .../org/autojs/autojs/ui/edit/EditorView.java | 7 +- .../autojs/ui/edit/editor/CodeEditor.java | 5 + .../ui/edit/editor/JavaScriptHighlighter.java | 14 +- .../ui/edit/editor/TextViewRedoUndoer.java | 290 ------------------ .../ui/edit/editor/TextViewUndoRedo.java | 9 +- .../autojs/ui/main/drawer/DrawerFragment.java | 21 ++ app/src/main/res/values/strings.xml | 5 + .../execution/RunnableScriptExecution.java | 2 + .../autojs/rhino/AndroidClassLoader.java | 1 + .../stardust/autojs/runtime/api/Threads.java | 2 +- .../stardust/autojs/script/JsBeautifier.java | 8 +- common/release/output.json | 2 +- 22 files changed, 167 insertions(+), 305 deletions(-) create mode 100644 app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java delete mode 100644 app/src/main/java/org/autojs/autojs/ui/edit/editor/TextViewRedoUndoer.java diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 259a89dcb7414dbe3332924ae967a0d3230dabae..4c2daf666ae5e458ff1e8b893dcae8e74665c0b2 100644 GIT binary patch delta 98 zcmV-o0GFUZm;~?+6d#eCcMwm;T6tvrM|vL8oNnq--X@bH0hAEkV!1BLQ>o_L zjPfRp6JofN#{qc|(?GG}j>(=SBE90{q%m=$lTZR45IwePWly%vn~smDYADU$q?3LE EU**p)3IG5A delta 98 zcmV-o0GFUZm;~$oaio!)cM#Jlvh5fTox6Vvn~%obxlNNJ0hADGR$^Rwntfn5 zjHH&5+;#|)#{qc|z*m9*T8^o%-Pn(JPkk`7lTZR45IofbHLa|VVXDhfaHl!SdXs(v EUjo-HWdHyG 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 From 723c7a7ff0fe850f1350e3372e28f1b8df1591fc Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 19 Sep 2018 16:41:01 +0800 Subject: [PATCH 05/14] fix(ui): some bugs on back pressed --- .../foreground/ForegroundService.java | 52 +++++++++++++++---- .../autojs/autojs/ui/doc/DocsFragment.java | 11 ---- .../autojs/autojs/ui/main/MainActivity.java | 8 +++ .../autojs/ui/main/ViewPagerFragment.java | 5 +- .../ui/main/community/CommunityFragment.java | 11 ---- .../autojs/ui/main/drawer/DrawerFragment.java | 6 +-- .../autojs/ui/main/sample/MarketFragment.java | 1 - .../ui/main/scripts/MyScriptListFragment.java | 18 +------ .../ui/main/task/TaskManagerFragment.java | 5 ++ .../core/ui/dialog/BlockedMaterialDialog.java | 2 +- 10 files changed, 63 insertions(+), 56 deletions(-) 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 index 563f2e8b..e9108beb 100644 --- a/app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java +++ b/app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java @@ -3,6 +3,7 @@ package org.autojs.autojs.external.foreground; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; +import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; @@ -12,11 +13,34 @@ import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; import android.support.v4.app.NotificationCompat; +import com.stardust.app.GlobalAppContext; + import org.autojs.autojs.R; +import org.autojs.autojs.ui.main.MainActivity_; public class ForegroundService extends Service { - private static final int NOTIFICATION_ID = 117; - private static final String CHANEL_ID = "foreground"; + + + private static final int NOTIFICATION_ID = 1; + private static final String CHANEL_ID = ForegroundService.class.getName() + ".foreground"; + + public static void start(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(new Intent(context, ForegroundService.class)); + } else { + context.startService(new Intent(context, ForegroundService.class)); + } + } + + public static void stop(Context context){ + context.stopService(new Intent(context, ForegroundService.class)); + } + + @Override + public void onCreate() { + super.onCreate(); + startForeground(); + } @Nullable @Override @@ -24,13 +48,7 @@ public class ForegroundService extends Service { return null; } - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - startForeground(); - return START_STICKY; - } - - private void startForeground(){ + private void startForeground() { startForeground(NOTIFICATION_ID, buildNotification()); } @@ -38,21 +56,33 @@ public class ForegroundService extends Service { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { createNotificationChannel(); } + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, MainActivity_.intent(this).get(), 0); 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) + .setWhen(System.currentTimeMillis()) + .setContentIntent(contentIntent) + .setChannelId(CHANEL_ID) .build(); } @RequiresApi(api = Build.VERSION_CODES.O) - private void createNotificationChannel(){ + 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); + NotificationChannel channel = new NotificationChannel(CHANEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT); channel.setDescription(description); + channel.enableLights(false); manager.createNotificationChannel(channel); } + + @Override + public void onDestroy() { + stopForeground(true); + super.onDestroy(); + + } } diff --git a/app/src/main/java/org/autojs/autojs/ui/doc/DocsFragment.java b/app/src/main/java/org/autojs/autojs/ui/doc/DocsFragment.java index 3ddfbda7..86914a6c 100644 --- a/app/src/main/java/org/autojs/autojs/ui/doc/DocsFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/doc/DocsFragment.java @@ -74,23 +74,12 @@ public class DocsFragment extends ViewPagerFragment implements BackPressedHandle } - @Override - public void onResume() { - super.onResume(); - ((BackPressedHandler.HostActivity) getActivity()) - .getBackPressedObserver() - .registerHandlerAtFront(this); - } - @Override public void onPause() { super.onPause(); Bundle savedWebViewState = new Bundle(); mWebView.saveState(savedWebViewState); getArguments().putBundle("savedWebViewState", savedWebViewState); - ((BackPressedHandler.HostActivity) getActivity()) - .getBackPressedObserver() - .unregisterHandler(this); } @Override diff --git a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.java b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.java index 026b77d2..c8d716dd 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.java @@ -37,6 +37,7 @@ import org.autojs.autojs.BuildConfig; import org.autojs.autojs.Pref; import org.autojs.autojs.R; import org.autojs.autojs.autojs.AutoJs; +import org.autojs.autojs.external.foreground.ForegroundService; import org.autojs.autojs.model.explorer.Explorers; import org.autojs.autojs.tool.AccessibilityServiceTool; import org.autojs.autojs.ui.BaseActivity; @@ -208,6 +209,7 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega public void exitCompletely() { finish(); FloatyWindowManger.hideCircularMenu(); + ForegroundService.stop(this); stopService(new Intent(this, FloatyService.class)); AutoJs.getInstance().getScriptEngineService().stopAll(); } @@ -264,6 +266,12 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega @Override public void onBackPressed() { + Fragment fragment = mPagerAdapter.getStoredFragment(mViewPager.getCurrentItem()); + if (fragment instanceof BackPressedHandler) { + if (((BackPressedHandler) fragment).onBackPressed(this)) { + return; + } + } if (!mBackPressObserver.onBackPressed(this)) { super.onBackPressed(); } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/ViewPagerFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/ViewPagerFragment.java index 4649dc02..068786c6 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/ViewPagerFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/ViewPagerFragment.java @@ -3,14 +3,17 @@ package org.autojs.autojs.ui.main; import android.support.annotation.CallSuper; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.view.View; +import com.stardust.util.BackPressedHandler; + /** * Created by Stardust on 2017/8/22. */ -public abstract class ViewPagerFragment extends Fragment { +public abstract class ViewPagerFragment extends Fragment implements BackPressedHandler { protected static final int ROTATION_GONE = -1; diff --git a/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityFragment.java index 203180e1..e9f0b637 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityFragment.java @@ -72,23 +72,12 @@ public class CommunityFragment extends ViewPagerFragment implements BackPressedH } } - @Override - public void onResume() { - super.onResume(); - ((BackPressedHandler.HostActivity) getActivity()) - .getBackPressedObserver() - .registerHandlerAtFront(this); - } - @Override public void onPause() { super.onPause(); Bundle savedWebViewState = new Bundle(); mWebView.saveState(savedWebViewState); getArguments().putBundle("savedWebViewState", savedWebViewState); - ((BackPressedHandler.HostActivity) getActivity()) - .getBackPressedObserver() - .unregisterHandler(this); } @Override 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 65b09364..09643151 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 @@ -147,7 +147,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment { } setChecked(mConnectionItem, DevPluginService.getInstance().isConnected()); if(Pref.isForegroundServiceEnabled()){ - GlobalAppContext.get().startService(new Intent(getContext(), ForegroundService.class)); + ForegroundService.start(GlobalAppContext.get()); setChecked(mForegroundServiceItem, true); } } @@ -265,9 +265,9 @@ 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)); + ForegroundService.start(GlobalAppContext.get()); }else { - GlobalAppContext.get().stopService(new Intent(getContext(), ForegroundService.class)); + ForegroundService.stop(GlobalAppContext.get()); } } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/sample/MarketFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/sample/MarketFragment.java index ede9cc57..5269ad05 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/sample/MarketFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/sample/MarketFragment.java @@ -62,7 +62,6 @@ public class MarketFragment extends ViewPagerFragment implements BackPressedHand @Override public boolean onBackPressed(Activity activity) { - return false; } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java index 23e04bf4..7b405475 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java @@ -35,7 +35,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers; * Created by Stardust on 2017/3/13. */ @EFragment(R.layout.fragment_my_script_list) -public class MyScriptListFragment extends ViewPagerFragment implements BackPressedHandler, FloatingActionMenu.OnFloatingActionButtonClickListener { +public class MyScriptListFragment extends ViewPagerFragment implements FloatingActionMenu.OnFloatingActionButtonClickListener { private static final String TAG = "MyScriptListFragment"; @@ -68,22 +68,6 @@ public class MyScriptListFragment extends ViewPagerFragment implements BackPress }); } - @Override - public void onResume() { - super.onResume(); - ((BackPressedHandler.HostActivity) getActivity()) - .getBackPressedObserver() - .registerHandlerAtFront(this); - } - - @Override - public void onPause() { - super.onPause(); - ((BackPressedHandler.HostActivity) getActivity()) - .getBackPressedObserver() - .unregisterHandler(this); - } - @Override protected void onFabClick(FloatingActionButton fab) { initFloatingActionMenuIfNeeded(fab); diff --git a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskManagerFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskManagerFragment.java index e0e8f293..d6ffb284 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskManagerFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskManagerFragment.java @@ -1,5 +1,6 @@ package org.autojs.autojs.ui.main.task; +import android.app.Activity; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.v4.widget.SwipeRefreshLayout; @@ -70,4 +71,8 @@ public class TaskManagerFragment extends ViewPagerFragment { AutoJs.getInstance().getScriptEngineService().stopAll(); } + @Override + public boolean onBackPressed(Activity activity) { + return false; + } } diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/BlockedMaterialDialog.java b/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/BlockedMaterialDialog.java index ed748eb8..b84f30df 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/BlockedMaterialDialog.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/BlockedMaterialDialog.java @@ -136,7 +136,7 @@ public class BlockedMaterialDialog extends MaterialDialog { } public MaterialDialog.Builder itemsCallbackMultiChoice(@Nullable Integer[] selectedIndices) { - dismissListener(dialog -> setAndNotify(new Integer[0])); + dismissListener(dialog -> setAndNotify(new int[0])); super.itemsCallbackMultiChoice(selectedIndices, (dialog, which, text) -> { setAndNotify(ArrayUtils.unbox(which)); return true; From 16709529e3f0a06b8bdd1a1fba39792c483b6ef4 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 19 Sep 2018 16:47:19 +0800 Subject: [PATCH 06/14] fix: Java.lang.NullPointerException: Attempt to invoke interface method 'com.stardust.autojs.engine.ScriptEngine com.stardust.autojs.execution.ScriptExecution.getEngine()' on a null object reference com.stardust.autojs.ScriptEngineService$1.onFinish(ScriptEngineService.java:70) com.stardust.autojs.ScriptEngineService$1.onSuccess(ScriptEngineService.java:66) com.stardust.autojs.execution.ScriptExecutionObserver.onSuccess(ScriptExecutionObserver.java:22) com.stardust.autojs.execution.ScriptExecuteActivity.finish(ScriptExecuteActivity.java:137) com.stardust.autojs.engine.LoopBasedJavaScriptEngine.forceStop(LoopBasedJavaScriptEngine.java:69) org.autojs.autojs.ui.main.task.Task$RunningTask.cancel(Task.java:100) org.autojs.autojs.ui.main.task.TaskListRecyclerView$TaskViewHolder.stop(TaskListRecyclerView.java:246) org.autojs.autojs.ui.main.task.TaskListRecyclerView$TaskViewHolder_ViewBinding$1.doClick(TaskListRecyclerView$TaskViewHolder_ViewBinding.java:34) butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22) android.view.View.performClick(View.java:5641) android.view.View$PerformClick.run(View.java:22533) android.os.Handler.handleCallback(Handler.java:751) android.os.Handler.dispatchMessage(Handler.java:95) android.os.Looper.loop(Looper.java:177) android.app.ActivityThread.main(ActivityThread.java:6674) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802) --- .../autojs/ui/main/scripts/MyScriptListFragment.java | 7 +++++-- .../stardust/view/accessibility/AccessibilityService.java | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java index 7b405475..a8fd7241 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java @@ -5,7 +5,9 @@ import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; +import android.support.v7.widget.RecyclerView; +import com.stardust.app.GlobalAppContext; import com.stardust.util.BackPressedHandler; import com.stardust.util.IntentUtil; @@ -26,6 +28,7 @@ import org.autojs.autojs.ui.main.ViewPagerFragment; import org.autojs.autojs.ui.project.ProjectConfigActivity; import org.autojs.autojs.ui.project.ProjectConfigActivity_; import org.autojs.autojs.ui.viewmodel.ExplorerItemList; +import org.autojs.autojs.ui.widget.ExpandableRecyclerView; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -63,7 +66,7 @@ public class MyScriptListFragment extends ViewPagerFragment implements FloatingA if (item.isEditable()) { Scripts.edit(item.toScriptFile()); } else { - IntentUtil.viewFile(getContext(), item.getPath()); + IntentUtil.viewFile(GlobalAppContext.get(), item.getPath()); } }); } @@ -82,7 +85,7 @@ public class MyScriptListFragment extends ViewPagerFragment implements FloatingA private void initFloatingActionMenuIfNeeded(final FloatingActionButton fab) { if (mFloatingActionMenu != null) return; - mFloatingActionMenu = ((FloatingActionMenu) getActivity().findViewById(R.id.floating_action_menu)); + mFloatingActionMenu = getActivity().findViewById(R.id.floating_action_menu); mFloatingActionMenu.getState() .observeOn(AndroidSchedulers.mainThread()) .subscribe(new SimpleObserver() { diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java index 203410d3..79122996 100644 --- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java +++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java @@ -61,7 +61,7 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi int type = event.getEventType(); if (type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || type == AccessibilityEvent.TYPE_VIEW_FOCUSED) { - AccessibilityNodeInfo root = super.getRootInActiveWindow(); + AccessibilityNodeInfo root = getRootInActiveWindow(); if (root != null) { mFastRootInActiveWindow = root; } @@ -109,7 +109,7 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi public AccessibilityNodeInfo getRootInActiveWindow() { try { return super.getRootInActiveWindow(); - } catch (IllegalStateException e) { + } catch (Exception e) { return null; } } From bb130f56ea2a367d35d284d9d2b9d9d913fd7831 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 19 Sep 2018 20:28:53 +0800 Subject: [PATCH 07/14] fix: sensors's callback persisted in loopers' ThreadLocal, causes ScriptExecuteActivity memory leak --- app/src/main/java/org/autojs/autojs/App.java | 2 +- .../main/java/com/stardust/autojs/AutoJs.java | 1 + .../stardust/autojs/ScriptEngineService.java | 17 +++++-- .../stardust/autojs/core/looper/Loopers.java | 15 +++--- .../autojs/engine/JavaScriptEngine.java | 6 +++ .../stardust/autojs/engine/ScriptEngine.java | 11 +++-- .../execution/ScriptExecuteActivity.java | 48 +++++++++---------- .../autojs/runtime/ScriptRuntime.java | 5 +- .../stardust/autojs/runtime/api/Sensors.java | 4 +- .../com/stardust/autojs/runtime/api/UI.java | 4 ++ 10 files changed, 68 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/org/autojs/autojs/App.java b/app/src/main/java/org/autojs/autojs/App.java index dabe48ab..b6335a4d 100644 --- a/app/src/main/java/org/autojs/autojs/App.java +++ b/app/src/main/java/org/autojs/autojs/App.java @@ -91,7 +91,7 @@ public class App extends MultiDexApplication { // You should not init your app in this process. return; } - LeakCanary.install(this); + //LeakCanary.install(this); } private void init() { diff --git a/autojs/src/main/java/com/stardust/autojs/AutoJs.java b/autojs/src/main/java/com/stardust/autojs/AutoJs.java index 2f95ba50..90f47f67 100644 --- a/autojs/src/main/java/com/stardust/autojs/AutoJs.java +++ b/autojs/src/main/java/com/stardust/autojs/AutoJs.java @@ -65,6 +65,7 @@ public abstract class AutoJs { mNotificationObserver = new AccessibilityNotificationObserver(mContext); mAccessibilityInfoProvider = new AccessibilityInfoProvider(mContext.getPackageManager()); mScriptEngineService = buildScriptEngineService(); + ScriptEngineService.setInstance(mScriptEngineService); init(); } diff --git a/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java b/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java index 7201205f..129b85da 100644 --- a/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java +++ b/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java @@ -67,9 +67,7 @@ public class ScriptEngineService { } private void onFinish(ScriptExecution execution) { - if (execution.getEngine() instanceof JavaScriptEngine) { - ((JavaScriptEngine) execution.getEngine()).getRuntime().onExit(); - } + } @Override @@ -87,6 +85,7 @@ public class ScriptEngineService { }; + private static ScriptEngineService sInstance; private final Context mContext; private UiHandler mUiHandler; private final Console mGlobalConsole; @@ -211,6 +210,18 @@ public class ScriptEngineService { return mScriptExecutions.get(id); } + public static void setInstance(ScriptEngineService service) { + if (sInstance != null) { + throw new IllegalStateException(); + } + sInstance = service; + } + + public static ScriptEngineService getInstance() { + return sInstance; + } + + private static class EngineLifecycleObserver implements ScriptEngineManager.EngineLifecycleCallback { private final Set mEngineLifecycleCallbacks = new LinkedHashSet<>(); diff --git a/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java b/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java index 203d4857..39a76b16 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java +++ b/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java @@ -5,7 +5,6 @@ import android.os.Looper; import android.os.MessageQueue; import android.util.Log; -import com.android.dx.util.IntSet; import com.stardust.autojs.runtime.ScriptRuntime; import com.stardust.autojs.runtime.api.Threads; import com.stardust.autojs.runtime.api.Timers; @@ -33,7 +32,7 @@ public class Loopers implements MessageQueue.IdleHandler { private volatile ThreadLocal waitWhenIdle = new ThreadLocal<>(); private volatile ThreadLocal> waitIds = new ThreadLocal<>(); private volatile ThreadLocal maxWaitId = new ThreadLocal<>(); - private volatile ThreadLocal> looperQuitHanders = new ThreadLocal<>(); + private volatile ThreadLocal> looperQuitHandlers = new ThreadLocal<>(); private volatile Looper mServantLooper; private Timers mTimers; private ScriptRuntime mScriptRuntime; @@ -58,17 +57,17 @@ public class Loopers implements MessageQueue.IdleHandler { return mMainLooper; } - public void addLooperQuiteHandler(LooperQuitHandler handler) { - CopyOnWriteArrayList handlers = looperQuitHanders.get(); + public void addLooperQuitHandler(LooperQuitHandler handler) { + CopyOnWriteArrayList handlers = looperQuitHandlers.get(); if (handlers == null) { handlers = new CopyOnWriteArrayList<>(); - looperQuitHanders.set(handlers); + looperQuitHandlers.set(handlers); } handlers.add(handler); } - public boolean removeLooperQuiteHandler(LooperQuitHandler handler) { - CopyOnWriteArrayList handlers = looperQuitHanders.get(); + public boolean removeLooperQuitHandler(LooperQuitHandler handler) { + CopyOnWriteArrayList handlers = looperQuitHandlers.get(); return handlers != null && handlers.remove(handler); } @@ -82,7 +81,7 @@ public class Loopers implements MessageQueue.IdleHandler { if (waitWhenIdle.get() || !waitIds.get().isEmpty()) { return false; } - CopyOnWriteArrayList handlers = looperQuitHanders.get(); + CopyOnWriteArrayList handlers = looperQuitHandlers.get(); if (handlers == null) { return true; } diff --git a/autojs/src/main/java/com/stardust/autojs/engine/JavaScriptEngine.java b/autojs/src/main/java/com/stardust/autojs/engine/JavaScriptEngine.java index abd7022d..957d4c69 100644 --- a/autojs/src/main/java/com/stardust/autojs/engine/JavaScriptEngine.java +++ b/autojs/src/main/java/com/stardust/autojs/engine/JavaScriptEngine.java @@ -45,6 +45,12 @@ public abstract class JavaScriptEngine extends ScriptEngine.AbstractScriptEngine return (ScriptSource) getTag(TAG_SOURCE); } + @Override + public synchronized void destroy() { + mRuntime.onExit(); + super.destroy(); + } + @Override public String toString() { return "ScriptEngine@" + Integer.toHexString(hashCode()) + "{" + diff --git a/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java index f0a2c09a..dca86616 100644 --- a/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java +++ b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java @@ -5,6 +5,7 @@ import android.support.annotation.CallSuper; import com.stardust.autojs.execution.ScriptExecution; import com.stardust.autojs.script.ScriptSource; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @@ -68,7 +69,7 @@ public interface ScriptEngine { abstract class AbstractScriptEngine implements ScriptEngine { - private Map mTags = new ConcurrentHashMap<>(); + private Map mTags = new HashMap<>(); private OnDestroyListener mOnDestroyListener; private boolean mDestroyed = false; private Exception mUncaughtException; @@ -76,9 +77,11 @@ public interface ScriptEngine { @Override public synchronized void setTag(String key, Object value) { - if (value == null) - return; - mTags.put(key, value); + if (value == null) { + mTags.remove(key); + } else { + mTags.put(key, value); + } } @Override diff --git a/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java b/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java index e4f6fb94..cdfc3db3 100644 --- a/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java +++ b/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java @@ -7,11 +7,13 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; +import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; +import com.stardust.autojs.ScriptEngineService; import com.stardust.autojs.core.eventloop.EventEmitter; import com.stardust.autojs.core.eventloop.SimpleEvent; import com.stardust.autojs.engine.JavaScriptEngine; @@ -21,7 +23,6 @@ import com.stardust.autojs.engine.ScriptEngineManager; import com.stardust.autojs.runtime.ScriptRuntime; import com.stardust.autojs.runtime.api.UI; import com.stardust.autojs.script.ScriptSource; -import com.stardust.util.IntentExtras; import org.mozilla.javascript.NativeObject; @@ -32,13 +33,13 @@ import org.mozilla.javascript.NativeObject; public class ScriptExecuteActivity extends AppCompatActivity { - private static final String EXTRA_EXECUTION = ScriptExecuteActivity.class.getName() + ".execution"; + private static final String LOG_TAG = "ScriptExecuteActivity"; + private static final String EXTRA_EXECUTION_ID = ScriptExecuteActivity.class.getName() + ".execution_id"; private Object mResult; private ScriptEngine mScriptEngine; private ScriptExecutionListener mExecutionListener; private ScriptSource mScriptSource; private ActivityScriptExecution mScriptExecution; - private IntentExtras mIntentExtras; private ScriptRuntime mRuntime; @@ -47,10 +48,8 @@ public class ScriptExecuteActivity extends AppCompatActivity { public static ActivityScriptExecution execute(Context context, ScriptEngineManager manager, ScriptExecutionTask task) { ActivityScriptExecution execution = new ActivityScriptExecution(manager, task); Intent i = new Intent(context, ScriptExecuteActivity.class) + .putExtra(EXTRA_EXECUTION_ID, execution.getId()) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - IntentExtras.newExtras() - .put(EXTRA_EXECUTION, execution) - .putInIntent(i); context.startActivity(i); return execution; } @@ -59,36 +58,30 @@ public class ScriptExecuteActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mIntentExtras = readIntentExtras(savedInstanceState); - if (mIntentExtras == null || mIntentExtras.get(EXTRA_EXECUTION) == null) { - finish(); + int executionId = getIntent().getIntExtra(EXTRA_EXECUTION_ID, ScriptExecution.NO_ID); + if (executionId == ScriptExecution.NO_ID) { + super.finish(); return; } - mScriptExecution = mIntentExtras.get(EXTRA_EXECUTION); + ScriptExecution execution = ScriptEngineService.getInstance().getScriptExecution(executionId); + if (execution == null || !(execution instanceof ActivityScriptExecution)) { + super.finish(); + return; + } + mScriptExecution = (ActivityScriptExecution) execution; mScriptSource = mScriptExecution.getSource(); mScriptEngine = mScriptExecution.createEngine(this); mExecutionListener = mScriptExecution.getListener(); mRuntime = ((JavaScriptEngine) mScriptEngine).getRuntime(); mEventEmitter = new EventEmitter(mRuntime.bridges); runScript(); + emit("create", savedInstanceState); } public EventEmitter getEventEmitter() { return mEventEmitter; } - private IntentExtras readIntentExtras(Bundle savedInstanceState) { - IntentExtras extras = IntentExtras.fromIntentAndRelease(getIntent()); - if (extras == null && savedInstanceState != null) { - int id = savedInstanceState.getInt(IntentExtras.EXTRA_ID, -1); - if (id == -1) { - return null; - } - extras = IntentExtras.fromIdAndRelease(id); - } - return extras; - } - private void runScript() { try { prepare(); @@ -130,6 +123,10 @@ public class ScriptExecuteActivity extends AppCompatActivity { @Override public void finish() { + if (mScriptExecution == null || mExecutionListener == null) { + super.finish(); + return; + } Exception exception = mScriptEngine.getUncaughtException(); if (exception != null) { onException(exception); @@ -142,6 +139,7 @@ public class ScriptExecuteActivity extends AppCompatActivity { @Override protected void onDestroy() { super.onDestroy(); + Log.d(LOG_TAG, "onDestroy"); mScriptEngine.put("activity", null); mScriptEngine.setTag("activity", null); mScriptEngine.destroy(); @@ -151,10 +149,8 @@ public class ScriptExecuteActivity extends AppCompatActivity { @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - if (mIntentExtras == null) - return; - IntentExtras extras = IntentExtras.newExtras().putAll(mIntentExtras); - outState.putInt(IntentExtras.EXTRA_ID, extras.getId()); + if (mScriptExecution != null) + outState.putInt(EXTRA_EXECUTION_ID, mScriptExecution.getId()); emit("save_instance_state", outState); } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java index 525c45de..a8493e44 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java @@ -5,6 +5,7 @@ import android.app.Activity; import android.content.Context; import android.os.Build; import android.os.Looper; +import android.util.Log; import com.stardust.app.GlobalAppContext; import com.stardust.autojs.R; @@ -333,7 +334,7 @@ public class ScriptRuntime { } } - public void loadDex(String path){ + public void loadDex(String path) { path = files.path(path); try { ((AndroidClassLoader) ContextFactory.getGlobal().getApplicationClassLoader()).loadDex(new File(path)); @@ -375,6 +376,7 @@ public class ScriptRuntime { } public void onExit() { + Log.d(TAG, "on exit"); //清除interrupt状态 ThreadCompat.interrupted(); //悬浮窗需要第一时间关闭以免出现恶意脚本全屏悬浮窗屏蔽屏幕并且在exit中写死循环的问题 @@ -398,6 +400,7 @@ public class ScriptRuntime { } ignoresException(sensors::unregisterAll); ignoresException(timers::recycle); + ignoresException(ui::recycle); } private void ignoresException(Runnable r) { diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Sensors.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Sensors.java index a2964dee..06cebbe6 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Sensors.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Sensors.java @@ -17,7 +17,6 @@ import java.lang.reflect.Field; import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; /** * Created by Stardust on 2018/2/5. @@ -92,7 +91,7 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler { mScriptBridges = runtime.bridges; mNoOpSensorEventEmitter = new SensorEventEmitter(runtime.bridges); mScriptRuntime = runtime; - runtime.loopers.addLooperQuiteHandler(this); + runtime.loopers.addLooperQuitHandler(this); } public SensorEventEmitter register(String sensorName) { @@ -167,5 +166,6 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler { } mSensorEventEmitters.clear(); } + mScriptRuntime.loopers.removeLooperQuitHandler(this); } } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java index 3ee193cd..e7b3980a 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java @@ -113,6 +113,10 @@ public class UI extends ProxyObject { } } + public void recycle(){ + mDynamicLayoutInflater.setContext(null); + } + private class Drawables extends com.stardust.autojs.core.ui.inflater.util.Drawables { @Override From 301a4286e5dc4e7c7d4e577ca143911b1902adc7 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 26 Sep 2018 23:43:13 +0800 Subject: [PATCH 08/14] fix: img.h not working; --- .../java/org/autojs/autojs/ui/common/ScriptOperations.java | 6 +++++- .../com/stardust/autojs/core/ui/widget/JsImageView.java | 2 +- .../java/com/stardust/autojs/project/ProjectConfig.java | 2 -- 3 files changed, 6 insertions(+), 4 deletions(-) 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 cf18a459..5d82198b 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 @@ -122,7 +122,11 @@ public class ScriptOperations { } private void notifyFileCreated(ScriptFile directory, ScriptFile scriptFile) { - mExplorer.notifyItemCreated(new ExplorerFileItem(scriptFile, mExplorerPage)); + if (scriptFile.isDirectory()) { + mExplorer.notifyItemCreated(new ExplorerDirPage(scriptFile, mExplorerPage)); + } else { + mExplorer.notifyItemCreated(new ExplorerFileItem(scriptFile, mExplorerPage)); + } } public void newFile() { diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsImageView.java b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsImageView.java index f37dcedf..a7317b39 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsImageView.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsImageView.java @@ -51,7 +51,7 @@ public class JsImageView extends RoundedImageView { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); + setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight()); if (mCircle) { setCornerRadius(getMeasuredWidth() / 2); } diff --git a/autojs/src/main/java/com/stardust/autojs/project/ProjectConfig.java b/autojs/src/main/java/com/stardust/autojs/project/ProjectConfig.java index b7d08797..a2ac8061 100644 --- a/autojs/src/main/java/com/stardust/autojs/project/ProjectConfig.java +++ b/autojs/src/main/java/com/stardust/autojs/project/ProjectConfig.java @@ -88,7 +88,6 @@ public class ProjectConfig { try { return fromJson(PFiles.read(context.getAssets().open(path))); } catch (Exception e) { - e.printStackTrace(); return null; } } @@ -97,7 +96,6 @@ public class ProjectConfig { try { return fromJson(PFiles.read(path)); } catch (Exception e) { - e.printStackTrace(); return null; } } From 00e687f10decf77e412cb6dbba131945f211f18e Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 26 Sep 2018 23:45:51 +0800 Subject: [PATCH 09/14] fix: crash on automator code generate --- .../com/stardust/autojs/codegeneration/ReadOnlyUiObject.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autojs/src/main/java/com/stardust/autojs/codegeneration/ReadOnlyUiObject.java b/autojs/src/main/java/com/stardust/autojs/codegeneration/ReadOnlyUiObject.java index c2fb2758..56aac9e5 100644 --- a/autojs/src/main/java/com/stardust/autojs/codegeneration/ReadOnlyUiObject.java +++ b/autojs/src/main/java/com/stardust/autojs/codegeneration/ReadOnlyUiObject.java @@ -17,12 +17,12 @@ public class ReadOnlyUiObject extends UiObject { private NodeInfo mNodeInfo; public ReadOnlyUiObject(NodeInfo info) { - super(info, info.depth, -1); + super(null, info.depth, -1); mNodeInfo = info; } public ReadOnlyUiObject(NodeInfo info, int indexInParent) { - super(info, info.depth, indexInParent); + super(null, info.depth, indexInParent); mNodeInfo = info; } From dcc09c40341a35ff893bb8a29207d544bf7a0939 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Thu, 27 Sep 2018 00:22:41 +0800 Subject: [PATCH 10/14] fix: cannot set w and h on root element of ui; fix: ui.post --- .../org/autojs/autojs/ui/splash/SplashActivity.java | 2 +- autojs/src/main/assets/modules/__ui__.js | 4 ++-- .../autojs/core/ui/inflater/DynamicLayoutInflater.java | 10 +++++++--- .../view/accessibility/AccessibilityService.java | 3 +-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/autojs/autojs/ui/splash/SplashActivity.java b/app/src/main/java/org/autojs/autojs/ui/splash/SplashActivity.java index fc73ba14..ec5f693a 100644 --- a/app/src/main/java/org/autojs/autojs/ui/splash/SplashActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/splash/SplashActivity.java @@ -51,7 +51,7 @@ public class SplashActivity extends BaseActivity { mNotStartMainActivity = getIntent().getBooleanExtra(NOT_START_MAIN_ACTIVITY, false); boolean forceShowAd = getIntent().getBooleanExtra(FORCE_SHOW_AD, false); setContentView(R.layout.activity_splash); - mFullScreenAdView = (FullScreenAdView) findViewById(R.id.full_screen_view); + mFullScreenAdView = findViewById(R.id.full_screen_view); if (!forceShowAd && !Pref.shouldShowAd()) { mFullScreenAdView.setVisibility(View.INVISIBLE); mHandler.postDelayed(this::enterNextActivity, 1500); diff --git a/autojs/src/main/assets/modules/__ui__.js b/autojs/src/main/assets/modules/__ui__.js index ba603891..e96a4b96 100644 --- a/autojs/src/main/assets/modules/__ui__.js +++ b/autojs/src/main/assets/modules/__ui__.js @@ -19,7 +19,7 @@ module.exports = function (runtime, global) { xml = xml.toXMLString(); } runtime.ui.layoutInflater.setContext(activity); - var view = runtime.ui.layoutInflater.inflate(xml); + var view = runtime.ui.layoutInflater.inflate(xml, activity.window.decorView, false); ui.setContentView(view); } @@ -80,7 +80,7 @@ module.exports = function (runtime, global) { ui.post = function (action, delay) { delay = delay || 0; - runtime.getUiHandler().postDelay(wrapUiAction(action), delay); + runtime.getUiHandler().postDelayed(wrapUiAction(action), delay); } ui.statusBarColor = function (color) { diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java index 6d1f1e17..a205c004 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java @@ -146,20 +146,24 @@ public class DynamicLayoutInflater { } public View inflate(String xml, @Nullable ViewGroup parent) { + return inflate(xml, parent, parent != null); + } + + public View inflate(String xml, @Nullable ViewGroup parent, boolean attachToParent) { View view = mLayoutInflaterDelegate.beforeInflation(xml, parent); if (view != null) return view; xml = convertXml(xml); - return mLayoutInflaterDelegate.afterInflation(doInflation(xml, parent), xml, parent); + return mLayoutInflaterDelegate.afterInflation(doInflation(xml, parent, attachToParent), xml, parent); } - protected View doInflation(String xml, @Nullable ViewGroup parent) { + protected View doInflation(String xml, @Nullable ViewGroup parent, boolean attachToParent) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(new ByteArrayInputStream(xml.getBytes())); - return inflate(document.getDocumentElement(), parent, true); + return inflate(document.getDocumentElement(), parent, attachToParent); } catch (Exception e) { throw new InflateException(e); } diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java index 79122996..5a993948 100644 --- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java +++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java @@ -24,7 +24,6 @@ import java.util.concurrent.locks.ReentrantLock; public class AccessibilityService extends android.accessibilityservice.AccessibilityService { - private static final String TAG = "AccessibilityService"; private static final SortedMap mDelegates = new TreeMap<>(); @@ -55,7 +54,7 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi @Override public void onAccessibilityEvent(final AccessibilityEvent event) { instance = this; - Log.v(TAG, "onAccessibilityEvent: " + event); + //Log.v(TAG, "onAccessibilityEvent: " + event); if (!containsAllEventTypes && !eventTypes.contains(event.getEventType())) return; int type = event.getEventType(); From cf16739e7531231e686ca87ad711ded5048d6dae Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Thu, 27 Sep 2018 13:56:08 +0800 Subject: [PATCH 11/14] fix: catch some crash on ui thread --- .../mozilla/javascript/VMBridge_custom.java | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java diff --git a/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java b/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java new file mode 100644 index 00000000..521b1084 --- /dev/null +++ b/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java @@ -0,0 +1,118 @@ +package org.mozilla.javascript; + +import android.os.Looper; +import android.util.Log; + +import org.mozilla.javascript.jdk15.VMBridge_jdk15; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class VMBridge_custom extends VMBridge_jdk15 { + + private static final String LOG_TAG = "VMBridge_custom"; + + public VMBridge_custom() throws SecurityException, InstantiationException { + } + + @Override + protected Object newInterfaceProxy(Object proxyHelper, ContextFactory cf, InterfaceAdapter adapter, Object target, Scriptable topScope) { + // --- The following code is copied from super class -- + Constructor c = (Constructor) proxyHelper; + InvocationHandler handler = (proxy, method, args) -> { + if (method.getDeclaringClass() == Object.class) { + String methodName = method.getName(); + if (methodName.equals("equals")) { + Object other = args[0]; + return proxy == other; + } + + if (methodName.equals("hashCode")) { + return target.hashCode(); + } + + if (methodName.equals("toString")) { + return "Proxy[" + target.toString() + "]"; + } + } + // Add thread check + //Check if the current thread is ui thread + if (Looper.myLooper() == Looper.getMainLooper()) { + // If so, catch any exception of invoking + // Because an exception on ui thread will cause the whole app to crash + try { + Object result = adapter.invoke(cf, target, topScope, proxy, method, args); + return castReturnValue(method, result); + } catch (Exception e) { + e.printStackTrace(); + // notify the script thread to exit + Object jsRuntime = topScope.get("runtime", null); + Log.d(LOG_TAG, "jsRuntime = " + jsRuntime); + if (jsRuntime instanceof NativeJavaObject) { + Object runtime = ((NativeJavaObject) jsRuntime).unwrap(); + Log.d(LOG_TAG, "runtime = " + runtime); + if(runtime instanceof com.stardust.autojs.runtime.ScriptRuntime){ + ((com.stardust.autojs.runtime.ScriptRuntime) runtime).exit(e); + } + } + // even if we caught the exception, we must return a value to for the method call. + return defaultValue(method.getReturnType()); + } + } else { + return castReturnValue(method, adapter.invoke(cf, target, topScope, proxy, method, args)); + } + }; + + // --- The following code is copied from super class -- + try { + Object proxy = c.newInstance(handler); + return proxy; + } catch (InvocationTargetException var10) { + throw Context.throwAsScriptRuntimeEx(var10); + } catch (IllegalAccessException var11) { + throw Kit.initCause(new IllegalStateException(), var11); + } catch (InstantiationException var12) { + throw Kit.initCause(new IllegalStateException(), var12); + } + } + + // cast the return value to boolean if needed. + // if a javascript function that implements a java interface returns nothing, + // it will be regarded as "false", like javascript behavior, instead of reporting error "undefined cannot be cast to boolean" + protected Object castReturnValue(Method method, Object returnValue) { + if (method.getReturnType().equals(Boolean.TYPE) || method.getReturnType().equals(Boolean.class)) { + return ScriptRuntime.toBoolean(returnValue); + } + return returnValue; + } + + protected Object defaultValue(Class type) { + if (type.equals(Boolean.TYPE) || type.equals(Boolean.class)) { + return false; + } + if (type.equals(Integer.TYPE) || type.equals(Integer.class)) { + return 0; + } + if (type.equals(Long.TYPE) || type.equals(Long.class)) { + return 0L; + } + if (type.equals(Float.TYPE) || type.equals(Float.class)) { + return 0F; + } + if (type.equals(Double.TYPE) || type.equals(Double.class)) { + return 0.0; + } + if (type.equals(Byte.TYPE) || type.equals(Byte.class)) { + return (byte) 0; + } + if (type.equals(Character.TYPE) || type.equals(Character.class)) { + return (char) 0; + } + if (type.isAssignableFrom(CharSequence.class)) { + return ""; + } + return null; + } +} From 025e594a010e702ac6ef6a51d6450c999808e003 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Fri, 28 Sep 2018 00:56:34 +0800 Subject: [PATCH 12/14] feat: intent task --- .idea/caches/build_file_checksums.ser | Bin 733 -> 733 bytes .idea/dictionaries/Stardust.xml | 1 + app/build.gradle | 5 - app/src/main/AndroidManifest.xml | 28 ++- app/src/main/java/org/autojs/autojs/App.java | 26 +-- .../BaseBroadcastReceiver.java} | 18 +- .../receiver/DynamicBroadcastReceiver.java | 79 +++++++ .../receiver/StaticBroadcastReceiver.java | 40 ++++ .../tasker/TaskerScriptEditActivity.java | 5 +- .../autojs/storage/database/BaseModel.java | 27 +++ .../autojs/storage/database/Database.java | 173 +++++++++++++++ .../storage/database/IntentTaskDatabase.java | 63 +++++- .../autojs/storage/database/ModelChange.java | 14 +- .../storage/database/TimedTaskDatabase.java | 74 ++++++- .../org/autojs/autojs/timing/IntentTask.java | 36 +-- .../autojs/autojs/timing/TaskReceiver.java | 2 +- .../org/autojs/autojs/timing/TimedTask.java | 55 +---- .../autojs/timing/TimedTaskManager.java | 114 +++++----- .../autojs/timing/TimedTaskScheduler.java | 6 +- .../autojs/ui/common/ScriptOperations.java | 2 + .../filechooser/FileChooserDialogBuilder.java | 2 +- .../org/autojs/autojs/ui/main/task/Task.java | 44 +++- .../autojs/autojs/ui/main/task/TaskGroup.java | 39 +++- .../ui/main/task/TaskListRecyclerView.java | 35 ++- .../ui/timing/TimedTaskSettingActivity.java | 56 +++-- .../layout/activity_timed_task_setting.xml | 78 ++++++- app/src/main/res/values/strings.xml | 8 +- .../main/java/com/stardust/util/BiMap.java | 11 + .../main/java/com/stardust/util/BiMaps.java | 206 ++++++++++++++++++ 29 files changed, 1008 insertions(+), 239 deletions(-) rename app/src/main/java/org/autojs/autojs/external/{boot/BootCompleteReceiver.java => receiver/BaseBroadcastReceiver.java} (71%) create mode 100644 app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceiver.java create mode 100644 app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java create mode 100644 app/src/main/java/org/autojs/autojs/storage/database/BaseModel.java create mode 100644 app/src/main/java/org/autojs/autojs/storage/database/Database.java create mode 100644 common/src/main/java/com/stardust/util/BiMap.java create mode 100644 common/src/main/java/com/stardust/util/BiMaps.java diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 4c2daf666ae5e458ff1e8b893dcae8e74665c0b2..d6a560997893d2dd4954d965d7a17989a86d8ae8 100644 GIT binary patch delta 37 vcmV+=0NVfE1>FUZmjz}S%&#PooOck8jREz+vWJovg&cHd`kmObBLTVrK?xA^ delta 37 vcmV+=0NVfE1>FUZmjz|;4iq1eoOcjU##(t~{6~5o(wuJUQQjuABLTVrFk}!9 diff --git a/.idea/dictionaries/Stardust.xml b/.idea/dictionaries/Stardust.xml index 4218d2eb..30ec0d12 100644 --- a/.idea/dictionaries/Stardust.xml +++ b/.idea/dictionaries/Stardust.xml @@ -3,6 +3,7 @@ capturer dismissable + flowable interruptible loopers prefill diff --git a/app/build.gradle b/app/build.gradle index 7c4f2275..0b280778 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -129,11 +129,6 @@ dependencies { exclude group: 'com.android.support' }) annotationProcessor 'com.github.bumptech.glide:compiler:4.2.0' - //dbflow - annotationProcessor "com.github.Raizlabs.DBFlow:dbflow-processor:4.1.2" - compile "com.github.Raizlabs.DBFlow:dbflow-core:4.1.2" - compile "com.github.Raizlabs.DBFlow:dbflow:4.1.2" - compile "com.github.Raizlabs.DBFlow:dbflow-rx2:4.1.2" //joda time compile 'joda-time:joda-time:2.9.9' // Tasker Plugin diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c0c87487..aa1cb820 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -133,10 +133,36 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/org/autojs/autojs/App.java b/app/src/main/java/org/autojs/autojs/App.java index b6335a4d..e42fae4d 100644 --- a/app/src/main/java/org/autojs/autojs/App.java +++ b/app/src/main/java/org/autojs/autojs/App.java @@ -1,11 +1,9 @@ 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; @@ -13,17 +11,17 @@ import android.widget.ImageView; import com.bumptech.glide.request.target.SimpleTarget; import com.bumptech.glide.request.transition.Transition; import com.flurry.android.FlurryAgent; -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; +import com.stardust.theme.ThemeColor; +import com.stardust.theme.ThemeColorManager; +import com.tencent.bugly.crashreport.CrashReport; import org.autojs.autojs.autojs.AutoJs; import org.autojs.autojs.autojs.key.GlobalKeyObserver; +import org.autojs.autojs.external.receiver.DynamicBroadcastReceiver; import org.autojs.autojs.network.GlideApp; import org.autojs.autojs.storage.database.IntentTaskDatabase; import org.autojs.autojs.storage.database.TimedTaskDatabase; @@ -31,11 +29,6 @@ import org.autojs.autojs.timing.TimedTaskScheduler; import org.autojs.autojs.tool.CrashHandler; import org.autojs.autojs.ui.error.ErrorReportActivity; -import com.stardust.theme.ThemeColor; -import com.stardust.theme.ThemeColorManager; -import com.tencent.bugly.crashreport.CrashReport; - - import java.lang.ref.WeakReference; /** @@ -48,6 +41,7 @@ public class App extends MultiDexApplication { private static final String BUGLY_APP_ID = "19b3607b53"; private static WeakReference instance; + private DynamicBroadcastReceiver mDynamicBroadcastReceiver; public static App getApp() { return instance.get(); @@ -92,17 +86,10 @@ public class App extends MultiDexApplication { return; } //LeakCanary.install(this); + } private void init() { - FlowManager.init(FlowConfig.builder(this) - .addDatabaseConfig(DatabaseConfig.builder(TimedTaskDatabase.class) - .modelNotifier(DirectModelNotifier.get()) - .build()) - .addDatabaseConfig(DatabaseConfig.builder(IntentTaskDatabase.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); @@ -111,6 +98,7 @@ public class App extends MultiDexApplication { } setupDrawableImageLoader(); TimedTaskScheduler.checkTasksRepeatedlyIfNeeded(this); + mDynamicBroadcastReceiver = new DynamicBroadcastReceiver(this); } private void setupDrawableImageLoader() { diff --git a/app/src/main/java/org/autojs/autojs/external/boot/BootCompleteReceiver.java b/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java similarity index 71% rename from app/src/main/java/org/autojs/autojs/external/boot/BootCompleteReceiver.java rename to app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java index 4e6be901..a7d68b87 100644 --- a/app/src/main/java/org/autojs/autojs/external/boot/BootCompleteReceiver.java +++ b/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java @@ -1,4 +1,4 @@ -package org.autojs.autojs.external.boot; +package org.autojs.autojs.external.receiver; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; @@ -7,6 +7,7 @@ import android.content.Intent; import android.util.Log; import android.widget.Toast; +import com.stardust.app.GlobalAppContext; import com.stardust.autojs.execution.ExecutionConfig; import org.autojs.autojs.autojs.AutoJs; @@ -17,23 +18,25 @@ import org.autojs.autojs.timing.TimedTaskManager; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; -public class BootCompleteReceiver extends BroadcastReceiver { +public class BaseBroadcastReceiver extends BroadcastReceiver { - private static final String LOG_TAG = "BootCompleteReceiver"; + private static final String LOG_TAG = "BaseBroadcastReceiver"; @SuppressLint("CheckResult") - @Override public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { - Log.i(LOG_TAG, "on boot complete"); + Log.d(LOG_TAG, "onReceive: action = " + intent.getAction() + ", intent = " + intent); + try { TimedTaskManager.getInstance().getIntentTaskOfAction(intent.getAction()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(intentTask -> runTask(context, intent, intentTask), Throwable::printStackTrace); + } catch (Exception e) { + GlobalAppContext.toast(e.getMessage()); } } - private void runTask(Context context, Intent intent, IntentTask task) { + static void runTask(Context context, Intent intent, IntentTask task) { + Log.d(LOG_TAG, "runTask: action = " + intent.getAction() + ", script = " + task.getScriptPath()); ScriptFile file = new ScriptFile(task.getScriptPath()); ExecutionConfig config = new ExecutionConfig(); config.setArgument("intent", intent.clone()); @@ -45,4 +48,5 @@ public class BootCompleteReceiver extends BroadcastReceiver { Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show(); } } + } diff --git a/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceiver.java b/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceiver.java new file mode 100644 index 00000000..62ff15c5 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceiver.java @@ -0,0 +1,79 @@ +package org.autojs.autojs.external.receiver; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.AudioManager; +import android.os.Build; + +import org.autojs.autojs.BuildConfig; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static android.content.Intent.ACTION_BATTERY_CHANGED; +import static android.content.Intent.ACTION_CONFIGURATION_CHANGED; +import static android.content.Intent.ACTION_DATE_CHANGED; +import static android.content.Intent.ACTION_PACKAGES_SUSPENDED; +import static android.content.Intent.ACTION_PACKAGES_UNSUSPENDED; +import static android.content.Intent.ACTION_PACKAGE_ADDED; +import static android.content.Intent.ACTION_PACKAGE_CHANGED; +import static android.content.Intent.ACTION_PACKAGE_DATA_CLEARED; +import static android.content.Intent.ACTION_PACKAGE_REMOVED; +import static android.content.Intent.ACTION_PACKAGE_RESTARTED; +import static android.content.Intent.ACTION_POWER_CONNECTED; +import static android.content.Intent.ACTION_POWER_DISCONNECTED; +import static android.content.Intent.ACTION_SHUTDOWN; +import static android.content.Intent.ACTION_TIMEZONE_CHANGED; +import static android.content.Intent.ACTION_TIME_CHANGED; +import static android.content.Intent.ACTION_TIME_TICK; +import static android.content.Intent.ACTION_UID_REMOVED; + +public class DynamicBroadcastReceiver extends BaseBroadcastReceiver { + + private static final List DEFAULT_ACTIONS = new ArrayList<>(Arrays.asList( + ACTION_TIME_TICK, + ACTION_BATTERY_CHANGED, + ACTION_CONFIGURATION_CHANGED + )); + + static { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + DEFAULT_ACTIONS.addAll(Arrays.asList( + ACTION_PACKAGES_SUSPENDED, + ACTION_PACKAGES_UNSUSPENDED + )); + } + } + + private boolean mRegistered = false; + private final Set mActions = new LinkedHashSet<>(); + private final Context mContext; + + + public DynamicBroadcastReceiver(Context context) { + mContext = context; + register(DEFAULT_ACTIONS); + } + + public void register(List actions) { + int oldSize = mActions.size(); + mActions.addAll(actions); + if (oldSize == mActions.size()) { + return; + } + IntentFilter filter = new IntentFilter(); + for (String action : mActions) { + filter.addAction(action); + } + if(mRegistered){ + mContext.unregisterReceiver(this); + } + mContext.registerReceiver(this, filter); + mRegistered = true; + } + +} diff --git a/app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java b/app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java new file mode 100644 index 00000000..55b93726 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java @@ -0,0 +1,40 @@ +package org.autojs.autojs.external.receiver; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class StaticBroadcastReceiver extends BaseBroadcastReceiver { + + static final List ACTIONS = new ArrayList<>(Arrays.asList( + "android.intent.action.BOOT_COMPLETED", + "android.intent.action.QUICKBOOT_POWERON", + "android.intent.action.TIME_SET", + "android.intent.action.TIMEZONE_CHANGED", + "android.intent.action.PACKAGE_ADDED", + "android.intent.action.PACKAGE_CHANGED", + "android.intent.action.PACKAGE_DATA_CLEARED", + "android.intent.action.PACKAGE_REMOVED", + "android.intent.action.PACKAGE_RESTARTED", + "android.intent.action.UID_REMOVED", + "android.intent.action.ACTION_POWER_CONNECTED", + "android.intent.action.ACTION_POWER_DISCONNECTED", + "android.intent.action.ACTION_SHUTDOWN", + "android.intent.action.DATE_CHANGED", + "android.intent.action.DREAMING_STARTED", + "android.intent.action.DREAMING_STOPPED", + "android.intent.action.HEADSET_PLUG", + "android.intent.action.INPUT_METHOD_CHANGED", + "android.intent.action.LOCALE_CHANGED", + "android.intent.action.MEDIA_BUTTON", + "android.intent.action.MEDIA_CHECKING", + "android.intent.action.MEDIA_MOUNTED", + "android.intent.action.PACKAGE_FIRST_LAUNCH", + "android.intent.action.PROVIDER_CHANGED", + "android.intent.action.WALLPAPER_CHANGED", + "android.intent.action.USER_UNLOCKED", + "android.intent.action.USER_PRESENT", + "android.net.conn.CONNECTIVITY_CHANGE" + )); + +} 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 4c0de0a1..764ad4e5 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 @@ -6,6 +6,7 @@ import android.content.Intent; import android.widget.Toast; import org.autojs.autojs.R; +import org.autojs.autojs.timing.TaskReceiver; import org.autojs.autojs.tool.EmptyObservers; import org.autojs.autojs.ui.BaseActivity; import org.autojs.autojs.ui.edit.EditorView; @@ -29,7 +30,9 @@ import static org.autojs.autojs.ui.edit.EditorView.EXTRA_SAVE_ENABLED; @EActivity(R.layout.activity_tasker_script_edit) public class TaskerScriptEditActivity extends BaseActivity { - public static final int REQUEST_CODE = "Love you. Can we go back?".hashCode() >> 16; + public static final int REQUEST_CODE = 10016; + public static final String EXTRA_INTENT_TASK_ID = "intent_task_id"; + public static final String EXTRA_TASK_ID = TaskReceiver.EXTRA_TASK_ID; public static void edit(Activity activity, String title, String summary, String content) { activity.startActivityForResult(new Intent(activity, TaskerScriptEditActivity_.class) diff --git a/app/src/main/java/org/autojs/autojs/storage/database/BaseModel.java b/app/src/main/java/org/autojs/autojs/storage/database/BaseModel.java new file mode 100644 index 00000000..76be2ef1 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/storage/database/BaseModel.java @@ -0,0 +1,27 @@ +package org.autojs.autojs.storage.database; + + +public abstract class BaseModel { + private long mId; + + public void setId(long id) { + mId = id; + } + + public long getId() { + return mId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BaseModel baseModel = (BaseModel) o; + return mId == baseModel.mId; + } + + @Override + public int hashCode() { + return (int)(mId ^ (mId >>> 32)); + } +} diff --git a/app/src/main/java/org/autojs/autojs/storage/database/Database.java b/app/src/main/java/org/autojs/autojs/storage/database/Database.java new file mode 100644 index 00000000..d42fea78 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/storage/database/Database.java @@ -0,0 +1,173 @@ +package org.autojs.autojs.storage.database; + +import android.content.ContentValues; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.autojs.autojs.timing.IntentTask; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.Callable; + +import io.reactivex.Flowable; +import io.reactivex.Observable; +import io.reactivex.schedulers.Schedulers; +import io.reactivex.subjects.PublishSubject; + +public abstract class Database { + + private final SQLiteDatabase mWritableSQLiteDatabase; + private final SQLiteDatabase mReadableSQLiteDatabase; + private final String mTable; + private final PublishSubject> mModelChange = PublishSubject.create(); + + public Database(SQLiteOpenHelper sqLiteOpenHelper, String table) { + mWritableSQLiteDatabase = sqLiteOpenHelper.getWritableDatabase(); + mReadableSQLiteDatabase = sqLiteOpenHelper.getWritableDatabase(); + mTable = table; + } + + public Observable exec(Callable callable) { + return Observable.fromCallable(callable) + .subscribeOn(Schedulers.io()); + } + + public Flowable execFlowable(Callable callable) { + return Flowable.fromCallable(callable) + .subscribeOn(Schedulers.io()); + } + + public PublishSubject> getModelChange() { + return mModelChange; + } + + public Observable delete(M model) { + return exec(() -> { + int delete = mWritableSQLiteDatabase.delete(mTable, "id = ?", + new String[]{String.valueOf(model.getId())}); + if (delete >= 1) { + mModelChange.onNext(new ModelChange<>(model, ModelChange.DELETE)); + } + return delete; + }); + } + + public Observable update(M model) { + return exec(() -> { + ContentValues values = asContentValues(model); + int update = mWritableSQLiteDatabase.update(mTable, values, "id = ?", arg(model.getId())); + if (update >= 1) { + mModelChange.onNext(new ModelChange<>(model, ModelChange.UPDATE)); + } + return update; + }); + } + + + public Observable insert(M model) { + return exec(() -> { + ContentValues values = asContentValues(model); + long id = mWritableSQLiteDatabase.insertOrThrow(mTable, null, values); + if (id >= 0) { + model.setId(id); + mModelChange.onNext(new ModelChange<>(model, ModelChange.INSERT)); + } + return id; + }); + } + + + protected abstract M createModelFromCursor(Cursor cursor); + + protected abstract ContentValues asContentValues(M model); + + public M queryById(long id) { + Cursor cursor = mReadableSQLiteDatabase.rawQuery("SELECT * FROM " + mTable + " WHERE id = ?", arg(id)); + if (!cursor.moveToFirst()) { + return null; + } + M model = createModelFromCursor(cursor); + cursor.close(); + return model; + } + + + public Flowable queryAllAsFlowable() { + return execFlowable(() -> + mReadableSQLiteDatabase.rawQuery("SELECT * FROM " + mTable, null) + ) + .flatMap(cursor -> Flowable.fromIterable(() -> new CursorIterator(cursor))) + .map(this::createModelFromCursor); + } + + public List queryAll() { + ArrayList list = new ArrayList<>(); + Cursor cursor = mReadableSQLiteDatabase.rawQuery("SELECT * FROM " + mTable, null); + while (cursor.moveToNext()) { + list.add(createModelFromCursor(cursor)); + } + cursor.close(); + return list; + } + + public long count() { + Cursor cursor = mReadableSQLiteDatabase.rawQuery("SELECT COUNT(*) FROM " + mTable, null); + if (cursor.moveToFirst()) { + return cursor.getLong(0); + } + cursor.close(); + return 0; + } + + + public Flowable query(String sql, Object... args) { + String[] strArgs = args(args); + return execFlowable(() -> + mReadableSQLiteDatabase.query(mTable, null, sql, strArgs, null, null, null) + ) + .flatMap(cursor -> Flowable.fromIterable(() -> new CursorIterator(cursor))) + .map(this::createModelFromCursor); + } + + private String[] args(Object[] args) { + if (args == null || args.length == 0) { + return null; + } + String[] a = new String[args.length]; + for (int i = 0; i < args.length; i++) { + a[i] = String.valueOf(args[i]); + } + return a; + } + + private String[] arg(Object value) { + return new String[]{String.valueOf(value)}; + } + + + private static class CursorIterator implements Iterator { + + private final Cursor mCursor; + + private CursorIterator(Cursor cursor) { + mCursor = cursor; + } + + @Override + public boolean hasNext() { + boolean next = mCursor.moveToNext(); + if (!next) { + mCursor.close(); + } + return next; + } + + @Override + public Cursor next() { + return mCursor; + } + } +} diff --git a/app/src/main/java/org/autojs/autojs/storage/database/IntentTaskDatabase.java b/app/src/main/java/org/autojs/autojs/storage/database/IntentTaskDatabase.java index 9ecc720d..9a8803d3 100644 --- a/app/src/main/java/org/autojs/autojs/storage/database/IntentTaskDatabase.java +++ b/app/src/main/java/org/autojs/autojs/storage/database/IntentTaskDatabase.java @@ -1,7 +1,64 @@ package org.autojs.autojs.storage.database; -import com.raizlabs.android.dbflow.annotation.Database; -@Database(version = 1) -public class IntentTaskDatabase { +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.autojs.autojs.timing.IntentTask; + +public class IntentTaskDatabase extends Database { + + private static final int VERSION = 1; + private static final String NAME = "IntentTaskDatabase"; + + public IntentTaskDatabase(Context context){ + super(new SQLHelper(context), IntentTask.TABLE); + } + + @Override + protected ContentValues asContentValues(IntentTask model) { + ContentValues values = new ContentValues(); + values.put("script_path", model.getScriptPath()); + values.put("action", model.getAction()); + values.put("category", model.getCategory()); + values.put("data_type", model.getDataType()); + return values; + } + + @Override + protected IntentTask createModelFromCursor(Cursor cursor) { + IntentTask task = new IntentTask(); + task.setId(cursor.getInt(0)); + task.setScriptPath(cursor.getString(1)); + task.setAction(cursor.getString(2)); + task.setCategory(cursor.getString(3)); + task.setDataType(cursor.getString(4)); + return task; + } + + + private static class SQLHelper extends SQLiteOpenHelper { + + public SQLHelper(Context context) { + super(context, NAME + ".db", null, VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE `" + IntentTask.TABLE + "`(" + + "`id` INTEGER PRIMARY KEY AUTOINCREMENT, " + + "`script_path` TEXT NOT NULL ON CONFLICT FAIL, " + + "`action` TEXT, " + + "`category` TEXT, " + + "`data_type` TEXT);"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + + } + } } diff --git a/app/src/main/java/org/autojs/autojs/storage/database/ModelChange.java b/app/src/main/java/org/autojs/autojs/storage/database/ModelChange.java index 2f8c9ff2..4cb78f77 100644 --- a/app/src/main/java/org/autojs/autojs/storage/database/ModelChange.java +++ b/app/src/main/java/org/autojs/autojs/storage/database/ModelChange.java @@ -1,6 +1,5 @@ package org.autojs.autojs.storage.database; -import com.raizlabs.android.dbflow.structure.BaseModel; /** * Created by Stardust on 2017/11/28. @@ -8,10 +7,15 @@ import com.raizlabs.android.dbflow.structure.BaseModel; public class ModelChange { - private final M mData; - private final BaseModel.Action mAction; + public static final int INSERT = 1; + public static final int UPDATE = 2; + public static final int DELETE = 3; - public ModelChange(M data, BaseModel.Action action) { + + private final M mData; + private final int mAction; + + public ModelChange(M data, int action) { mData = data; mAction = action; } @@ -20,7 +24,7 @@ public class ModelChange { return mData; } - public BaseModel.Action getAction() { + public int getAction() { return mAction; } diff --git a/app/src/main/java/org/autojs/autojs/storage/database/TimedTaskDatabase.java b/app/src/main/java/org/autojs/autojs/storage/database/TimedTaskDatabase.java index 8e3fc3c9..868de3df 100644 --- a/app/src/main/java/org/autojs/autojs/storage/database/TimedTaskDatabase.java +++ b/app/src/main/java/org/autojs/autojs/storage/database/TimedTaskDatabase.java @@ -1,12 +1,74 @@ package org.autojs.autojs.storage.database; -import com.raizlabs.android.dbflow.annotation.Database; -/** - * Created by Stardust on 2017/11/28. - */ -@Database(version = 1) -public class TimedTaskDatabase { +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import org.autojs.autojs.timing.TimedTask; + +public class TimedTaskDatabase extends Database { + + private static final int VERSION = 3; + private static final String NAME = "TimedTaskDatabase"; + + public TimedTaskDatabase(Context context) { + super(new SQLHelper(context), TimedTask.TABLE); + } + + @Override + protected ContentValues asContentValues(TimedTask model) { + ContentValues values = new ContentValues(); + values.put("time", model.getTimeFlag()); + values.put("scheduled", model.isScheduled()); + values.put("delay", model.getDelay()); + values.put("interval", model.getInterval()); + values.put("loop_times", model.getLoopTimes()); + values.put("millis", model.getMillis()); + values.put("script_path", model.getScriptPath()); + return values; + } + + @Override + protected TimedTask createModelFromCursor(Cursor cursor) { + TimedTask task = new TimedTask(); + task.setId(cursor.getInt(0)); + task.setTimeFlag(cursor.getLong(1)); + task.setScheduled(cursor.getInt(2) != 0); + task.setDelay(cursor.getLong(3)); + task.setInterval(cursor.getLong(4)); + task.setLoopTimes(cursor.getInt(5)); + task.setMillis(cursor.getLong(6)); + task.setScriptPath(cursor.getString(7)); + return task; + } + + + private static class SQLHelper extends SQLiteOpenHelper { + + public SQLHelper(Context context) { + super(context, NAME + ".db", null, VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE `" + TimedTask.TABLE + "`(" + + "`id` INTEGER PRIMARY KEY AUTOINCREMENT, " + + "`time` INTEGER, " + + "`scheduled` INTEGER, " + + "`delay` INTEGER, " + + "`interval` INTEGER, " + + "`loop_times` INTEGER, " + + "`millis` INTEGER, " + + "`script_path` TEXT);"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + + } + } } diff --git a/app/src/main/java/org/autojs/autojs/timing/IntentTask.java b/app/src/main/java/org/autojs/autojs/timing/IntentTask.java index 937e47fa..1937ea84 100644 --- a/app/src/main/java/org/autojs/autojs/timing/IntentTask.java +++ b/app/src/main/java/org/autojs/autojs/timing/IntentTask.java @@ -2,33 +2,19 @@ package org.autojs.autojs.timing; import android.content.IntentFilter; -import com.raizlabs.android.dbflow.annotation.Column; -import com.raizlabs.android.dbflow.annotation.NotNull; -import com.raizlabs.android.dbflow.annotation.PrimaryKey; -import com.raizlabs.android.dbflow.annotation.Table; +import org.autojs.autojs.storage.database.BaseModel; -import org.autojs.autojs.storage.database.IntentTaskDatabase; -import org.autojs.autojs.storage.database.TimedTaskDatabase; +public class IntentTask extends BaseModel { -@Table(database = IntentTaskDatabase.class) -public class IntentTask { + public static final String TABLE = "IntentTask"; - @PrimaryKey(autoincrement = true, quickCheckAutoIncrement = true) - @Column(name = "id") - int mId = -1; + private String mScriptPath; - @NotNull - @Column(name = "script_path") - String mScriptPath; + private String mAction; - @Column(name = "action") - String mAction; + private String mCategory; - @Column(name = "category") - String mCategory; - - @Column(name = "data_type") - String mDataType; + private String mDataType; public IntentFilter getIntentFilter() { IntentFilter filter = new IntentFilter(); @@ -48,14 +34,6 @@ public class IntentTask { return filter; } - public int getId() { - return mId; - } - - public void setId(int id) { - mId = id; - } - public String getScriptPath() { return mScriptPath; } diff --git a/app/src/main/java/org/autojs/autojs/timing/TaskReceiver.java b/app/src/main/java/org/autojs/autojs/timing/TaskReceiver.java index 56cf7f31..85a618e3 100644 --- a/app/src/main/java/org/autojs/autojs/timing/TaskReceiver.java +++ b/app/src/main/java/org/autojs/autojs/timing/TaskReceiver.java @@ -20,7 +20,7 @@ public class TaskReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { ScriptIntents.handleIntent(context, intent); - int id = intent.getIntExtra(EXTRA_TASK_ID, -1); + long id = intent.getLongExtra(EXTRA_TASK_ID, -1); if (id >= 0) { TimedTaskManager.getInstance().notifyTaskFinished(id); } diff --git a/app/src/main/java/org/autojs/autojs/timing/TimedTask.java b/app/src/main/java/org/autojs/autojs/timing/TimedTask.java index 44999aee..63a861ac 100644 --- a/app/src/main/java/org/autojs/autojs/timing/TimedTask.java +++ b/app/src/main/java/org/autojs/autojs/timing/TimedTask.java @@ -4,13 +4,10 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -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 org.autojs.autojs.external.ScriptIntents; -import org.autojs.autojs.storage.database.TimedTaskDatabase; +import org.autojs.autojs.external.ScriptIntents; +import org.autojs.autojs.storage.database.BaseModel; import org.joda.time.DateTime; import org.joda.time.DateTimeConstants; import org.joda.time.LocalDateTime; @@ -19,11 +16,9 @@ import org.joda.time.LocalTime; import java.util.concurrent.TimeUnit; -/** - * Created by Stardust on 2017/11/27. - */ -@Table(database = TimedTaskDatabase.class) -public class TimedTask { +public class TimedTask extends BaseModel { + + public static final String TABLE = "TimedTask"; private static final int FLAG_DISPOSABLE = 0; public final static int FLAG_SUNDAY = 0x1; @@ -36,29 +31,18 @@ public class TimedTask { private static final int FLAG_EVERYDAY = 0x7F; private static final int REQUEST_CODE = 2000; - @PrimaryKey(autoincrement = true, quickCheckAutoIncrement = true) - @Column(name = "id") - int mId = -1; - - @Column(name = "time") long mTimeFlag; - @Column(name = "scheduled") boolean mScheduled; - @Column(name = "delay") long mDelay = 0; - @Column(name = "interval") long mInterval = 0; - @Column(name = "loop_times") int mLoopTimes = 1; - @Column(name = "millis") long mMillis; - @Column(name = "script_path") String mScriptPath; public TimedTask() { @@ -148,19 +132,10 @@ public class TimedTask { return mMillis; } - public int getId() { - return mId; - } - public String getScriptPath() { return mScriptPath; } - - public void setId(int id) { - mId = id; - } - public long getTimeFlag() { return mTimeFlag; } @@ -207,7 +182,7 @@ public class TimedTask { public Intent createIntent() { return new Intent(TaskReceiver.ACTION_TASK) - .putExtra(TaskReceiver.EXTRA_TASK_ID, mId) + .putExtra(TaskReceiver.EXTRA_TASK_ID, getId()) .putExtra(ScriptIntents.EXTRA_KEY_PATH, mScriptPath) .putExtra(ScriptIntents.EXTRA_KEY_DELAY, mDelay) .putExtra(ScriptIntents.EXTRA_KEY_LOOP_TIMES, mLoopTimes) @@ -216,14 +191,14 @@ public class TimedTask { public PendingIntent createPendingIntent(Context context) { - return PendingIntent.getBroadcast(context, REQUEST_CODE + 1 + getId(), + return PendingIntent.getBroadcast(context, (int) ((REQUEST_CODE + 1 + getId()) % 65535), createIntent(), PendingIntent.FLAG_UPDATE_CURRENT); } @Override public String toString() { return "TimedTask{" + - "mId=" + mId + + "mId=" + getId() + ", mTimeFlag=" + mTimeFlag + ", mScheduled=" + mScheduled + ", mDelay=" + mDelay + @@ -234,20 +209,6 @@ public class TimedTask { '}'; } - @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); diff --git a/app/src/main/java/org/autojs/autojs/timing/TimedTaskManager.java b/app/src/main/java/org/autojs/autojs/timing/TimedTaskManager.java index 9640c9e3..97169850 100644 --- a/app/src/main/java/org/autojs/autojs/timing/TimedTaskManager.java +++ b/app/src/main/java/org/autojs/autojs/timing/TimedTaskManager.java @@ -1,28 +1,20 @@ package org.autojs.autojs.timing; +import android.annotation.SuppressLint; import android.content.Context; -import android.content.Intent; -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.app.GlobalAppContext; -import org.autojs.autojs.Pref; +import org.autojs.autojs.storage.database.IntentTaskDatabase; import org.autojs.autojs.storage.database.ModelChange; +import org.autojs.autojs.storage.database.TimedTaskDatabase; +import org.autojs.autojs.tool.EmptyObservers; -import java.io.File; import java.util.List; import io.reactivex.Flowable; import io.reactivex.Observable; -import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.PublishSubject; /** @@ -31,12 +23,10 @@ import io.reactivex.subjects.PublishSubject; //TODO rx public class TimedTaskManager { - private static TimedTaskManager sInstance; - private ModelAdapter mTimedTaskModelAdapter; - private ModelAdapter mIntentTaskModelAdapter; private Context mContext; - private PublishSubject> mTimedTaskChanges = PublishSubject.create(); + private TimedTaskDatabase mTimedTaskDatabase; + private IntentTaskDatabase mIntentTaskDatabase; public static TimedTaskManager getInstance() { if (sInstance == null) { @@ -45,104 +35,108 @@ public class TimedTaskManager { return sInstance; } + @SuppressLint("CheckResult") public TimedTaskManager(Context context) { mContext = context; - mTimedTaskModelAdapter = FlowManager.getModelAdapter(TimedTask.class); - mIntentTaskModelAdapter = FlowManager.getModelAdapter(IntentTask.class); - DirectModelNotifier.get().registerForModelChanges(TimedTask.class, new DirectModelNotifier.ModelChangedListener() { - @Override - public void onModelChanged(@NonNull TimedTask model, @NonNull BaseModel.Action action) { - mTimedTaskChanges.onNext(new ModelChange<>(model, action)); - if (action == BaseModel.Action.DELETE && countTasks() == 0) { - TimedTaskScheduler.stopRtcRepeating(mContext); - } else if (action == BaseModel.Action.INSERT) { - TimedTaskScheduler.checkTasksRepeatedlyIfNeeded(mContext); - } - } - - @Override - public void onTableChanged(@Nullable Class tableChanged, @NonNull BaseModel.Action action) { - + mTimedTaskDatabase = new TimedTaskDatabase(context); + mIntentTaskDatabase = new IntentTaskDatabase(context); + mTimedTaskDatabase.getModelChange().subscribe(change -> { + int action = change.getAction(); + if (action == ModelChange.DELETE && countTasks() == 0) { + TimedTaskScheduler.stopRtcRepeating(mContext); + } else if (action == ModelChange.INSERT) { + TimedTaskScheduler.checkTasksRepeatedlyIfNeeded(mContext); } }); } - public void notifyTaskFinished(int id) { + @SuppressLint("CheckResult") + public void notifyTaskFinished(long id) { TimedTask task = getTimedTask(id); if (task == null) return; if (task.isDisposable()) { - mTimedTaskModelAdapter.delete(task); + mTimedTaskDatabase.delete(task) + .subscribe(EmptyObservers.consumer(), Throwable::printStackTrace); } else { task.setScheduled(false); - mTimedTaskModelAdapter.update(task); + mTimedTaskDatabase.update(task) + .subscribe(EmptyObservers.consumer(), Throwable::printStackTrace); } } + @SuppressLint("CheckResult") public void removeTask(TimedTask timedTask) { TimedTaskScheduler.cancel(mContext, timedTask); - mTimedTaskModelAdapter.delete(timedTask); + mTimedTaskDatabase.delete(timedTask) + .subscribe(EmptyObservers.consumer(), Throwable::printStackTrace); } + @SuppressLint("CheckResult") public void addTask(TimedTask timedTask) { - mTimedTaskModelAdapter.insert(timedTask); + mTimedTaskDatabase.insert(timedTask) + .subscribe(EmptyObservers.consumer(), Throwable::printStackTrace);; TimedTaskScheduler.scheduleTaskIfNeeded(mContext, timedTask); } + @SuppressLint("CheckResult") public void addTask(IntentTask intentTask) { - mIntentTaskModelAdapter.insert(intentTask); + mIntentTaskDatabase.insert(intentTask) + .subscribe(EmptyObservers.consumer(), Throwable::printStackTrace); } + @SuppressLint("CheckResult") public void removeTask(IntentTask intentTask) { - mIntentTaskModelAdapter.delete(intentTask); + mIntentTaskDatabase.delete(intentTask) + .subscribe(EmptyObservers.consumer(), Throwable::printStackTrace);; } public Flowable getAllTasks() { - return RXSQLite.rx(SQLite.select().from(TimedTask.class)) - .queryStreamResults() - .subscribeOn(Schedulers.io()); + return mTimedTaskDatabase.queryAllAsFlowable(); } public Flowable getIntentTaskOfAction(String action) { - IntentTask intentTask = new IntentTask(); - intentTask.setAction(Intent.ACTION_BOOT_COMPLETED); - intentTask.setScriptPath(new File(Pref.getScriptDirPath(), "boot.js").getPath()); - return Flowable.just(intentTask); -// return RXSQLite.rx(SQLite.select().from(IntentTask.class)) -// .queryStreamResults() -// .subscribeOn(Schedulers.io()); + return mIntentTaskDatabase.query("action = ?", action); } public Observable> getTimeTaskChanges() { - return mTimedTaskChanges; + return mTimedTaskDatabase.getModelChange(); } + @SuppressLint("CheckResult") public void notifyTaskScheduled(TimedTask timedTask) { timedTask.setScheduled(true); - mTimedTaskModelAdapter.update(timedTask); + mTimedTaskDatabase.update(timedTask) + .subscribe(EmptyObservers.consumer(), Throwable::printStackTrace); } public List getAllTasksAsList() { - return SQLite.select().from(TimedTask.class) - .queryList(); + return mTimedTaskDatabase.queryAll(); } - public TimedTask getTimedTask(int taskId) { - return SQLite.select() - .from(TimedTask.class) - .where(TimedTask_Table.id.is(taskId)) - .querySingle(); + public TimedTask getTimedTask(long taskId) { + return mTimedTaskDatabase.queryById(taskId); } + @SuppressLint("CheckResult") public void updateTask(TimedTask task) { - mTimedTaskModelAdapter.update(task); + mTimedTaskDatabase.update(task) + .subscribe(EmptyObservers.consumer(), Throwable::printStackTrace); TimedTaskScheduler.cancel(mContext, task); TimedTaskScheduler.scheduleTaskIfNeeded(mContext, task); } public long countTasks() { - return SQLite.select().from(TimedTask.class).count(); + return mTimedTaskDatabase.count(); + } + + public List getAllIntentTasksAsList() { + return mIntentTaskDatabase.queryAll(); + } + + public Observable> getIntentTaskChanges() { + return mIntentTaskDatabase.getModelChange(); } } diff --git a/app/src/main/java/org/autojs/autojs/timing/TimedTaskScheduler.java b/app/src/main/java/org/autojs/autojs/timing/TimedTaskScheduler.java index 5373d21c..62356666 100644 --- a/app/src/main/java/org/autojs/autojs/timing/TimedTaskScheduler.java +++ b/app/src/main/java/org/autojs/autojs/timing/TimedTaskScheduler.java @@ -28,7 +28,6 @@ public class TimedTaskScheduler extends BroadcastReceiver { private static final long INTERVAL = TimeUnit.MINUTES.toMillis(1); private static final long ONE_HOUR = TimeUnit.HOURS.toMillis(1); private static PendingIntent sCheckTasksPendingIntent; - private static long mNextRtcWakeupMillis = -1; @Override public void onReceive(Context context, Intent intent) { @@ -38,7 +37,7 @@ public class TimedTaskScheduler extends BroadcastReceiver { } @SuppressLint("CheckResult") - private static void checkTasks(Context context) { + public static void checkTasks(Context context) { TimedTaskManager.getInstance().getAllTasks() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -83,7 +82,7 @@ public class TimedTaskScheduler extends BroadcastReceiver { public static void checkTasksRepeatedlyIfNeeded(Context context) { - if (TimedTaskManager.getInstance().countTasks() > 0 && mNextRtcWakeupMillis > 0) { + if (TimedTaskManager.getInstance().countTasks() > 0) { setupNextRtcWakeup(context, System.currentTimeMillis() + 5000); } } @@ -95,7 +94,6 @@ public class TimedTaskScheduler extends BroadcastReceiver { } AlarmManager alarmManager = getAlarmManager(context); setExactCompat(alarmManager, createTaskCheckPendingIntent(context), millis); - mNextRtcWakeupMillis = millis; } 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 5d82198b..5803da69 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 @@ -22,6 +22,7 @@ import com.stardust.app.GlobalAppContext; import com.stardust.pio.PFile; import com.stardust.pio.PFiles; import com.stardust.pio.UncheckedIOException; +import com.tencent.bugly.crashreport.BuglyLog; import org.autojs.autojs.Pref; import org.autojs.autojs.R; @@ -319,6 +320,7 @@ public class ScriptOperations { public Observable download(String url) { + BuglyLog.i(LOG_TAG, "dir = " + Pref.getScriptDirPath() + ", sdcard = " + Environment.getExternalStorageDirectory() + ", url = " + url); String fileName = DownloadManager.parseFileNameLocally(url); return new FileChooserDialogBuilder(mContext) .title(R.string.text_select_save_path) diff --git a/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java b/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java index 7021f7d0..abd73d02 100644 --- a/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java +++ b/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java @@ -6,6 +6,7 @@ import android.support.annotation.StringRes; import com.afollestad.materialdialogs.MaterialDialog; import com.stardust.pio.PFile; +import com.tencent.bugly.crashreport.BuglyLog; import org.autojs.autojs.R; import org.autojs.autojs.model.explorer.Explorer; @@ -66,7 +67,6 @@ public class FileChooserDialogBuilder extends ThemeColorMaterialDialogBuilder { public FileChooserDialogBuilder dir(String rootDir, String initialDir) { mRootDir = rootDir; mInitialDir = initialDir; - return this; } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/task/Task.java b/app/src/main/java/org/autojs/autojs/ui/main/task/Task.java index a6ed37aa..4e5e03f4 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/task/Task.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/task/Task.java @@ -8,6 +8,7 @@ import com.stardust.autojs.script.JavaScriptSource; import com.stardust.pio.PFiles; import org.autojs.autojs.R; +import org.autojs.autojs.timing.IntentTask; import org.autojs.autojs.timing.TimedTask; import org.autojs.autojs.timing.TimedTaskManager; @@ -30,10 +31,24 @@ public abstract class Task { public static class PendingTask extends Task { private TimedTask mTimedTask; + private IntentTask mIntentTask; public PendingTask(TimedTask timedTask) { mTimedTask = timedTask; + mIntentTask = null; + } + + public PendingTask(IntentTask intentTask) { + mIntentTask = intentTask; + mTimedTask = null; + } + + public boolean taskEquals(Object task){ + if(mTimedTask != null){ + return mTimedTask.equals(task); + } + return mIntentTask.equals(task); } public TimedTask getTimedTask() { @@ -42,14 +57,20 @@ public abstract class Task { @Override public String getName() { - return PFiles.getSimplifiedPath(mTimedTask.getScriptPath()); + return PFiles.getSimplifiedPath(getScriptPath()); } @Override public String getDesc() { - long nextTime = mTimedTask.getNextTime(); - return GlobalAppContext.getString(R.string.text_next_run_time) + ": " + - DateTimeFormat.shortDateTime().print(nextTime); + if (mTimedTask != null) { + long nextTime = mTimedTask.getNextTime(); + return GlobalAppContext.getString(R.string.text_next_run_time) + ": " + + DateTimeFormat.shortDateTime().print(nextTime); + } else { + assert mIntentTask != null; + return mIntentTask.getAction(); + } + } @Override @@ -57,9 +78,18 @@ public abstract class Task { TimedTaskManager.getInstance().removeTask(mTimedTask); } + private String getScriptPath() { + if (mTimedTask != null) { + return mTimedTask.getScriptPath(); + } else { + assert mIntentTask != null; + return mIntentTask.getScriptPath(); + } + } + @Override public String getEngineName() { - if (mTimedTask.getScriptPath().endsWith(".js")) { + if (getScriptPath().endsWith(".js")) { return JavaScriptSource.ENGINE; } else { return AutoFileSource.ENGINE; @@ -69,6 +99,10 @@ public abstract class Task { public void setTimedTask(TimedTask timedTask) { mTimedTask = timedTask; } + + public void setIntentTask(IntentTask intentTask) { + mIntentTask = intentTask; + } } public static class RunningTask extends Task { diff --git a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskGroup.java b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskGroup.java index a1aef3d6..8a4f7e68 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskGroup.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskGroup.java @@ -8,6 +8,7 @@ import com.stardust.autojs.execution.ScriptExecution; import org.autojs.autojs.R; import org.autojs.autojs.autojs.AutoJs; +import org.autojs.autojs.timing.IntentTask; import org.autojs.autojs.timing.TimedTask; import org.autojs.autojs.timing.TimedTaskManager; @@ -55,39 +56,55 @@ public abstract class TaskGroup implements Parent { @Override public void refresh() { - List timedTasks = TimedTaskManager.getInstance().getAllTasksAsList(); - mTasks.clear(); - for (TimedTask timedTask : timedTasks) { + for (TimedTask timedTask : TimedTaskManager.getInstance().getAllTasksAsList()) { mTasks.add(new Task.PendingTask(timedTask)); } + for (IntentTask intentTask : TimedTaskManager.getInstance().getAllIntentTasksAsList()) { + mTasks.add(new Task.PendingTask(intentTask)); + } } - public int addTask(TimedTask timedTask) { + public int addTask(Object task) { int pos = mTasks.size(); - mTasks.add(new Task.PendingTask(timedTask)); + if (task instanceof TimedTask) { + mTasks.add(new Task.PendingTask((TimedTask) task)); + } else if (task instanceof IntentTask) { + mTasks.add(new Task.PendingTask((IntentTask) task)); + } else { + throw new IllegalArgumentException("task = " + task); + } return pos; } - public int removeTask(TimedTask data) { + public int removeTask(Object data) { int i = indexOf(data); if (i >= 0) mTasks.remove(i); return i; } - private int indexOf(TimedTask data) { + private int indexOf(Object data) { for (int i = 0; i < mTasks.size(); i++) { - if (((Task.PendingTask) mTasks.get(i)).getTimedTask().equals(data)) { + Task.PendingTask task = (Task.PendingTask) mTasks.get(i); + if (task.taskEquals(data)) { return i; } } return -1; } - public int updateTask(TimedTask task) { + + public int updateTask(Object task) { int i = indexOf(task); - if (i >= 0) - ((Task.PendingTask) mTasks.get(i)).setTimedTask(task); + if (i >= 0) { + if (task instanceof TimedTask) { + ((Task.PendingTask) mTasks.get(i)).setTimedTask((TimedTask) task); + } else if (task instanceof IntentTask) { + ((Task.PendingTask) mTasks.get(i)).setIntentTask((IntentTask) task); + } else { + throw new IllegalArgumentException("task = " + task); + } + } return i; } } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java index aba82132..6825c9fe 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java @@ -13,30 +13,27 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import com.stardust.autojs.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; 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.workground.WrapContentLinearLayoutManager; +import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; import org.autojs.autojs.R; import org.autojs.autojs.autojs.AutoJs; +import org.autojs.autojs.external.tasker.TaskerScriptEditActivity; import org.autojs.autojs.storage.database.ModelChange; +import org.autojs.autojs.timing.IntentTask; import org.autojs.autojs.timing.TaskReceiver; import org.autojs.autojs.timing.TimedTask; import org.autojs.autojs.timing.TimedTaskManager; import org.autojs.autojs.ui.timing.TimedTaskSettingActivity_; -import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; - import java.util.ArrayList; import java.util.List; @@ -60,7 +57,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView { private TaskGroup.PendingTaskGroup mPendingTaskGroup; private Adapter mAdapter; private Disposable mTimedTaskChangeDisposable; - private final ScriptEngineService mScriptEngineService = AutoJs.getInstance().getScriptEngineService(); + private Disposable mIntentTaskChangeDisposable; private ScriptExecutionListener mScriptExecutionListener = new SimpleScriptExecutionListener() { @Override public void onStart(final ScriptExecution execution) { @@ -135,7 +132,10 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView { AutoJs.getInstance().getScriptEngineService().registerGlobalScriptExecutionListener(mScriptExecutionListener); mTimedTaskChangeDisposable = TimedTaskManager.getInstance().getTimeTaskChanges() .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::onTimedTaskChange); + .subscribe(this::onTaskChange); + mIntentTaskChangeDisposable = TimedTaskManager.getInstance().getIntentTaskChanges() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::onTaskChange); } @Override @@ -151,26 +151,25 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView { super.onDetachedFromWindow(); AutoJs.getInstance().getScriptEngineService().unregisterGlobalScriptExecutionListener(mScriptExecutionListener); mTimedTaskChangeDisposable.dispose(); + mIntentTaskChangeDisposable.dispose(); } - void onTimedTaskChange(ModelChange taskChange) { - if (taskChange.getAction() == BaseModel.Action.INSERT) { + void onTaskChange(ModelChange taskChange) { + if (taskChange.getAction() == ModelChange.INSERT) { mAdapter.notifyChildInserted(1, mPendingTaskGroup.addTask(taskChange.getData())); - } else if (taskChange.getAction() == BaseModel.Action.DELETE) { + } else if (taskChange.getAction() == ModelChange.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) { + } else if (taskChange.getAction() == ModelChange.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(); } } @@ -250,7 +249,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView { void onItemClick(View view) { if (mTask instanceof Task.PendingTask) { TimedTaskSettingActivity_.intent(getContext()) - .extra(TaskReceiver.EXTRA_TASK_ID, ((Task.PendingTask) mTask).getTimedTask().getId()) + .extra(TaskerScriptEditActivity.EXTRA_TASK_ID, ((Task.PendingTask) mTask).getTimedTask().getId()) .start(); } } @@ -263,8 +262,8 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView { TaskGroupViewHolder(@NonNull View itemView) { super(itemView); - title = (TextView) itemView.findViewById(R.id.title); - icon = (ImageView) itemView.findViewById(R.id.icon); + title = itemView.findViewById(R.id.title); + icon = itemView.findViewById(R.id.icon); itemView.setOnClickListener(view -> { if (isExpanded()) { collapseView(); diff --git a/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java b/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java index b62898b4..130c49cf 100644 --- a/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java @@ -18,6 +18,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CompoundButton; +import android.widget.EditText; import android.widget.LinearLayout; import android.widget.RadioButton; import android.widget.RadioGroup; @@ -27,6 +28,9 @@ import android.widget.Toast; import com.github.aakira.expandablelayout.ExpandableRelativeLayout; import com.stardust.autojs.execution.ExecutionConfig; +import com.stardust.util.BiMap; +import com.stardust.util.BiMaps; +import com.stardust.util.MapEntries; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.CheckedChange; @@ -49,6 +53,7 @@ import org.joda.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Created by Stardust on 2017/11/28. @@ -62,6 +67,13 @@ public class TimedTaskSettingActivity extends BaseActivity { private static final int REQUEST_CODE_IGNORE_BATTERY = 27101; private static final String LOG_TAG = "TimedTaskSettings"; + private static final BiMap ACTIONS = BiMaps.newBuilder() + .put(R.id.run_on_boot, Intent.ACTION_BOOT_COMPLETED) + .put(R.id.run_on_screen_off, Intent.ACTION_SCREEN_OFF) + .put(R.id.run_on_screen_on, Intent.ACTION_SCREEN_ON) + .build(); + + @ViewById(R.id.toolbar) Toolbar mToolbar; @@ -77,9 +89,14 @@ public class TimedTaskSettingActivity extends BaseActivity { @ViewById(R.id.weekly_task_radio) RadioButton mWeeklyTaskRadio; - @ViewById(R.id.run_on_boot_radio) - RadioButton mRunOnBootRadio; + @ViewById(R.id.run_on_broadcast) + RadioButton mRunOnBroadcast; + @ViewById(R.id.action) + EditText mOtherBroadcastAction; + + @ViewById(R.id.broadcast_group) + RadioGroup mBroadcastGroup; @ViewById(R.id.disposable_task_time) TextView mDisposableTaskTime; @@ -98,14 +115,13 @@ public class TimedTaskSettingActivity extends BaseActivity { private List mDayOfWeekCheckBoxes = new ArrayList<>(); - 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); + long taskId = getIntent().getLongExtra(TaskReceiver.EXTRA_TASK_ID, -1); if (taskId != -1) { mTimedTask = TimedTaskManager.getInstance().getTimedTask(taskId); if (mTimedTask != null) { @@ -175,7 +191,7 @@ public class TimedTaskSettingActivity extends BaseActivity { } - @CheckedChange({R.id.daily_task_radio, R.id.weekly_task_radio, R.id.disposable_task_radio}) + @CheckedChange({R.id.daily_task_radio, R.id.weekly_task_radio, R.id.disposable_task_radio, R.id.run_on_broadcast}) void onCheckedChanged(CompoundButton button) { ExpandableRelativeLayout relativeLayout = findExpandableLayoutOf(button); if (button.isChecked()) { @@ -271,8 +287,6 @@ public class TimedTaskSettingActivity extends BaseActivity { } else { createOrUpdateTimedTask(); } - - return true; } return super.onOptionsItemSelected(item); @@ -288,12 +302,8 @@ public class TimedTaskSettingActivity extends BaseActivity { } private void createOrUpdateTimedTask() { - if (mRunOnBootRadio.isChecked()) { - IntentTask task = new IntentTask(); - task.setAction(Intent.ACTION_BOOT_COMPLETED); - task.setScriptPath(mScriptFile.getPath()); - TimedTaskManager.getInstance().addTask(task); - finish(); + if (mRunOnBroadcast.isChecked()) { + createIntentTask(); return; } TimedTask task = createTimedTask(); @@ -308,4 +318,24 @@ public class TimedTaskSettingActivity extends BaseActivity { } finish(); } + + + private void createIntentTask() { + int buttonId = mBroadcastGroup.getCheckedRadioButtonId(); + String action; + if(buttonId == R.id.run_on_other_broadcast){ + action = mOtherBroadcastAction.getText().toString(); + if(action.isEmpty()){ + mOtherBroadcastAction.setError(getString(R.string.text_should_not_be_empty)); + return; + } + }else { + action = ACTIONS.get(buttonId); + } + IntentTask task = new IntentTask(); + task.setAction(action); + task.setScriptPath(mScriptFile.getPath()); + TimedTaskManager.getInstance().addTask(task); + finish(); + } } diff --git a/app/src/main/res/layout/activity_timed_task_setting.xml b/app/src/main/res/layout/activity_timed_task_setting.xml index b72f9cca..4d90b0e8 100644 --- a/app/src/main/res/layout/activity_timed_task_setting.xml +++ b/app/src/main/res/layout/activity_timed_task_setting.xml @@ -253,12 +253,86 @@ + android:text="@string/text_run_on_broadcast"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0bebb257..0f1f535d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -382,7 +382,7 @@ 使用系统闹钟唤醒Auto.js 连接失败: %s 确定要删除%s吗 - 开机时运行 + 特定事件(广播)触发运行 搜索Java包/类 类/包名 查看文档 @@ -403,4 +403,10 @@ 前台服务通知 Auto.js保持运行中 点击进入主界面 + 开机时运行 + 亮屏时运行 + 息屏时运行 + 其他事件(广播) + 广播Action + android.intent.action. diff --git a/common/src/main/java/com/stardust/util/BiMap.java b/common/src/main/java/com/stardust/util/BiMap.java new file mode 100644 index 00000000..65420801 --- /dev/null +++ b/common/src/main/java/com/stardust/util/BiMap.java @@ -0,0 +1,11 @@ +package com.stardust.util; + +import java.util.Map; +import java.util.Set; + +public interface BiMap extends Map { + + K getKey(V value); + + Set valueSet(); +} diff --git a/common/src/main/java/com/stardust/util/BiMaps.java b/common/src/main/java/com/stardust/util/BiMaps.java new file mode 100644 index 00000000..a809c5b4 --- /dev/null +++ b/common/src/main/java/com/stardust/util/BiMaps.java @@ -0,0 +1,206 @@ +package com.stardust.util; + +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.RequiresApi; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class BiMaps { + + public static BiMap make(Map keyToValue, Map valueToKey) { + return new BiMapImpl<>(keyToValue, valueToKey); + } + + public static BiMapBuilder newBuilder() { + return new BiMapBuilder<>(); + } + + public static class BiMapBuilder { + + private final BiMap mBiMap = make(new HashMap(), new HashMap()); + + public BiMapBuilder put(K key, V value) { + mBiMap.put(key, value); + return this; + } + + public BiMap build() { + return mBiMap; + } + + } + + private static class BiMapImpl implements BiMap { + + private final Map mKVMap; + private final Map mVKMap; + + private BiMapImpl(Map kvMap, Map vkMap) { + mKVMap = kvMap; + mVKMap = vkMap; + } + + @Override + public int size() { + return mKVMap.size(); + } + + @Override + public boolean isEmpty() { + return mKVMap.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return mKVMap.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return mVKMap.containsKey(value); + } + + @Override + public V get(Object key) { + return mKVMap.get(key); + } + + @Override + public V put(K key, V value) { + V put = mKVMap.put(key, value); + mVKMap.put(value, key); + return put; + } + + @Override + public V remove(Object key) { + V remove = mKVMap.remove(key); + if (remove != null) { + mVKMap.remove(key); + } + return remove; + } + + @Override + public void putAll(@NonNull Map m) { + mKVMap.putAll(m); + } + + @Override + public void clear() { + mKVMap.clear(); + mVKMap.clear(); + } + + @NonNull + @Override + public Set keySet() { + return mKVMap.keySet(); + } + + @Override + public K getKey(V value) { + return mVKMap.get(value); + } + + @Override + public Set valueSet() { + return mVKMap.keySet(); + } + + @NonNull + @Override + public Collection values() { + return mKVMap.values(); + } + + @NonNull + @Override + public Set> entrySet() { + return mKVMap.entrySet(); + } + + @Override + public boolean equals(Object o) { + return mKVMap.equals(o); + } + + @Override + public int hashCode() { + return mKVMap.hashCode(); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public V getOrDefault(Object key, V defaultValue) { + return mKVMap.getOrDefault(key, defaultValue); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public void forEach(BiConsumer action) { + mKVMap.forEach(action); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public void replaceAll(BiFunction function) { + mKVMap.replaceAll(function); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public V putIfAbsent(K key, V value) { + return mKVMap.putIfAbsent(key, value); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public boolean remove(Object key, Object value) { + return mKVMap.remove(key, value); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public boolean replace(K key, V oldValue, V newValue) { + return mKVMap.replace(key, oldValue, newValue); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public V replace(K key, V value) { + return mKVMap.replace(key, value); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public V computeIfAbsent(K key, Function mappingFunction) { + return mKVMap.computeIfAbsent(key, mappingFunction); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public V computeIfPresent(K key, BiFunction remappingFunction) { + return mKVMap.computeIfPresent(key, remappingFunction); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public V compute(K key, BiFunction remappingFunction) { + return mKVMap.compute(key, remappingFunction); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public V merge(K key, V value, BiFunction remappingFunction) { + return mKVMap.merge(key, value, remappingFunction); + } + } +} From 02b1587f6bb94faa30e4fb9a4277244146e05f22 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Fri, 28 Sep 2018 13:46:01 +0800 Subject: [PATCH 13/14] feat: intent task --- app/src/main/AndroidManifest.xml | 8 ++ app/src/main/java/org/autojs/autojs/App.java | 27 +++- .../receiver/BaseBroadcastReceiver.java | 3 +- ...er.java => DynamicBroadcastReceivers.java} | 67 +++++----- .../tasker/TaskerScriptEditActivity.java | 1 - .../autojs/pluginclient/DevPluginService.java | 16 +-- .../autojs/timing/TimedTaskManager.java | 29 ++++- .../org/autojs/autojs/ui/main/task/Task.java | 29 ++++- .../autojs/autojs/ui/main/task/TaskGroup.java | 1 + .../ui/main/task/TaskListRecyclerView.java | 6 +- .../autojs/ui/settings/SettingsActivity.java | 16 +-- .../ui/timing/TimedTaskSettingActivity.java | 121 ++++++++++++++---- .../layout/activity_timed_task_setting.xml | 72 +++++++++++ app/src/main/res/values/strings.xml | 16 ++- .../stardust/autojs/runtime/api/Sensors.java | 32 ++--- .../autojs/script/JavaScriptSource.java | 10 +- .../stardust/autojs/script/ScriptSource.java | 11 -- .../simple_action/ActionFactory.java | 20 +-- .../util/{MapEntries.java => MapBuilder.java} | 11 +- 19 files changed, 359 insertions(+), 137 deletions(-) rename app/src/main/java/org/autojs/autojs/external/receiver/{DynamicBroadcastReceiver.java => DynamicBroadcastReceivers.java} (50%) rename common/src/main/java/com/stardust/util/{MapEntries.java => MapBuilder.java} (66%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index aa1cb820..d68b0544 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -164,6 +164,14 @@ + + + + + + + + instance; - private DynamicBroadcastReceiver mDynamicBroadcastReceiver; + private DynamicBroadcastReceivers mDynamicBroadcastReceivers; public static App getApp() { return instance.get(); @@ -56,6 +58,10 @@ public class App extends MultiDexApplication { init(); } + public DynamicBroadcastReceivers getDynamicBroadcastReceivers() { + return mDynamicBroadcastReceivers; + } + private void setUpStaticsTool() { if (BuildConfig.DEBUG) return; @@ -98,7 +104,18 @@ public class App extends MultiDexApplication { } setupDrawableImageLoader(); TimedTaskScheduler.checkTasksRepeatedlyIfNeeded(this); - mDynamicBroadcastReceiver = new DynamicBroadcastReceiver(this); + initDynamicBroadcastReceivers(); + } + + @SuppressLint("CheckResult") + private void initDynamicBroadcastReceivers() { + mDynamicBroadcastReceivers = new DynamicBroadcastReceivers(this); + TimedTaskManager.getInstance().getAllIntentTasks() + .filter(task -> task.getAction() != null) + .map(IntentTask::getAction) + .collectInto(new ArrayList(), ArrayList::add) + .subscribe(list -> mDynamicBroadcastReceivers.register(list), + Throwable::printStackTrace); } private void setupDrawableImageLoader() { diff --git a/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java b/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java index a7d68b87..5cad9f4f 100644 --- a/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java +++ b/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java @@ -4,6 +4,7 @@ import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.util.Log; import android.widget.Toast; @@ -24,7 +25,7 @@ public class BaseBroadcastReceiver extends BroadcastReceiver { @SuppressLint("CheckResult") public void onReceive(Context context, Intent intent) { - Log.d(LOG_TAG, "onReceive: action = " + intent.getAction() + ", intent = " + intent); + Log.d(LOG_TAG, "onReceive: intent = " + intent + ", this = " + this); try { TimedTaskManager.getInstance().getIntentTaskOfAction(intent.getAction()) .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceiver.java b/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceivers.java similarity index 50% rename from app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceiver.java rename to app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceivers.java index 62ff15c5..b837f046 100644 --- a/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceiver.java +++ b/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceivers.java @@ -1,41 +1,31 @@ package org.autojs.autojs.external.receiver; +import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; import android.content.IntentFilter; -import android.media.AudioManager; import android.os.Build; -import org.autojs.autojs.BuildConfig; - import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import static android.content.Intent.ACTION_BATTERY_CHANGED; import static android.content.Intent.ACTION_CONFIGURATION_CHANGED; -import static android.content.Intent.ACTION_DATE_CHANGED; import static android.content.Intent.ACTION_PACKAGES_SUSPENDED; import static android.content.Intent.ACTION_PACKAGES_UNSUSPENDED; -import static android.content.Intent.ACTION_PACKAGE_ADDED; -import static android.content.Intent.ACTION_PACKAGE_CHANGED; -import static android.content.Intent.ACTION_PACKAGE_DATA_CLEARED; -import static android.content.Intent.ACTION_PACKAGE_REMOVED; -import static android.content.Intent.ACTION_PACKAGE_RESTARTED; -import static android.content.Intent.ACTION_POWER_CONNECTED; -import static android.content.Intent.ACTION_POWER_DISCONNECTED; -import static android.content.Intent.ACTION_SHUTDOWN; -import static android.content.Intent.ACTION_TIMEZONE_CHANGED; -import static android.content.Intent.ACTION_TIME_CHANGED; +import static android.content.Intent.ACTION_SCREEN_OFF; +import static android.content.Intent.ACTION_SCREEN_ON; import static android.content.Intent.ACTION_TIME_TICK; -import static android.content.Intent.ACTION_UID_REMOVED; -public class DynamicBroadcastReceiver extends BaseBroadcastReceiver { +public class DynamicBroadcastReceivers { private static final List DEFAULT_ACTIONS = new ArrayList<>(Arrays.asList( ACTION_TIME_TICK, + ACTION_SCREEN_OFF, + ACTION_SCREEN_ON, ACTION_BATTERY_CHANGED, ACTION_CONFIGURATION_CHANGED )); @@ -49,31 +39,40 @@ public class DynamicBroadcastReceiver extends BaseBroadcastReceiver { } } - private boolean mRegistered = false; private final Set mActions = new LinkedHashSet<>(); + private final List mReceivers = new ArrayList<>(); private final Context mContext; - public DynamicBroadcastReceiver(Context context) { + public DynamicBroadcastReceivers(Context context) { mContext = context; register(DEFAULT_ACTIONS); } - public void register(List actions) { - int oldSize = mActions.size(); - mActions.addAll(actions); - if (oldSize == mActions.size()) { - return; - } - IntentFilter filter = new IntentFilter(); - for (String action : mActions) { - filter.addAction(action); - } - if(mRegistered){ - mContext.unregisterReceiver(this); - } - mContext.registerReceiver(this, filter); - mRegistered = true; + public void register(String action) { + register(Collections.singletonList(action)); } + public void register(List actions) { + IntentFilter filter = new IntentFilter(); + for (String action : actions) { + if (!StaticBroadcastReceiver.ACTIONS.contains(action) + && !mActions.contains(action)) { + mActions.add(action); + filter.addAction(action); + } + } + if (filter.countActions() == 0) { + return; + } + BaseBroadcastReceiver receiver = new BaseBroadcastReceiver(); + mContext.registerReceiver(receiver, filter); + } + + public void unregisterAll() { + for (BroadcastReceiver receiver : mReceivers) { + mContext.unregisterReceiver(receiver); + } + mReceivers.clear(); + } } 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 764ad4e5..345d9ea8 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 @@ -31,7 +31,6 @@ import static org.autojs.autojs.ui.edit.EditorView.EXTRA_SAVE_ENABLED; public class TaskerScriptEditActivity extends BaseActivity { public static final int REQUEST_CODE = 10016; - public static final String EXTRA_INTENT_TASK_ID = "intent_task_id"; public static final String EXTRA_TASK_ID = TaskReceiver.EXTRA_TASK_ID; public static void edit(Activity activity, String title, String summary, String content) { diff --git a/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginService.java b/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginService.java index 2824b3cb..51de8c25 100644 --- a/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginService.java +++ b/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginService.java @@ -12,10 +12,9 @@ import android.util.Pair; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.stardust.util.MapEntries; +import com.stardust.util.MapBuilder; import org.autojs.autojs.BuildConfig; -import org.autojs.autojs.tool.EmptyObservers; import java.io.IOException; import java.net.SocketTimeoutException; @@ -24,7 +23,6 @@ import java.util.concurrent.TimeUnit; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.PublishSubject; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -171,12 +169,12 @@ public class DevPluginService { @WorkerThread private void sayHelloToServer(JsonWebSocket socket) throws IOException { - writeMap(socket, TYPE_HELLO, new MapEntries() - .entry("device_name", Build.BRAND + " " + Build.MODEL) - .entry("client_version", CLIENT_VERSION) - .entry("app_version", BuildConfig.VERSION_NAME) - .entry("app_version_code", BuildConfig.VERSION_CODE) - .map()); + writeMap(socket, TYPE_HELLO, new MapBuilder() + .put("device_name", Build.BRAND + " " + Build.MODEL) + .put("client_version", CLIENT_VERSION) + .put("app_version", BuildConfig.VERSION_NAME) + .put("app_version_code", BuildConfig.VERSION_CODE) + .build()); mHandshakeTimeoutHandler.postDelayed(() -> { if (mSocket != socket && !socket.isClosed()) { onHandshakeTimeout(socket); diff --git a/app/src/main/java/org/autojs/autojs/timing/TimedTaskManager.java b/app/src/main/java/org/autojs/autojs/timing/TimedTaskManager.java index 97169850..a8898ce9 100644 --- a/app/src/main/java/org/autojs/autojs/timing/TimedTaskManager.java +++ b/app/src/main/java/org/autojs/autojs/timing/TimedTaskManager.java @@ -3,9 +3,11 @@ package org.autojs.autojs.timing; import android.annotation.SuppressLint; import android.content.Context; +import android.text.TextUtils; import com.stardust.app.GlobalAppContext; +import org.autojs.autojs.App; import org.autojs.autojs.storage.database.IntentTaskDatabase; import org.autojs.autojs.storage.database.ModelChange; import org.autojs.autojs.storage.database.TimedTaskDatabase; @@ -15,7 +17,6 @@ import java.util.List; import io.reactivex.Flowable; import io.reactivex.Observable; -import io.reactivex.subjects.PublishSubject; /** * Created by Stardust on 2017/11/27. @@ -82,7 +83,12 @@ public class TimedTaskManager { @SuppressLint("CheckResult") public void addTask(IntentTask intentTask) { mIntentTaskDatabase.insert(intentTask) - .subscribe(EmptyObservers.consumer(), Throwable::printStackTrace); + .subscribe(i -> { + if(!TextUtils.isEmpty(intentTask.getAction())){ + App.getApp().getDynamicBroadcastReceivers() + .register(intentTask.getAction()); + } + }, Throwable::printStackTrace); } @SuppressLint("CheckResult") @@ -128,6 +134,17 @@ public class TimedTaskManager { TimedTaskScheduler.scheduleTaskIfNeeded(mContext, task); } + @SuppressLint("CheckResult") + public void updateTask(IntentTask task) { + mIntentTaskDatabase.update(task) + .subscribe(i -> { + if(i > 0 && !TextUtils.isEmpty(task.getAction())){ + App.getApp().getDynamicBroadcastReceivers() + .register(task.getAction()); + } + }, Throwable::printStackTrace); + } + public long countTasks() { return mTimedTaskDatabase.count(); } @@ -139,4 +156,12 @@ public class TimedTaskManager { public Observable> getIntentTaskChanges() { return mIntentTaskDatabase.getModelChange(); } + + public IntentTask getIntentTask(long intentTaskId) { + return mIntentTaskDatabase.queryById(intentTaskId); + } + + public Flowable getAllIntentTasks() { + return mIntentTaskDatabase.queryAllAsFlowable(); + } } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/task/Task.java b/app/src/main/java/org/autojs/autojs/ui/main/task/Task.java index 4e5e03f4..3ad1ec0a 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/task/Task.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/task/Task.java @@ -1,11 +1,14 @@ package org.autojs.autojs.ui.main.task; +import android.content.Intent; + import com.stardust.app.GlobalAppContext; import com.stardust.autojs.engine.ScriptEngine; import com.stardust.autojs.execution.ScriptExecution; import com.stardust.autojs.script.AutoFileSource; import com.stardust.autojs.script.JavaScriptSource; import com.stardust.pio.PFiles; +import com.stardust.util.MapBuilder; import org.autojs.autojs.R; import org.autojs.autojs.timing.IntentTask; @@ -14,12 +17,17 @@ import org.autojs.autojs.timing.TimedTaskManager; import org.joda.time.format.DateTimeFormat; +import java.util.Map; + +import static org.autojs.autojs.ui.timing.TimedTaskSettingActivity.ACTION_DESC_MAP; + /** * Created by Stardust on 2017/11/28. */ public abstract class Task { + public abstract String getName(); public abstract String getDesc(); @@ -30,6 +38,7 @@ public abstract class Task { public static class PendingTask extends Task { + private TimedTask mTimedTask; private IntentTask mIntentTask; @@ -44,8 +53,8 @@ public abstract class Task { mTimedTask = null; } - public boolean taskEquals(Object task){ - if(mTimedTask != null){ + public boolean taskEquals(Object task) { + if (mTimedTask != null) { return mTimedTask.equals(task); } return mIntentTask.equals(task); @@ -68,6 +77,10 @@ public abstract class Task { DateTimeFormat.shortDateTime().print(nextTime); } else { assert mIntentTask != null; + Integer desc = ACTION_DESC_MAP.get(mIntentTask.getAction()); + if(desc != null){ + return GlobalAppContext.getString(desc); + } return mIntentTask.getAction(); } @@ -75,7 +88,11 @@ public abstract class Task { @Override public void cancel() { - TimedTaskManager.getInstance().removeTask(mTimedTask); + if (mTimedTask != null) { + TimedTaskManager.getInstance().removeTask(mTimedTask); + } else { + TimedTaskManager.getInstance().removeTask(mIntentTask); + } } private String getScriptPath() { @@ -103,6 +120,12 @@ public abstract class Task { public void setIntentTask(IntentTask intentTask) { mIntentTask = intentTask; } + + public long getId() { + if(mTimedTask != null) + return mTimedTask.getId(); + return mIntentTask.getId(); + } } public static class RunningTask extends Task { diff --git a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskGroup.java b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskGroup.java index 8a4f7e68..18a6f018 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskGroup.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskGroup.java @@ -56,6 +56,7 @@ public abstract class TaskGroup implements Parent { @Override public void refresh() { + mTasks.clear(); for (TimedTask timedTask : TimedTaskManager.getInstance().getAllTasksAsList()) { mTasks.add(new Task.PendingTask(timedTask)); } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java index 6825c9fe..3371aa46 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java @@ -32,6 +32,7 @@ import org.autojs.autojs.timing.IntentTask; import org.autojs.autojs.timing.TaskReceiver; import org.autojs.autojs.timing.TimedTask; import org.autojs.autojs.timing.TimedTaskManager; +import org.autojs.autojs.ui.timing.TimedTaskSettingActivity; import org.autojs.autojs.ui.timing.TimedTaskSettingActivity_; import java.util.ArrayList; @@ -248,8 +249,11 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView { void onItemClick(View view) { if (mTask instanceof Task.PendingTask) { + Task.PendingTask task = (Task.PendingTask) mTask; + String extra = task.getTimedTask() == null ? TimedTaskSettingActivity.EXTRA_INTENT_TASK_ID + : TimedTaskSettingActivity.EXTRA_TASK_ID; TimedTaskSettingActivity_.intent(getContext()) - .extra(TaskerScriptEditActivity.EXTRA_TASK_ID, ((Task.PendingTask) mTask).getTimedTask().getId()) + .extra(extra, task.getId()) .start(); } } diff --git a/app/src/main/java/org/autojs/autojs/ui/settings/SettingsActivity.java b/app/src/main/java/org/autojs/autojs/ui/settings/SettingsActivity.java index bcf4ccbc..a8423d6d 100644 --- a/app/src/main/java/org/autojs/autojs/ui/settings/SettingsActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/settings/SettingsActivity.java @@ -12,7 +12,7 @@ import android.view.View; import com.stardust.theme.app.ColorSelectActivity; import com.stardust.theme.preference.ThemeColorPreferenceFragment; import com.stardust.theme.util.ListBuilder; -import com.stardust.util.MapEntries; +import com.stardust.util.MapBuilder; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EActivity; @@ -100,14 +100,14 @@ public class SettingsActivity extends BaseActivity { @Override public void onStart() { super.onStart(); - ACTION_MAP = new MapEntries() - .entry(getString(R.string.text_theme_color), () -> selectThemeColor(getActivity())) - .entry(getString(R.string.text_check_for_updates), () -> new UpdateCheckDialog(getActivity()) + ACTION_MAP = new MapBuilder() + .put(getString(R.string.text_theme_color), () -> selectThemeColor(getActivity())) + .put(getString(R.string.text_check_for_updates), () -> new UpdateCheckDialog(getActivity()) .show()) - .entry(getString(R.string.text_issue_report), () -> startActivity(new Intent(getActivity(), IssueReporterActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))) - .entry(getString(R.string.text_about_me_and_repo), () -> startActivity(new Intent(getActivity(), AboutActivity_.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))) - .entry(getString(R.string.text_licenses), () -> showLicenseDialog()) - .map(); + .put(getString(R.string.text_issue_report), () -> startActivity(new Intent(getActivity(), IssueReporterActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))) + .put(getString(R.string.text_about_me_and_repo), () -> startActivity(new Intent(getActivity(), AboutActivity_.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))) + .put(getString(R.string.text_licenses), () -> showLicenseDialog()) + .build(); } @Override diff --git a/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java b/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java index 130c49cf..0997e7c3 100644 --- a/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java @@ -3,6 +3,8 @@ package org.autojs.autojs.ui.timing; import android.app.DatePickerDialog; import android.app.TimePickerDialog; import android.content.Intent; +import android.graphics.ColorFilter; +import android.net.ConnectivityManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -30,7 +32,7 @@ import com.github.aakira.expandablelayout.ExpandableRelativeLayout; import com.stardust.autojs.execution.ExecutionConfig; import com.stardust.util.BiMap; import com.stardust.util.BiMaps; -import com.stardust.util.MapEntries; +import com.stardust.util.MapBuilder; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.CheckedChange; @@ -61,16 +63,44 @@ import java.util.Map; @EActivity(R.layout.activity_timed_task_setting) public class TimedTaskSettingActivity extends BaseActivity { + public static final String EXTRA_INTENT_TASK_ID = "intent_task_id"; + public static final String EXTRA_TASK_ID = TaskReceiver.EXTRA_TASK_ID; private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormat.forPattern("HH:mm"); private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormat.forPattern("yy-MM-dd"); private static final int REQUEST_CODE_IGNORE_BATTERY = 27101; + private static final String LOG_TAG = "TimedTaskSettings"; + + public static final Map ACTION_DESC_MAP = new MapBuilder() + .put(Intent.ACTION_BOOT_COMPLETED, R.string.text_run_on_boot) + .put(Intent.ACTION_SCREEN_OFF, R.string.text_run_on_screen_off) + .put(Intent.ACTION_SCREEN_ON, R.string.text_run_on_screen_on) + .put(Intent.ACTION_USER_PRESENT, R.string.text_run_on_screen_unlock) + .put(Intent.ACTION_BATTERY_CHANGED, R.string.text_run_on_battery_change) + .put(Intent.ACTION_POWER_CONNECTED, R.string.text_run_on_power_connect) + .put(Intent.ACTION_POWER_DISCONNECTED, R.string.text_run_on_power_disconnect) + .put(ConnectivityManager.CONNECTIVITY_ACTION, R.string.text_run_on_conn_change) + .put(Intent.ACTION_PACKAGE_ADDED, R.string.text_run_on_package_install) + .put(Intent.ACTION_PACKAGE_REMOVED, R.string.text_run_on_package_uninstall) + .put(Intent.ACTION_PACKAGE_REPLACED, R.string.text_run_on_package_update) + .put(Intent.ACTION_HEADSET_PLUG, R.string.text_run_on_headset_plug) + .build(); + private static final BiMap ACTIONS = BiMaps.newBuilder() .put(R.id.run_on_boot, Intent.ACTION_BOOT_COMPLETED) .put(R.id.run_on_screen_off, Intent.ACTION_SCREEN_OFF) .put(R.id.run_on_screen_on, Intent.ACTION_SCREEN_ON) + .put(R.id.run_on_screen_unlock, Intent.ACTION_USER_PRESENT) + .put(R.id.run_on_battery_change, Intent.ACTION_BATTERY_CHANGED) + .put(R.id.run_on_power_connect, Intent.ACTION_POWER_CONNECTED) + .put(R.id.run_on_power_disconnect, Intent.ACTION_POWER_DISCONNECTED) + .put(R.id.run_on_conn_change, ConnectivityManager.CONNECTIVITY_ACTION) + .put(R.id.run_on_package_install, Intent.ACTION_PACKAGE_ADDED) + .put(R.id.run_on_package_uninstall, Intent.ACTION_PACKAGE_REMOVED) + .put(R.id.run_on_package_update, Intent.ACTION_PACKAGE_REPLACED) + .put(R.id.run_on_headset_plug, Intent.ACTION_HEADSET_PLUG) .build(); @@ -90,7 +120,10 @@ public class TimedTaskSettingActivity extends BaseActivity { RadioButton mWeeklyTaskRadio; @ViewById(R.id.run_on_broadcast) - RadioButton mRunOnBroadcast; + RadioButton mRunOnBroadcastRadio; + + @ViewById(R.id.run_on_other_broadcast) + RadioButton mRunOnOtherBroadcast; @ViewById(R.id.action) EditText mOtherBroadcastAction; @@ -117,22 +150,31 @@ public class TimedTaskSettingActivity extends BaseActivity { private ScriptFile mScriptFile; private TimedTask mTimedTask; + private IntentTask mIntentTask; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - long taskId = getIntent().getLongExtra(TaskReceiver.EXTRA_TASK_ID, -1); + long taskId = getIntent().getLongExtra(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(); + long intentTaskId = getIntent().getLongExtra(EXTRA_INTENT_TASK_ID, -1); + if (intentTaskId != -1) { + mIntentTask = TimedTaskManager.getInstance().getIntentTask(intentTaskId); + if (mIntentTask != null) { + mScriptFile = new ScriptFile(mIntentTask.getScriptPath()); + } + } else { + String path = getIntent().getStringExtra(ScriptIntents.EXTRA_KEY_PATH); + if (TextUtils.isEmpty(path)) { + finish(); + } + mScriptFile = new ScriptFile(path); } - mScriptFile = new ScriptFile(path); } } @@ -144,7 +186,7 @@ public class TimedTaskSettingActivity extends BaseActivity { mToolbar.setSubtitle(mScriptFile.getName()); } findDayOfWeekCheckBoxes(mWeeklyTaskContainer); - setUpTime(); + setUpTaskSettings(); } private void findDayOfWeekCheckBoxes(ViewGroup parent) { @@ -161,13 +203,32 @@ public class TimedTaskSettingActivity extends BaseActivity { } - private void setUpTime() { + private void setUpTaskSettings() { mDisposableTaskDate.setText(DATE_FORMATTER.print(LocalDate.now())); mDisposableTaskTime.setText(TIME_FORMATTER.print(LocalTime.now())); - if (mTimedTask == null) { - mDailyTaskRadio.setChecked(true); + if (mTimedTask != null) { + setupTime(); return; } + if (mIntentTask != null) { + setupAction(); + return; + } + mDailyTaskRadio.setChecked(true); + } + + private void setupAction() { + mRunOnBroadcastRadio.setChecked(true); + Integer buttonId = ACTIONS.getKey(mIntentTask.getAction()); + if (buttonId == null) { + mRunOnOtherBroadcast.setChecked(true); + mOtherBroadcastAction.setText(mIntentTask.getAction()); + } else { + ((RadioButton) findViewById(buttonId)).setChecked(true); + } + } + + private void setupTime() { if (mTimedTask.isDisposable()) { mDisposableTaskRadio.setChecked(true); mDisposableTaskTime.setText(TIME_FORMATTER.print(mTimedTask.getMillis())); @@ -187,7 +248,6 @@ public class TimedTaskSettingActivity extends BaseActivity { mDayOfWeekCheckBoxes.get(i).setChecked(mTimedTask.hasDayOfWeek(i + 1)); } } - } @@ -285,7 +345,7 @@ public class TimedTaskSettingActivity extends BaseActivity { startActivityForResult(new Intent().setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) .setData(Uri.parse("package:" + getPackageName())), REQUEST_CODE_IGNORE_BATTERY); } else { - createOrUpdateTimedTask(); + createOrUpdateTask(); } return true; } @@ -296,14 +356,14 @@ public class TimedTaskSettingActivity extends BaseActivity { protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_IGNORE_BATTERY) { Log.d(LOG_TAG, "result code = " + requestCode); - createOrUpdateTimedTask(); + createOrUpdateTask(); } super.onActivityResult(requestCode, resultCode, data); } - private void createOrUpdateTimedTask() { - if (mRunOnBroadcast.isChecked()) { - createIntentTask(); + private void createOrUpdateTask() { + if (mRunOnBroadcastRadio.isChecked()) { + createOrUpdateIntentTask(); return; } TimedTask task = createTimedTask(); @@ -311,6 +371,9 @@ public class TimedTaskSettingActivity extends BaseActivity { return; if (mTimedTask == null) { TimedTaskManager.getInstance().addTask(task); + if (mIntentTask != null) { + TimedTaskManager.getInstance().removeTask(mIntentTask); + } Toast.makeText(this, R.string.text_already_create, Toast.LENGTH_SHORT).show(); } else { task.setId(mTimedTask.getId()); @@ -320,22 +383,36 @@ public class TimedTaskSettingActivity extends BaseActivity { } - private void createIntentTask() { + private void createOrUpdateIntentTask() { int buttonId = mBroadcastGroup.getCheckedRadioButtonId(); + if (buttonId == -1) { + Toast.makeText(this, R.string.error_empty_selection, Toast.LENGTH_SHORT).show(); + return; + } String action; - if(buttonId == R.id.run_on_other_broadcast){ + if (buttonId == R.id.run_on_other_broadcast) { action = mOtherBroadcastAction.getText().toString(); - if(action.isEmpty()){ + if (action.isEmpty()) { mOtherBroadcastAction.setError(getString(R.string.text_should_not_be_empty)); return; } - }else { + } else { action = ACTIONS.get(buttonId); } IntentTask task = new IntentTask(); task.setAction(action); task.setScriptPath(mScriptFile.getPath()); - TimedTaskManager.getInstance().addTask(task); + if (mIntentTask != null) { + task.setId(mIntentTask.getId()); + TimedTaskManager.getInstance().updateTask(task); + Toast.makeText(this, R.string.text_already_create, Toast.LENGTH_SHORT).show(); + } else { + TimedTaskManager.getInstance().addTask(task); + if (mTimedTask != null) { + TimedTaskManager.getInstance().removeTask(mTimedTask); + } + } + finish(); } } diff --git a/app/src/main/res/layout/activity_timed_task_setting.xml b/app/src/main/res/layout/activity_timed_task_setting.xml index 4d90b0e8..ee7e0c11 100644 --- a/app/src/main/res/layout/activity_timed_task_setting.xml +++ b/app/src/main/res/layout/activity_timed_task_setting.xml @@ -303,6 +303,78 @@ android:paddingLeft="8dp" android:text="@string/text_run_on_screen_off"/> + + + + + + + + + + + + + + + + + + 前台服务通知 Auto.js保持运行中 点击进入主界面 - 开机时运行 - 亮屏时运行 - 息屏时运行 其他事件(广播) 广播Action android.intent.action. + 开机时 + 亮屏时 + 息屏时 + 请选择一个广播事件选项 + 电量变化时 + 屏幕解锁时 + 电源连接时 + 电源断开时 + 网络连接变化时 + 新应用安装时 + 应用卸载时 + 应用更新时 + 耳机插拔时 diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Sensors.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Sensors.java index 06cebbe6..e011e6f4 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Sensors.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Sensors.java @@ -11,7 +11,7 @@ import com.stardust.autojs.core.eventloop.EventEmitter; import com.stardust.autojs.core.looper.Loopers; import com.stardust.autojs.runtime.ScriptBridges; import com.stardust.autojs.runtime.ScriptRuntime; -import com.stardust.util.MapEntries; +import com.stardust.util.MapBuilder; import java.lang.reflect.Field; import java.util.HashSet; @@ -59,21 +59,21 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler { } - private static final Map SENSORS = new MapEntries() - .entry("ACCELEROMETER", Sensor.TYPE_ACCELEROMETER) - .entry("MAGNETIC_FIELD", Sensor.TYPE_MAGNETIC_FIELD) - .entry("ORIENTATION", Sensor.TYPE_ORIENTATION) - .entry("GYROSCOPE", Sensor.TYPE_GYROSCOPE) - .entry("LIGHT", Sensor.TYPE_LIGHT) - .entry("TEMPERATURE", Sensor.TYPE_TEMPERATURE) - .entry("PRESSURE", Sensor.TYPE_PRESSURE) - .entry("AMBIENT_TEMPERATURE", Sensor.TYPE_AMBIENT_TEMPERATURE) - .entry("PROXIMITY", Sensor.TYPE_PROXIMITY) - .entry("GRAVITY", Sensor.TYPE_GRAVITY) - .entry("LINEAR_ACCELERATION", Sensor.TYPE_LINEAR_ACCELERATION) - .entry("RELATIVE_HUMIDITY", Sensor.TYPE_RELATIVE_HUMIDITY) - .entry("AMBIENT_TEMPERATURE", Sensor.TYPE_AMBIENT_TEMPERATURE) - .map(); + private static final Map SENSORS = new MapBuilder() + .put("ACCELEROMETER", Sensor.TYPE_ACCELEROMETER) + .put("MAGNETIC_FIELD", Sensor.TYPE_MAGNETIC_FIELD) + .put("ORIENTATION", Sensor.TYPE_ORIENTATION) + .put("GYROSCOPE", Sensor.TYPE_GYROSCOPE) + .put("LIGHT", Sensor.TYPE_LIGHT) + .put("TEMPERATURE", Sensor.TYPE_TEMPERATURE) + .put("PRESSURE", Sensor.TYPE_PRESSURE) + .put("AMBIENT_TEMPERATURE", Sensor.TYPE_AMBIENT_TEMPERATURE) + .put("PROXIMITY", Sensor.TYPE_PROXIMITY) + .put("GRAVITY", Sensor.TYPE_GRAVITY) + .put("LINEAR_ACCELERATION", Sensor.TYPE_LINEAR_ACCELERATION) + .put("RELATIVE_HUMIDITY", Sensor.TYPE_RELATIVE_HUMIDITY) + .put("AMBIENT_TEMPERATURE", Sensor.TYPE_AMBIENT_TEMPERATURE) + .build(); public boolean ignoresUnsupportedSensor = false; public final Delay delay = new Delay(); diff --git a/autojs/src/main/java/com/stardust/autojs/script/JavaScriptSource.java b/autojs/src/main/java/com/stardust/autojs/script/JavaScriptSource.java index c6008135..93e8f0fa 100644 --- a/autojs/src/main/java/com/stardust/autojs/script/JavaScriptSource.java +++ b/autojs/src/main/java/com/stardust/autojs/script/JavaScriptSource.java @@ -3,7 +3,7 @@ package com.stardust.autojs.script; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.stardust.util.MapEntries; +import com.stardust.util.MapBuilder; import java.io.Reader; import java.io.StringReader; @@ -23,10 +23,10 @@ public abstract class JavaScriptSource extends ScriptSource { public static final int EXECUTION_MODE_UI = 0x00000001; public static final int EXECUTION_MODE_AUTO = 0x00000002; - private static final Map EXECUTION_MODES = new MapEntries() - .entry("ui", EXECUTION_MODE_UI) - .entry("auto", EXECUTION_MODE_AUTO) - .map(); + private static final Map EXECUTION_MODES = new MapBuilder() + .put("ui", EXECUTION_MODE_UI) + .put("auto", EXECUTION_MODE_AUTO) + .build(); private static final int EXECUTION_MODE_STRING_MAX_LENGTH = 7; private int mExecutionMode = -1; diff --git a/autojs/src/main/java/com/stardust/autojs/script/ScriptSource.java b/autojs/src/main/java/com/stardust/autojs/script/ScriptSource.java index 53303a1a..b66d3b74 100644 --- a/autojs/src/main/java/com/stardust/autojs/script/ScriptSource.java +++ b/autojs/src/main/java/com/stardust/autojs/script/ScriptSource.java @@ -1,17 +1,6 @@ package com.stardust.autojs.script; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.view.View; - -import com.stardust.util.MapEntries; - -import java.io.Reader; import java.io.Serializable; -import java.io.StringReader; -import java.util.Arrays; -import java.util.List; -import java.util.Map; /** * Created by Stardust on 2017/4/2. diff --git a/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.java b/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.java index 50c27c2f..e18fe2e9 100644 --- a/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.java +++ b/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.java @@ -7,7 +7,7 @@ import android.support.annotation.RequiresApi; import android.view.accessibility.AccessibilityNodeInfo; import com.stardust.automator.UiObject; -import com.stardust.util.MapEntries; +import com.stardust.util.MapBuilder; import java.util.Map; @@ -17,15 +17,15 @@ import java.util.Map; public class ActionFactory { - private static Map searchUpAction = new MapEntries() - .entry(AccessibilityNodeInfo.ACTION_CLICK, null) - .entry(AccessibilityNodeInfo.ACTION_LONG_CLICK, null) - .entry(AccessibilityNodeInfo.ACTION_SELECT, null) - .entry(AccessibilityNodeInfo.ACTION_FOCUS, null) - .entry(AccessibilityNodeInfo.ACTION_SELECT, null) - .entry(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null) - .entry(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null) - .map(); + private static Map searchUpAction = new MapBuilder() + .put(AccessibilityNodeInfo.ACTION_CLICK, null) + .put(AccessibilityNodeInfo.ACTION_LONG_CLICK, null) + .put(AccessibilityNodeInfo.ACTION_SELECT, null) + .put(AccessibilityNodeInfo.ACTION_FOCUS, null) + .put(AccessibilityNodeInfo.ACTION_SELECT, null) + .put(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null) + .put(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null) + .build(); public static SimpleAction createActionWithTextFilter(int action, String text, int index) { if (searchUpAction.containsKey(action)) diff --git a/common/src/main/java/com/stardust/util/MapEntries.java b/common/src/main/java/com/stardust/util/MapBuilder.java similarity index 66% rename from common/src/main/java/com/stardust/util/MapEntries.java rename to common/src/main/java/com/stardust/util/MapBuilder.java index 588ed5a5..3f465b81 100644 --- a/common/src/main/java/com/stardust/util/MapEntries.java +++ b/common/src/main/java/com/stardust/util/MapBuilder.java @@ -2,30 +2,29 @@ package com.stardust.util; import java.util.HashMap; import java.util.Map; -import java.util.TreeMap; /** * Created by Stardust on 2017/1/26. */ -public class MapEntries { +public class MapBuilder { private Map mMap; - public MapEntries() { + public MapBuilder() { this(new HashMap()); } - public MapEntries(Map map) { + public MapBuilder(Map map) { mMap = map; } - public MapEntries entry(K key, V value) { + public MapBuilder put(K key, V value) { mMap.put(key, value); return this; } - public Map map() { + public Map build() { return mMap; } From 9d1fdf3fe94f6ff773eb33a485f9909b404eaad5 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Fri, 28 Sep 2018 14:20:21 +0800 Subject: [PATCH 14/14] feat: intent task --- .../receiver/BaseBroadcastReceiver.java | 1 - .../autojs/autojs/model/explorer/Explorer.java | 4 ++++ ...erSamleItem.java => ExplorerSampleItem.java} | 8 ++++---- .../model/explorer/WorkspaceFileProvider.java | 7 ++++++- .../autojs/autojs/ui/explorer/ExplorerView.java | 9 +++++++++ .../ui/timing/TimedTaskSettingActivity.java | 4 ++++ .../res/layout/activity_timed_task_setting.xml | 17 +++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 8 files changed, 46 insertions(+), 6 deletions(-) rename app/src/main/java/org/autojs/autojs/model/explorer/{ExplorerSamleItem.java => ExplorerSampleItem.java} (58%) diff --git a/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java b/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java index 5cad9f4f..791fcbb4 100644 --- a/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java +++ b/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java @@ -4,7 +4,6 @@ import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.os.Bundle; import android.util.Log; import android.widget.Toast; diff --git a/app/src/main/java/org/autojs/autojs/model/explorer/Explorer.java b/app/src/main/java/org/autojs/autojs/model/explorer/Explorer.java index ade9ea3f..cb8a5e39 100644 --- a/app/src/main/java/org/autojs/autojs/model/explorer/Explorer.java +++ b/app/src/main/java/org/autojs/autojs/model/explorer/Explorer.java @@ -30,6 +30,10 @@ public class Explorer { this(explorerProvider, cacheSize, EventBus.getDefault()); } + public ExplorerProvider getProvider() { + return mExplorerProvider; + } + public void notifyChildrenChanged(ExplorerPage page) { clearCache(page); mEventBus.post(new ExplorerChangeEvent(page, CHILDREN_CHANGE, null)); diff --git a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerSamleItem.java b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerSampleItem.java similarity index 58% rename from app/src/main/java/org/autojs/autojs/model/explorer/ExplorerSamleItem.java rename to app/src/main/java/org/autojs/autojs/model/explorer/ExplorerSampleItem.java index f469acd9..48170710 100644 --- a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerSamleItem.java +++ b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerSampleItem.java @@ -4,16 +4,16 @@ import com.stardust.pio.PFile; import java.io.File; -public class ExplorerSamleItem extends ExplorerFileItem { - public ExplorerSamleItem(PFile file, ExplorerPage parent) { +public class ExplorerSampleItem extends ExplorerFileItem { + public ExplorerSampleItem(PFile file, ExplorerPage parent) { super(file, parent); } - public ExplorerSamleItem(String path, ExplorerPage parent) { + public ExplorerSampleItem(String path, ExplorerPage parent) { super(path, parent); } - public ExplorerSamleItem(File file, ExplorerPage parent) { + public ExplorerSampleItem(File file, ExplorerPage parent) { super(file, parent); } diff --git a/app/src/main/java/org/autojs/autojs/model/explorer/WorkspaceFileProvider.java b/app/src/main/java/org/autojs/autojs/model/explorer/WorkspaceFileProvider.java index 403cad93..e9a147d2 100644 --- a/app/src/main/java/org/autojs/autojs/model/explorer/WorkspaceFileProvider.java +++ b/app/src/main/java/org/autojs/autojs/model/explorer/WorkspaceFileProvider.java @@ -8,6 +8,7 @@ import com.stardust.pio.PFile; import com.stardust.pio.PFiles; import org.autojs.autojs.Pref; +import org.autojs.autojs.model.sample.SampleFile; import java.io.File; import java.io.FileFilter; @@ -52,7 +53,7 @@ public class WorkspaceFileProvider extends ExplorerFileProvider { } } else { if (file.getPath().startsWith(mSampleDir.getPath())) { - p.addChild(new ExplorerSamleItem(file, p)); + p.addChild(new ExplorerSampleItem(file, p)); } else { p.addChild(new ExplorerFileItem(file, p)); } @@ -98,6 +99,10 @@ public class WorkspaceFileProvider extends ExplorerFileProvider { }); } + public static void resetSample(SampleFile sampleFile){ + + } + @Override protected ExplorerDirPage createExplorerPage(String path, ExplorerPage parent) { ExplorerDirPage page = super.createExplorerPage(path, parent); diff --git a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java index e250921c..a91384ff 100644 --- a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java +++ b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java @@ -27,7 +27,11 @@ import org.autojs.autojs.model.explorer.ExplorerFileItem; import org.autojs.autojs.model.explorer.ExplorerItem; import org.autojs.autojs.model.explorer.ExplorerPage; import org.autojs.autojs.model.explorer.ExplorerProjectPage; +import org.autojs.autojs.model.explorer.ExplorerSampleItem; import org.autojs.autojs.model.explorer.ExplorerSamplePage; +import org.autojs.autojs.model.explorer.Explorers; +import org.autojs.autojs.model.explorer.WorkspaceFileProvider; +import org.autojs.autojs.model.sample.SampleFile; import org.autojs.autojs.model.script.ScriptFile; import org.autojs.autojs.model.script.Scripts; import org.autojs.autojs.ui.project.BuildActivity; @@ -306,6 +310,8 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR case R.id.action_sort_by_size: sort(ExplorerItemList.SORT_TYPE_SIZE, mDirSortMenuShowing); break; + case R.id.reset: + // WorkspaceFileProvider.resetSample(mSelectedItem.toScriptFile()); default: return false; } @@ -487,6 +493,9 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR } if (!mExplorerItem.canRename()) { menu.removeItem(R.id.rename); + } + if(mExplorerItem instanceof ExplorerSampleItem){ + } popupMenu.setOnMenuItemClickListener(ExplorerView.this); popupMenu.show(); diff --git a/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java b/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java index 0997e7c3..a4d4ce31 100644 --- a/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java @@ -86,6 +86,8 @@ public class TimedTaskSettingActivity extends BaseActivity { .put(Intent.ACTION_PACKAGE_REMOVED, R.string.text_run_on_package_uninstall) .put(Intent.ACTION_PACKAGE_REPLACED, R.string.text_run_on_package_update) .put(Intent.ACTION_HEADSET_PLUG, R.string.text_run_on_headset_plug) + .put(Intent.ACTION_CONFIGURATION_CHANGED, R.string.text_run_on_config_change) + .put(Intent.ACTION_TIME_TICK, R.string.text_run_on_time_tick) .build(); private static final BiMap ACTIONS = BiMaps.newBuilder() @@ -101,6 +103,8 @@ public class TimedTaskSettingActivity extends BaseActivity { .put(R.id.run_on_package_uninstall, Intent.ACTION_PACKAGE_REMOVED) .put(R.id.run_on_package_update, Intent.ACTION_PACKAGE_REPLACED) .put(R.id.run_on_headset_plug, Intent.ACTION_HEADSET_PLUG) + .put(R.id.run_on_config_change, Intent.ACTION_CONFIGURATION_CHANGED) + .put(R.id.run_on_time_tick, Intent.ACTION_TIME_TICK) .build(); diff --git a/app/src/main/res/layout/activity_timed_task_setting.xml b/app/src/main/res/layout/activity_timed_task_setting.xml index ee7e0c11..fc19525c 100644 --- a/app/src/main/res/layout/activity_timed_task_setting.xml +++ b/app/src/main/res/layout/activity_timed_task_setting.xml @@ -375,6 +375,22 @@ android:paddingLeft="8dp" android:text="@string/text_run_on_headset_plug"/> + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 31637940..ec195a39 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -419,4 +419,6 @@ 应用卸载时 应用更新时 耳机插拔时 + 每分钟一次 + 某些设置(屏幕方向,地区等)更改时