6.1.1 - 新增应用更新功能 修复编辑器页面/安卓10存储权限 异常消息资源化
This commit is contained in:
@@ -1,30 +1,5 @@
|
||||
package com.stardust.autojs.core.accessibility;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.autojs.BuildConfig;
|
||||
import com.stardust.autojs.annotation.ScriptInterface;
|
||||
import com.stardust.autojs.rhino.continuation.Continuation;
|
||||
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||
import com.stardust.automator.ActionArgument;
|
||||
import com.stardust.automator.UiGlobalSelector;
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.automator.UiObjectCollection;
|
||||
import com.stardust.automator.filter.Filter;
|
||||
import com.stardust.concurrent.VolatileBox;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
|
||||
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT;
|
||||
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE;
|
||||
@@ -57,6 +32,31 @@ import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.Acces
|
||||
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS;
|
||||
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.BuildConfig;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.annotation.ScriptInterface;
|
||||
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||
import com.stardust.automator.ActionArgument;
|
||||
import com.stardust.automator.UiGlobalSelector;
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.automator.UiObjectCollection;
|
||||
import com.stardust.automator.filter.Filter;
|
||||
import com.stardust.concurrent.VolatileBox;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
@@ -168,8 +168,7 @@ public class UiSelector extends UiGlobalSelector {
|
||||
@NonNull
|
||||
public UiObjectCollection untilFind() {
|
||||
if (isUiThread()) {
|
||||
// TODO: 2018/11/1 配置字符串
|
||||
throw new IllegalThreadStateException("不能在ui线程执行阻塞操作, 请在子线程或子脚本执行untilFind()");
|
||||
throw new IllegalThreadStateException(GlobalAppContext.getString(R.string.error_function_called_in_ui_thread, "untilFind"));
|
||||
}
|
||||
UiObjectCollection uiObjectCollection = find();
|
||||
while (uiObjectCollection.empty()) {
|
||||
@@ -189,8 +188,7 @@ public class UiSelector extends UiGlobalSelector {
|
||||
@ScriptInterface
|
||||
public UiObject findOne(long timeout) {
|
||||
if (isUiThread()) {
|
||||
// TODO: 2018/11/1 配置字符串
|
||||
throw new IllegalThreadStateException("不能在ui线程执行阻塞操作, 请在子线程或子脚本执行findOne()");
|
||||
throw new IllegalThreadStateException(GlobalAppContext.getString(R.string.error_function_called_in_ui_thread, "findOne"));
|
||||
}
|
||||
UiObjectCollection uiObjectCollection = find(1);
|
||||
long start = SystemClock.uptimeMillis();
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.stardust.autojs.core.console;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.util.UiHandler;
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
@@ -49,7 +51,7 @@ public class GlobalConsole extends ConsoleImpl {
|
||||
case android.util.Log.ASSERT:
|
||||
return Level.FATAL;
|
||||
}
|
||||
throw new IllegalArgumentException("invalid level = " + level);
|
||||
throw new IllegalArgumentException(GlobalAppContext.getString(R.string.error_illegal_argument, "level", level));
|
||||
}
|
||||
|
||||
private String getLevelChar(int level) {
|
||||
|
||||
@@ -2,6 +2,9 @@ package com.stardust.autojs.core.database;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
|
||||
public class CursorHelper {
|
||||
|
||||
|
||||
@@ -12,7 +15,8 @@ public class CursorHelper {
|
||||
case Cursor.FIELD_TYPE_INTEGER -> cursor.getInt(column);
|
||||
case Cursor.FIELD_TYPE_NULL -> null;
|
||||
case Cursor.FIELD_TYPE_BLOB -> cursor.getBlob(column);
|
||||
default -> throw new IllegalArgumentException("unknown type");
|
||||
default -> throw new IllegalArgumentException(GlobalAppContext
|
||||
.getString(R.string.error_illegal_argument, "column", column));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.stardust.autojs.core.eventloop;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.looper.Timer;
|
||||
import com.stardust.autojs.runtime.ScriptBridges;
|
||||
import com.stardust.autojs.runtime.exception.ScriptException;
|
||||
@@ -40,7 +42,8 @@ public class EventEmitter {
|
||||
|
||||
private void ensureListenersNotAtLimit() {
|
||||
if (mMaxListeners != 0 && mListenerWrappers.size() >= mMaxListeners) {
|
||||
throw new ScriptException(new TooManyListenersException("max = " + mMaxListeners));
|
||||
throw new ScriptException(new TooManyListenersException(GlobalAppContext
|
||||
.getString(R.string.error_max_listeners_exceeded, mMaxListeners)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import android.media.Image;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.opencv.Mat;
|
||||
import com.stardust.autojs.core.opencv.OpenCVHelper;
|
||||
import com.stardust.pio.UncheckedIOException;
|
||||
@@ -85,7 +87,7 @@ public class ImageWrapper implements Recyclable {
|
||||
mHeight = bitmap.getHeight();
|
||||
} else {
|
||||
if (mat == null) {
|
||||
throw new Error("Both bitmap and mat are null");
|
||||
throw new Error(GlobalAppContext.getString(R.string.error_both_bitmap_and_mat_are_null));
|
||||
}
|
||||
mWidth = mat.cols();
|
||||
mHeight = mat.rows();
|
||||
@@ -204,7 +206,7 @@ public class ImageWrapper implements Recyclable {
|
||||
|
||||
public void ensureNotRecycled() {
|
||||
if (isRecycled()) {
|
||||
throw new IllegalStateException("Image has been recycled");
|
||||
throw new IllegalStateException(GlobalAppContext.getString(R.string.error_image_has_been_recycled));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.record.inputevent.EventFormatException;
|
||||
import com.stardust.autojs.core.util.Shell;
|
||||
|
||||
@@ -91,7 +92,9 @@ public class InputEventObserver {
|
||||
|
||||
public void observe() {
|
||||
if (mShell != null)
|
||||
throw new IllegalStateException("observe() should be called only once");
|
||||
throw new IllegalStateException(mContext
|
||||
.getString(R.string.error_function_called_more_than_once,
|
||||
"InputEventObserver.observe"));
|
||||
mShell = new Shell(mContext, true);
|
||||
mShell.setCallback(new Shell.SimpleCallback() {
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.stardust.autojs.core.internal;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/7/19.
|
||||
*/
|
||||
@@ -18,7 +21,8 @@ public class Functions {
|
||||
} else if (func instanceof Func4) {
|
||||
return ((Func4) func).call(args[0], args[1], args[2], args[3]);
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown func: " + func);
|
||||
throw new IllegalArgumentException(GlobalAppContext
|
||||
.getString(R.string.error_illegal_argument, "func", func));
|
||||
}
|
||||
|
||||
public interface Func {
|
||||
|
||||
@@ -5,6 +5,8 @@ import android.os.Looper;
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.engine.RhinoJavaScriptEngine;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||
@@ -88,7 +90,7 @@ public class TimerThread extends ThreadCompat {
|
||||
|
||||
public Timer getTimer() {
|
||||
if (mTimer == null) {
|
||||
throw new IllegalStateException("thread is not alive");
|
||||
throw new IllegalStateException(GlobalAppContext.getString(R.string.error_thread_is_not_alive));
|
||||
}
|
||||
return mTimer;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
@@ -39,6 +40,7 @@ import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.internal.MDButton;
|
||||
import com.stardust.app.DialogUtils;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.eventloop.EventEmitter;
|
||||
import com.stardust.util.UiHandler;
|
||||
|
||||
@@ -78,7 +80,7 @@ public class JsDialog {
|
||||
Context context = mDialog.getContext();
|
||||
if (!DialogUtils.isActivityContext(context)) {
|
||||
Window window = mDialog.getWindow();
|
||||
if (window != null){
|
||||
if (window != null) {
|
||||
int type;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
@@ -95,7 +97,8 @@ public class JsDialog {
|
||||
case "positive" -> DialogAction.POSITIVE;
|
||||
case "negative" -> DialogAction.NEGATIVE;
|
||||
case "neutral" -> DialogAction.NEUTRAL;
|
||||
default -> throw new IllegalArgumentException("unknown action " + action);
|
||||
default -> throw new IllegalArgumentException(getContext()
|
||||
.getString(R.string.error_illegal_argument, "action", action));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ public class DynamicLayoutInflater {
|
||||
} else if (attr.length == 2) {
|
||||
applyAttribute(context, setter, view, attr[0], attr[1], entry.getValue(), parent, attrs);
|
||||
} else {
|
||||
throw new InflateException("illegal attr name: " + entry.getKey());
|
||||
throw new InflateException("Illegal attr name: " + entry.getKey());
|
||||
}
|
||||
}
|
||||
setter.applyPendingAttributes(view, parent);
|
||||
|
||||
@@ -4,6 +4,8 @@ import android.view.InflateException;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.ui.inflater.ResourceParser;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Colors;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Dimensions;
|
||||
@@ -44,7 +46,7 @@ public class ImageViewInflater<V extends ImageView> extends BaseViewInflater<V>
|
||||
view.setMaxWidth(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "path":
|
||||
getDrawables().setupWithImage(view, wrapAsPath(value));
|
||||
getDrawables().setupWithImage(view, wrapAsPath(value));
|
||||
break;
|
||||
case "scaleType":
|
||||
view.setScaleType(parseScaleType(value));
|
||||
@@ -59,13 +61,14 @@ public class ImageViewInflater<V extends ImageView> extends BaseViewInflater<V>
|
||||
view.setImageTintMode(TINT_MODES.get(value));
|
||||
break;
|
||||
case "url":
|
||||
getDrawables().setupWithImage(view, wrapAsUrl(value));
|
||||
getDrawables().setupWithImage(view, wrapAsUrl(value));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String wrapAsPath(String value) {
|
||||
if (!value.startsWith("file://")) {
|
||||
return "file://" + value;
|
||||
@@ -80,8 +83,8 @@ public class ImageViewInflater<V extends ImageView> extends BaseViewInflater<V>
|
||||
return value;
|
||||
}
|
||||
|
||||
private ImageView.ScaleType parseScaleType(String value) {
|
||||
switch (value.toLowerCase()) {
|
||||
private ImageView.ScaleType parseScaleType(String scaleType) {
|
||||
switch (scaleType.toLowerCase()) {
|
||||
case "center":
|
||||
return ImageView.ScaleType.CENTER;
|
||||
case "center_crop":
|
||||
@@ -99,6 +102,7 @@ public class ImageViewInflater<V extends ImageView> extends BaseViewInflater<V>
|
||||
case "matrix":
|
||||
return ImageView.ScaleType.MATRIX;
|
||||
}
|
||||
throw new InflateException("unknown scale type: " + value);
|
||||
throw new InflateException(GlobalAppContext
|
||||
.getString(R.string.error_illegal_argument, "scaleType", scaleType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import android.view.InflateException;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.stardust.autojs.R;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -56,7 +58,7 @@ public class Dimensions {
|
||||
}
|
||||
Matcher m = DIMENSION_PATTERN.matcher(dimension);
|
||||
if (!m.matches()) {
|
||||
throw new InflateException("dimension cannot be resolved: " + dimension);
|
||||
throw new InflateException(context.getString(R.string.error_illegal_argument, "dimension", dimension));
|
||||
}
|
||||
int unit = m.groupCount() == 2 ? UNITS.get(m.group(2), TypedValue.COMPLEX_UNIT_DIP) : TypedValue.COMPLEX_UNIT_DIP;
|
||||
float value = Integer.parseInt(m.group(1));
|
||||
|
||||
@@ -44,7 +44,7 @@ public class ValueMapper<V> {
|
||||
public V get(String key) {
|
||||
V v = mHashMap.get(key);
|
||||
if (v == null) {
|
||||
throw new InflateException(String.format("unknown value for %s: %s", mAttrName, key));
|
||||
throw new InflateException(String.format("Unknown value for %s: %s", mAttrName, key));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.stardust.autojs.core.ui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
|
||||
import com.google.android.material.snackbar.BaseTransientBottomBar;
|
||||
import com.stardust.autojs.R;
|
||||
|
||||
/**
|
||||
* Created by SuperMonster003 on May 30, 2022.
|
||||
*/
|
||||
|
||||
public class CustomSnackbar extends BaseTransientBottomBar<CustomSnackbar> {
|
||||
|
||||
private final View mContent;
|
||||
|
||||
protected CustomSnackbar(@NonNull Context context, @NonNull ViewGroup parent, @NonNull View content, @NonNull com.google.android.material.snackbar.ContentViewCallback contentViewCallback) {
|
||||
super(context, parent, content, contentViewCallback);
|
||||
mContent = content;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static CustomSnackbar make(@NonNull View view, @NonNull CharSequence text, @Duration int duration) {
|
||||
return makeInternal(/* context= */ null, view, text, duration);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static CustomSnackbar makeInternal(@Nullable Context context, @NonNull View view, @NonNull CharSequence text, @Duration int duration) {
|
||||
final ViewGroup parent = findSuitableParent(view);
|
||||
if (parent == null) {
|
||||
throw new IllegalArgumentException("No suitable parent found from the given view. Please provide a valid view.");
|
||||
}
|
||||
|
||||
if (context == null) {
|
||||
context = parent.getContext();
|
||||
}
|
||||
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
final CustomSnackbarContentLayout content = (CustomSnackbarContentLayout) inflater.inflate(R.layout.snackbar_custom, parent, false);
|
||||
final CustomSnackbar snackbar = new CustomSnackbar(context, parent, content, content);
|
||||
|
||||
snackbar.setText(text);
|
||||
snackbar.setDuration(duration);
|
||||
|
||||
return snackbar;
|
||||
}
|
||||
|
||||
// @Copied by SuperMonster003 on May 30, 2022.
|
||||
// ! From: com.stardust.autojs.core.ui.widget.CustomSnackbar.findSuitableParent
|
||||
@Nullable
|
||||
private static ViewGroup findSuitableParent(View view) {
|
||||
ViewGroup fallback = null;
|
||||
do {
|
||||
if (view instanceof CoordinatorLayout) {
|
||||
// We've found a CoordinatorLayout, use it
|
||||
return (ViewGroup) view;
|
||||
} else if (view instanceof FrameLayout) {
|
||||
if (view.getId() == android.R.id.content) {
|
||||
// If we've hit the decor content view, then we didn't find a CoL in the
|
||||
// hierarchy, so use it.
|
||||
return (ViewGroup) view;
|
||||
} else {
|
||||
// It's not the content view but we'll use it as our fallback
|
||||
fallback = (ViewGroup) view;
|
||||
}
|
||||
}
|
||||
|
||||
if (view != null) {
|
||||
// Else, we will loop and crawl up the view hierarchy and try to find a parent
|
||||
final ViewParent parent = view.getParent();
|
||||
view = parent instanceof View ? (View) parent : null;
|
||||
}
|
||||
} while (view != null);
|
||||
|
||||
// If we reach here then we didn't find a CoL or a suitable content view so we'll fallback
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public CustomSnackbar setText(@NonNull CharSequence message) {
|
||||
((CustomSnackbarContentLayout) mContent).getCustomTextView().setText(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CustomSnackbar setActionOne(@StringRes int resId, View.OnClickListener listener) {
|
||||
return setActionOne(getContext().getText(resId), listener);
|
||||
}
|
||||
|
||||
public CustomSnackbar setActionTwo(@StringRes int resId, View.OnClickListener listener) {
|
||||
return setActionTwo(getContext().getText(resId), listener);
|
||||
}
|
||||
|
||||
public CustomSnackbar setActionOne(@Nullable CharSequence text, @Nullable final View.OnClickListener listener) {
|
||||
return setAction(text, listener, ((CustomSnackbarContentLayout) mContent).getActionOneView());
|
||||
}
|
||||
|
||||
public CustomSnackbar setActionTwo(@Nullable CharSequence text, @Nullable final View.OnClickListener listener) {
|
||||
return setAction(text, listener, ((CustomSnackbarContentLayout) mContent).getActionTwoView());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public CustomSnackbar setAction(@StringRes int resId, View.OnClickListener listener, Button view) {
|
||||
return setAction(getContext().getText(resId), listener, view);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public CustomSnackbar setAction(@Nullable CharSequence text, @Nullable final View.OnClickListener listener, Button view) {
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
view.setVisibility(View.GONE);
|
||||
} else {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
view.setText(text);
|
||||
}
|
||||
view.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onClick(v);
|
||||
}
|
||||
// Now dismiss the Snackbar
|
||||
dispatchDismiss(BaseCallback.DISMISS_EVENT_ACTION);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.stardust.autojs.core.ui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.material.snackbar.ContentViewCallback;
|
||||
import com.stardust.autojs.R;
|
||||
|
||||
/**
|
||||
* Created by SuperMonster003 on May 30, 2022.
|
||||
*/
|
||||
|
||||
public class CustomSnackbarContentLayout extends LinearLayout implements ContentViewCallback {
|
||||
|
||||
public CustomSnackbarContentLayout(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public CustomSnackbarContentLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public Button getActionOneView() {
|
||||
return findViewById(R.id.snackbar_action_one);
|
||||
}
|
||||
|
||||
public Button getActionTwoView() {
|
||||
return findViewById(R.id.snackbar_action_two);
|
||||
}
|
||||
|
||||
public TextView getCustomTextView() {
|
||||
return findViewById(R.id.snackbar_text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateContentIn(int delay, int duration) {
|
||||
TextView mTextView = getCustomTextView();
|
||||
Button mActionOneView = getActionOneView();
|
||||
Button mActionTwoView = getActionTwoView();
|
||||
|
||||
mTextView.setAlpha(0f);
|
||||
mTextView.animate().alpha(1f).setDuration(duration).setStartDelay(delay).start();
|
||||
|
||||
if (mActionOneView.getVisibility() == VISIBLE) {
|
||||
mActionOneView.setAlpha(0f);
|
||||
mActionOneView.animate().alpha(1f).setDuration(duration).setStartDelay(delay).start();
|
||||
}
|
||||
|
||||
if (mActionTwoView.getVisibility() == VISIBLE) {
|
||||
mActionTwoView.setAlpha(0f);
|
||||
mActionTwoView.animate().alpha(1f).setDuration(duration).setStartDelay(delay).start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateContentOut(int delay, int duration) {
|
||||
TextView mTextView = getCustomTextView();
|
||||
Button mActionOneView = getActionOneView();
|
||||
Button mActionTwoView = getActionTwoView();
|
||||
|
||||
mTextView.setAlpha(1f);
|
||||
mTextView.animate().alpha(0f).setDuration(duration).setStartDelay(delay).start();
|
||||
|
||||
if (mActionOneView.getVisibility() == VISIBLE) {
|
||||
mActionOneView.setAlpha(1f);
|
||||
mActionOneView.animate().alpha(0f).setDuration(duration).setStartDelay(delay).start();
|
||||
}
|
||||
|
||||
if (mActionTwoView.getVisibility() == VISIBLE) {
|
||||
mActionTwoView.setAlpha(1f);
|
||||
mActionTwoView.animate().alpha(0f).setDuration(duration).setStartDelay(delay).start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package com.stardust.autojs.core.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.runtime.api.AbstractShell;
|
||||
import com.stardust.autojs.util.ProcessUtils;
|
||||
import com.stardust.pio.UncheckedIOException;
|
||||
@@ -178,7 +180,7 @@ public class ProcessShell extends AbstractShell {
|
||||
public static Result execCommand(String[] commands, boolean isRoot) {
|
||||
Result commandResult = new Result();
|
||||
if (commands == null || commands.length == 0)
|
||||
throw new IllegalArgumentException("command is empty");
|
||||
throw new IllegalArgumentException(GlobalAppContext.getString(R.string.error_empty_shell_command));
|
||||
Process process = null;
|
||||
DataOutputStream os = null;
|
||||
try {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.stardust.autojs.engine;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.script.JavaScriptSource;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
@@ -29,7 +31,7 @@ public abstract class JavaScriptEngine extends ScriptEngine.AbstractScriptEngine
|
||||
|
||||
public void setRuntime(ScriptRuntime runtime) {
|
||||
if (mRuntime != null) {
|
||||
throw new IllegalStateException("a runtime has been set");
|
||||
throw new IllegalStateException(GlobalAppContext.getString(R.string.error_a_runtime_has_been_set));
|
||||
}
|
||||
mRuntime = runtime;
|
||||
mRuntime.engines.setCurrentEngine(this);
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.stardust.autojs.engine;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.execution.ScriptExecution;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
@@ -105,8 +107,10 @@ public interface ScriptEngine<S extends ScriptSource> {
|
||||
}
|
||||
|
||||
public void setOnDestroyListener(OnDestroyListener onDestroyListener) {
|
||||
if (mOnDestroyListener != null)
|
||||
throw new SecurityException("setOnDestroyListener can be called only once");
|
||||
if (mOnDestroyListener != null) {
|
||||
throw new SecurityException(GlobalAppContext.getString(R.string.error_function_called_more_than_once,
|
||||
"AbstractScriptEngine.setOnDestroyListener"));
|
||||
}
|
||||
mOnDestroyListener = onDestroyListener;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.stardust.autojs.engine;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
import com.stardust.util.Supplier;
|
||||
|
||||
@@ -64,16 +66,18 @@ public class ScriptEngineFactory {
|
||||
@NonNull
|
||||
public ScriptEngine createEngineByNameOrThrow(String name) {
|
||||
ScriptEngine engine = createEngine(name);
|
||||
if (engine == null)
|
||||
throw new EngineNotFoundException("name: " + name);
|
||||
if (engine == null) {
|
||||
throw new EngineNotFoundException(GlobalAppContext.getString(R.string.error_illegal_argument, "name", name));
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ScriptEngine createEngineOfSourceOrThrow(ScriptSource source) {
|
||||
ScriptEngine engine = createEngineOfSource(source);
|
||||
if (engine == null)
|
||||
throw new EngineNotFoundException("source: " + source);
|
||||
if (engine == null) {
|
||||
throw new EngineNotFoundException(GlobalAppContext.getString(R.string.error_illegal_argument, "source", source));
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.stardust.autojs.rhino;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.dx.command.dexer.Main;
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.pio.PFiles;
|
||||
import com.stardust.util.MD5;
|
||||
|
||||
@@ -94,7 +96,7 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa
|
||||
public void loadJar(File jar) throws IOException {
|
||||
Log.d(LOG_TAG, "loadJar: jar = " + jar);
|
||||
if (!jar.exists() || !jar.canRead()) {
|
||||
throw new FileNotFoundException("File does not exist or readable: " + jar.getPath());
|
||||
throw new FileNotFoundException(GlobalAppContext.getString(R.string.file_not_exist_or_readable, jar.getPath()));
|
||||
}
|
||||
File dexFile = new File(mCacheDir, generateDexFileName(jar));
|
||||
if (dexFile.exists()) {
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ScriptBridges {
|
||||
|
||||
private void checkBridges() {
|
||||
if (mBridges == null)
|
||||
throw new IllegalStateException("no bridges set");
|
||||
throw new IllegalStateException("No bridges have been set");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -227,8 +227,9 @@ public class ScriptRuntime {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
if (loopers != null)
|
||||
throw new IllegalStateException("already initialized");
|
||||
if (loopers != null) {
|
||||
throw new IllegalStateException("Already initialized");
|
||||
}
|
||||
threads = new Threads(this);
|
||||
timers = new Timers(this);
|
||||
loopers = new Loopers(this);
|
||||
@@ -243,7 +244,7 @@ public class ScriptRuntime {
|
||||
|
||||
public void setTopLevelScope(TopLevelScope topLevelScope) {
|
||||
if (mTopLevelScope != null) {
|
||||
throw new IllegalStateException("top level has already exists");
|
||||
throw new IllegalStateException("Top level has already exists");
|
||||
}
|
||||
mTopLevelScope = topLevelScope;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class AccessibilityConfig {
|
||||
|
||||
public void addWhiteList(String packageName) {
|
||||
if (mSealed)
|
||||
throw new IllegalStateException("sealed");
|
||||
throw new IllegalStateException("Sealed");
|
||||
mWhiteList.add(packageName);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@ import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.annotation.ScriptInterface;
|
||||
import com.stardust.util.IntentUtil;
|
||||
|
||||
@@ -110,15 +112,21 @@ public class AppUtils {
|
||||
|
||||
@ScriptInterface
|
||||
public void viewFile(String path) {
|
||||
if (path == null)
|
||||
throw new NullPointerException("path == null");
|
||||
if (path == null) {
|
||||
throw new NullPointerException(mContext
|
||||
.getString(R.string.error_method_called_with_null_argument,
|
||||
"AppUtils.viewFile", "path"));
|
||||
}
|
||||
IntentUtil.viewFile(mContext, path, mFileProviderAuthority);
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public void editFile(String path) {
|
||||
if (path == null)
|
||||
throw new NullPointerException("path == null");
|
||||
if (path == null) {
|
||||
throw new NullPointerException(mContext
|
||||
.getString(R.string.error_method_called_with_null_argument,
|
||||
"AppUtils.editFile", "path"));
|
||||
}
|
||||
IntentUtil.editFile(mContext, path, mFileProviderAuthority);
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ public class Device {
|
||||
public boolean isCharging() {
|
||||
Intent intent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
if (intent == null) {
|
||||
throw new ScriptException("Cannot retrieve the battery state");
|
||||
throw new ScriptException(mContext.getString(R.string.error_cannot_retrieve_battery_state));
|
||||
}
|
||||
int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
|
||||
return plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB;
|
||||
@@ -310,7 +310,7 @@ public class Device {
|
||||
private <T> T getSystemService(String service) {
|
||||
Object systemService = mContext.getSystemService(service);
|
||||
if (systemService == null) {
|
||||
throw new RuntimeException("should never happen..." + service);
|
||||
throw new RuntimeException("Should never happen... " + service);
|
||||
}
|
||||
return (T) systemService;
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
mScriptRuntime.ensureAccessibilityServiceEnabled();
|
||||
AccessibilityService service = mAccessibilityBridge.getService();
|
||||
if (service == null)
|
||||
throw new ScriptException("AccessibilityService = null");
|
||||
throw new ScriptException(mContext.getString(R.string.error_no_accessibility_service));
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@ import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.annotation.ScriptVariable;
|
||||
import com.stardust.autojs.core.image.ColorFinder;
|
||||
import com.stardust.autojs.core.image.ImageWrapper;
|
||||
@@ -99,7 +103,7 @@ public class Images {
|
||||
|
||||
public synchronized ImageWrapper captureScreen() {
|
||||
if (mScreenCapturer == null) {
|
||||
throw new SecurityException("No screen capture permission");
|
||||
throw new SecurityException(mContext.getString(R.string.error_no_screen_capture_permission));
|
||||
}
|
||||
Image capture = mScreenCapturer.capture();
|
||||
if (capture == mPreCapture && mPreCaptureImage != null) {
|
||||
@@ -123,15 +127,12 @@ public class Images {
|
||||
return false;
|
||||
}
|
||||
|
||||
public ImageWrapper copy(ImageWrapper image) {
|
||||
public ImageWrapper copy(@NonNull ImageWrapper image) {
|
||||
return image.clone();
|
||||
}
|
||||
|
||||
public boolean save(ImageWrapper image, String path, String format, int quality) throws IOException {
|
||||
public boolean save(@NonNull ImageWrapper image, String path, String format, int quality) throws IOException {
|
||||
Bitmap.CompressFormat compressFormat = parseImageFormat(format);
|
||||
if (compressFormat == null) {
|
||||
throw new IllegalArgumentException("unknown format " + format);
|
||||
}
|
||||
Bitmap bitmap = image.getBitmap();
|
||||
FileOutputStream outputStream = new FileOutputStream(mScriptRuntime.files.path(path));
|
||||
return bitmap.compress(compressFormat, quality, outputStream);
|
||||
@@ -139,14 +140,17 @@ public class Images {
|
||||
|
||||
public static int pixel(ImageWrapper image, int x, int y) {
|
||||
if (image == null) {
|
||||
throw new NullPointerException("image = null");
|
||||
throw new NullPointerException(GlobalAppContext
|
||||
.getString(R.string.error_method_called_with_null_argument, "Images.pixel", "image"));
|
||||
}
|
||||
return image.pixel(x, y);
|
||||
}
|
||||
|
||||
public static ImageWrapper concat(ImageWrapper img1, ImageWrapper img2, int direction) {
|
||||
if (!Arrays.asList(Gravity.START, Gravity.END, Gravity.TOP, Gravity.BOTTOM).contains(direction)) {
|
||||
throw new IllegalArgumentException("unknown direction " + direction);
|
||||
throw new IllegalArgumentException(GlobalAppContext
|
||||
.getString(R.string.error_illegal_argument,
|
||||
"direction", direction));
|
||||
}
|
||||
int width;
|
||||
int height;
|
||||
@@ -175,13 +179,13 @@ public class Images {
|
||||
return ImageWrapper.ofBitmap(bitmap);
|
||||
}
|
||||
|
||||
public ImageWrapper rotate(ImageWrapper img, float x, float y, float degree) {
|
||||
public ImageWrapper rotate(@NonNull ImageWrapper img, float x, float y, float degree) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postRotate(degree, x, y);
|
||||
return ImageWrapper.ofBitmap(Bitmap.createBitmap(img.getBitmap(), 0, 0, img.getWidth(), img.getHeight(), matrix, true));
|
||||
}
|
||||
|
||||
public ImageWrapper clip(ImageWrapper img, int x, int y, int w, int h) {
|
||||
public ImageWrapper clip(@NonNull ImageWrapper img, int x, int y, int w, int h) {
|
||||
return ImageWrapper.ofBitmap(Bitmap.createBitmap(img.getBitmap(), x, y, w, h));
|
||||
}
|
||||
|
||||
@@ -199,11 +203,8 @@ public class Images {
|
||||
return Base64.encodeToString(toBytes(wrapper, format, quality), Base64.NO_WRAP);
|
||||
}
|
||||
|
||||
public byte[] toBytes(ImageWrapper wrapper, String format, int quality) {
|
||||
public byte[] toBytes(@NonNull ImageWrapper wrapper, String format, int quality) {
|
||||
Bitmap.CompressFormat compressFormat = parseImageFormat(format);
|
||||
if (compressFormat == null) {
|
||||
throw new IllegalArgumentException("Unknown format " + format);
|
||||
}
|
||||
Bitmap bitmap = wrapper.getBitmap();
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
bitmap.compress(compressFormat, quality, outputStream);
|
||||
@@ -219,7 +220,8 @@ public class Images {
|
||||
case "png" -> Bitmap.CompressFormat.PNG;
|
||||
case "jpeg", "jpg" -> Bitmap.CompressFormat.JPEG;
|
||||
case "webp" -> Bitmap.CompressFormat.WEBP;
|
||||
default -> null;
|
||||
default -> throw new IllegalArgumentException(GlobalAppContext
|
||||
.getString(R.string.error_illegal_argument, "format", format));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -237,7 +239,7 @@ public class Images {
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveBitmap(Bitmap bitmap, String path) {
|
||||
public static void saveBitmap(@NonNull Bitmap bitmap, String path) {
|
||||
try {
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(path));
|
||||
} catch (FileNotFoundException e) {
|
||||
@@ -279,10 +281,14 @@ public class Images {
|
||||
public Point findImage(ImageWrapper image, ImageWrapper template, float weakThreshold, float threshold, Rect rect, int maxLevel) {
|
||||
initOpenCvIfNeeded();
|
||||
if (image == null) {
|
||||
throw new NullPointerException("Param image is null");
|
||||
throw new NullPointerException(GlobalAppContext
|
||||
.getString(R.string.error_method_called_with_null_argument,
|
||||
"Images.findImage", "image"));
|
||||
}
|
||||
if (template == null) {
|
||||
throw new NullPointerException("Param template is null");
|
||||
throw new NullPointerException(GlobalAppContext
|
||||
.getString(R.string.error_method_called_with_null_argument,
|
||||
"Images.findImage", "template"));
|
||||
}
|
||||
Mat src = image.getMat();
|
||||
if (rect != null) {
|
||||
@@ -307,10 +313,14 @@ public class Images {
|
||||
public List<TemplateMatching.Match> matchTemplate(ImageWrapper image, ImageWrapper template, float weakThreshold, float threshold, Rect rect, int maxLevel, int limit) {
|
||||
initOpenCvIfNeeded();
|
||||
if (image == null) {
|
||||
throw new NullPointerException("Param image is null");
|
||||
throw new NullPointerException(GlobalAppContext
|
||||
.getString(R.string.error_method_called_with_null_argument,
|
||||
"Images.matchTemplate", "image"));
|
||||
}
|
||||
if (template == null) {
|
||||
throw new NullPointerException("Param template is null");
|
||||
throw new NullPointerException(GlobalAppContext
|
||||
.getString(R.string.error_method_called_with_null_argument,
|
||||
"Images.matchTemplate", "template"));
|
||||
}
|
||||
Mat src = image.getMat();
|
||||
if (rect != null) {
|
||||
|
||||
@@ -8,6 +8,8 @@ import android.hardware.SensorManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.eventloop.EventEmitter;
|
||||
import com.stardust.autojs.core.looper.Loopers;
|
||||
import com.stardust.autojs.runtime.ScriptBridges;
|
||||
@@ -98,7 +100,9 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler {
|
||||
|
||||
public SensorEventEmitter register(String sensorName, int delay) {
|
||||
if (sensorName == null) {
|
||||
throw new NullPointerException("sensorName = null");
|
||||
throw new NullPointerException(GlobalAppContext
|
||||
.getString(R.string.error_method_called_with_null_argument,
|
||||
"Sensors.register", "sensorName"));
|
||||
}
|
||||
Sensor sensor = getSensor(sensorName);
|
||||
if (sensor == null) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.stardust.autojs.runtime.api;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.looper.MainThreadProxy;
|
||||
import com.stardust.autojs.core.looper.TimerThread;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
@@ -45,7 +47,7 @@ public class Threads {
|
||||
TimerThread thread = createThread(runnable);
|
||||
synchronized (mThreads) {
|
||||
if (mExit) {
|
||||
throw new IllegalStateException("Script is on exiting");
|
||||
throw new IllegalStateException(GlobalAppContext.getString(R.string.error_script_is_on_exiting));
|
||||
}
|
||||
mThreads.add(thread);
|
||||
thread.setName(mMainThread.getName() + " (Spawn-" + mSpawnCount + ")");
|
||||
|
||||
@@ -56,7 +56,9 @@ public class RootTool {
|
||||
if (key.equals(AUTO_DETECT.key)) {
|
||||
return AUTO_DETECT;
|
||||
}
|
||||
throw new Error("Unknown RootMode number");
|
||||
throw new IllegalArgumentException(GlobalAppContext
|
||||
.getString(R.string.error_illegal_argument,
|
||||
"RootMode", key));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
48
autojs/src/main/res/layout/snackbar_custom.xml
Normal file
48
autojs/src/main/res/layout/snackbar_custom.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<view xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
class="com.stardust.autojs.core.ui.widget.CustomSnackbarContentLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:theme="@style/Theme.Holo">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/snackbar_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:paddingTop="@dimen/snackbar_padding_vertical"
|
||||
android:paddingBottom="@dimen/snackbar_padding_vertical"
|
||||
android:paddingLeft="@dimen/snackbar_padding_horizontal"
|
||||
android:paddingRight="@dimen/snackbar_padding_horizontal"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="@integer/snackbar_text_max_lines"
|
||||
android:textSize="@dimen/snackbar_text_size"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/snackbar_action_two"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:textSize="@dimen/snackbar_text_size"
|
||||
android:textAllCaps="false"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/snackbar_extra_spacing_horizontal"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:minWidth="@dimen/snackbar_min_width"
|
||||
android:textColor="@color/colorAccent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/snackbar_action_one"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:textSize="@dimen/snackbar_text_size"
|
||||
android:textAllCaps="false"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/snackbar_extra_spacing_horizontal"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:minWidth="@dimen/snackbar_min_width"
|
||||
android:textColor="@color/colorAccent"/>
|
||||
</view>
|
||||
@@ -36,4 +36,20 @@
|
||||
<string name="text_start_running">Running</string>
|
||||
<string name="text_root_mode_description">If you have exotic root or abnormal state for root access, you can force set root to root or non-root.</string>
|
||||
<string name="text_hidden_files_description">Whether the hidden files and folders show or not in file explorer. A file or folder is considered to be hidden if its name begins with a period character (\".\").</string>
|
||||
<string name="text_updates_snack_bar_act_view">View</string>
|
||||
<string name="text_updates_snack_bar_act_later">Later</string>
|
||||
<string name="error_function_called_in_ui_thread">UI thread can\'t be blocked. Try running %s() in sub-thread or sub-script</string>
|
||||
<string name="error_max_listeners_exceeded">Max listeners exceeded: %d</string>
|
||||
<string name="error_both_bitmap_and_mat_are_null">Both bitmap and mat are null</string>
|
||||
<string name="error_image_has_been_recycled">Image has been recycled</string>
|
||||
<string name="error_function_called_more_than_once">%s() called more than once</string>
|
||||
<string name="error_thread_is_not_alive">Thread is not alive</string>
|
||||
<string name="error_empty_shell_command">Command is empty</string>
|
||||
<string name="error_a_runtime_has_been_set">A runtime has been set</string>
|
||||
<string name="file_not_exist_or_readable">File doesn\'t exist or readable: %s</string>
|
||||
<string name="error_cannot_retrieve_battery_state">Can\'t retrieve the battery state</string>
|
||||
<string name="error_no_screen_capture_permission">No screen capture permission</string>
|
||||
<string name="error_no_accessibility_service">No accessibility service</string>
|
||||
<string name="error_method_called_with_null_argument">%s() called with null argument: %s</string>
|
||||
<string name="error_script_is_on_exiting">Script is on exiting</string>
|
||||
</resources>
|
||||
|
||||
@@ -37,4 +37,20 @@
|
||||
<string name="entry_hidden_files_show">显示隐藏文件和文件夹</string>
|
||||
<string name="text_root_mode_description">如果设备使用非常规 Root 方式或 Root 权限检测异常, 可设置强制 Root 或 强制非 Root 模式.</string>
|
||||
<string name="text_hidden_files_description">设置是否在文件浏览器页面显示隐藏文件和文件夹 (文件名以 \".\" 开头)</string>
|
||||
<string name="text_updates_snack_bar_act_view">查看更新</string>
|
||||
<string name="text_updates_snack_bar_act_later">稍后提示</string>
|
||||
<string name="error_function_called_in_ui_thread">UI 线程内无法执行阻塞操作. 可尝试在子线程或子脚本中执行 %s()</string>
|
||||
<string name="error_max_listeners_exceeded">超出最大监听器数量限制: %d</string>
|
||||
<string name="error_both_bitmap_and_mat_are_null">Bitmap 与 Mat 不能同时为 null</string>
|
||||
<string name="error_image_has_been_recycled">图像资源已被回收</string>
|
||||
<string name="error_function_called_more_than_once">%s() 调用不能超过一次</string>
|
||||
<string name="error_thread_is_not_alive">线程处于非活动状态</string>
|
||||
<string name="error_empty_shell_command">命令为空</string>
|
||||
<string name="error_a_runtime_has_been_set">运行时已存在</string>
|
||||
<string name="file_not_exist_or_readable">文件不存在或不可读: %s</string>
|
||||
<string name="error_cannot_retrieve_battery_state">无法获取设备电池状态</string>
|
||||
<string name="error_no_screen_capture_permission">缺少屏幕捕获权限</string>
|
||||
<string name="error_no_accessibility_service">没有无障碍服务</string>
|
||||
<string name="error_method_called_with_null_argument">%s() 传入的 %s 参数为空</string>
|
||||
<string name="error_script_is_on_exiting">脚本正在退出中</string>
|
||||
</resources>
|
||||
@@ -1,4 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="floaty_window_offset">12dp</dimen>
|
||||
<dimen name="snackbar_padding_vertical">14dp</dimen>
|
||||
<dimen name="snackbar_padding_horizontal">12dp</dimen>
|
||||
<integer name="snackbar_text_max_lines">2</integer>
|
||||
<dimen name="snackbar_extra_spacing_horizontal">0dp</dimen>
|
||||
<dimen name="snackbar_min_width">48dp</dimen>
|
||||
<dimen name="snackbar_text_size">14sp</dimen>
|
||||
</resources>
|
||||
@@ -56,4 +56,20 @@
|
||||
<string name="key_gesture_observing" translatable="false">key_gesture_observing</string>
|
||||
<string name="text_root_mode_description">If you have exotic root or abnormal state for root access, you can force set root to root or non-root.</string>
|
||||
<string name="text_hidden_files_description">Whether the hidden files and folders show or not in file explorer. A file or folder is considered to be hidden if its name begins with a period character (\".\").</string>
|
||||
<string name="text_updates_snack_bar_act_view">View</string>
|
||||
<string name="text_updates_snack_bar_act_later">Later</string>
|
||||
<string name="error_function_called_in_ui_thread">UI thread can\'t be blocked. Try running %s() in sub-thread or sub-script</string>
|
||||
<string name="error_max_listeners_exceeded">Max listeners exceeded: %d</string>
|
||||
<string name="error_both_bitmap_and_mat_are_null">Both bitmap and mat are null</string>
|
||||
<string name="error_image_has_been_recycled">Image has been recycled</string>
|
||||
<string name="error_function_called_more_than_once">%s() called more than once</string>
|
||||
<string name="error_thread_is_not_alive">Thread is not alive</string>
|
||||
<string name="error_empty_shell_command">Command is empty</string>
|
||||
<string name="error_a_runtime_has_been_set">A runtime has been set</string>
|
||||
<string name="file_not_exist_or_readable">File doesn\'t exist or readable: %s</string>
|
||||
<string name="error_cannot_retrieve_battery_state">Can\'t retrieve the battery state</string>
|
||||
<string name="error_no_screen_capture_permission">No screen capture permission</string>
|
||||
<string name="error_no_accessibility_service">No accessibility service</string>
|
||||
<string name="error_method_called_with_null_argument">%s() called with null argument: %s</string>
|
||||
<string name="error_script_is_on_exiting">Script is on exiting</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user