6.4.0 - 新增 barcode/qrcode/shizuku 等模块; 适配高版本系统语言设置; 优化打包功能; 支持应用快捷方式; 修复屏幕旋转相关问题

This commit is contained in:
SuperMonster003
2023-10-30 17:16:58 +08:00
parent 8fc9564c63
commit ef7b1b719c
163 changed files with 4619 additions and 1442 deletions

View File

@@ -2,6 +2,8 @@ package org.autojs.autojs.core.console;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
@@ -57,29 +59,53 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
public ConsoleView(Context context) {
super(context);
init();
init(null);
}
public ConsoleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
init(attrs);
}
public ConsoleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
init(attrs);
}
@SuppressLint("ClickableViewAccessibility")
private void init() {
private void init(@Nullable AttributeSet attrs) {
inflate(getContext(), R.layout.console_view, this);
for (Map.Entry<Integer, Integer> map : getLogLevelMap().entrySet()) {
Map<Integer, Integer> logLevelColorResIdMap = getLogLevelMap();
Map<Integer, Integer> logLevelColorIntMap = getLogLevelMap();
if (attrs != null) {
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.ConsoleView);
logLevelColorIntMap.put(Log.VERBOSE, ta.getColor(R.styleable.ConsoleView_color_verbose, Color.TRANSPARENT));
logLevelColorIntMap.put(Log.DEBUG, ta.getColor(R.styleable.ConsoleView_color_debug, Color.TRANSPARENT));
logLevelColorIntMap.put(Log.INFO, ta.getColor(R.styleable.ConsoleView_color_info, Color.TRANSPARENT));
logLevelColorIntMap.put(Log.WARN, ta.getColor(R.styleable.ConsoleView_color_warn, Color.TRANSPARENT));
logLevelColorIntMap.put(Log.ERROR, ta.getColor(R.styleable.ConsoleView_color_error, Color.TRANSPARENT));
logLevelColorIntMap.put(Log.ASSERT, ta.getColor(R.styleable.ConsoleView_color_assert, Color.TRANSPARENT));
ta.recycle();
}
for (Map.Entry<Integer, Integer> map : logLevelColorResIdMap.entrySet()) {
int logLevel = map.getKey();
int colorResKey = map.getValue();
mColors.put(logLevel, getContext().getColor(colorResKey));
}
for (Map.Entry<Integer, Integer> map : logLevelColorIntMap.entrySet()) {
int logLevel = map.getKey();
int colorInt = map.getValue();
if (colorInt != Color.TRANSPARENT) {
mColors.put(logLevel, colorInt);
}
}
ScaleGestureDetector mScaleGestureDetector = new ScaleGestureDetector(getContext(), getSimpleOnScaleGestureListener());
mLogListRecyclerView = findViewById(R.id.log_list);
@@ -166,24 +192,28 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
adapter.setDebugTextColor(color);
}
}
public void setInfoTextColor(int color) {
Adapter adapter = (Adapter) mLogListRecyclerView.getAdapter();
if (adapter != null) {
adapter.setInfoTextColor(color);
}
}
public void setWarnTextColor(int color) {
Adapter adapter = (Adapter) mLogListRecyclerView.getAdapter();
if (adapter != null) {
adapter.setWarnTextColor(color);
}
}
public void setErrorTextColor(int color) {
Adapter adapter = (Adapter) mLogListRecyclerView.getAdapter();
if (adapter != null) {
adapter.setErrorTextColor(color);
}
}
public void setAssertTextColor(int color) {
Adapter adapter = (Adapter) mLogListRecyclerView.getAdapter();
if (adapter != null) {
@@ -319,7 +349,7 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
public void showEditText() {
post(() -> {
mWindow.requestWindowFocus();
//mInputContainer.setVisibility(VISIBLE);
// mInputContainer.setVisibility(VISIBLE);
mEditText.requestFocus();
});
}
@@ -359,7 +389,7 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
if (textSize > 0) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
} else {
textSize = DisplayUtils.pxToSp(getContext(), textView.getTextSize());
textSize = DisplayUtils.pxToSp(textView.getTextSize());
}
textView.setClickable(false);
textView.setLongClickable(false);

View File

@@ -19,12 +19,12 @@ class FloatingConsoleView : ConsoleView {
}
override fun getLogLevelMap(): MutableMap<Int, Int> = MapBuilder<Int, Int>()
.put(Log.VERBOSE,R.color.floating_console_view_verbose)
.put(Log.DEBUG,R.color.floating_console_view_debug)
.put(Log.INFO,R.color.floating_console_view_info)
.put(Log.WARN,R.color.floating_console_view_warn)
.put(Log.ERROR,R.color.floating_console_view_error)
.put(Log.ASSERT,R.color.floating_console_view_assert)
.put(Log.VERBOSE, R.color.floating_console_view_verbose)
.put(Log.DEBUG, R.color.floating_console_view_debug)
.put(Log.INFO, R.color.floating_console_view_info)
.put(Log.WARN, R.color.floating_console_view_warn)
.put(Log.ERROR, R.color.floating_console_view_error)
.put(Log.ASSERT, R.color.floating_console_view_assert)
.build()
}

View File

@@ -8,8 +8,6 @@ import static android.util.Log.VERBOSE;
import static android.util.Log.WARN;
import static android.util.Log.d;
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
import org.apache.log4j.Level;
@@ -24,11 +22,10 @@ import java.util.Locale;
/**
* Created by Stardust on 2017/10/22.
*/
@SuppressLint("ConstantLocale")
public class GlobalConsole extends ConsoleImpl {
private static final String TAG = GlobalConsole.class.getSimpleName();
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
private static final Logger LOGGER = Logger.getLogger(GlobalConsole.class);
private final SimpleDateFormat mDateFormat = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
public GlobalConsole(UiHandler uiHandler) {
super(uiHandler);
@@ -38,7 +35,7 @@ public class GlobalConsole extends ConsoleImpl {
@NonNull
public String println(int level, @NonNull CharSequence charSequence) {
String log = String.format(Locale.getDefault(), "%s/%s: %s",
DATE_FORMAT.format(new Date()), getLevelChar(level), charSequence);
mDateFormat.format(new Date()), getLevelChar(level), charSequence);
LOGGER.log(toLog4jLevel(level), log);
d(TAG, log);
super.println(level, log);

View File

@@ -31,7 +31,6 @@ public class EventEmitter {
}
}
private class Listeners {
private final CopyOnWriteArrayList<ListenerWrapper> mListenerWrappers = new CopyOnWriteArrayList<>();
@@ -134,8 +133,9 @@ public class EventEmitter {
public boolean emit(String eventName, Object... args) {
Listeners listeners = mListenersMap.get(eventName);
if (listeners == null || listeners.empty())
if (listeners == null || listeners.empty()) {
return false;
}
listeners.emit(args);
return true;
}
@@ -146,8 +146,9 @@ public class EventEmitter {
public int listenerCount(String eventName) {
Listeners listeners = mListenersMap.get(eventName);
if (listeners == null)
if (listeners == null) {
return 0;
}
return listeners.count();
}
@@ -177,8 +178,9 @@ public class EventEmitter {
public EventEmitter removeListener(String eventName, Object listener) {
Listeners listeners = mListenersMap.get(eventName);
if (listeners != null)
if (listeners != null) {
listeners.remove(listener);
}
return this;
}
@@ -195,5 +197,4 @@ public class EventEmitter {
return defaultMaxListeners;
}
}

View File

@@ -20,12 +20,12 @@ import android.view.OrientationEventListener;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.autojs.autojs.lang.ThreadCompat;
import org.autojs.autojs.runtime.ScriptRuntime;
import org.autojs.autojs.runtime.api.ScreenMetrics;
import org.autojs.autojs.runtime.exception.ScriptException;
import org.autojs.autojs.runtime.exception.ScriptInterruptedException;
import org.autojs.autojs.util.ForegroundServiceUtils;
import org.autojs.autojs.lang.ThreadCompat;
import org.autojs.autojs.runtime.api.ScreenMetrics;
import java.util.ArrayList;
import java.util.Collections;

View File

@@ -45,6 +45,7 @@ class NotificationListenerService : android.service.notification.NotificationLis
}
companion object {
@JvmStatic
var instance: NotificationListenerService? = null
private set
}

View File

@@ -4,6 +4,7 @@ import android.content.Context
import android.util.AttributeSet
import android.util.Log
import org.apache.log4j.Logger
import org.autojs.autojs.AutoJs
import org.autojs.autojs.core.console.ConsoleImpl
import org.autojs.autojs.core.console.ConsoleView
import org.autojs.autojs.core.console.GlobalConsole
@@ -22,22 +23,24 @@ class JsConsoleView : ConsoleView {
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
// init {
// setConsole(object : GlobalConsole(UiHandler(context)) {
// override fun println(level: Int, charSequence: CharSequence): String {
// val log = String.format(Locale.getDefault(), "%s", charSequence)
// LOGGER.log(toLog4jLevel(level), log)
// Log.d(TAG, log)
// super.println(level, log)
// return log
// }
// })
// }
//
// override fun onNewLog(logEntry: ConsoleImpl.LogEntry?) {
// if (logEntry != null) {
// ViewUtils.showToast(context, logEntry.content.toString())
// }
// }
init {
// setConsole(object : GlobalConsole(UiHandler(context)) {
// override fun println(level: Int, charSequence: CharSequence): String {
// val log = String.format(Locale.getDefault(), "%s", charSequence)
// LOGGER.log(toLog4jLevel(level), log)
// Log.d(TAG, log)
// super.println(level, log)
// return log
// }
// })
setConsole(AutoJs.instance.globalConsole)
}
override fun onNewLog(logEntry: ConsoleImpl.LogEntry?) {
// if (logEntry != null) {
// ViewUtils.showToast(context, logEntry.content.toString())
// }
super.onNewLog(logEntry)
}
}

View File

@@ -48,7 +48,7 @@ public class TaskerScriptEditActivity extends BaseActivity {
ViewUtils.showToast(TaskerScriptEditActivity.this, ex.getMessage(), true);
finish();
});
setToolbarAsBack(mEditorView.getName());
setToolbarAsBack(mEditorView.name);
}
public static void edit(Activity activity, String title, String summary, String content) {
@@ -61,9 +61,7 @@ public class TaskerScriptEditActivity extends BaseActivity {
@Override
public void finish() {
CodeEditor editor = mEditorView.editor;
if (editor != null) {
setResult(RESULT_OK, new Intent().putExtra(EXTRA_CONTENT, editor.getText()));
}
setResult(RESULT_OK, new Intent().putExtra(EXTRA_CONTENT, editor.getText()));
TaskerScriptEditActivity.super.finish();
}

View File

@@ -1,23 +1,24 @@
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.
* Modified by SuperMonster003 as of Oct 27, 2023.
*/
class SettingsActivity : AppCompatActivity() {
override fun onCreate(@Nullable savedInstanceState: Bundle?) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupViews()
}
private fun setupViews() {
setContentView(R.layout.activity_settings_inrt)
fragmentManager.beginTransaction().replace(R.id.fragment_setting, PreferenceFragment()).commit()
supportFragmentManager.beginTransaction().replace(R.id.fragment_setting, PreferenceFragment()).commit()
val toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.setTitle(R.string.text_settings)
setSupportActionBar(toolbar)
@@ -25,14 +26,10 @@ class SettingsActivity : AppCompatActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
class PreferenceFragment : androidx.preference.PreferenceFragment() {
override fun onCreate(@Nullable savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
class PreferenceFragment : androidx.preference.PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preference_inrt)
}
}
}

View File

@@ -34,11 +34,9 @@ class SplashActivity : AppCompatActivity() {
}
private fun main() {
checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE)
checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
private fun runScript() {
Thread {
try {

View File

@@ -0,0 +1,42 @@
package org.autojs.autojs.permission
import android.content.Context
import org.autojs.autojs.runtime.api.WrappedShizuku
import org.autojs.autojs.ui.main.drawer.PermissionItemHelper
import org.autojs.autojs.util.ViewUtils
import org.autojs.autojs6.R
import rikka.shizuku.Shizuku
class ShizukuPermission(override val context: Context) : PermissionItemHelper {
override fun has() = WrappedShizuku.hasPermission()
override fun request() {
when {
!WrappedShizuku.isInstalled() -> ViewUtils.showToast(context, R.string.error_shizuku_is_not_installed)
Shizuku.isPreV11() -> ViewUtils.showToast(context, R.string.error_shizuku_version_is_not_supported)
else -> {
try {
if (!Shizuku.shouldShowRequestPermissionRationale()) {
WrappedShizuku.requestPermission()
return
}
} catch (e: Throwable) {
e.printStackTrace()
}
WrappedShizuku.config(true) ?: ViewUtils.showToast(context, R.string.error_failed_to_grant_shizuku_access)
}
}
}
override fun revoke() {
when {
!WrappedShizuku.isInstalled() -> ViewUtils.showToast(context, R.string.error_shizuku_is_not_installed)
Shizuku.isPreV11() -> ViewUtils.showToast(context, R.string.error_shizuku_version_is_not_supported)
else -> WrappedShizuku.config(false) ?: ViewUtils.showToast(context, R.string.error_failed_to_revoke_shizuku_access)
}
}
}

View File

@@ -104,8 +104,9 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
}
public void observeKey() {
if (mListeningKey)
if (mListeningKey) {
return;
}
AccessibilityService service = getAccessibilityService();
// @Dubious by SuperMonster003 on Feb 11, 2022.
@@ -129,8 +130,9 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
}
public void observeTouch() {
if (mTouchObserver != null)
if (mTouchObserver != null) {
return;
}
ensureHandler();
mLoopers.waitWhenIdle(true);
mTouchObserver = new TouchObserver(InputEventObserver.initObserver(mContext));
@@ -155,11 +157,13 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
}
private void ensureKeyInterceptor() {
if (mKeyInterceptor != null)
if (mKeyInterceptor != null) {
return;
}
mKeyInterceptor = event -> {
if (mInterceptsAllKey)
if (mInterceptsAllKey) {
return true;
}
String keyName = KeyEvent.keyCodeToString(event.getKeyCode()).substring(8).toLowerCase(Language.getPrefLanguage().getLocale());
return mInterceptedKeys.contains(keyName);
};
@@ -169,12 +173,12 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
private AccessibilityService getAccessibilityService() {
mScriptRuntime.ensureAccessibilityServiceEnabled();
AccessibilityService service = mAccessibilityBridge.getService();
if (service == null)
if (service == null) {
throw new ScriptException(mContext.getString(R.string.error_no_accessibility_service));
}
return service;
}
public Events onKeyDown(String keyName, Object listener) {
on(PREFIX_KEY_DOWN + keyName, listener);
return this;
@@ -224,21 +228,35 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
}
public void observeNotification() {
if (mListeningNotification)
if (mListeningNotification) {
return;
}
mListeningNotification = true;
ensureHandler();
mLoopers.waitWhenIdle(true);
if (NotificationListenerService.Companion.getInstance() == null) {
mContext.startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));
throw new ScriptException(mContext.getString(R.string.text_notification_service_disabled));
if (NotificationListenerService.getInstance() != null) {
NotificationListenerService.getInstance().addListener(this);
return;
}
NotificationListenerService.Companion.getInstance().addListener(this);
Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
throw new ScriptException(mContext.getString(R.string.text_notification_service_disabled));
}
public void removeNotificationObserver() {
mAccessibilityBridge.getNotificationObserver().removeNotificationListener(this);
if (NotificationListenerService.getInstance() != null) {
NotificationListenerService.getInstance().removeListener(this);
}
mListeningNotification = false;
mLoopers.waitWhenIdle(mListeningToast);
}
public void observeToast() {
if (mListeningToast)
if (mListeningToast) {
return;
}
mAccessibilityBridge.ensureServiceEnabled();
mListeningToast = true;
ensureHandler();
@@ -246,6 +264,14 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
mAccessibilityBridge.getNotificationObserver().addToastListener(this);
}
public void removeToastObserver() {
mAccessibilityBridge.getNotificationObserver().removeToastListener(this);
if (NotificationListenerService.getInstance() != null) {
NotificationListenerService.getInstance().removeListener(this);
}
mListeningToast = false;
mLoopers.waitWhenIdle(mListeningNotification);
}
public Events onNotification(Object listener) {
on("notification", listener);
@@ -271,11 +297,10 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
mTouchObserver.stop();
}
if (mListeningNotification) {
mAccessibilityBridge.getNotificationObserver().removeNotificationListener(this);
mAccessibilityBridge.getNotificationObserver().removeToastListener(this);
if (NotificationListenerService.Companion.getInstance() != null) {
NotificationListenerService.Companion.getInstance().removeListener(this);
}
removeNotificationObserver();
}
if (mListeningToast) {
removeToastObserver();
}
if (mKeyInterceptor != null) {
AccessibilityService service = mAccessibilityBridge.getService();
@@ -284,6 +309,7 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
}
mKeyInterceptor = null;
}
mLoopers.waitWhenIdle(false);
}
@Override
@@ -313,7 +339,6 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
public void onNotification(@NonNull final Notification notification) {
mHandler.post(() -> emit("notification", notification));
}
@Override

View File

@@ -24,34 +24,34 @@ class ScreenMetrics(private var designWidth: Int, private var designHeight: Int)
@JvmOverloads
fun scaleX(x: Int, width: Int = designWidth) = when {
width == 0 || !isInitialized -> x
width == 0 || !mIsInitialized -> x
else -> x * deviceScreenWidth / width
}
@JvmOverloads
fun scaleY(y: Int, height: Int = designHeight) = when {
height == 0 || !isInitialized -> y
height == 0 || !mIsInitialized -> y
else -> y * deviceScreenHeight / height
}
@JvmOverloads
fun rescaleX(x: Int, width: Int = designWidth) = when {
width == 0 || !isInitialized -> x
width == 0 || !mIsInitialized -> x
else -> x * width / deviceScreenWidth
}
@JvmOverloads
fun rescaleY(y: Int, height: Int = designHeight) = when {
height == 0 || !isInitialized -> y
height == 0 || !mIsInitialized -> y
else -> y * height / deviceScreenHeight
}
companion object {
private var mWindowManager: WindowManager? = null
private var mResources: Resources? = null
var resources: Resources? = null
private var isInitialized = false
private var mWindowManager: WindowManager? = null
private var mIsInitialized = false
@Suppress("DEPRECATION")
@JvmStatic
@@ -60,7 +60,7 @@ class ScreenMetrics(private var designWidth: Int, private var designHeight: Int)
@JvmStatic
val orientation: Int
get() = mResources?.configuration?.orientation ?: ORIENTATION_PORTRAIT
get() = resources?.configuration?.orientation ?: ORIENTATION_PORTRAIT
@JvmStatic
val isScreenPortrait: Boolean
@@ -74,7 +74,7 @@ class ScreenMetrics(private var designWidth: Int, private var designHeight: Int)
@Suppress("DEPRECATION")
val deviceScreenWidth: Int
get() {
mResources?.displayMetrics?.widthPixels?.takeIf { it > 0 }?.let { return it }
resources?.displayMetrics?.widthPixels?.takeIf { it > 0 }?.let { return it }
val metricsLegacy = DisplayMetrics()
val display = mWindowManager?.defaultDisplay?.apply { getRealMetrics(metricsLegacy) }
@@ -89,7 +89,7 @@ class ScreenMetrics(private var designWidth: Int, private var designHeight: Int)
@Suppress("DEPRECATION")
val deviceScreenHeight: Int
get() {
mResources?.displayMetrics?.heightPixels?.takeIf { it > 0 }?.let { return it }
resources?.displayMetrics?.heightPixels?.takeIf { it > 0 }?.let { return it }
val metricsLegacy = DisplayMetrics()
val display = mWindowManager?.defaultDisplay?.apply { getRealMetrics(metricsLegacy) }
@@ -111,9 +111,9 @@ class ScreenMetrics(private var designWidth: Int, private var designHeight: Int)
@JvmStatic
fun init(activity: Activity) {
resources = activity.resources
mWindowManager = activity.windowManager
mResources = activity.resources
isInitialized = true
mIsInitialized = true
}
private fun toOriAwarePoint(a: Int, b: Int) = arrayOf(minOf(a, b), maxOf(a, b))

View File

@@ -1,15 +1,19 @@
package org.autojs.autojs.runtime.api
import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.os.IBinder
import android.util.Log
import org.autojs.autojs.App
import org.autojs.autojs.annotation.ScriptInterface
import org.autojs.autojs.app.GlobalAppContext
import org.autojs.autojs.core.shizuku.IUserService
import org.autojs.autojs.core.shizuku.UserService
import org.autojs.autojs.util.ViewUtils
import org.autojs.autojs6.BuildConfig
import org.autojs.autojs6.R
import rikka.shizuku.Shizuku
import org.autojs.autojs.runtime.api.AbstractShell.Result as ShellResult
@@ -23,6 +27,9 @@ object WrappedShizuku {
private val TAG: String = WrappedShizuku::class.java.simpleName
private val context
get() = GlobalAppContext.get()
private val mRequestCode = "shizuku-request-code".hashCode()
private val mUserServiceConnection: ServiceConnection = object : ServiceConnection {
@@ -36,7 +43,7 @@ object WrappedShizuku {
}
override fun onServiceDisconnected(componentName: ComponentName) {
// ... ...
Log.d(TAG, "onServiceDisconnected: ${componentName.className}")
}
}
@@ -46,16 +53,16 @@ object WrappedShizuku {
.debuggable(BuildConfig.DEBUG)
.version(BuildConfig.VERSION_CODE)
private val mBinderReceivedListener = {
// if (Shizuku.isPreV11()) {
// binding.text1.setText("Shizuku pre-v11 is not supported")
// } else {
// binding.text1.setText("Binder received")
// }
private val mBinderReceivedListener = Shizuku.OnBinderReceivedListener {
if (Shizuku.isPreV11()) {
Log.d(TAG, "Shizuku pre-v11 is not supported")
} else {
Log.d(TAG, "Binder received")
}
}
private val mBinderDeadListener = {
// binding.text1.setText("Binder dead")
private val mBinderDeadListener = Shizuku.OnBinderDeadListener {
Log.d(TAG, "Binder dead")
}
private val mRequestPermissionResultListener: (requestCode: Int, grantResult: Int) -> Unit = { requestCode: Int, grantResult: Int ->
@@ -71,53 +78,65 @@ object WrappedShizuku {
Shizuku.addRequestPermissionResultListener(mRequestPermissionResultListener)
}
internal fun bindUserServiceIfNeeded() {
if (hasPermission()) {
bindUserService()
}
}
private fun bindUserService() {
val res = StringBuilder()
try {
if (Shizuku.getVersion() < 10) {
res.append("requires Shizuku API 10")
} else {
if (!Shizuku.isPreV11()) {
Shizuku.bindUserService(mUserServiceArgs, mUserServiceConnection)
}
} catch (tr: Throwable) {
tr.printStackTrace()
res.append(tr)
} catch (e: Throwable) {
e.printStackTrace()
}
// binding.text3.setText(res.toString().trim { it <= ' ' })
}
private fun unbindUserService() {
val res = StringBuilder()
try {
if (Shizuku.getVersion() < 10) {
res.append("requires Shizuku API 10")
} else {
if (!Shizuku.isPreV11()) {
Shizuku.unbindUserService(mUserServiceArgs, mUserServiceConnection, true)
}
} catch (tr: Throwable) {
tr.printStackTrace()
res.append(tr)
} catch (_: Throwable) {
// Ignored.
}
// binding.text3.setText(res.toString().trim { it <= ' ' })
}
internal fun checkShizukuPermission() = try {
when {
Shizuku.isPreV11() -> false
Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED -> true.also { bindUserService() }
Shizuku.shouldShowRequestPermissionRationale() -> false
else -> false.also { Shizuku.requestPermission(mRequestCode) }
}
@ScriptInterface
fun isInstalled() = getLaunchIntent() != null
@ScriptInterface
fun hasPermission() = try {
Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
} catch (e: Throwable) {
false.also { e.printStackTrace() }
}
@ScriptInterface
fun requestPermission() = Shizuku.requestPermission(mRequestCode)
@ScriptInterface
@JvmOverloads
fun config(isRequest: Boolean? = null): Intent? {
return getLaunchIntent()?.also {
context.startActivity(it)
val message = when (isRequest) {
true -> "${context.getString(R.string.text_grant_autojs6_access_in_shizuku_app)} (${context.getString(R.string.text_shizuku_service_may_need_to_be_run_first)})"
false -> context.getString(R.string.text_revoke_autojs6_access_in_shizuku_app)
else -> null
}
ViewUtils.showToast(context, message, true)
}
}
@ScriptInterface
fun execCommand(cmd: String): ShellResult {
ensureService()
return try {
ShellResult.fromJson(service!!.execCommand(cmd))
} catch (e: Exception) {
} catch (e: Throwable) {
ShellResult().apply {
code = 1
error = e.message ?: ""
@@ -133,7 +152,7 @@ object WrappedShizuku {
@ScriptInterface
fun ensureService() {
service ?: throw IllegalStateException("Shizuku service is not available")
service ?: throw IllegalStateException(context.getString(R.string.error_unable_to_use_shizuku_service))
}
internal fun onDestroy() {
@@ -143,4 +162,10 @@ object WrappedShizuku {
Shizuku.removeRequestPermissionResultListener(mRequestPermissionResultListener)
}
private fun getLaunchIntent(): Intent? {
return context.packageManager.getLaunchIntentForPackage(org.autojs.autojs.util.App.SHIZUKU.packageName)?.apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
}
}

View File

@@ -3,13 +3,13 @@ package org.autojs.autojs.service
import android.content.Context
import android.content.Intent
import android.provider.Settings
import org.autojs.autojs.core.notification.NotificationListenerService.Companion.instance
import org.autojs.autojs.core.notification.NotificationListenerService
import org.autojs.autojs.ui.main.drawer.ServiceItemHelper
class NotificationService(override val context: Context) : ServiceItemHelper {
override val isRunning: Boolean
get() = instance != null
get() = NotificationListenerService.instance != null
override fun start() {
config()

View File

@@ -193,7 +193,7 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc
if (!mEditorView.isTextChanged) {
return
}
val text = mEditorView.editor!!.text
val text = mEditorView.editor.text
if (text.length < 256 * 1024) {
outState.putString("text", text)
} else {
@@ -228,7 +228,7 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc
.observeOn(Schedulers.io())
.map { PFiles.read(it) }
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ mEditorView.editor!!.text = it }, Throwable::printStackTrace)
.subscribe({ mEditorView.editor.text = it }, Throwable::printStackTrace)
}
}

View File

@@ -197,7 +197,7 @@ public class EditorMenu {
}
private void startBuildApkActivity() {
Uri uri = mEditorView.getUri();
Uri uri = mEditorView.uri;
if (uri != null) {
BuildActivity.launch(mContext, uri.getPath());
}
@@ -217,12 +217,10 @@ public class EditorMenu {
.title(R.string.text_pinch_to_zoom)
.items(R.array.values_editor_pinch_to_zoom_strategy)
.itemsCallbackSingleChoice(defSelectedIndex, (dialog, itemView, which, text) -> {
if (mEditorView.editor != null) {
String newKey = itemKeys.get(which);
if (!Objects.equals(newKey, itemKey)) {
Pref.putString(key, newKey);
mEditorView.editor.notifyPinchToZoomStrategyChanged(newKey);
}
String newKey = itemKeys.get(which);
if (!Objects.equals(newKey, itemKey)) {
Pref.putString(key, newKey);
mEditorView.editor.notifyPinchToZoomStrategyChanged(newKey);
}
return true;
})

View File

@@ -16,8 +16,8 @@ import android.util.AttributeSet
import android.util.Log
import android.util.SparseBooleanArray
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.FragmentActivity
@@ -26,9 +26,6 @@ import com.google.android.material.snackbar.Snackbar
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.androidannotations.annotations.AfterViews
import org.androidannotations.annotations.EViewGroup
import org.androidannotations.annotations.ViewById
import org.autojs.autojs.AutoJs
import org.autojs.autojs.engine.JavaScriptEngine
import org.autojs.autojs.engine.ScriptEngine
@@ -77,6 +74,7 @@ import org.autojs.autojs.util.Observers
import org.autojs.autojs.util.ViewUtils.showSnack
import org.autojs.autojs.util.ViewUtils.showToast
import org.autojs.autojs6.R
import org.autojs.autojs6.databinding.EditorViewBinding
import java.io.File
/**
@@ -84,62 +82,49 @@ import java.io.File
* Modified by SuperMonster003 as of May 1, 2023.
* Transformed by SuperMonster003 on May 1, 2023.
*/
@SuppressLint("NonConstantResourceId")
@EViewGroup(R.layout.editor_view)
// FIXME by SuperMonster003 on May 13, 2023.
// ! Failed many times to migrate this view with annotation to view binding.
// ! And this is the last view with annotation in the whole project so far.
// FIXME by SuperMonster003 on Oct 18, 2023.
// ! Gradle property "android.nonFinalResIds"
// ! can't be enabled (by default since Android Gradle Plugin version 8.0),
// ! as final resource ID used in current class.
open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, ToolbarFragment.OnMenuItemClickListener {
@SuppressLint("CheckResult")
class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFragment.OnMenuItemClickListener {
private var binding: EditorViewBinding = EditorViewBinding.bind(View.inflate(context, R.layout.editor_view, this))
@JvmField
@ViewById(R.id.editor)
var editor: CodeEditor? = null
val editor: CodeEditor = binding.editor
@JvmField
@ViewById(R.id.debug_bar)
var debugBar: DebugBar? = null
val debugBar: DebugBar = binding.debugBar
@JvmField
@ViewById(R.id.code_completion_bar)
var mCodeCompletionBar: CodeCompletionBar? = null
@JvmField
@ViewById(R.id.input_method_enhance_bar)
var mInputMethodEnhanceBar: View? = null
@JvmField
@ViewById(R.id.symbol_bar)
var mSymbolBar: CodeCompletionBar? = null
@JvmField
@ViewById(R.id.functions)
var mShowFunctionsButton: ImageView? = null
@JvmField
@ViewById(R.id.functions_keyboard)
var mFunctionsKeyboard: FunctionsKeyboardView? = null
@JvmField
@ViewById(R.id.docs)
var mDocsWebView: EWebView? = null
@JvmField
@ViewById(R.id.drawer_layout)
var mDrawerLayout: DrawerLayout? = null
var name: String? = null
private set
@JvmField
var uri: Uri? = null
private set
var scriptExecutionId = 0
private set
val activity: FragmentActivity
get() {
var context = context
while (context !is Activity && context is ContextWrapper) {
context = context.baseContext
}
return context as FragmentActivity
}
val isTextChanged: Boolean
get() = editor.isTextChanged
private val scriptExecution: ScriptExecution?
get() = AutoJs.instance.scriptEngineService.getScriptExecution(scriptExecutionId)
private val mCodeCompletionBar: CodeCompletionBar = binding.codeCompletionBar
private val mInputMethodEnhanceBar: View = binding.inputMethodEnhanceBar
private val mSymbolBar: CodeCompletionBar = binding.symbolBar
private val mShowFunctionsButton: ImageView = binding.functions
private val mFunctionsKeyboard: FunctionsKeyboardView = binding.functionsKeyboard
private val mDocsWebView: EWebView = binding.docs
private val mDrawerLayout: DrawerLayout = binding.drawerLayout
private var mReadOnly = false
private var mAutoCompletion: AutoCompletion? = null
private var mEditorTheme: Theme? = null
@@ -156,7 +141,7 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
val line = intent.getIntExtra(EXTRA_EXCEPTION_LINE_NUMBER, -1)
val col = intent.getIntExtra(EXTRA_EXCEPTION_COLUMN_NUMBER, 0)
if (line >= 1) {
editor!!.jumpTo(line - 1, col)
editor.jumpTo(line - 1, col)
}
msg?.let { showErrorMessage(it) }
}
@@ -169,9 +154,26 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
private var mTmpSavedFileForRunning: File? = null
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
init {
setUpEditor()
setUpInputMethodEnhancedBar()
setUpFunctionsKeyboard()
setMenuItemStatus(R.id.save, false)
mDocsWebView.apply {
webView.settings.displayZoomControls = true
webView.loadUrl(getUrl("index.html"))
}
Themes.getCurrent(context)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { theme: Theme? -> setTheme(theme) }
initNormalToolbar()
}
@SuppressLint("UnspecifiedRegisterReceiverFlag")
override fun onAttachedToWindow() {
super.onAttachedToWindow()
@@ -203,14 +205,14 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
findViewById<View>(R.id.run).visibility = GONE
}
if (mReadOnly) {
editor!!.setReadOnly(true)
editor.setReadOnly(true)
}
}
}
fun setRestoredText(text: String) {
mRestoredText = text
editor!!.text = text
editor.text = text
}
private fun handleText(intent: Intent): Observable<String> {
@@ -241,11 +243,11 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
private fun setInitialText(text: String) {
if (mRestoredText != null) {
editor!!.text = mRestoredText!!
editor.text = mRestoredText!!
mRestoredText = null
return
}
editor!!.setInitialText(text)
editor.setInitialText(text)
}
private fun setMenuItemStatus(id: Int, enabled: Boolean) {
@@ -263,23 +265,6 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
return mMenuItemStatus[id, defValue]
}
@SuppressLint("CheckResult")
@AfterViews
fun init() {
setUpEditor()
setUpInputMethodEnhancedBar()
setUpFunctionsKeyboard()
setMenuItemStatus(R.id.save, false)
mDocsWebView?.apply {
webView.settings.displayZoomControls = true
webView.loadUrl(getUrl("index.html"))
}
Themes.getCurrent(context)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { theme: Theme? -> setTheme(theme) }
initNormalToolbar()
}
private fun initNormalToolbar() {
mNormalToolbar.apply {
setOnMenuItemClickListener(this@EditorView)
@@ -298,7 +283,7 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
.setFunctionsView(mFunctionsKeyboard)
.setFunctionsTrigger(mShowFunctionsButton)
.setEditView(editor!!.codeEditText)
.setEditView(editor.codeEditText)
.build()
// @ArchivedTodo by 抠脚本人 on Jul 10, 2023.
@@ -313,21 +298,21 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
// ! 此处的点击事件回调注册是为了使功能键盘智能提示的属性可以实现其接口对应的功能:
// ! 点击: 自动补全, 并根据情况添加括号或句点符号等.
// ! 长按: 以浮动窗口形式展示 [方法/属性/模块] 对应的文档内容 (如果存在的话).
mFunctionsKeyboard!!.setClickCallback(this)
mFunctionsKeyboard.setClickCallback(this)
mShowFunctionsButton!!.setOnLongClickListener {
true.also { editor!!.beautifyCode() }
mShowFunctionsButton.setOnLongClickListener {
true.also { editor.beautifyCode() }
}
}
private fun setUpInputMethodEnhancedBar() {
mSymbolBar!!.let { bar ->
mSymbolBar.let { bar ->
bar.setOnHintClickListener(this)
bar.codeCompletions = Symbols.getSymbols()
}
mCodeCompletionBar!!.let { bar ->
mCodeCompletionBar.let { bar ->
bar.setOnHintClickListener(this)
AutoCompletion(context, editor!!.codeEditText).apply {
AutoCompletion(context, editor.codeEditText).apply {
setAutoCompleteCallback { bar.codeCompletions = it }
mAutoCompletion = this
}
@@ -335,14 +320,14 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
}
private fun setUpEditor() {
editor!!.let { editor ->
editor.let { editor ->
editor.codeEditText.let { editText ->
editText.addTextChangedListener(SimpleTextWatcher { _ ->
setMenuItemStatus(R.id.save, editor.isTextChanged)
setMenuItemStatus(R.id.undo, editor.canUndo())
setMenuItemStatus(R.id.redo, editor.canRedo())
})
editText.textSize = getEditorTextSize(pxToSp(context, editText.textSize).toInt()).toFloat()
editText.textSize = getEditorTextSize(pxToSp(editText.textSize).toInt()).toFloat()
}
editor.addCursorChangeCallback(object : CodeEditor.CursorChangeCallback {
override fun onCursorChange(line: String, cursor: Int) {
@@ -360,22 +345,22 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
private fun setTheme(theme: Theme?) {
theme?.let {
mEditorTheme = it
editor!!.setTheme(it)
mInputMethodEnhanceBar!!.setBackgroundColor(it.imeBarBackgroundColor)
editor.setTheme(it)
mInputMethodEnhanceBar.setBackgroundColor(it.imeBarBackgroundColor)
val textColor = it.imeBarForegroundColor
mCodeCompletionBar!!.setTextColor(textColor)
mSymbolBar!!.setTextColor(textColor)
mShowFunctionsButton!!.setColorFilter(textColor)
mCodeCompletionBar.setTextColor(textColor)
mSymbolBar.setTextColor(textColor)
mShowFunctionsButton.setColorFilter(textColor)
invalidate()
}
}
fun onBackPressed(): Boolean {
if (mDrawerLayout!!.isDrawerOpen(GravityCompat.START)) {
if (mDocsWebView!!.webView.canGoBack()) {
mDocsWebView!!.webView.goBack()
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
if (mDocsWebView.webView.canGoBack()) {
mDocsWebView.webView.goBack()
} else {
mDrawerLayout!!.closeDrawer(GravityCompat.START)
mDrawerLayout.closeDrawer(GravityCompat.START)
}
return true
}
@@ -423,20 +408,20 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
return run(true, file, uri!!.path)
}
private fun undo() = editor!!.undo()
private fun undo() = editor.undo()
private fun redo() = editor!!.redo()
private fun redo() = editor.redo()
fun save(): Observable<String> {
val path = uri!!.path
val backPath = "$path.save"
move(path!!, backPath)
return Observable.just(editor!!.text)
return Observable.just(editor.text)
.observeOn(Schedulers.io())
.doOnNext { s: String? -> write(context.contentResolver.openOutputStream(uri!!)!!, s!!) }
.observeOn(AndroidSchedulers.mainThread())
.doOnNext {
editor!!.markTextAsSaved()
editor.markTextAsSaved()
setMenuItemStatus(R.id.save, false)
}
.doOnNext {
@@ -451,13 +436,7 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
}
private fun doWithCurrentEngine(callback: Callback<ScriptEngine<*>>) {
val execution = AutoJs.instance.scriptEngineService.getScriptExecution(scriptExecutionId)
if (execution != null) {
val engine = execution.engine
if (engine != null) {
callback.call(engine)
}
}
scriptExecution?.engine?.let { callback.call(it) }
}
@SuppressLint("CheckResult")
@@ -470,9 +449,9 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
}
}
private fun findNext() = editor!!.findNext()
private fun findNext() = editor.findNext()
private fun findPrev() = editor!!.findPrev()
private fun findPrev() = editor.findPrev()
private fun cancelSearch() = showNormalToolbar()
@@ -482,22 +461,10 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
.commitAllowingStateLoss()
}
val activity: FragmentActivity
get() {
var context = context
while (context !is Activity && context is ContextWrapper) {
context = context.baseContext
}
return context as FragmentActivity
}
fun replace() {
editor!!.replaceSelection()
editor.replaceSelection()
}
val isTextChanged: Boolean
get() = editor!!.isTextChanged
fun showConsole() {
doWithCurrentEngine { engine: ScriptEngine<*> -> (engine as JavaScriptEngine).runtime.console.show() }
}
@@ -509,32 +476,32 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
}
fun beautifyCode() {
editor!!.beautifyCode()
editor.beautifyCode()
}
@SuppressLint("CheckResult")
fun selectEditorTheme() {
editor!!.setProgress(true)
editor.setProgress(true)
Themes.getAllThemes(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { themes: List<Theme?> ->
editor!!.setProgress(false)
editor.setProgress(false)
selectEditorTheme(themes)
}
}
fun selectTextSize() {
TextSizeSettingDialogBuilder(context)
.initialValue(pxToSp(context, editor!!.codeEditText.textSize).toInt())
.initialValue(pxToSp(editor.codeEditText.textSize).toInt())
.callback { value: Int -> setTextSize(value) }
.show()
}
fun setTextSize(value: Int) {
setEditorTextSize(value)
editor!!.codeEditText.textSize = value.toFloat()
editor!!.lastTextSize = value
editor.codeEditText.textSize = value.toFloat()
editor.lastTextSize = value
}
private fun selectEditorTheme(themes: List<Theme?>) {
@@ -557,7 +524,7 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
@Throws(CheckedPatternSyntaxException::class)
fun find(keywords: String, usingRegex: Boolean) {
editor!!.find(keywords, usingRegex)
editor.find(keywords, usingRegex)
showSearchToolbar(false)
}
@@ -572,21 +539,21 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
@Throws(CheckedPatternSyntaxException::class)
fun replace(keywords: String, replacement: String, usingRegex: Boolean) {
editor!!.replace(keywords, replacement, usingRegex)
editor.replace(keywords, replacement, usingRegex)
showSearchToolbar(true)
}
@Throws(CheckedPatternSyntaxException::class)
fun replaceAll(keywords: String, replacement: String, usingRegex: Boolean) {
editor!!.replaceAll(keywords, replacement, usingRegex)
editor.replaceAll(keywords, replacement, usingRegex)
}
fun debug() {
activity.supportFragmentManager.beginTransaction()
.replace(R.id.toolbar_menu, DebugToolbarFragment())
.commit()
debugBar!!.visibility = VISIBLE
mInputMethodEnhanceBar!!.visibility = GONE
debugBar.visibility = VISIBLE
mInputMethodEnhanceBar.visibility = GONE
mDebugging = true
}
@@ -597,9 +564,9 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
fragment.detachDebugger()
}
showNormalToolbar()
editor!!.setDebuggingLine(-1)
debugBar!!.visibility = GONE
mInputMethodEnhanceBar!!.visibility = VISIBLE
editor.setDebuggingLine(-1)
debugBar.visibility = GONE
mInputMethodEnhanceBar.visibility = VISIBLE
mDebugging = false
}
@@ -627,7 +594,7 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
// editor!!.commentLine()
// } else editor!!.insert(completion.insertText)
editor!!.insert(completion.insertText)
editor.insert(completion.insertText)
}
override fun onHintLongClick(completions: CodeCompletions, pos: Int) {
@@ -653,7 +620,7 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
completions[pos].let {
when {
// @Inspired by 抠脚本人 (https://github.com/little-alei) on Jul 13, 2023.
it.insertText == "/" -> editor!!.commentHelper.handle()
it.insertText == "/" -> editor.commentHelper.handle()
it.url != null -> showManual(it.url, it.hint)
}
}
@@ -665,8 +632,8 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
.title(title)
.url(absUrl)
.pinToLeft {
mDocsWebView!!.webView.loadUrl(absUrl)
mDrawerLayout!!.openDrawer(GravityCompat.START)
mDocsWebView.webView.loadUrl(absUrl)
mDrawerLayout.openDrawer(GravityCompat.START)
}
.show()
}
@@ -681,12 +648,12 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
p = "$p()"
}
if (property.isGlobal) {
editor!!.insert(p)
editor.insert(p)
} else {
editor!!.insert(m.name + "." + p)
editor.insert(m.name + "." + p)
}
if (!property.isVariable) {
editor!!.moveCursor(-1)
editor.moveCursor(-1)
}
mFunctionsKeyboardHelper!!.hideFunctionsLayout(true)
}
@@ -699,15 +666,9 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
}
}
val scriptExecution: ScriptExecution?
get() = AutoJs.instance.scriptEngineService.getScriptExecution(scriptExecutionId)
override fun onSaveInstanceState(): Parcelable? {
val bundle = Bundle()
val superData = super.onSaveInstanceState()
bundle.putParcelable("super_data", superData)
bundle.putInt("script_execution_id", scriptExecutionId)
return bundle
override fun onSaveInstanceState() = Bundle().apply {
putParcelable("super_data", super.onSaveInstanceState())
putInt("script_execution_id", scriptExecutionId)
}
override fun onRestoreInstanceState(state: Parcelable) {
@@ -721,17 +682,17 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
}
fun destroy() {
editor!!.destroy()
editor.destroy()
mAutoCompletion?.shutdown()
}
@SuppressLint("CheckResult")
private fun saveToTmpFile(): Observable<File> {
return Observable.fromCallable {
val tmp = TmpScriptFiles.create(context)
write(tmp, editor!!.text)
mTmpSavedFileForRunning = tmp
tmp
TmpScriptFiles.create(context).also {
write(it, editor.text)
mTmpSavedFileForRunning = it
}
}.observeOn(Schedulers.io())
}
@@ -748,4 +709,5 @@ open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, Toolbar
const val EXTRA_SAVE_ENABLED = "saveEnabled"
const val EXTRA_RUN_ENABLED = "runEnabled"
}
}

View File

@@ -59,7 +59,7 @@ class CodeEditor : HVScrollView {
val codeEditText: CodeEditText = binding.codeEditText.also {
it.addTextChangedListener(AutoIndent(it))
lastTextSize = getEditorTextSize(pxToSp(it.context, it.textSize).toInt())
lastTextSize = getEditorTextSize(pxToSp(it.textSize).toInt())
}
val lineCount

View File

@@ -1,301 +0,0 @@
package org.autojs.autojs.ui.edit.toolbar;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import org.autojs.autojs.execution.ScriptExecution;
import org.autojs.autojs.pio.PFiles;
import org.autojs.autojs.rhino.debug.DebugCallback;
import org.autojs.autojs.rhino.debug.Debugger;
import org.autojs.autojs.rhino.debug.Dim;
import org.autojs.autojs.runtime.exception.ScriptInterruptedException;
import org.autojs.autojs.ui.edit.EditorView;
import org.autojs.autojs.ui.edit.debug.CodeEvaluator;
import org.autojs.autojs.ui.edit.debug.DebugBar;
import org.autojs.autojs.ui.edit.debug.DebuggerSingleton;
import org.autojs.autojs.ui.edit.debug.WatchingVariable;
import org.autojs.autojs.ui.edit.editor.CodeEditor;
import org.autojs.autojs.util.ViewUtils;
import org.autojs.autojs6.R;
import org.autojs.autojs6.databinding.FragmentDebugToolbarBinding;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.List;
public class DebugToolbarFragment extends ToolbarFragment implements DebugCallback, CodeEditor.CursorChangeCallback, CodeEvaluator {
private static final String LOG_TAG = "DebugToolbarFragment";
private EditorView mEditorView;
private boolean mCursorChangeFromUser = true;
private Debugger mDebugger;
private Handler mHandler;
private String mCurrentEditorSourceUrl;
private String mInitialEditorSourceUrl;
private String mInitialEditorSource;
private final RecyclerView.AdapterDataObserver mVariableChangeObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
updateWatchingVariables(positionStart, positionStart + itemCount);
}
};
private final CodeEditor.BreakpointChangeListener mBreakpointChangeListener = new CodeEditor.BreakpointChangeListener() {
@Override
public void onBreakpointChange(int line, boolean enabled) {
if (mDebugger != null) {
mDebugger.breakpoint(line + 1, enabled);
}
}
@Override
public void onAllBreakpointRemoved(int count) {
mDebugger.clearAllBreakpoints();
}
};
private FragmentDebugToolbarBinding binding;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = FragmentDebugToolbarBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mEditorView = findEditorView(view);
mDebugger = DebuggerSingleton.get();
mDebugger.setWeakDebugCallback(new WeakReference<>(this));
setInterrupted(false);
mCurrentEditorSourceUrl = mInitialEditorSourceUrl = mEditorView.getUri().toString();
mInitialEditorSource = mEditorView.editor.getText();
setupEditor();
ScriptExecution execution = mEditorView.run(false);
if (execution != null) {
mDebugger.attach(execution);
} else {
mEditorView.exitDebugging();
}
Log.d(LOG_TAG, "onViewCreated");
// @Caution by SuperMonster003 on May 13, 2023.
// ! Do not place these listeners into onCreateView method.
binding.stepOver.setOnClickListener(v -> stepOver());
binding.stepInto.setOnClickListener(v -> stepInto());
binding.stepOut.setOnClickListener(v -> stepOut());
binding.stopScript.setOnClickListener(v -> stopScript());
binding.resumeScript.setOnClickListener(v -> resumeScript());
}
private void setupEditor() {
CodeEditor editor = mEditorView.editor;
editor.setRedoUndoEnabled(false);
editor.addCursorChangeCallback(this);
editor.setBreakpointChangeListener(mBreakpointChangeListener);
DebugBar debugBar = mEditorView.debugBar;
debugBar.registerVariableChangeObserver(mVariableChangeObserver);
debugBar.setCodeEvaluator(this);
}
private void setInterrupted(boolean interrupted) {
setMenuItemStatus(R.id.step_into, interrupted);
setMenuItemStatus(R.id.step_over, interrupted);
setMenuItemStatus(R.id.step_out, interrupted);
setMenuItemStatus(R.id.resume_script, interrupted);
if (!interrupted && mEditorView != null) {
mEditorView.editor.setDebuggingLine(-1);
}
}
public void detachDebugger() {
if (!mDebugger.isAttached()) {
return;
}
Log.d(LOG_TAG, "detachDebugger");
mDebugger.detach();
if (mEditorView == null) {
return;
}
CodeEditor editor = mEditorView.editor;
if (!TextUtils.equals(mInitialEditorSourceUrl, mCurrentEditorSourceUrl)) {
editor.setText(mInitialEditorSource);
}
editor.setRedoUndoEnabled(true);
DebugBar debugBar = mEditorView.debugBar;
debugBar.setTitle(null);
debugBar.setCodeEvaluator(null);
}
void stepOver() {
setInterrupted(false);
mDebugger.stepOver();
}
void stepInto() {
setInterrupted(false);
mDebugger.stepInto();
}
void stepOut() {
setInterrupted(false);
mDebugger.stepOut();
}
void stopScript() {
mEditorView.forceStop();
}
void resumeScript() {
setInterrupted(false);
mDebugger.resume();
}
@Override
public void updateSourceText(Dim.SourceInfo sourceInfo) {
Log.d(LOG_TAG, "updateSourceText: url = " + sourceInfo.url());
sourceInfo.removeAllBreakpoints();
for (CodeEditor.Breakpoint breakpoint : mEditorView.editor.getBreakpoints().values()) {
int line = breakpoint.line + 1;
if (sourceInfo.breakableLine(line)) {
sourceInfo.breakpoint(line, breakpoint.enabled);
Log.d(LOG_TAG, "not breakable: " + line);
}
}
}
@Override
public void enterInterrupt(Dim.StackFrame stackFrame, String threadName, String message) {
showDebuggingLineOnEditor(stackFrame, message);
mHandler.post(this::updateWatchingVariables);
}
private void updateWatchingVariables() {
updateWatchingVariables(0, mEditorView.debugBar.getWatchingVariables().size());
}
private void updateWatchingVariables(int start, int end) {
if (!mDebugger.isAttached()) {
return;
}
DebugBar debugBar = mEditorView.debugBar;
List<WatchingVariable> variables = debugBar.getWatchingVariables();
for (int i = start; i < end; i++) {
WatchingVariable variable = variables.get(i);
String value = eval(variable.getName());
variable.setValue(value);
}
debugBar.refresh(start, end - start);
}
public String eval(String expr) {
return mDebugger.eval(expr);
}
private void showDebuggingLineOnEditor(Dim.StackFrame stackFrame, String message) {
//如果调试进入到其他脚本(例如模块脚本),则改变当前编辑器的文本为自动调试的脚本的代码
String source;
//标记是否需要更改编辑器文本
boolean shouldChangeText = !stackFrame.getUrl().equals(mCurrentEditorSourceUrl);
if (shouldChangeText) {
source = stackFrame.sourceInfo().source();
} else {
source = null;
}
mCurrentEditorSourceUrl = stackFrame.getUrl();
final int line = stackFrame.getLineNumber() - 1;
mHandler.post(() -> {
if (mEditorView == null) {
return;
}
if (shouldChangeText) {
mEditorView.editor.setText(source);
}
mCursorChangeFromUser = false;
mEditorView.editor.setDebuggingLine(line);
mEditorView.editor.jumpTo(line, 0);
mEditorView.debugBar.setTitle(PFiles.getName(mCurrentEditorSourceUrl));
setInterrupted(true);
if (message != null && !message.equals(ScriptInterruptedException.class.getName())) {
ViewUtils.showToast(mEditorView.getContext(), message, true);
}
});
}
@Override
public void onCursorChange(String line, int ch) {
if (ch == 0 && !mCursorChangeFromUser) {
mCursorChangeFromUser = true;
return;
}
mCursorChangeFromUser = true;
if (!mDebugger.isAttached()) {
return;
}
String variable = findVariableOnCursor(line, ch);
Log.d(LOG_TAG, "onCursorChange: variable = " + variable + ", ch = " + ch + ", line = " + line);
String value = eval(variable);
mEditorView.debugBar.updateCurrentVariable(variable, value);
}
private String findVariableOnCursor(String line, int ch) {
int end;
for (end = ch; end < line.length(); end++) {
if (!isIdentifierChar(line.charAt(end))) {
break;
}
}
int start;
for (start = Math.min(ch - 1, line.length() - 1); start >= 0; start--) {
if (!isIdentifierChar(line.charAt(start))) {
break;
}
}
start++;
if (start < end && start < line.length() && start >= 0) {
return line.substring(start, end);
}
return null;
}
private boolean isIdentifierChar(char c) {
return Character.isDigit(c) || Character.isLetter(c) || c == '.' || c == '_';
}
@Override
public List<Integer> getMenuItemIds() {
return Arrays.asList(R.id.step_over, R.id.step_into, R.id.step_out, R.id.resume_script, R.id.stop_script);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mEditorView == null) {
return;
}
CodeEditor editor = mEditorView.editor;
editor.removeCursorChangeCallback(this);
editor.setBreakpointChangeListener(null);
DebugBar debugBar = mEditorView.debugBar;
debugBar.unregisterVariableChangeObserver(mVariableChangeObserver);
}
}

View File

@@ -0,0 +1,263 @@
package org.autojs.autojs.ui.edit.toolbar
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
import org.autojs.autojs.pio.PFiles.getName
import org.autojs.autojs.rhino.debug.DebugCallback
import org.autojs.autojs.rhino.debug.Debugger
import org.autojs.autojs.rhino.debug.Dim
import org.autojs.autojs.runtime.exception.ScriptInterruptedException
import org.autojs.autojs.ui.edit.EditorView
import org.autojs.autojs.ui.edit.debug.CodeEvaluator
import org.autojs.autojs.ui.edit.debug.DebuggerSingleton
import org.autojs.autojs.ui.edit.editor.CodeEditor.BreakpointChangeListener
import org.autojs.autojs.ui.edit.editor.CodeEditor.CursorChangeCallback
import org.autojs.autojs.util.ViewUtils.showToast
import org.autojs.autojs6.R
import org.autojs.autojs6.databinding.FragmentDebugToolbarBinding
import java.lang.ref.WeakReference
/**
* Transformed by SuperMonster003 on Oct 27, 2023.
*/
class DebugToolbarFragment : ToolbarFragment(), DebugCallback, CursorChangeCallback, CodeEvaluator {
private lateinit var binding: FragmentDebugToolbarBinding
private lateinit var mEditorView: EditorView
private lateinit var mDebugger: Debugger
private lateinit var mHandler: Handler
private lateinit var mCurrentEditorSourceUrl: String
private lateinit var mInitialEditorSourceUrl: String
private lateinit var mInitialEditorSource: String
private var mCursorChangeFromUser = true
private val mVariableChangeObserver: AdapterDataObserver = object : AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
updateWatchingVariables(positionStart, positionStart + itemCount)
}
}
private val mBreakpointChangeListener: BreakpointChangeListener = object : BreakpointChangeListener {
override fun onBreakpointChange(line: Int, enabled: Boolean) {
mDebugger.breakpoint(line + 1, enabled)
}
override fun onAllBreakpointRemoved(count: Int) {
mDebugger.clearAllBreakpoints()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mHandler = Handler(Looper.getMainLooper())
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return FragmentDebugToolbarBinding.inflate(inflater, container, false)
.also { binding = it }.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mEditorView = findEditorView(view)
mDebugger = DebuggerSingleton.get()
mDebugger.setWeakDebugCallback(WeakReference(this))
setInterrupted(false)
mInitialEditorSourceUrl = mEditorView.uri.toString()
mCurrentEditorSourceUrl = mInitialEditorSourceUrl
mInitialEditorSource = mEditorView.editor.text
setupEditor()
val execution = mEditorView.run(false)
if (execution != null) {
mDebugger.attach(execution)
} else {
mEditorView.exitDebugging()
}
Log.d(LOG_TAG, "onViewCreated")
// @Caution by SuperMonster003 on May 13, 2023.
// ! Do not place these listeners into onCreateView method.
binding.stepOver.setOnClickListener { stepOver() }
binding.stepInto.setOnClickListener { stepInto() }
binding.stepOut.setOnClickListener { stepOut() }
binding.stopScript.setOnClickListener { stopScript() }
binding.resumeScript.setOnClickListener { resumeScript() }
}
private fun setupEditor() {
mEditorView.editor.apply {
setRedoUndoEnabled(false)
addCursorChangeCallback(this@DebugToolbarFragment)
setBreakpointChangeListener(mBreakpointChangeListener)
}
mEditorView.debugBar.apply {
registerVariableChangeObserver(mVariableChangeObserver)
setCodeEvaluator(this@DebugToolbarFragment)
}
}
private fun setInterrupted(interrupted: Boolean) {
setMenuItemStatus(R.id.step_into, interrupted)
setMenuItemStatus(R.id.step_over, interrupted)
setMenuItemStatus(R.id.step_out, interrupted)
setMenuItemStatus(R.id.resume_script, interrupted)
if (!interrupted) {
mEditorView.editor.setDebuggingLine(-1)
}
}
fun detachDebugger() {
if (!mDebugger.isAttached) {
return
}
Log.d(LOG_TAG, "detachDebugger")
mDebugger.detach()
mEditorView.editor.also {
if (!TextUtils.equals(mInitialEditorSourceUrl, mCurrentEditorSourceUrl)) {
it.text = mInitialEditorSource
}
it.setRedoUndoEnabled(true)
}
mEditorView.debugBar.apply {
setTitle(null)
setCodeEvaluator(null)
}
}
private fun stepOver() = setInterrupted(false).also { mDebugger.stepOver() }
private fun stepInto() = setInterrupted(false).also { mDebugger.stepInto() }
private fun stepOut() = setInterrupted(false).also { mDebugger.stepOut() }
private fun stopScript() = mEditorView.forceStop()
private fun resumeScript() = setInterrupted(false).also { mDebugger.resume() }
override fun updateSourceText(sourceInfo: Dim.SourceInfo) {
Log.d(LOG_TAG, "updateSourceText: url = " + sourceInfo.url())
sourceInfo.removeAllBreakpoints()
for (breakpoint in mEditorView.editor.breakpoints.values) {
val line = breakpoint.line + 1
if (sourceInfo.breakableLine(line)) {
sourceInfo.breakpoint(line, breakpoint.enabled)
Log.d(LOG_TAG, "not breakable: $line")
}
}
}
override fun enterInterrupt(stackFrame: Dim.StackFrame, threadName: String, message: String) {
showDebuggingLineOnEditor(stackFrame, message)
mHandler.post { updateWatchingVariables() }
}
private fun updateWatchingVariables(start: Int = 0, end: Int = mEditorView.debugBar.watchingVariables.size) {
if (!mDebugger.isAttached) {
return
}
val debugBar = mEditorView.debugBar
val variables = debugBar.watchingVariables
for (i in start until end) {
val variable = variables[i]
variable.value = eval(variable.name)
}
debugBar.refresh(start, end - start)
}
override fun eval(expr: String): String = mDebugger.eval(expr)
private fun showDebuggingLineOnEditor(stackFrame: Dim.StackFrame, message: String?) {
// 标记是否需要更改编辑器文本
val shouldChangeText = stackFrame.url != mCurrentEditorSourceUrl
// 如果调试进入到其他脚本 (例如模块脚本), 则改变当前编辑器的文本为自动调试的脚本的代码
val source: String? = if (shouldChangeText) stackFrame.sourceInfo().source() else null
mCurrentEditorSourceUrl = stackFrame.url
val line = stackFrame.lineNumber - 1
mHandler.post {
source?.let { mEditorView.editor.text = it }
mCursorChangeFromUser = false
mEditorView.editor.setDebuggingLine(line)
mEditorView.editor.jumpTo(line, 0)
mEditorView.debugBar.setTitle(getName(mCurrentEditorSourceUrl))
setInterrupted(true)
if (message != ScriptInterruptedException::class.java.name) {
showToast(mEditorView.context, message, true)
}
}
}
override fun onCursorChange(line: String, cursor: Int) {
if (cursor == 0 && !mCursorChangeFromUser) {
mCursorChangeFromUser = true
return
}
mCursorChangeFromUser = true
if (!mDebugger.isAttached) {
return
}
val variable = findVariableOnCursor(line, cursor)
Log.d(LOG_TAG, "onCursorChange: variable = $variable, ch = $cursor, line = $line")
variable?.let {
eval(it)
mEditorView.debugBar.updateCurrentVariable(variable, it)
}
}
private fun findVariableOnCursor(line: String, ch: Int): String? {
var end = ch
while (end < line.length) {
if (!isIdentifierChar(line[end])) {
break
}
end++
}
var start = (ch - 1).coerceAtMost(line.length - 1)
while (start >= 0) {
if (!isIdentifierChar(line[start])) {
break
}
start--
}
start++
return if (start < end && start < line.length && start >= 0) {
line.substring(start, end)
} else null
}
private fun isIdentifierChar(c: Char): Boolean {
return Character.isDigit(c) || Character.isLetter(c) || c == '.' || c == '_'
}
override fun getMenuItemIds(): List<Int> {
return listOf(R.id.step_over, R.id.step_into, R.id.step_out, R.id.resume_script, R.id.stop_script)
}
override fun onDestroy() {
super.onDestroy()
mEditorView.editor.apply {
removeCursorChangeCallback(this@DebugToolbarFragment)
setBreakpointChangeListener(null)
}
mEditorView.debugBar.apply {
unregisterVariableChangeObserver(mVariableChangeObserver)
}
}
companion object {
private const val LOG_TAG = "DebugToolbarFragment"
}
}

View File

@@ -123,7 +123,7 @@ class MainActivity : BaseActivity(), DelegateHost, HostActivity {
override fun onStart() {
super.onStart()
WrappedShizuku.checkShizukuPermission()
WrappedShizuku.bindUserServiceIfNeeded()
}
private fun recreateIfNeeded() {

View File

@@ -2,7 +2,6 @@ package org.autojs.autojs.ui.main.drawer
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -18,6 +17,7 @@ import org.autojs.autojs.permission.DisplayOverOtherAppsPermission
import org.autojs.autojs.permission.IgnoreBatteryOptimizationsPermission
import org.autojs.autojs.permission.MediaProjectionPermission
import org.autojs.autojs.permission.PostNotificationPermission
import org.autojs.autojs.permission.ShizukuPermission
import org.autojs.autojs.permission.UsageStatsPermission
import org.autojs.autojs.permission.WriteSecureSettingsPermission
import org.autojs.autojs.permission.WriteSystemSettingsPermission
@@ -55,7 +55,6 @@ open class DrawerFragment : Fragment() {
private lateinit var mDrawerMenu: RecyclerView
private lateinit var mContext: Context
private lateinit var mActivity: MainActivity
// private lateinit var mReceiver: BatteryChangedReceiver
private lateinit var mAccessibilityServiceItem: DrawerMenuToggleableItem
private lateinit var mForegroundServiceItem: DrawerMenuToggleableItem
@@ -70,29 +69,21 @@ open class DrawerFragment : Fragment() {
private lateinit var mWriteSystemSettingsItem: DrawerMenuToggleableItem
private lateinit var mWriteSecuritySettingsItem: DrawerMenuToggleableItem
private lateinit var mProjectMediaAccessItem: DrawerMenuToggleableItem
private lateinit var mShizukuAccessItem: DrawerMenuToggleableItem
private lateinit var mNightModeItem: DrawerMenuToggleableItem
private lateinit var mAutoNightModeItem: DrawerMenuToggleableItem
private lateinit var mKeepScreenOnWhenInForegroundItem: DrawerMenuToggleableItem
private lateinit var mThemeColorItem: DrawerMenuShortcutItem
private lateinit var mAboutAppAndDevItem: DrawerMenuShortcutItem
private val actionBatteryChangedIntentFilter = IntentFilter().apply {
addAction("android.intent.action.ACTION_BATTERY_CHANGED")
addAction("android.intent.action.ACTION_POWER_CONNECTED")
addAction("android.intent.action.ACTION_POWER_DISCONNECTED")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EventBus.getDefault().register(this)
// mReceiver = BatteryChangedReceiver()
mContext = requireContext()
mActivity = (requireActivity() as MainActivity).apply {
// registerReceiver(mReceiver, actionBatteryChangedIntentFilter)
}
mActivity = (requireActivity() as MainActivity)
mAccessibilityServiceItem = DrawerMenuToggleableItem(
AccessibilityService(mContext),
@@ -224,6 +215,13 @@ open class DrawerFragment : Fragment() {
R.string.text_project_media_access_description,
)
mShizukuAccessItem = DrawerMenuToggleableItem(
ShizukuPermission(mContext),
R.drawable.ic_app_shizuku_representative,
R.string.text_shizuku_access,
R.string.text_shizuku_access_description,
)
mAutoNightModeItem = DrawerMenuToggleableItem(
object : DrawerMenuItemCustomHelper(mContext) {
override fun toggle() {
@@ -397,6 +395,7 @@ open class DrawerFragment : Fragment() {
mWriteSystemSettingsItem,
mWriteSecuritySettingsItem,
mProjectMediaAccessItem,
mShizukuAccessItem,
DrawerMenuGroup(R.string.text_appearance),
mAutoNightModeItem,
mNightModeItem,
@@ -432,6 +431,7 @@ open class DrawerFragment : Fragment() {
mWriteSystemSettingsItem,
mWriteSecuritySettingsItem,
mProjectMediaAccessItem,
mShizukuAccessItem,
mKeepScreenOnWhenInForegroundItem,
).forEach { it.sync() }
@@ -446,8 +446,6 @@ open class DrawerFragment : Fragment() {
companion object {
private val TAG = DrawerFragment::class.java.simpleName
lateinit var drawerMenuAdapter: DrawerMenuAdapter
private set
@@ -458,27 +456,4 @@ open class DrawerFragment : Fragment() {
}
// class BatteryChangedReceiver : BroadcastReceiver() {
//
// override fun onReceive(context: Context, intent: Intent) {
// val action = intent.action ?: return
// when {
// action.matches(Regex("android.intent.action.ACTION_(POWER_CONNECTED|BATTERY_CHANGED)", RegexOption.IGNORE_CASE)) -> {
// Log.d(TAG, "Received broadcast: $action")
//
// // FIXME by SuperMonster003 on Jun 7, 2023.
// // ! Code below doesn't work.
//
// // if (DeviceUtils.isPowerSourceUSB(context)) {
// // Log.d(TAG, "Current power source is USB")
// // drawerMenuAdapter.drawerMenuItems.find { it.title == R.string.text_server_mode }
// // ?.takeUnless { it.isChecked }
// // ?.let { it.subtitle = "true" }
// // }
// }
// }
// }
//
// }
}

View File

@@ -77,7 +77,6 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
private MaterialDialog mProgressDialog;
private String mSource;
private boolean mIsDefaultIcon = true;
private boolean mIsApkTemplateInAssets = false;
@SuppressLint("SetTextI18n")
@Override
@@ -102,9 +101,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
binding.fab.setOnClickListener(v -> buildApk());
binding.selectSource.setOnClickListener(v -> selectSourceFilePath());
binding.selectOutput.setOnClickListener(v -> selectOutputDirPath());
binding.selectTemplate.setOnClickListener(
v -> selectTemplateFilePath()
);
binding.selectTemplate.setOnClickListener(v -> selectTemplateFilePath());
mIcon.setOnClickListener(v -> selectIcon());
setToolbarAsBack(R.string.text_build_apk);
@@ -112,9 +109,8 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
if (mSource != null) {
setupWithSourceFile(new ScriptFile(mSource));
}
mIsApkTemplateInAssets = checkApkTemplateInAssets();
if (mIsApkTemplateInAssets) {
mTemplatePath.setText("file:///android_asset/template.apk");
if (checkApkTemplateInAssets()) {
mTemplatePath.setText(R.string.path_android_asset_template);
}
}
@@ -319,7 +315,11 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
}
private ApkBuilder callApkBuilder(File tmpDir, File outApk, ApkBuilder.AppConfig appConfig) throws Exception {
InputStream templateApk = mTemplatePath.getText() != null ? (mTemplatePath.getText().toString().equals("file:///android_asset/template.apk") ? getAssets().open("template.apk") : new java.io.FileInputStream(mTemplatePath.getText().toString())) : ApkBuilderPluginHelper.openTemplateApk(BuildActivity.this);
InputStream templateApk = mTemplatePath.getText() != null
? mTemplatePath.getText().toString().equals(getString(R.string.path_android_asset_template))
? getAssets().open(TEMPLATE_APK_PATH)
: new java.io.FileInputStream(mTemplatePath.getText().toString())
: ApkBuilderPluginHelper.openTemplateApk(BuildActivity.this);
return new ApkBuilder(templateApk, outApk, tmpDir.getPath())
.setProgressCallback(BuildActivity.this)
.prepare()

View File

@@ -1,36 +1,56 @@
package org.autojs.autojs.util
import android.content.Context
import android.os.Build
import android.util.DisplayMetrics
import android.util.DisplayMetrics.DENSITY_DEFAULT
import android.util.TypedValue
import android.util.TypedValue.COMPLEX_UNIT_DIP
import android.util.TypedValue.COMPLEX_UNIT_SP
import org.autojs.autojs.app.GlobalAppContext
import org.autojs.autojs.runtime.api.ScreenMetrics
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.round
import kotlin.math.roundToInt
@Suppress("unused")
object DisplayUtils {
@JvmStatic
val displayMetrics: DisplayMetrics
get() = ScreenMetrics.resources?.displayMetrics ?: GlobalAppContext.get().resources.displayMetrics
/**
* This method converts dp unit to equivalent pixels, depending on device density.
*
* @param ctx Context to get resources and device specific display metrics
* @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
* @return A float value to represent px equivalent to dp depending on device density
*/
@JvmStatic
fun dpToPx(ctx: Context, dp: Float) = dp * (ctx.resources.displayMetrics.densityDpi.toFloat() / DENSITY_DEFAULT)
fun dpToPx(dp: Float) = TypedValue.applyDimension(COMPLEX_UNIT_DIP, dp, displayMetrics)
/**
* This method converts device specific pixels to density independent pixels.
*
* @param ctx Context to get resources and device specific display metrics
* @param px A value in px (pixels) unit. Which we need to convert into db
* @return A float value to represent dp equivalent to px value
*/
@JvmStatic
fun pxToDp(ctx: Context, px: Float) = px / (ctx.resources.displayMetrics.densityDpi.toFloat() / DENSITY_DEFAULT)
fun pxToDp(px: Float): Float {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
return TypedValue.deriveDimension(COMPLEX_UNIT_DIP, px, displayMetrics)
}
return px / (displayMetrics.densityDpi.toFloat() / DENSITY_DEFAULT)
}
@JvmStatic
fun pxToSp(ctx: Context, px: Float) = px / ctx.resources.displayMetrics.scaledDensity
fun pxToSp(px: Float): Float {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
return TypedValue.deriveDimension(COMPLEX_UNIT_SP, px, displayMetrics)
}
@Suppress("DEPRECATION")
return px / displayMetrics.scaledDensity
}
@JvmOverloads
@JvmStatic