From 330ae87f4c3fa907dde98628f3364d7b946486c5 Mon Sep 17 00:00:00 2001 From: Ai <132525856+LZX284@users.noreply.github.com> Date: Sat, 30 Sep 2023 13:51:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6=E6=89=93=E5=8C=85=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit autoJS打包目前只能兼容V1版本的签名,而由于谷歌的限制,如果targetSdk为30或以上的话,打包的应用就无法安装,所以打包(构建时选择inrt分支)时需要将TARGET_SDK_VERSION设置为29或以下。 --- app/build.gradle.kts | 57 ++- app/src/main/AndroidManifest.xml | 360 +++++++++--------- .../java/org/autojs/autojs/AbstractAutoJs.kt | 24 +- app/src/main/java/org/autojs/autojs/AutoJs.kt | 2 +- .../main/java/org/autojs/autojs/inrt/App.kt | 86 +++++ .../org/autojs/autojs/inrt/LogActivity.kt | 51 +++ .../main/java/org/autojs/autojs/inrt/Pref.kt | 50 +++ .../autojs/autojs/inrt/SettingsActivity.kt | 38 ++ .../org/autojs/autojs/inrt/SplashActivity.kt | 89 +++++ .../org/autojs/autojs/inrt/autojs/AutoJs.kt | 98 +++++ .../autojs/inrt/autojs/GlobalKeyObserver.kt | 93 +++++ .../autojs/ScriptExecutionGlobalListener.kt | 36 ++ .../autojs/inrt/autojs/XJavaScriptEngine.kt | 44 +++ .../inrt/launch/AssetsProjectLauncher.kt | 110 ++++++ .../inrt/launch/GlobalProjectLauncher.kt | 10 + .../org/autojs/autojs/inrt/launch/MD5.java | 31 ++ .../main/res/layout/activity_main_inrt.xml | 30 ++ .../res/layout/activity_settings_inrt.xml | 29 ++ .../main/res/layout/activity_splash_inrt.xml | 22 ++ app/src/main/res/menu/menu_main_inrt.xml | 7 + app/src/main/res/values/attrs.xml | 8 + app/src/main/res/xml/preference_inrt.xml | 45 +++ app/src/main/res/xml/provider_paths.xml | 3 +- 23 files changed, 1141 insertions(+), 182 deletions(-) create mode 100644 app/src/main/java/org/autojs/autojs/inrt/App.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/LogActivity.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/Pref.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/SettingsActivity.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/autojs/AutoJs.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/autojs/GlobalKeyObserver.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/autojs/ScriptExecutionGlobalListener.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/autojs/XJavaScriptEngine.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/launch/GlobalProjectLauncher.kt create mode 100644 app/src/main/java/org/autojs/autojs/inrt/launch/MD5.java create mode 100644 app/src/main/res/layout/activity_main_inrt.xml create mode 100644 app/src/main/res/layout/activity_settings_inrt.xml create mode 100644 app/src/main/res/layout/activity_splash_inrt.xml create mode 100644 app/src/main/res/menu/menu_main_inrt.xml create mode 100644 app/src/main/res/xml/preference_inrt.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1411ca8d..5f6e6dc8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -288,6 +288,45 @@ android { minSdk = versions.sdkVersionMin targetSdk = versions.sdkVersionTarget testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + buildConfigField("boolean", "isInrt", "false") + } + + flavorDimensions.add("channel") + productFlavors { + create("app") { + dimension = "channel" + versionCode = versions.appVersionCode + versionName = versions.appVersionName + buildConfigField("String", "CHANNEL", "\"app\"") + buildConfigField("boolean", "isInrt", "false") + manifestPlaceholders.putAll( + mapOf( + "CHANNEL" to "app", + "appName" to "@string/app_name", + "intentCategory" to "android.intent.category.LAUNCHER", + "intentCategoryInrt" to "android.intent.category.DEFAULT", + "authorities" to "org.autojs.autojs6.fileprovider" + ) + ) + } + + create("inrt") { + dimension = "channel" + applicationIdSuffix = ".inrt" + versionCode = versions.appVersionCode + versionName = versions.appVersionName + buildConfigField("String", "CHANNEL", "\"inrt\"") + buildConfigField("boolean", "isInrt", "true") + manifestPlaceholders.putAll( + mapOf( + "CHANNEL" to "inrt", + "appName" to "AutoJs6.inrt", + "intentCategory" to "android.intent.category.DEFAULT", + "intentCategoryInrt" to "android.intent.category.LAUNCHER", + "authorities" to "org.autojs.autojs6.inrt.fileprovider" + ) + ) + } } compileOptions { @@ -312,6 +351,9 @@ android { "META-INF/ASL2.0", "META-INF/*.kotlin_module", ).let { resources.pickFirsts.addAll(it) } + jniLibs { + useLegacyPackaging = true + } } kotlinOptions { @@ -369,13 +411,22 @@ android { javaCompileOptions { annotationProcessorOptions { mapOf( - "resourcePackageName" to (this@defaultConfig.applicationId ?: this@Build_gradle.applicationId), + "resourcePackageName" to (this@defaultConfig.applicationId + ?: this@Build_gradle.applicationId), "androidManifestFile" to ("$projectDir/src/main/AndroidManifest.xml") ).let { arguments(it) } } } - buildConfigField("String", "VERSION_DATE", "\"${Utils.getDateString("MMM d, yyyy", "GMT+08:00")}\"") - buildConfigField("String", "VSCODE_EXT_REQUIRED_VERSION", "\"${versions.vscodeExtRequiredVersion}\"") + buildConfigField( + "String", + "VERSION_DATE", + "\"${Utils.getDateString("MMM d, yyyy", "GMT+08:00")}\"" + ) + buildConfigField( + "String", + "VSCODE_EXT_REQUIRED_VERSION", + "\"${versions.vscodeExtRequiredVersion}\"" + ) } applicationVariants.all { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8523e9c6..60658c6f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,9 +1,9 @@ + xmlns:tools="http://schemas.android.com/tools"> + android:required="false"/> - + - + - + + tools:ignore="ProtectedPermissions"/> + tools:ignore="QueryAllPackagesPermission"/> + tools:ignore="ProtectedPermissions"/> + tools:ignore="ProtectedPermissions"/> + tools:ignore="ProtectedPermissions"/> - + - + - + - + - + + android:name="CHANNEL" + android:value="${CHANNEL}"/> - - - - + + @@ -150,148 +149,138 @@ android:name="org.autojs.autojs.ui.main.MainActivity" android:exported="true" android:launchMode="singleTask" - android:theme="@style/AppTheme.FullScreen" /> + android:theme="@style/AppTheme.FullScreen"/> + android:theme="@android:style/Theme.NoDisplay"> - + - + - - - - + android:theme="@style/EditorTheme"/> + android:theme="@style/AppTheme.Settings"/> + android:theme="@style/AppTheme.Settings"/> + android:theme="@style/AppTheme.Settings"/> - + + android:configChanges="orientation|keyboardHidden|screenSize|locale"/> + android:configChanges="orientation|keyboardHidden|screenSize|locale"/> - + - + + android:theme="@style/AppTheme.FullScreen"> - + - + - + - + + android:theme="@style/AppTheme.Transparent"/> - + - + - + - + - + - + - + + android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> + android:value="true"/> - + + android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> + android:value="true"/> - + @@ -305,7 +294,7 @@ tools:ignore="ExportedActivity"> - + @@ -316,71 +305,71 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + tools:ignore="BatteryLife"/> - + - + - + - + - + - + @@ -395,99 +384,99 @@ - + + android:label="@string/text_edit_script"> - + - + - + - + - + - + - + - + + android:theme="@android:style/Theme.NoDisplay"> - + - + - + - + - + - + - + - + + android:theme="@style/AppTheme.Transparent"> - + - + - + - + - + - + - + - + + android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> - + @@ -496,12 +485,12 @@ android:exported="false"> - + + android:resource="@xml/script_widget_config"/> @@ -509,7 +498,7 @@ android:name="org.autojs.autojs.timing.TaskReceiver" android:exported="false"> - + @@ -525,44 +514,44 @@ + android:theme="@style/MtAppTheme.FullScreen"/> + android:theme="@style/ScriptTheme"/> + android:theme="@style/ScriptTheme.Transparent"/> + android:theme="@style/ScriptTheme.Transparent"/> + android:exported="true" + android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> - + + android:resource="@xml/accessibility_service_config"/> + android:foregroundServiceType="mediaProjection"/> + android:permission="android.permission.INTERACT_ACROSS_USERS_FULL"/> + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/AbstractAutoJs.kt b/app/src/main/java/org/autojs/autojs/AbstractAutoJs.kt index eb2992d5..c44f0599 100644 --- a/app/src/main/java/org/autojs/autojs/AbstractAutoJs.kt +++ b/app/src/main/java/org/autojs/autojs/AbstractAutoJs.kt @@ -20,6 +20,7 @@ import org.autojs.autojs.engine.RootAutomatorEngine import org.autojs.autojs.engine.ScriptEngineManager import org.autojs.autojs.engine.ScriptEngineService import org.autojs.autojs.engine.ScriptEngineServiceBuilder +import org.autojs.autojs.inrt.autojs.XJavaScriptEngine import org.autojs.autojs.pref.Pref.registerOnSharedPreferenceChangeListener import org.autojs.autojs.rhino.InterruptibleAndroidContextFactory import org.autojs.autojs.runtime.ScriptRuntime @@ -58,9 +59,17 @@ abstract class AbstractAutoJs protected constructor(protected val application: A val infoProvider = ActivityInfoProvider(context) val scriptEngineManager = ScriptEngineManager(context) val scriptEngineService: ScriptEngineService = run { - scriptEngineManager.registerEngine(JavaScriptSource.ENGINE) { - LoopBasedJavaScriptEngine(context).also { engine -> - engine.runtime = createRuntime().also { runtime = it } + if (org.autojs.autojs6.BuildConfig.isInrt) { + scriptEngineManager.registerEngine(JavaScriptSource.ENGINE) { + XJavaScriptEngine(context).also { engine -> + engine.runtime = createRuntime().also { runtime = it } + } + } + } else { + scriptEngineManager.registerEngine(JavaScriptSource.ENGINE) { + LoopBasedJavaScriptEngine(context).also { engine -> + engine.runtime = createRuntime().also { runtime = it } + } } } initContextFactory() @@ -84,7 +93,14 @@ abstract class AbstractAutoJs protected constructor(protected val application: A } private fun initContextFactory() { - ContextFactory.initGlobal(InterruptibleAndroidContextFactory(File(context.cacheDir, "classes"))) + ContextFactory.initGlobal( + InterruptibleAndroidContextFactory( + File( + context.cacheDir, + "classes" + ) + ) + ) } protected open fun createRuntime(): ScriptRuntime = ScriptRuntime.Builder() diff --git a/app/src/main/java/org/autojs/autojs/AutoJs.kt b/app/src/main/java/org/autojs/autojs/AutoJs.kt index 88c9cedd..cbeeea10 100644 --- a/app/src/main/java/org/autojs/autojs/AutoJs.kt +++ b/app/src/main/java/org/autojs/autojs/AutoJs.kt @@ -38,7 +38,7 @@ import java.util.concurrent.Executors * Modified by SuperMonster003 as of Dec 1, 2021. * Transformed by SuperMonster003 on Oct 10, 2022. */ -class AutoJs private constructor(private val appContext: Application) : AbstractAutoJs(appContext) { +open class AutoJs(private val appContext: Application) : AbstractAutoJs(appContext) { // @Thank to Zen2H private val printExecutor = Executors.newSingleThreadExecutor() diff --git a/app/src/main/java/org/autojs/autojs/inrt/App.kt b/app/src/main/java/org/autojs/autojs/inrt/App.kt new file mode 100644 index 00000000..f504699f --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/App.kt @@ -0,0 +1,86 @@ +package org.autojs.autojs.inrt + +import android.app.Application +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.net.Uri +import android.view.View +import android.widget.ImageView + +import com.bumptech.glide.Glide +import com.bumptech.glide.request.target.SimpleTarget +import com.bumptech.glide.request.transition.Transition +import org.autojs.autojs.inrt.App +import org.autojs.autojs.AutoJs +import org.autojs.autojs.inrt.autojs.GlobalKeyObserver +import org.autojs.autojs.app.GlobalAppContext +import org.autojs.autojs.core.ui.inflater.ImageLoader +import org.autojs.autojs.core.ui.inflater.util.Drawables +import java.lang.ref.WeakReference + +/** + * Created by Stardust on 2017/7/1. + */ +class App : Application() { + companion object { + + private const val BUGLY_APP_ID = "19b3607b53" + + private lateinit var instance: WeakReference + + val app: App + get() = instance.get()!! + + } + + override fun onCreate() { + super.onCreate() + GlobalAppContext.set(this) + instance = WeakReference(this) + AutoJs.initInstance(this) + GlobalKeyObserver.init() + Drawables.defaultImageLoader=object : ImageLoader { + override fun loadInto(imageView: ImageView, uri: Uri) { + Glide.with(this@App) + .load(uri) + .into(imageView) + } + + override fun loadIntoBackground(view: View, uri: Uri) { + Glide.with(this@App) + .load(uri) + .into(object : SimpleTarget() { + override fun onResourceReady(resource: Drawable, transition: Transition?) { + view.background = resource + } + }) + } + + override fun load(view: View, uri: Uri): Drawable { + throw UnsupportedOperationException() + } + + override fun load(view: View, uri: Uri, drawableCallback: ImageLoader.DrawableCallback) { + Glide.with(this@App) + .load(uri) + .into(object : SimpleTarget() { + override fun onResourceReady(resource: Drawable, transition: Transition?) { + drawableCallback.onLoaded(resource) + } + }) + } + + override fun load(view: View, uri: Uri, bitmapCallback: ImageLoader.BitmapCallback) { + Glide.with(this@App) + .asBitmap() + .load(uri) + .into(object : SimpleTarget() { + override fun onResourceReady(resource: Bitmap, transition: Transition?) { + bitmapCallback.onLoaded(resource) + } + }) + } + } + } + +} diff --git a/app/src/main/java/org/autojs/autojs/inrt/LogActivity.kt b/app/src/main/java/org/autojs/autojs/inrt/LogActivity.kt new file mode 100644 index 00000000..6786b216 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/LogActivity.kt @@ -0,0 +1,51 @@ +package org.autojs.autojs.inrt + +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import android.view.Menu +import android.view.MenuItem +import android.view.View + +import org.autojs.autojs.AutoJs +import org.autojs.autojs.inrt.launch.GlobalProjectLauncher +import org.autojs.autojs.core.console.ConsoleImpl +import org.autojs.autojs.core.console.ConsoleView +import org.autojs.autojs6.R + +class LogActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setupView() + if (intent.getBooleanExtra(EXTRA_LAUNCH_SCRIPT, false)) { + GlobalProjectLauncher.launch(this) + } + } + + private fun setupView() { + setContentView(R.layout.activity_main_inrt) + val toolbar = findViewById(R.id.toolbar) + setSupportActionBar(toolbar) + val consoleView = findViewById(R.id.console) + consoleView.setConsole(AutoJs.instance.globalConsole as ConsoleImpl) + consoleView.findViewById(R.id.input_container).visibility = View.GONE + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + startActivity(Intent(this, SettingsActivity::class.java)) + return true + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.menu_main_inrt, menu) + return true + } + + companion object { + + + const val EXTRA_LAUNCH_SCRIPT = "launch_script" + } +} diff --git a/app/src/main/java/org/autojs/autojs/inrt/Pref.kt b/app/src/main/java/org/autojs/autojs/inrt/Pref.kt new file mode 100644 index 00000000..8152e754 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/Pref.kt @@ -0,0 +1,50 @@ +package org.autojs.autojs.inrt + +import android.content.SharedPreferences +import androidx.preference.PreferenceManager + +import org.autojs.autojs.app.GlobalAppContext +import org.autojs.autojs6.R + +/** + * Created by Stardust on 2017/12/8. + */ +object Pref { + + private const val KEY_FIRST_USING = "key_first_using" + private var sPreferences: SharedPreferences? = null + + private val preferences: SharedPreferences + get() { + return sPreferences ?: run { + val pref = PreferenceManager.getDefaultSharedPreferences(GlobalAppContext.get()) + sPreferences = pref + pref + } + } + + val isFirstUsing: Boolean + get() { + val firstUsing = preferences.getBoolean(KEY_FIRST_USING, true) + if (firstUsing) { + preferences.edit().putBoolean(KEY_FIRST_USING, false).apply() + } + return firstUsing + } + + private fun getString(res: Int): String { + return GlobalAppContext.get().getString(res) + } + + fun shouldEnableAccessibilityServiceByRoot(): Boolean { + return preferences.getBoolean(getString(R.string.key_enable_a11y_service_with_root_access), true) + } + + fun shouldHideLogs(): Boolean { + return preferences.getBoolean(getString(R.string.key_not_showing_main_activity), false) + } + + fun shouldStopAllScriptsWhenVolumeUp(): Boolean { + return preferences.getBoolean(getString(R.string.key_use_volume_control_running), true) + } +} diff --git a/app/src/main/java/org/autojs/autojs/inrt/SettingsActivity.kt b/app/src/main/java/org/autojs/autojs/inrt/SettingsActivity.kt new file mode 100644 index 00000000..44899e85 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/SettingsActivity.kt @@ -0,0 +1,38 @@ +package org.autojs.autojs.inrt + +import android.os.Bundle +import androidx.annotation.Nullable +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import org.autojs.autojs6.R + +/** + * Created by Stardust on 2017/12/8. + */ +class SettingsActivity : AppCompatActivity() { + override fun onCreate(@Nullable savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setupViews() + } + + private fun setupViews() { + setContentView(R.layout.activity_settings_inrt) + fragmentManager.beginTransaction().replace(R.id.fragment_setting, PreferenceFragment()).commit() + val toolbar = findViewById(R.id.toolbar) + toolbar.setTitle(R.string.text_settings) + setSupportActionBar(toolbar) + toolbar.setNavigationOnClickListener { finish() } + supportActionBar?.setDisplayHomeAsUpEnabled(true) + } + + class PreferenceFragment : androidx.preference.PreferenceFragment() { + + override fun onCreate(@Nullable savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.preference_inrt) + } + } +} diff --git a/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt b/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt new file mode 100644 index 00000000..b760e121 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt @@ -0,0 +1,89 @@ +package org.autojs.autojs.inrt + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager.PERMISSION_DENIED +import android.graphics.Typeface +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.widget.TextView +import android.widget.Toast +import androidx.annotation.NonNull +import androidx.annotation.Nullable +import androidx.appcompat.app.AppCompatActivity +import org.autojs.autojs.AutoJs +import org.autojs.autojs.inrt.launch.GlobalProjectLauncher +import org.autojs.autojs6.R + +/** + * Created by Stardust on 2018/2/2. + */ +class SplashActivity : AppCompatActivity() { + + override fun onCreate(@Nullable savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_splash_inrt) + val slug = findViewById(R.id.slug) + slug.typeface = Typeface.createFromAsset(assets, "roboto_medium.ttf") + if (!Pref.isFirstUsing) { + main() + } else { + Handler(Looper.myLooper()!!).postDelayed({ this@SplashActivity.main() }, INIT_TIMEOUT) + } + } + + private fun main() { + checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_PHONE_STATE) + } + + + private fun runScript() { + Thread { + try { + GlobalProjectLauncher.launch(this) + } catch (e: Exception) { + e.printStackTrace() + runOnUiThread { + Toast.makeText(this@SplashActivity, e.message, Toast.LENGTH_LONG).show() + startActivity(Intent(this@SplashActivity, LogActivity::class.java)) + AutoJs.instance.globalConsole.printAllStackTrace(e) + } + } + }.start() + } + + override fun onRequestPermissionsResult(requestCode: Int, @NonNull permissions: Array, @NonNull grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + runScript() + } + + private fun checkPermission(vararg permissions: String) { + val requestPermissions = getRequestPermissions(permissions) + if (requestPermissions.isNotEmpty()) { + requestPermissions(requestPermissions, PERMISSION_REQUEST_CODE) + } else { + runScript() + } + } + + + private fun getRequestPermissions(permissions: Array): Array { + val list = ArrayList() + for (permission in permissions) { + if (checkSelfPermission(permission) == PERMISSION_DENIED) { + list.add(permission) + } + } + return list.toTypedArray() + } + + companion object { + + private const val PERMISSION_REQUEST_CODE = 11186 + private const val INIT_TIMEOUT: Long = 1000 + } + +} + diff --git a/app/src/main/java/org/autojs/autojs/inrt/autojs/AutoJs.kt b/app/src/main/java/org/autojs/autojs/inrt/autojs/AutoJs.kt new file mode 100644 index 00000000..a835fb6c --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/autojs/AutoJs.kt @@ -0,0 +1,98 @@ +package org.autojs.autojs.inrt.autojs + +import android.annotation.SuppressLint +import android.app.Application +import android.content.Context +import org.autojs.autojs.app.GlobalAppContext +import org.autojs.autojs.inrt.LogActivity +import org.autojs.autojs.inrt.SettingsActivity +import org.autojs.autojs.core.accessibility.AccessibilityTool +import org.autojs.autojs.core.accessibility.AccessibilityService +import org.autojs.autojs.runtime.ScriptRuntime +import org.autojs.autojs.runtime.api.AppUtils +import org.autojs.autojs.runtime.exception.ScriptException +import org.autojs.autojs.runtime.exception.ScriptInterruptedException +import org.autojs.autojs.script.JavaScriptSource +import org.autojs.autojs6.R + + +/** + * Created by Stardust on 2017/4/2. + */ +class AutoJs private constructor(application: Application) : org.autojs.autojs.AutoJs(application) { + + init { + scriptEngineService.registerGlobalScriptExecutionListener(ScriptExecutionGlobalListener()) + scriptEngineManager.registerEngine(JavaScriptSource.ENGINE) { + val engine = XJavaScriptEngine(application) + engine.runtime = createRuntime() + engine + } + } + + override fun createAppUtils(context: Context): AppUtils { + return AppUtils(context, context.packageName + ".fileprovider") + } + + override fun ensureAccessibilityServiceEnabled() { + if (AccessibilityService.instance != null) { + return + } + var errorMessage: String? = null + if (isAccessibilityServiceEnabled()) { + errorMessage = GlobalAppContext.get().getString(R.string.text_a11y_service_enabled_but_not_running) + } else if (!getAccessibilityServiceTool().service.enableIfNeededAndWaitFor(2000)) { + errorMessage = GlobalAppContext.get().getString(R.string.error_no_accessibility_permission) + } + if (errorMessage != null) { + getAccessibilityServiceTool().launchSettings() + throw ScriptException(errorMessage) + } + } + + override fun waitForAccessibilityServiceEnabled(timeout: Long) { + if (AccessibilityService.instance != null) { + return + } + var errorMessage: String? = null + if (isAccessibilityServiceEnabled()) { + errorMessage = GlobalAppContext.get().getString(R.string.text_a11y_service_enabled_but_not_running) + } else if (!getAccessibilityServiceTool().service.enableIfNeededAndWaitFor(2000)) { + errorMessage = GlobalAppContext.get().getString(R.string.error_no_accessibility_permission) + } + if (errorMessage != null) { + getAccessibilityServiceTool().launchSettings() + if (!AccessibilityService.waitForEnabled(timeout)) { + throw ScriptInterruptedException() + } + } + } + + override fun createRuntime(): ScriptRuntime { + val runtime = super.createRuntime() + runtime.putProperty("class.settings", SettingsActivity::class.java) + runtime.putProperty("class.console", LogActivity::class.java) + return runtime + } + + private fun getAccessibilityServiceTool(): AccessibilityTool { + return AccessibilityTool(application) + } + + private fun isAccessibilityServiceEnabled(): Boolean { + return getAccessibilityServiceTool().service.isEnabled() + } + + companion object { + + @SuppressLint("StaticFieldLeak") + @JvmStatic + lateinit var instance: AutoJs + private set + + @Synchronized + fun initInstance(application: Application) { + instance = AutoJs(application) + } + } +} diff --git a/app/src/main/java/org/autojs/autojs/inrt/autojs/GlobalKeyObserver.kt b/app/src/main/java/org/autojs/autojs/inrt/autojs/GlobalKeyObserver.kt new file mode 100644 index 00000000..bc3af708 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/autojs/GlobalKeyObserver.kt @@ -0,0 +1,93 @@ +package org.autojs.autojs.inrt.autojs + +import android.util.Log +import android.view.KeyEvent + +import org.autojs.autojs.app.GlobalAppContext +import org.autojs.autojs.inrt.Pref +import org.autojs.autojs.core.accessibility.AccessibilityService +import org.autojs.autojs.core.accessibility.OnKeyListener +import org.autojs.autojs.core.inputevent.InputEventObserver +import org.autojs.autojs.core.inputevent.ShellKeyObserver + + +/** + * Created by Stardust on 2017/8/14. + */ +class GlobalKeyObserver internal constructor() : OnKeyListener, ShellKeyObserver.KeyListener { + private var mVolumeDownFromShell: Boolean = false + private var mVolumeDownFromAccessibility: Boolean = false + private var mVolumeUpFromShell: Boolean = false + private var mVolumeUpFromAccessibility: Boolean = false + + init { + AccessibilityService.stickOnKeyObserver + .addListener(this) + val observer = ShellKeyObserver() + observer.setKeyListener(this) + InputEventObserver.getGlobal(GlobalAppContext.get()).addListener(observer) + } + + fun onVolumeUp() { + Log.d(LOG_TAG, "onVolumeUp at " + System.currentTimeMillis()) + if (Pref.shouldStopAllScriptsWhenVolumeUp()) { + AutoJs.instance.scriptEngineService.stopAllAndToast() + } + } + + override fun onKeyEvent(keyCode: Int, event: KeyEvent) { + if (event.action != KeyEvent.ACTION_UP) + return + if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { + if (mVolumeDownFromShell) { + mVolumeDownFromShell = false + return + } + mVolumeUpFromAccessibility = true + onVolumeDown() + } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { + if (mVolumeUpFromShell) { + mVolumeUpFromShell = false + return + } + mVolumeUpFromAccessibility = true + onVolumeUp() + } + } + + fun onVolumeDown() { + + } + + + override fun onKeyDown(keyName: String) { + + } + + override fun onKeyUp(keyName: String) { + if ("KEY_VOLUMEUP" == keyName) { + if (mVolumeUpFromAccessibility) { + mVolumeUpFromAccessibility = false + return + } + mVolumeUpFromShell = true + onVolumeUp() + } else if ("KEY_VOLUMEDOWN" == keyName) { + if (mVolumeDownFromAccessibility) { + mVolumeDownFromAccessibility = false + return + } + mVolumeDownFromShell = true + onVolumeDown() + } + } + + companion object { + private const val LOG_TAG = "GlobalKeyObserver" + private val sSingleton = GlobalKeyObserver() + + fun init() { + //do nothing + } + } +} diff --git a/app/src/main/java/org/autojs/autojs/inrt/autojs/ScriptExecutionGlobalListener.kt b/app/src/main/java/org/autojs/autojs/inrt/autojs/ScriptExecutionGlobalListener.kt new file mode 100644 index 00000000..b6ed525d --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/autojs/ScriptExecutionGlobalListener.kt @@ -0,0 +1,36 @@ +package org.autojs.autojs.inrt.autojs + +import org.autojs.autojs.app.GlobalAppContext +import org.autojs.autojs.execution.ScriptExecution +import org.autojs.autojs.execution.ScriptExecutionListener +import org.autojs.autojs6.R + +/** + * Created by Stardust on 2017/5/3. + */ +class ScriptExecutionGlobalListener : ScriptExecutionListener { + + override fun onStart(execution: ScriptExecution) { + execution.engine.setTag(ENGINE_TAG_START_TIME, System.currentTimeMillis()) + } + + override fun onSuccess(execution: ScriptExecution, result: Any?) { + onFinish(execution) + } + + private fun onFinish(execution: ScriptExecution) { + val millis = execution.engine.getTag(ENGINE_TAG_START_TIME) as Long? ?: return + val seconds = (System.currentTimeMillis() - millis) / 1000.0 + AutoJs.instance.scriptEngineService.globalConsole + .verbose(GlobalAppContext.get().getString(R.string.text_execution_finished), execution.source.toString(), seconds) + } + + override fun onException(execution: ScriptExecution, e: Throwable) { + onFinish(execution) + } + + companion object { + private const val ENGINE_TAG_START_TIME = "start_time" + } + +} diff --git a/app/src/main/java/org/autojs/autojs/inrt/autojs/XJavaScriptEngine.kt b/app/src/main/java/org/autojs/autojs/inrt/autojs/XJavaScriptEngine.kt new file mode 100644 index 00000000..9dcb0402 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/autojs/XJavaScriptEngine.kt @@ -0,0 +1,44 @@ +package org.autojs.autojs.inrt.autojs + +import android.content.Context +import org.autojs.autojs.engine.LoopBasedJavaScriptEngine +import org.autojs.autojs.engine.encryption.ScriptEncryption +import org.autojs.autojs.pio.PFiles +import org.autojs.autojs.script.EncryptedScriptFileHeader +import org.autojs.autojs.script.JavaScriptFileSource +import org.autojs.autojs.script.ScriptSource +import org.autojs.autojs.script.StringScriptSource +import java.io.File +import java.security.GeneralSecurityException + +class XJavaScriptEngine(context: Context) : LoopBasedJavaScriptEngine(context) { + + + override fun execute(source: ScriptSource, callback: ExecuteCallback?) { + if (source is JavaScriptFileSource) { + try { + if (execute(source.file)) { + return + } + } catch (e: Throwable) { + e.printStackTrace() + return + } + } + super.execute(source, callback) + } + + private fun execute(file: File): Boolean { + val bytes = PFiles.readBytes(file.path) + if (!EncryptedScriptFileHeader.isValidFile(bytes)) { + return false + } + try { + super.execute(StringScriptSource(file.name, String(ScriptEncryption.decrypt(bytes, EncryptedScriptFileHeader.BLOCK_SIZE)))) + } catch (e: GeneralSecurityException) { + e.printStackTrace() + } + return true + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt b/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt new file mode 100644 index 00000000..44d71563 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt @@ -0,0 +1,110 @@ +package org.autojs.autojs.inrt.launch + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.Handler +import android.os.Looper +import android.text.TextUtils +import org.autojs.autojs.inrt.LogActivity +import org.autojs.autojs.inrt.Pref +import org.autojs.autojs.AutoJs +import org.autojs.autojs.engine.encryption.ScriptEncryption +import org.autojs.autojs.execution.ExecutionConfig +import org.autojs.autojs.execution.ScriptExecution +import org.autojs.autojs.pio.PFiles +import org.autojs.autojs.pio.UncheckedIOException +import org.autojs.autojs.project.ProjectConfig +import org.autojs.autojs.script.JavaScriptFileSource +import org.autojs.autojs.script.JavaScriptSource +import java.io.File +import java.io.IOException + +/** + * Created by Stardust on 2018/1/24. + */ +open class AssetsProjectLauncher(private val mAssetsProjectDir: String, private val mActivity: Context) { + private val mProjectDir: String = File(mActivity.filesDir, "project/").path + private val mProjectConfig: ProjectConfig = ProjectConfig.fromAssets(mActivity, ProjectConfig.configFileOfDir(mAssetsProjectDir)) + private val mMainScriptFile: File = File(mProjectDir, mProjectConfig.mainScriptFile) + private val mHandler: Handler = Handler(Looper.getMainLooper()) + private var mScriptExecution: ScriptExecution? = null + + init { + prepare() + } + + fun launch(activity: Activity) { + //如果需要隐藏日志界面,则直接运行脚本 + if (mProjectConfig.launchConfig.shouldHideLogs() || Pref.shouldHideLogs()) { + runScript(activity) + } else { + //如果不隐藏日志界面 + //如果当前已经是日志界面则直接运行脚本 + if (activity is LogActivity) { + runScript(null) + } else { + //否则显示日志界面并在日志界面中运行脚本 + mHandler.post { + activity.startActivity(Intent(mActivity, LogActivity::class.java) + .putExtra(LogActivity.EXTRA_LAUNCH_SCRIPT, true)) + activity.finish() + } + } + } + } + + private fun runScript(activity: Activity?) { + if (mScriptExecution != null && mScriptExecution!!.engine != null && + !mScriptExecution!!.engine.isDestroyed) { + return + } + try { + val source = JavaScriptFileSource("main", mMainScriptFile) + val config = ExecutionConfig(workingDirectory = mProjectDir) + if (source.executionMode and JavaScriptSource.EXECUTION_MODE_UI != 0) { + config.intentFlags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_TASK_ON_HOME + } else { + activity?.finish() + } + mScriptExecution = AutoJs.instance.scriptEngineService.execute(source, config) + } catch (e: Exception) { + AutoJs.instance.globalConsole.error(e) + } + + } + + private fun prepare() { + val projectConfigPath = PFiles.join(mProjectDir, ProjectConfig.CONFIG_FILE_NAME) + val projectConfig = ProjectConfig.fromFile(projectConfigPath) + if (projectConfig != null && + TextUtils.equals(projectConfig.buildInfo.buildId, mProjectConfig.buildInfo.buildId)) { + initKey(projectConfig) + return + } + initKey(mProjectConfig) + PFiles.deleteRecursively(File(mProjectDir)) + try { + PFiles.copyAssetDir(mActivity.assets, mAssetsProjectDir, mProjectDir, null) + } catch (e: IOException) { + throw UncheckedIOException(e) + } + } + + private fun initKey(projectConfig: ProjectConfig) { + val key = MD5.md5(projectConfig.packageName + projectConfig.versionName + projectConfig.mainScriptFile) + val vec = MD5.md5(projectConfig.buildInfo.buildId + projectConfig.name).substring(0, 16) + try { + val fieldKey = ScriptEncryption::class.java.getDeclaredField("mKey") + fieldKey.isAccessible = true + fieldKey.set(null, key) + val fieldVector = ScriptEncryption::class.java.getDeclaredField("mInitVector") + fieldVector.isAccessible = true + fieldVector.set(null, vec) + } catch (e: Exception) { + e.printStackTrace() + } + + } + +} diff --git a/app/src/main/java/org/autojs/autojs/inrt/launch/GlobalProjectLauncher.kt b/app/src/main/java/org/autojs/autojs/inrt/launch/GlobalProjectLauncher.kt new file mode 100644 index 00000000..dc170910 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/launch/GlobalProjectLauncher.kt @@ -0,0 +1,10 @@ +package org.autojs.autojs.inrt.launch + +import android.annotation.SuppressLint +import org.autojs.autojs.app.GlobalAppContext + +/** + * Created by Stardust on 2018/3/21. + */ +@SuppressLint("StaticFieldLeak") +object GlobalProjectLauncher: AssetsProjectLauncher("project", GlobalAppContext.get()) diff --git a/app/src/main/java/org/autojs/autojs/inrt/launch/MD5.java b/app/src/main/java/org/autojs/autojs/inrt/launch/MD5.java new file mode 100644 index 00000000..94b3584e --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/launch/MD5.java @@ -0,0 +1,31 @@ +package org.autojs.autojs.inrt.launch; + +import java.security.MessageDigest; + +public class MD5 { + + public static byte[] md5Bytes(String message) { + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(message.getBytes()); + return md5.digest(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String md5(String message) { + byte[] bytes = md5Bytes(message); + StringBuilder hexString = new StringBuilder(32); + for (byte b : bytes) { + String hex = Integer.toHexString(0xFF & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + + + } +} diff --git a/app/src/main/res/layout/activity_main_inrt.xml b/app/src/main/res/layout/activity_main_inrt.xml new file mode 100644 index 00000000..14b9d00f --- /dev/null +++ b/app/src/main/res/layout/activity_main_inrt.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings_inrt.xml b/app/src/main/res/layout/activity_settings_inrt.xml new file mode 100644 index 00000000..20175b9c --- /dev/null +++ b/app/src/main/res/layout/activity_settings_inrt.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_splash_inrt.xml b/app/src/main/res/layout/activity_splash_inrt.xml new file mode 100644 index 00000000..1b3de0b0 --- /dev/null +++ b/app/src/main/res/layout/activity_splash_inrt.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_main_inrt.xml b/app/src/main/res/menu/menu_main_inrt.xml new file mode 100644 index 00000000..d692ebb8 --- /dev/null +++ b/app/src/main/res/menu/menu_main_inrt.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 29872499..cf3a65ff 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -75,4 +75,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/preference_inrt.xml b/app/src/main/res/xml/preference_inrt.xml new file mode 100644 index 00000000..25e87e6e --- /dev/null +++ b/app/src/main/res/xml/preference_inrt.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml index 3e5ddda3..aae5c0bb 100644 --- a/app/src/main/res/xml/provider_paths.xml +++ b/app/src/main/res/xml/provider_paths.xml @@ -1,6 +1,7 @@ - + + \ No newline at end of file