Merge branch 'dev' of https://github.com/hyb1996/NoRootScriptDroid into dev
# Conflicts: # .idea/caches/build_file_checksums.ser
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,4 +11,5 @@
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
*.apk
|
||||
*.exe
|
||||
*.exe
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
1
.idea/dictionaries/Stardust.xml
generated
1
.idea/dictionaries/Stardust.xml
generated
@@ -3,6 +3,7 @@
|
||||
<words>
|
||||
<w>capturer</w>
|
||||
<w>dismissable</w>
|
||||
<w>flowable</w>
|
||||
<w>interruptible</w>
|
||||
<w>loopers</w>
|
||||
<w>prefill</w>
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -146,6 +141,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')
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
android:theme="@style/IssueReporterTheme"/>
|
||||
|
||||
|
||||
<service android:name=".external.foreground.ForegroundService"/>
|
||||
<service android:name=".external.ScriptExecutionIntentService"/>
|
||||
|
||||
<activity android:name=".external.tasker.TaskPrefEditActivity_"/>
|
||||
@@ -132,10 +133,44 @@
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<receiver android:name="org.autojs.autojs.external.boot.BootCompleteReceiver" >
|
||||
<receiver android:name="org.autojs.autojs.external.receiver.StaticBroadcastReceiver" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
<action android:name="android.intent.action.TIME_SET"/>
|
||||
<action android:name="android.intent.action.TIMEZONE_CHANGED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_ADDED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_CHANGED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_RESTARTED"/>
|
||||
<action android:name="android.intent.action.UID_REMOVED"/>
|
||||
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
|
||||
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
|
||||
<action android:name="android.intent.action.ACTION_SHUTDOWN"/>
|
||||
<action android:name="android.intent.action.DATE_CHANGED"/>
|
||||
<action android:name="android.intent.action.DREAMING_STARTED"/>
|
||||
<action android:name="android.intent.action.DREAMING_STOPPED"/>
|
||||
<action android:name="android.intent.action.HEADSET_PLUG"/>
|
||||
<action android:name="android.intent.action.INPUT_METHOD_CHANGED"/>
|
||||
<action android:name="android.intent.action.LOCALE_CHANGED"/>
|
||||
<action android:name="android.intent.action.MEDIA_BUTTON"/>
|
||||
<action android:name="android.intent.action.MEDIA_CHECKING"/>
|
||||
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_FIRST_LAUNCH"/>
|
||||
<action android:name="android.intent.action.PROVIDER_CHANGED"/>
|
||||
<action android:name="android.intent.action.WALLPAPER_CHANGED"/>
|
||||
<action android:name="android.intent.action.USER_UNLOCKED"/>
|
||||
<action android:name="android.intent.action.USER_PRESENT"/>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_ADDED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_CHANGED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_RESTARTED"/>
|
||||
<data android:scheme="package"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.autojs.autojs;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
@@ -10,29 +12,26 @@ 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 org.autojs.autojs.autojs.AutoJs;
|
||||
import org.autojs.autojs.autojs.key.GlobalKeyObserver;
|
||||
import org.autojs.autojs.network.GlideApp;
|
||||
import org.autojs.autojs.storage.database.IntentTaskDatabase;
|
||||
import org.autojs.autojs.storage.database.TimedTaskDatabase;
|
||||
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 org.autojs.autojs.autojs.AutoJs;
|
||||
import org.autojs.autojs.autojs.key.GlobalKeyObserver;
|
||||
import org.autojs.autojs.external.receiver.DynamicBroadcastReceivers;
|
||||
import org.autojs.autojs.network.GlideApp;
|
||||
import org.autojs.autojs.timing.IntentTask;
|
||||
import org.autojs.autojs.timing.TimedTaskManager;
|
||||
import org.autojs.autojs.timing.TimedTaskScheduler;
|
||||
import org.autojs.autojs.tool.CrashHandler;
|
||||
import org.autojs.autojs.ui.error.ErrorReportActivity;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
@@ -44,6 +43,7 @@ public class App extends MultiDexApplication {
|
||||
private static final String BUGLY_APP_ID = "19b3607b53";
|
||||
|
||||
private static WeakReference<App> instance;
|
||||
private DynamicBroadcastReceivers mDynamicBroadcastReceivers;
|
||||
|
||||
public static App getApp() {
|
||||
return instance.get();
|
||||
@@ -58,6 +58,10 @@ public class App extends MultiDexApplication {
|
||||
init();
|
||||
}
|
||||
|
||||
public DynamicBroadcastReceivers getDynamicBroadcastReceivers() {
|
||||
return mDynamicBroadcastReceivers;
|
||||
}
|
||||
|
||||
private void setUpStaticsTool() {
|
||||
if (BuildConfig.DEBUG)
|
||||
return;
|
||||
@@ -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,17 +86,16 @@ 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() {
|
||||
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);
|
||||
@@ -96,6 +104,18 @@ public class App extends MultiDexApplication {
|
||||
}
|
||||
setupDrawableImageLoader();
|
||||
TimedTaskScheduler.checkTasksRepeatedlyIfNeeded(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<String>(), ArrayList::add)
|
||||
.subscribe(list -> mDynamicBroadcastReceivers.register(list),
|
||||
Throwable::printStackTrace);
|
||||
}
|
||||
|
||||
private void setupDrawableImageLoader() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
88
app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java
vendored
Normal file
88
app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
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;
|
||||
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 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 = 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
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void startForeground() {
|
||||
startForeground(NOTIFICATION_ID, buildNotification());
|
||||
}
|
||||
|
||||
private Notification buildNotification() {
|
||||
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() {
|
||||
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_DEFAULT);
|
||||
channel.setDescription(description);
|
||||
channel.enableLights(false);
|
||||
manager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
stopForeground(true);
|
||||
super.onDestroy();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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: intent = " + intent + ", this = " + this);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
78
app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceivers.java
vendored
Normal file
78
app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceivers.java
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package org.autojs.autojs.external.receiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
|
||||
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_PACKAGES_SUSPENDED;
|
||||
import static android.content.Intent.ACTION_PACKAGES_UNSUSPENDED;
|
||||
import static android.content.Intent.ACTION_SCREEN_OFF;
|
||||
import static android.content.Intent.ACTION_SCREEN_ON;
|
||||
import static android.content.Intent.ACTION_TIME_TICK;
|
||||
|
||||
public class DynamicBroadcastReceivers {
|
||||
|
||||
private static final List<String> DEFAULT_ACTIONS = new ArrayList<>(Arrays.asList(
|
||||
ACTION_TIME_TICK,
|
||||
ACTION_SCREEN_OFF,
|
||||
ACTION_SCREEN_ON,
|
||||
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 final Set<String> mActions = new LinkedHashSet<>();
|
||||
private final List<BroadcastReceiver> mReceivers = new ArrayList<>();
|
||||
private final Context mContext;
|
||||
|
||||
|
||||
public DynamicBroadcastReceivers(Context context) {
|
||||
mContext = context;
|
||||
register(DEFAULT_ACTIONS);
|
||||
}
|
||||
|
||||
public void register(String action) {
|
||||
register(Collections.singletonList(action));
|
||||
}
|
||||
|
||||
public void register(List<String> 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();
|
||||
}
|
||||
}
|
||||
40
app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java
vendored
Normal file
40
app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java
vendored
Normal file
@@ -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<String> 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"
|
||||
));
|
||||
|
||||
}
|
||||
@@ -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,8 @@ 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_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)
|
||||
@@ -63,4 +65,9 @@ public class TaskerScriptEditActivity extends BaseActivity {
|
||||
TaskerScriptEditActivity.super.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
mEditorView.destroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,4 +161,7 @@ public class AutoCompletion {
|
||||
}
|
||||
|
||||
|
||||
public void shutdown(){
|
||||
mExecutorService.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<String, Object>()
|
||||
.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<String, Object>()
|
||||
.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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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<M extends BaseModel> {
|
||||
|
||||
private final SQLiteDatabase mWritableSQLiteDatabase;
|
||||
private final SQLiteDatabase mReadableSQLiteDatabase;
|
||||
private final String mTable;
|
||||
private final PublishSubject<ModelChange<M>> mModelChange = PublishSubject.create();
|
||||
|
||||
public Database(SQLiteOpenHelper sqLiteOpenHelper, String table) {
|
||||
mWritableSQLiteDatabase = sqLiteOpenHelper.getWritableDatabase();
|
||||
mReadableSQLiteDatabase = sqLiteOpenHelper.getWritableDatabase();
|
||||
mTable = table;
|
||||
}
|
||||
|
||||
public <T> Observable<T> exec(Callable<T> callable) {
|
||||
return Observable.fromCallable(callable)
|
||||
.subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
public <T> Flowable<T> execFlowable(Callable<T> callable) {
|
||||
return Flowable.fromCallable(callable)
|
||||
.subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
public PublishSubject<ModelChange<M>> getModelChange() {
|
||||
return mModelChange;
|
||||
}
|
||||
|
||||
public Observable<Integer> 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<Integer> 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<Long> 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<M> queryAllAsFlowable() {
|
||||
return execFlowable(() ->
|
||||
mReadableSQLiteDatabase.rawQuery("SELECT * FROM " + mTable, null)
|
||||
)
|
||||
.flatMap(cursor -> Flowable.fromIterable(() -> new CursorIterator(cursor)))
|
||||
.map(this::createModelFromCursor);
|
||||
}
|
||||
|
||||
public List<M> queryAll() {
|
||||
ArrayList<M> 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<M> 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<Cursor> {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<IntentTask> {
|
||||
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<M> {
|
||||
|
||||
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<M> {
|
||||
return mData;
|
||||
}
|
||||
|
||||
public BaseModel.Action getAction() {
|
||||
public int getAction() {
|
||||
return mAction;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<TimedTask> {
|
||||
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,29 +1,22 @@
|
||||
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 android.text.TextUtils;
|
||||
|
||||
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.App;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/27.
|
||||
@@ -31,12 +24,10 @@ import io.reactivex.subjects.PublishSubject;
|
||||
//TODO rx
|
||||
public class TimedTaskManager {
|
||||
|
||||
|
||||
private static TimedTaskManager sInstance;
|
||||
private ModelAdapter<TimedTask> mTimedTaskModelAdapter;
|
||||
private ModelAdapter<IntentTask> mIntentTaskModelAdapter;
|
||||
private Context mContext;
|
||||
private PublishSubject<ModelChange<TimedTask>> mTimedTaskChanges = PublishSubject.create();
|
||||
private TimedTaskDatabase mTimedTaskDatabase;
|
||||
private IntentTaskDatabase mIntentTaskDatabase;
|
||||
|
||||
public static TimedTaskManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
@@ -45,104 +36,132 @@ 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<TimedTask>() {
|
||||
@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(i -> {
|
||||
if(!TextUtils.isEmpty(intentTask.getAction())){
|
||||
App.getApp().getDynamicBroadcastReceivers()
|
||||
.register(intentTask.getAction());
|
||||
}
|
||||
}, Throwable::printStackTrace);
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
public void removeTask(IntentTask intentTask) {
|
||||
mIntentTaskModelAdapter.delete(intentTask);
|
||||
mIntentTaskDatabase.delete(intentTask)
|
||||
.subscribe(EmptyObservers.consumer(), Throwable::printStackTrace);;
|
||||
}
|
||||
|
||||
public Flowable<TimedTask> getAllTasks() {
|
||||
return RXSQLite.rx(SQLite.select().from(TimedTask.class))
|
||||
.queryStreamResults()
|
||||
.subscribeOn(Schedulers.io());
|
||||
return mTimedTaskDatabase.queryAllAsFlowable();
|
||||
}
|
||||
|
||||
public Flowable<IntentTask> 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<ModelChange<TimedTask>> 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<TimedTask> 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);
|
||||
}
|
||||
|
||||
@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 SQLite.select().from(TimedTask.class).count();
|
||||
return mTimedTaskDatabase.count();
|
||||
}
|
||||
|
||||
public List<IntentTask> getAllIntentTasksAsList() {
|
||||
return mIntentTaskDatabase.queryAll();
|
||||
}
|
||||
|
||||
public Observable<ModelChange<IntentTask>> getIntentTaskChanges() {
|
||||
return mIntentTaskDatabase.getModelChange();
|
||||
}
|
||||
|
||||
public IntentTask getIntentTask(long intentTaskId) {
|
||||
return mIntentTaskDatabase.queryById(intentTaskId);
|
||||
}
|
||||
|
||||
public Flowable<IntentTask> getAllIntentTasks() {
|
||||
return mIntentTaskDatabase.queryAllAsFlowable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -122,7 +123,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() {
|
||||
@@ -315,9 +320,11 @@ public class ScriptOperations {
|
||||
|
||||
|
||||
public Observable<ScriptFile> 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)
|
||||
.dir(Pref.getScriptDirPath())
|
||||
.chooseDir()
|
||||
.singleChoice()
|
||||
.map(saveDir -> new File(saveDir, fileName).getPath())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -180,6 +180,7 @@ EditActivity extends BaseActivity implements OnActivityResultDelegate.DelegateHo
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
mEditorView.destroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
package org.autojs.autojs.ui.edit.editor;
|
||||
/*
|
||||
* Copyright 2016. SHENQINCI(沈钦赐)<946736079@qq.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.widget.EditText;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* 撤销和恢复撤销
|
||||
* Created by 沈钦赐 on 16/6/23.
|
||||
*/
|
||||
public class TextViewRedoUndoer {
|
||||
//操作序号(一次编辑可能对应多个操作,如替换文字,就是删除+插入)
|
||||
int index;
|
||||
//撤销栈
|
||||
Stack<Action> history = new Stack<>();
|
||||
//恢复栈
|
||||
Stack<Action> historyBack = new Stack<>();
|
||||
|
||||
private Editable editable;
|
||||
private EditText editText;
|
||||
//自动操作标志,防止重复回调,导致无限撤销
|
||||
private boolean flag = false;
|
||||
|
||||
private int mInitialHistoryStackSize;
|
||||
private boolean mEnabled = true;
|
||||
|
||||
public TextViewRedoUndoer(@NonNull EditText editText) {
|
||||
this.editable = editText.getText();
|
||||
this.editText = editText;
|
||||
editText.addTextChangedListener(new Watcher());
|
||||
}
|
||||
|
||||
protected void onEditableChanged(Editable s) {
|
||||
|
||||
}
|
||||
|
||||
protected void onTextChanged(Editable s) {
|
||||
if (history.size() < mInitialHistoryStackSize) {
|
||||
mInitialHistoryStackSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 清理记录
|
||||
* Clear history.
|
||||
*/
|
||||
public final void clearHistory() {
|
||||
history.clear();
|
||||
historyBack.clear();
|
||||
mInitialHistoryStackSize = 0;
|
||||
}
|
||||
|
||||
public boolean canUndo() {
|
||||
return !history.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销
|
||||
* Undo.
|
||||
*/
|
||||
public final void undo() {
|
||||
if (history.empty()) return;
|
||||
//锁定操作
|
||||
flag = true;
|
||||
Action action = history.pop();
|
||||
historyBack.push(action);
|
||||
if (action.isAdd) {
|
||||
//撤销添加
|
||||
editable.delete(action.startCursor, action.startCursor + action.actionTarget.length());
|
||||
editText.setSelection(action.startCursor, action.startCursor);
|
||||
} else {
|
||||
//插销删除
|
||||
editable.insert(action.startCursor, action.actionTarget);
|
||||
if (action.endCursor == action.startCursor) {
|
||||
editText.setSelection(action.startCursor + action.actionTarget.length());
|
||||
} else {
|
||||
editText.setSelection(action.startCursor, action.endCursor);
|
||||
}
|
||||
}
|
||||
//释放操作
|
||||
flag = false;
|
||||
//判断是否是下一个动作是否和本动作是同一个操作,直到不同为止
|
||||
if (!history.empty() && history.peek().index == action.index) {
|
||||
undo();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canRedo() {
|
||||
return !historyBack.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复
|
||||
* Redo.
|
||||
*/
|
||||
public final void redo() {
|
||||
if (historyBack.empty()) return;
|
||||
flag = true;
|
||||
Action action = historyBack.pop();
|
||||
history.push(action);
|
||||
if (action.isAdd) {
|
||||
//恢复添加
|
||||
editable.insert(action.startCursor, action.actionTarget);
|
||||
if (action.endCursor == action.startCursor) {
|
||||
editText.setSelection(action.startCursor + action.actionTarget.length());
|
||||
} else {
|
||||
editText.setSelection(action.startCursor, action.endCursor);
|
||||
}
|
||||
} else {
|
||||
//恢复删除
|
||||
editable.delete(action.startCursor, action.startCursor + action.actionTarget.length());
|
||||
editText.setSelection(action.startCursor, action.startCursor);
|
||||
}
|
||||
flag = false;
|
||||
//判断是否是下一个动作是否和本动作是同一个操作
|
||||
if (!historyBack.empty() && historyBack.peek().index == action.index)
|
||||
redo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 首次设置文本
|
||||
* Set default text.
|
||||
*/
|
||||
public final void setDefaultText(CharSequence text) {
|
||||
clearHistory();
|
||||
flag = true;
|
||||
editable.replace(0, editable.length(), text);
|
||||
flag = false;
|
||||
}
|
||||
|
||||
public boolean isTextChanged() {
|
||||
return history.size() != mInitialHistoryStackSize;
|
||||
}
|
||||
|
||||
public void markTextAsUnchanged() {
|
||||
mInitialHistoryStackSize = history.size();
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
mEnabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
private class Watcher implements TextWatcher {
|
||||
|
||||
/**
|
||||
* Before text changed.
|
||||
*
|
||||
* @param s the s
|
||||
* @param start the start 起始光标
|
||||
* @param count the endCursor 选择数量
|
||||
* @param after the after 替换增加的文字数
|
||||
*/
|
||||
@Override
|
||||
public final void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
if (!editText.isEnabled() || !mEnabled) {
|
||||
return;
|
||||
}
|
||||
if (flag) return;
|
||||
int end = start + count;
|
||||
if (end > start && end <= s.length()) {
|
||||
CharSequence charSequence = s.subSequence(start, end);
|
||||
//删除了文字
|
||||
if (charSequence.length() > 0) {
|
||||
Action action = new Action(charSequence, start, false);
|
||||
if (count > 1) {
|
||||
//如果一次超过一个字符,说名用户选择了,然后替换或者删除操作
|
||||
action.setSelectCount(count);
|
||||
} else if (count == 1 && count == after) {
|
||||
//一个字符替换
|
||||
action.setSelectCount(count);
|
||||
}
|
||||
//还有一种情况:选择一个字符,然后删除(暂时没有考虑这种情况)
|
||||
|
||||
history.push(action);
|
||||
historyBack.clear();
|
||||
action.setIndex(++index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On text changed.
|
||||
*
|
||||
* @param s the s
|
||||
* @param start the start 起始光标
|
||||
* @param before the before 选择数量
|
||||
* @param count the endCursor 添加的数量
|
||||
*/
|
||||
@Override
|
||||
public final void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
if (!editText.isEnabled() || !mEnabled) {
|
||||
return;
|
||||
}
|
||||
if (flag) return;
|
||||
int end = start + count;
|
||||
if (end > start) {
|
||||
CharSequence charSequence = s.subSequence(start, end);
|
||||
//添加文字
|
||||
if (charSequence.length() > 0) {
|
||||
Action action = new Action(charSequence, start, true);
|
||||
|
||||
history.push(action);
|
||||
historyBack.clear();
|
||||
if (before > 0) {
|
||||
//文字替换(先删除再增加),删除和增加是同一个操作,所以不需要增加序号
|
||||
action.setIndex(index);
|
||||
} else {
|
||||
action.setIndex(++index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void afterTextChanged(Editable s) {
|
||||
if (!editText.isEnabled() || !mEnabled) {
|
||||
return;
|
||||
}
|
||||
if (flag) return;
|
||||
if (s != editable) {
|
||||
editable = s;
|
||||
onEditableChanged(s);
|
||||
}
|
||||
TextViewRedoUndoer.this.onTextChanged(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class Action {
|
||||
/**
|
||||
* 改变字符.
|
||||
*/
|
||||
CharSequence actionTarget;
|
||||
/**
|
||||
* 光标位置.
|
||||
*/
|
||||
int startCursor;
|
||||
int endCursor;
|
||||
/**
|
||||
* 标志增加操作.
|
||||
*/
|
||||
boolean isAdd;
|
||||
/**
|
||||
* 操作序号.
|
||||
*/
|
||||
int index;
|
||||
|
||||
|
||||
public Action(CharSequence actionTag, int startCursor, boolean add) {
|
||||
this.actionTarget = actionTag;
|
||||
this.startCursor = startCursor;
|
||||
this.endCursor = startCursor;
|
||||
this.isAdd = add;
|
||||
}
|
||||
|
||||
public void setSelectCount(int count) {
|
||||
this.endCursor = endCursor + count;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -111,7 +115,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);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()){
|
||||
ForegroundService.start(GlobalAppContext.get());
|
||||
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){
|
||||
ForegroundService.start(GlobalAppContext.get());
|
||||
}else {
|
||||
ForegroundService.stop(GlobalAppContext.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void inputRemoteHost() {
|
||||
String host = Pref.getServerAddressOrDefault(WifiTool.getRouterIp(getActivity()));
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
|
||||
@@ -62,7 +62,6 @@ public class MarketFragment extends ViewPagerFragment implements BackPressedHand
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed(Activity activity) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -35,7 +38,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";
|
||||
|
||||
@@ -63,27 +66,11 @@ public class MyScriptListFragment extends ViewPagerFragment implements BackPress
|
||||
if (item.isEditable()) {
|
||||
Scripts.edit(item.toScriptFile());
|
||||
} else {
|
||||
IntentUtil.viewFile(getContext(), item.getPath());
|
||||
IntentUtil.viewFile(GlobalAppContext.get(), item.getPath());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@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);
|
||||
@@ -98,7 +85,7 @@ public class MyScriptListFragment extends ViewPagerFragment implements BackPress
|
||||
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<Boolean>() {
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
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;
|
||||
import org.autojs.autojs.timing.TimedTask;
|
||||
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();
|
||||
@@ -29,11 +38,26 @@ 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,24 +66,47 @@ 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;
|
||||
Integer desc = ACTION_DESC_MAP.get(mIntentTask.getAction());
|
||||
if(desc != null){
|
||||
return GlobalAppContext.getString(desc);
|
||||
}
|
||||
return mIntentTask.getAction();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
TimedTaskManager.getInstance().removeTask(mTimedTask);
|
||||
if (mTimedTask != null) {
|
||||
TimedTaskManager.getInstance().removeTask(mTimedTask);
|
||||
} else {
|
||||
TimedTaskManager.getInstance().removeTask(mIntentTask);
|
||||
}
|
||||
}
|
||||
|
||||
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 +116,16 @@ public abstract class Task {
|
||||
public void setTimedTask(TimedTask timedTask) {
|
||||
mTimedTask = timedTask;
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
@@ -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,56 @@ public abstract class TaskGroup implements Parent<Task> {
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
List<TimedTask> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,30 +13,28 @@ 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 org.autojs.autojs.ui.timing.TimedTaskSettingActivity_;
|
||||
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -60,7 +58,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 +133,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 +152,25 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView {
|
||||
super.onDetachedFromWindow();
|
||||
AutoJs.getInstance().getScriptEngineService().unregisterGlobalScriptExecutionListener(mScriptExecutionListener);
|
||||
mTimedTaskChangeDisposable.dispose();
|
||||
mIntentTaskChangeDisposable.dispose();
|
||||
}
|
||||
|
||||
void onTimedTaskChange(ModelChange<TimedTask> 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();
|
||||
}
|
||||
}
|
||||
@@ -249,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(TaskReceiver.EXTRA_TASK_ID, ((Task.PendingTask) mTask).getTimedTask().getId())
|
||||
.extra(extra, task.getId())
|
||||
.start();
|
||||
}
|
||||
}
|
||||
@@ -263,8 +266,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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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<String, Runnable>()
|
||||
.entry(getString(R.string.text_theme_color), () -> selectThemeColor(getActivity()))
|
||||
.entry(getString(R.string.text_check_for_updates), () -> new UpdateCheckDialog(getActivity())
|
||||
ACTION_MAP = new MapBuilder<String, Runnable>()
|
||||
.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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
@@ -18,6 +20,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 +30,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.MapBuilder;
|
||||
|
||||
import org.androidannotations.annotations.AfterViews;
|
||||
import org.androidannotations.annotations.CheckedChange;
|
||||
@@ -49,6 +55,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.
|
||||
@@ -56,12 +63,51 @@ import java.util.List;
|
||||
@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<String, Integer> ACTION_DESC_MAP = new MapBuilder<String, Integer>()
|
||||
.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)
|
||||
.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<Integer, String> ACTIONS = BiMaps.<Integer, String>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)
|
||||
.put(R.id.run_on_config_change, Intent.ACTION_CONFIGURATION_CHANGED)
|
||||
.put(R.id.run_on_time_tick, Intent.ACTION_TIME_TICK)
|
||||
.build();
|
||||
|
||||
|
||||
@ViewById(R.id.toolbar)
|
||||
Toolbar mToolbar;
|
||||
|
||||
@@ -77,9 +123,17 @@ 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 mRunOnBroadcastRadio;
|
||||
|
||||
@ViewById(R.id.run_on_other_broadcast)
|
||||
RadioButton mRunOnOtherBroadcast;
|
||||
|
||||
@ViewById(R.id.action)
|
||||
EditText mOtherBroadcastAction;
|
||||
|
||||
@ViewById(R.id.broadcast_group)
|
||||
RadioGroup mBroadcastGroup;
|
||||
|
||||
@ViewById(R.id.disposable_task_time)
|
||||
TextView mDisposableTaskTime;
|
||||
@@ -98,25 +152,33 @@ public class TimedTaskSettingActivity extends BaseActivity {
|
||||
|
||||
private List<CheckBox> mDayOfWeekCheckBoxes = new ArrayList<>();
|
||||
|
||||
|
||||
private ScriptFile mScriptFile;
|
||||
private TimedTask mTimedTask;
|
||||
private IntentTask mIntentTask;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
int taskId = getIntent().getIntExtra(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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -128,7 +190,7 @@ public class TimedTaskSettingActivity extends BaseActivity {
|
||||
mToolbar.setSubtitle(mScriptFile.getName());
|
||||
}
|
||||
findDayOfWeekCheckBoxes(mWeeklyTaskContainer);
|
||||
setUpTime();
|
||||
setUpTaskSettings();
|
||||
}
|
||||
|
||||
private void findDayOfWeekCheckBoxes(ViewGroup parent) {
|
||||
@@ -145,13 +207,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()));
|
||||
@@ -171,11 +252,10 @@ public class TimedTaskSettingActivity extends BaseActivity {
|
||||
mDayOfWeekCheckBoxes.get(i).setChecked(mTimedTask.hasDayOfWeek(i + 1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@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()) {
|
||||
@@ -269,10 +349,8 @@ 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;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
@@ -282,18 +360,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 (mRunOnBootRadio.isChecked()) {
|
||||
IntentTask task = new IntentTask();
|
||||
task.setAction(Intent.ACTION_BOOT_COMPLETED);
|
||||
task.setScriptPath(mScriptFile.getPath());
|
||||
TimedTaskManager.getInstance().addTask(task);
|
||||
finish();
|
||||
private void createOrUpdateTask() {
|
||||
if (mRunOnBroadcastRadio.isChecked()) {
|
||||
createOrUpdateIntentTask();
|
||||
return;
|
||||
}
|
||||
TimedTask task = createTimedTask();
|
||||
@@ -301,6 +375,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());
|
||||
@@ -308,4 +385,38 @@ public class TimedTaskSettingActivity extends BaseActivity {
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
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());
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -253,12 +253,175 @@
|
||||
</com.github.aakira.expandablelayout.ExpandableRelativeLayout>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_boot_radio"
|
||||
android:id="@+id/run_on_broadcast"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:text="@string/text_run_on_boot"/>
|
||||
android:text="@string/text_run_on_broadcast"/>
|
||||
|
||||
<com.github.aakira.expandablelayout.ExpandableRelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:ael_expanded="false"
|
||||
app:ael_interpolator="fastOutSlowIn"
|
||||
app:ael_orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/broadcast_group"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_boot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_boot"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_screen_on"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_screen_on"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_screen_off"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_screen_off"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_screen_unlock"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_screen_unlock"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_battery_change"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_battery_change"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_power_connect"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_power_connect"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_power_disconnect"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_power_disconnect"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_conn_change"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_conn_change"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_package_install"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_package_install"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_package_uninstall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_package_uninstall"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_package_update"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_package_update"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_headset_plug"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_headset_plug"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_config_change"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_config_change"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_time_tick"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_time_tick"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/run_on_other_broadcast"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:text="@string/text_run_on_other_broadcast"/>
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="36dp"
|
||||
android:layout_marginTop="2dp">
|
||||
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/action"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/text_broadcast_action"
|
||||
android:maxLines="2"
|
||||
android:text="@string/text_broadcast_action_prefix"/>
|
||||
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</com.github.aakira.expandablelayout.ExpandableRelativeLayout>
|
||||
</RadioGroup>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -382,7 +382,7 @@
|
||||
<string name="text_use_alarm_clock">使用系统闹钟唤醒Auto.js</string>
|
||||
<string name="error_connect_to_remote">连接失败: %s</string>
|
||||
<string name="text_are_you_sure_to_delete">确定要删除%s吗</string>
|
||||
<string name="text_run_on_boot">开机时运行</string>
|
||||
<string name="text_run_on_broadcast">特定事件(广播)触发运行</string>
|
||||
<string name="text_search_java_class">搜索Java包/类</string>
|
||||
<string name="text_class_or_package_name">类/包名</string>
|
||||
<string name="text_view_docs">查看文档</string>
|
||||
@@ -397,4 +397,28 @@
|
||||
<string name="text_project_location">项目位置</string>
|
||||
<string name="text_new_project">新建项目</string>
|
||||
<string name="text_js_file">js文件</string>
|
||||
<string name="text_invalid_project">无效项目</string>
|
||||
<string name="text_foreground_service">前台服务</string>
|
||||
<string name="key_foreground_servie">key_foreground_service</string>
|
||||
<string name="foreground_notification_channel_name">前台服务通知</string>
|
||||
<string name="foreground_notification_title">Auto.js保持运行中</string>
|
||||
<string name="foreground_notification_text">点击进入主界面</string>
|
||||
<string name="text_run_on_other_broadcast">其他事件(广播)</string>
|
||||
<string name="text_broadcast_action">广播Action</string>
|
||||
<string name="text_broadcast_action_prefix">android.intent.action.</string>
|
||||
<string name="text_run_on_boot">开机时</string>
|
||||
<string name="text_run_on_screen_on">亮屏时</string>
|
||||
<string name="text_run_on_screen_off">息屏时</string>
|
||||
<string name="error_empty_selection">请选择一个广播事件选项</string>
|
||||
<string name="text_run_on_battery_change">电量变化时</string>
|
||||
<string name="text_run_on_screen_unlock">屏幕解锁时</string>
|
||||
<string name="text_run_on_power_connect">电源连接时</string>
|
||||
<string name="text_run_on_power_disconnect">电源断开时</string>
|
||||
<string name="text_run_on_conn_change">网络连接变化时</string>
|
||||
<string name="text_run_on_package_install">新应用安装时</string>
|
||||
<string name="text_run_on_package_uninstall">应用卸载时</string>
|
||||
<string name="text_run_on_package_update">应用更新时</string>
|
||||
<string name="text_run_on_headset_plug">耳机插拔时</string>
|
||||
<string name="text_run_on_time_tick">每分钟一次</string>
|
||||
<string name="text_run_on_config_change">某些设置(屏幕方向,地区等)更改时</string>
|
||||
</resources>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -65,6 +65,7 @@ public abstract class AutoJs {
|
||||
mNotificationObserver = new AccessibilityNotificationObserver(mContext);
|
||||
mAccessibilityInfoProvider = new AccessibilityInfoProvider(mContext.getPackageManager());
|
||||
mScriptEngineService = buildScriptEngineService();
|
||||
ScriptEngineService.setInstance(mScriptEngineService);
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ScriptEngineManager.EngineLifecycleCallback> mEngineLifecycleCallbacks = new LinkedHashSet<>();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Boolean> waitWhenIdle = new ThreadLocal<>();
|
||||
private volatile ThreadLocal<HashSet<Integer>> waitIds = new ThreadLocal<>();
|
||||
private volatile ThreadLocal<Integer> maxWaitId = new ThreadLocal<>();
|
||||
private volatile ThreadLocal<CopyOnWriteArrayList<LooperQuitHandler>> looperQuitHanders = new ThreadLocal<>();
|
||||
private volatile ThreadLocal<CopyOnWriteArrayList<LooperQuitHandler>> 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<LooperQuitHandler> handlers = looperQuitHanders.get();
|
||||
public void addLooperQuitHandler(LooperQuitHandler handler) {
|
||||
CopyOnWriteArrayList<LooperQuitHandler> handlers = looperQuitHandlers.get();
|
||||
if (handlers == null) {
|
||||
handlers = new CopyOnWriteArrayList<>();
|
||||
looperQuitHanders.set(handlers);
|
||||
looperQuitHandlers.set(handlers);
|
||||
}
|
||||
handlers.add(handler);
|
||||
}
|
||||
|
||||
public boolean removeLooperQuiteHandler(LooperQuitHandler handler) {
|
||||
CopyOnWriteArrayList<LooperQuitHandler> handlers = looperQuitHanders.get();
|
||||
public boolean removeLooperQuitHandler(LooperQuitHandler handler) {
|
||||
CopyOnWriteArrayList<LooperQuitHandler> 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<LooperQuitHandler> handlers = looperQuitHanders.get();
|
||||
CopyOnWriteArrayList<LooperQuitHandler> handlers = looperQuitHandlers.get();
|
||||
if (handlers == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()) + "{" +
|
||||
|
||||
@@ -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<S extends ScriptSource> {
|
||||
abstract class AbstractScriptEngine<S extends ScriptSource> implements ScriptEngine<S> {
|
||||
|
||||
|
||||
private Map<String, Object> mTags = new ConcurrentHashMap<>();
|
||||
private Map<String, Object> mTags = new HashMap<>();
|
||||
private OnDestroyListener mOnDestroyListener;
|
||||
private boolean mDestroyed = false;
|
||||
private Exception mUncaughtException;
|
||||
@@ -76,9 +77,11 @@ public interface ScriptEngine<S extends ScriptSource> {
|
||||
|
||||
@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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -11,13 +11,12 @@ 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;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2018/2/5.
|
||||
@@ -60,21 +59,21 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler {
|
||||
}
|
||||
|
||||
|
||||
private static final Map<String, Integer> SENSORS = new MapEntries<String, Integer>()
|
||||
.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<String, Integer> SENSORS = new MapBuilder<String, Integer>()
|
||||
.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();
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<String, Integer> EXECUTION_MODES = new MapEntries<String, Integer>()
|
||||
.entry("ui", EXECUTION_MODE_UI)
|
||||
.entry("auto", EXECUTION_MODE_AUTO)
|
||||
.map();
|
||||
private static final Map<String, Integer> EXECUTION_MODES = new MapBuilder<String, Integer>()
|
||||
.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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
118
autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java
Normal file
118
autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Integer, Object> searchUpAction = new MapEntries<Integer, Object>()
|
||||
.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<Integer, Object> searchUpAction = new MapBuilder<Integer, Object>()
|
||||
.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))
|
||||
|
||||
@@ -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<Integer, AccessibilityDelegate> mDelegates = new TreeMap<>();
|
||||
@@ -55,13 +54,13 @@ 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();
|
||||
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 +108,7 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi
|
||||
public AccessibilityNodeInfo getRootInActiveWindow() {
|
||||
try {
|
||||
return super.getRootInActiveWindow();
|
||||
} catch (IllegalStateException e) {
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":416},"path":"commonRelease-4.0.2 Alpha11.apk","properties":{"packageId":"org.autojs.autojs","split":"","minSdkVersion":"17"}}]
|
||||
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":421},"path":"commonRelease-4.0.3 Alpha2.apk","properties":{"packageId":"org.autojs.autojs","split":"","minSdkVersion":"17"}}]
|
||||
11
common/src/main/java/com/stardust/util/BiMap.java
Normal file
11
common/src/main/java/com/stardust/util/BiMap.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.stardust.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface BiMap<K, V> extends Map<K, V> {
|
||||
|
||||
K getKey(V value);
|
||||
|
||||
Set<V> valueSet();
|
||||
}
|
||||
206
common/src/main/java/com/stardust/util/BiMaps.java
Normal file
206
common/src/main/java/com/stardust/util/BiMaps.java
Normal file
@@ -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 <K, V> BiMap<K, V> make(Map<K, V> keyToValue, Map<V, K> valueToKey) {
|
||||
return new BiMapImpl<>(keyToValue, valueToKey);
|
||||
}
|
||||
|
||||
public static <K, V> BiMapBuilder<K, V> newBuilder() {
|
||||
return new BiMapBuilder<>();
|
||||
}
|
||||
|
||||
public static class BiMapBuilder<K, V> {
|
||||
|
||||
private final BiMap<K, V> mBiMap = make(new HashMap<K, V>(), new HashMap<V, K>());
|
||||
|
||||
public BiMapBuilder<K, V> put(K key, V value) {
|
||||
mBiMap.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BiMap<K, V> build() {
|
||||
return mBiMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class BiMapImpl<K, V> implements BiMap<K, V> {
|
||||
|
||||
private final Map<K, V> mKVMap;
|
||||
private final Map<V, K> mVKMap;
|
||||
|
||||
private BiMapImpl(Map<K, V> kvMap, Map<V, K> 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<? extends K, ? extends V> m) {
|
||||
mKVMap.putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
mKVMap.clear();
|
||||
mVKMap.clear();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return mKVMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey(V value) {
|
||||
return mVKMap.get(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> valueSet() {
|
||||
return mVKMap.keySet();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return mKVMap.values();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Set<Entry<K, V>> 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<? super K, ? super V> action) {
|
||||
mKVMap.forEach(action);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
@Override
|
||||
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> 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<? super K, ? extends V> mappingFunction) {
|
||||
return mKVMap.computeIfAbsent(key, mappingFunction);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
@Override
|
||||
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||
return mKVMap.computeIfPresent(key, remappingFunction);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
@Override
|
||||
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||
return mKVMap.compute(key, remappingFunction);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
@Override
|
||||
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
|
||||
return mKVMap.merge(key, value, remappingFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<K, V> {
|
||||
public class MapBuilder<K, V> {
|
||||
|
||||
private Map<K, V> mMap;
|
||||
|
||||
public MapEntries() {
|
||||
public MapBuilder() {
|
||||
this(new HashMap<K, V>());
|
||||
}
|
||||
|
||||
public MapEntries(Map<K, V> map) {
|
||||
public MapBuilder(Map<K, V> map) {
|
||||
mMap = map;
|
||||
}
|
||||
|
||||
public MapEntries<K, V> entry(K key, V value) {
|
||||
public MapBuilder<K, V> put(K key, V value) {
|
||||
mMap.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<K, V> map() {
|
||||
public Map<K, V> build() {
|
||||
return mMap;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user