mirror of
https://github.com/TonyJiangWJ/Auto.js.git
synced 2026-06-12 21:01:32 +08:00
修改截图代码,多脚本之间可以共享截图权限。被其他脚本抢占截图权限后可以自动重新获取权限
This commit is contained in:
parent
15319c6fe2
commit
673f27d2d3
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,3 +14,4 @@ build/
|
||||
*.exe
|
||||
.idea/caches/build_file_checksums.ser
|
||||
.idea/
|
||||
*.log
|
||||
|
||||
@ -6,6 +6,9 @@ apply plugin: 'com.jakewharton.butterknife'
|
||||
def AAVersion = '4.8.0'
|
||||
def SupportLibVersion = '28.0.0'
|
||||
def homePath = System.properties['user.home']
|
||||
def storePasswd = System.getenv('autojspasswd')
|
||||
def keyPasswd = System.getenv('autojspasswd')
|
||||
def alias = System.getenv('autojsalias')
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
@ -18,9 +21,9 @@ android {
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file(homePath + '/auto-js-t-pkcs12.jks')
|
||||
storePassword System.getenv('autojspasswd')
|
||||
keyPassword System.getenv('autojspasswd')
|
||||
keyAlias = System.getenv('autojsalias')
|
||||
storePassword storePasswd
|
||||
keyPassword keyPasswd
|
||||
keyAlias = alias
|
||||
}
|
||||
debug {
|
||||
storeFile file('debug/autojs-pkcs12-debug.jks')
|
||||
@ -53,7 +56,7 @@ android {
|
||||
shrinkResources false
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.release
|
||||
signingConfig signingConfigs.debug
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
release {
|
||||
|
||||
74
app/src/main/assets/sample/复杂界面/应用浏览器.js
Normal file
74
app/src/main/assets/sample/复杂界面/应用浏览器.js
Normal file
@ -0,0 +1,74 @@
|
||||
"ui";
|
||||
|
||||
let pm = context.getPackageManager();
|
||||
let iconCache = {};
|
||||
|
||||
let IconView = (function () {
|
||||
// 继承ui.Widget
|
||||
util.extend(IconView, ui.Widget);
|
||||
|
||||
function IconView() {
|
||||
// 调用父类构造函数
|
||||
ui.Widget.call(this);
|
||||
// 自定义属性packageName
|
||||
this.defineAttr("packageName", (view, name, defaultGetter) => {
|
||||
return this._packageName;
|
||||
}, (view, name, value, defaultSetter) => {
|
||||
this._packageName = value;
|
||||
view.setImageDrawable(iconCache[value]);
|
||||
});
|
||||
}
|
||||
IconView.prototype.render = function () {
|
||||
return (
|
||||
<img w="*" h="*" scaleType="fitXY"/>
|
||||
);
|
||||
}
|
||||
ui.registerWidget("icon", IconView);
|
||||
return IconView;
|
||||
})();
|
||||
|
||||
let apps = [];
|
||||
|
||||
ui.layout(
|
||||
<vertical bg="#ffffff">
|
||||
<list id="apps" layout_weight="1">
|
||||
<linear bg="?selectableItemBackground" w="*" gravity="center_vertical">
|
||||
<icon packageName="{{this.packageName}}" w="80" h="80" />
|
||||
<vertical h="auto">
|
||||
<text id="name" textSize="16sp" textColor="#000000" text="{{this.appName}}" maxLines="1" ellipsize="end" />
|
||||
<text id="path" textSize="13sp" textColor="#929292" text="{{this.packageName}}" marginTop="4" maxLines="1" ellipsize="end" />
|
||||
</vertical>
|
||||
</linear>
|
||||
</list>
|
||||
<progressbar id="progressbar" indeterminate="true" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal" />
|
||||
</vertical>
|
||||
);
|
||||
|
||||
ui.apps.setDataSource(apps);
|
||||
|
||||
ui.apps.on("item_click", function (item, pos) {
|
||||
toast(util.inspect(item));
|
||||
});
|
||||
|
||||
// 启动线程来扫描app
|
||||
threads.start(function () {
|
||||
listApps(apps);
|
||||
// 切换回UI线程隐藏进度条
|
||||
ui.run(() => {
|
||||
ui.progressbar.attr("visibility", "gone");
|
||||
});
|
||||
});
|
||||
|
||||
function listApps(apps) {
|
||||
let list = pm.getInstalledPackages(0);
|
||||
list.forEach(pkgInfo => {
|
||||
let appInfo = pm.getApplicationInfo(pkgInfo.packageName, android.content.pm.PackageManager.GET_META_DATA)
|
||||
apps.push({
|
||||
appName: appInfo.loadLabel(pm),
|
||||
packageName: pkgInfo.packageName,
|
||||
versionName: pkgInfo.versionName,
|
||||
versionCode: pkgInfo.versionCode,
|
||||
});
|
||||
iconCache[pkgInfo.packageName] = pkgInfo.applicationInfo.loadIcon(pm)
|
||||
});
|
||||
}
|
||||
@ -1,71 +0,0 @@
|
||||
"ui";
|
||||
|
||||
var IconView = (function() {
|
||||
//继承ui.Widget
|
||||
util.extend(IconView, ui.Widget);
|
||||
|
||||
function IconView() {
|
||||
//调用父类构造函数
|
||||
ui.Widget.call(this);
|
||||
//自定义属性color,定义按钮颜色
|
||||
this.defineAttr("icon", (view, name, defaultGetter) => {
|
||||
return this._icon;
|
||||
}, (view, name, value, defaultSetter) => {
|
||||
this._icon = value;
|
||||
view.setImageResource(value);
|
||||
});
|
||||
}
|
||||
IconView.prototype.render = function() {
|
||||
return (
|
||||
<img />
|
||||
);
|
||||
}
|
||||
ui.registerWidget("icon", IconView);
|
||||
return IconView;
|
||||
})();
|
||||
|
||||
var apps = [];
|
||||
|
||||
ui.layout(
|
||||
<vertical bg="#ffffff">
|
||||
<list id="files" layout_weight="1">
|
||||
<linear bg="?selectableItemBackground">
|
||||
<icon icon="{{this.icon}}" w="50" h="70" margin="16" />
|
||||
<vertical>
|
||||
<text id="name" textSize="16sp" textColor="#000000" text="{{this.appName}}" marginTop="16" maxLines="1" ellipsize="end"/>
|
||||
<text id="path" textSize="13sp" textColor="#929292" text="{{this.packageName}}" marginTop="8" maxLines="1" ellipsize="end"/>
|
||||
</vertical>
|
||||
</linear>
|
||||
</list>
|
||||
<progressbar id="progressbar" indeterminate="true" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>
|
||||
</vertical>
|
||||
);
|
||||
|
||||
ui.apps.setDataSource(musicFiles);
|
||||
|
||||
ui.apps.on("item_click", function(item, pos){
|
||||
toast(item);
|
||||
});
|
||||
|
||||
//启动线程来扫描音乐文件
|
||||
threads.start(function () {
|
||||
listApps(apps);
|
||||
ui.run(()=> {
|
||||
ui.progressbar.setVisility(8);
|
||||
});
|
||||
});
|
||||
|
||||
function listApps(apps) {
|
||||
var pm = context.getPackageManager();
|
||||
let list = pm.getInstalledPackages(0);
|
||||
for(let i = 0; i < list.size(); i++){
|
||||
let p = list.get(i);
|
||||
apps.push({
|
||||
appName: p.applicationInfo.loadLabel(pm).toString(),
|
||||
packageName: p.packageName,
|
||||
versionName: p.versionName,
|
||||
versionCode: p.versionCode,
|
||||
icon: p.applicationInfo.loadIcon(pm)
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -53,6 +53,8 @@ public class DocsFragment extends ViewPagerFragment implements BackPressedHandle
|
||||
@AfterViews
|
||||
void setUpViews() {
|
||||
mWebView = mEWebView.getWebView();
|
||||
mWebView.getSettings().setSupportZoom(false);
|
||||
mWebView.getSettings().setBuiltInZoomControls(false);
|
||||
mEWebView.getSwipeRefreshLayout().setOnRefreshListener(() -> {
|
||||
if (TextUtils.equals(mWebView.getUrl(), mIndexUrl)) {
|
||||
loadUrl();
|
||||
|
||||
@ -101,9 +101,9 @@ public abstract class AutoJs {
|
||||
return exception;
|
||||
});
|
||||
ResourceMonitor.setUnclosedResourceDetectedHandler(mGlobalConsole::error);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
mContext.startForegroundService(new Intent(mContext, CaptureForegroundService.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
// mContext.startForegroundService(new Intent(mContext, CaptureForegroundService.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
// }
|
||||
}
|
||||
|
||||
public abstract void ensureAccessibilityServiceEnabled();
|
||||
|
||||
@ -49,6 +49,7 @@ public class CaptureForegroundService extends Service {
|
||||
|
||||
return new NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle("Recording")
|
||||
.setContentText("本通知为截图权限需要")
|
||||
.setSmallIcon(R.drawable.autojs_material)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentIntent(contentIntent)
|
||||
|
||||
@ -0,0 +1,292 @@
|
||||
package com.stardust.autojs.core.image.capture;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
import android.media.Image;
|
||||
import android.media.ImageReader;
|
||||
import android.media.projection.MediaProjection;
|
||||
import android.media.projection.MediaProjectionManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.OrientationEventListener;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.stardust.autojs.runtime.exception.ScriptException;
|
||||
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||
import com.stardust.lang.ThreadCompat;
|
||||
import com.stardust.util.ScreenMetrics;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Created by TonyJiangWJ on 2022/1/22
|
||||
*/
|
||||
public class GlobalScreenCapture {
|
||||
public static final int ORIENTATION_AUTO = Configuration.ORIENTATION_UNDEFINED;
|
||||
public static final int ORIENTATION_LANDSCAPE = Configuration.ORIENTATION_LANDSCAPE;
|
||||
public static final int ORIENTATION_PORTRAIT = Configuration.ORIENTATION_PORTRAIT;
|
||||
|
||||
private static final String TAG = "GlobalScreenCapture";
|
||||
private final ConcurrentHashMap<Thread, Boolean> registeredThreads = new ConcurrentHashMap<>();
|
||||
|
||||
private MediaProjectionManager mProjectionManager;
|
||||
private ImageReader mImageReader;
|
||||
private MediaProjection mMediaProjection;
|
||||
private VirtualDisplay mVirtualDisplay;
|
||||
private volatile Looper mImageAcquireLooper;
|
||||
private volatile Image mUnderUsingImage;
|
||||
private Context mContext;
|
||||
private Intent mData;
|
||||
private Handler mHandler;
|
||||
private final AtomicReference<Image> mCachedImage = new AtomicReference<>();
|
||||
private volatile Exception mException;
|
||||
|
||||
private final int mScreenDensity;
|
||||
private int mOrientation = -1;
|
||||
private int mDetectedOrientation;
|
||||
private OrientationEventListener mOrientationEventListener;
|
||||
|
||||
private boolean hasPermission;
|
||||
private boolean noRegister;
|
||||
|
||||
private GlobalScreenCapture() {
|
||||
mScreenDensity = ScreenMetrics.getDeviceScreenDensity();
|
||||
}
|
||||
|
||||
private static class Holder {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private final static GlobalScreenCapture INSTANCE = new GlobalScreenCapture();
|
||||
}
|
||||
|
||||
public static GlobalScreenCapture getInstance() {
|
||||
return Holder.INSTANCE;
|
||||
}
|
||||
|
||||
public synchronized void initCapture(Context context, Intent data, int orientation) {
|
||||
Log.d(TAG, "initCapture: ");
|
||||
mProjectionManager = (MediaProjectionManager) context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
|
||||
mMediaProjection = mProjectionManager.getMediaProjection(Activity.RESULT_OK, (Intent) data.clone());
|
||||
mContext = context;
|
||||
mData = (Intent) data.clone();
|
||||
new Thread(() -> {
|
||||
Looper.prepare();
|
||||
mHandler = new Handler(Looper.myLooper());
|
||||
synchronized (GlobalScreenCapture.this) {
|
||||
GlobalScreenCapture.this.notifyAll();
|
||||
}
|
||||
Looper.loop();
|
||||
}).start();
|
||||
synchronized (this) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new ScriptInterruptedException();
|
||||
}
|
||||
}
|
||||
observeOrientation();
|
||||
setOrientation(orientation);
|
||||
hasPermission = true;
|
||||
}
|
||||
|
||||
public synchronized boolean hasPermission() {
|
||||
return hasPermission;
|
||||
}
|
||||
|
||||
public void setOrientation(int orientation) {
|
||||
if (mOrientation == orientation) {
|
||||
return;
|
||||
}
|
||||
mOrientation = orientation;
|
||||
mDetectedOrientation = mContext.getResources().getConfiguration().orientation;
|
||||
refreshVirtualDisplay(mOrientation == ORIENTATION_AUTO ? mDetectedOrientation : mOrientation);
|
||||
}
|
||||
|
||||
|
||||
private void observeOrientation() {
|
||||
mOrientationEventListener = new OrientationEventListener(mContext) {
|
||||
@Override
|
||||
public void onOrientationChanged(int o) {
|
||||
int orientation = mContext.getResources().getConfiguration().orientation;
|
||||
if (mOrientation == ORIENTATION_AUTO && mDetectedOrientation != orientation) {
|
||||
mDetectedOrientation = orientation;
|
||||
try {
|
||||
refreshVirtualDisplay(orientation);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
mException = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
if (mOrientationEventListener.canDetectOrientation()) {
|
||||
mOrientationEventListener.enable();
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshVirtualDisplay(int orientation) {
|
||||
if (mImageAcquireLooper != null) {
|
||||
mImageAcquireLooper.quit();
|
||||
}
|
||||
if (mImageReader != null) {
|
||||
mImageReader.close();
|
||||
}
|
||||
if (mVirtualDisplay != null) {
|
||||
mVirtualDisplay.release();
|
||||
}
|
||||
try {
|
||||
mMediaProjection = mProjectionManager.getMediaProjection(Activity.RESULT_OK, (Intent) mData.clone());
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "refreshVirtualDisplay: 获取新projection失败 可能只是MIUI的bug " + e);
|
||||
}
|
||||
int screenHeight = ScreenMetrics.getOrientationAwareScreenHeight(orientation);
|
||||
int screenWidth = ScreenMetrics.getOrientationAwareScreenWidth(orientation);
|
||||
initVirtualDisplay(screenWidth, screenHeight, mScreenDensity);
|
||||
startAcquireImageLoop();
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
private void initVirtualDisplay(int width, int height, int screenDensity) {
|
||||
mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 3);
|
||||
try {
|
||||
mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG,
|
||||
width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
||||
mImageReader.getSurface(), null, null);
|
||||
} catch (SecurityException e) {
|
||||
Log.d(TAG, "initVirtualDisplay: 获取virtualDisplay失败" + e);
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
private void startAcquireImageLoop() {
|
||||
if (mImageReader == null) {
|
||||
// 初始化virtualDisplay异常
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHandler != null) {
|
||||
setImageListener(mHandler);
|
||||
return;
|
||||
}
|
||||
new Thread(() -> {
|
||||
Log.d(TAG, "AcquireImageLoop: start");
|
||||
Looper.prepare();
|
||||
mImageAcquireLooper = Looper.myLooper();
|
||||
setImageListener(new Handler());
|
||||
Looper.loop();
|
||||
Log.d(TAG, "AcquireImageLoop: stop");
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void setImageListener(Handler handler) {
|
||||
mImageReader.setOnImageAvailableListener(reader -> {
|
||||
try {
|
||||
if (noRegister) {
|
||||
return;
|
||||
}
|
||||
Image oldCacheImage = mCachedImage.getAndSet(null);
|
||||
if (oldCacheImage != null) {
|
||||
oldCacheImage.close();
|
||||
}
|
||||
mCachedImage.set(reader.acquireLatestImage());
|
||||
} catch (Exception e) {
|
||||
mException = e;
|
||||
}
|
||||
|
||||
}, handler);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public synchronized Image capture() {
|
||||
Exception e = mException;
|
||||
if (e != null) {
|
||||
mException = null;
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
Thread thread = ThreadCompat.currentThread();
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (!thread.isInterrupted()) {
|
||||
Image cachedImage = mCachedImage.getAndSet(null);
|
||||
if (cachedImage != null) {
|
||||
if (mUnderUsingImage != null) {
|
||||
mUnderUsingImage.close();
|
||||
}
|
||||
mUnderUsingImage = cachedImage;
|
||||
return cachedImage;
|
||||
}
|
||||
if (System.currentTimeMillis() - startTime > 1000) {
|
||||
startTime = System.currentTimeMillis();
|
||||
this.refreshVirtualDisplay(mOrientation);
|
||||
}
|
||||
}
|
||||
throw new ScriptInterruptedException();
|
||||
}
|
||||
|
||||
public synchronized void unregister(Looper looper) {
|
||||
Log.d(TAG, "unregister: " + looper.getThread().getName());
|
||||
registeredThreads.remove(looper.getThread());
|
||||
Iterator<Thread> keyThreads = registeredThreads.keySet().iterator();
|
||||
while (keyThreads.hasNext()) {
|
||||
Thread thread = keyThreads.next();
|
||||
if (!thread.isAlive()) {
|
||||
keyThreads.remove();
|
||||
}
|
||||
}
|
||||
noRegister = registeredThreads.size() == 0;
|
||||
if (noRegister) {
|
||||
Log.d(TAG, "全部引擎已注销,释放截图权限,清除通知");
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void register(Looper looper) {
|
||||
Log.d(TAG, "新引擎注册:" + looper.getThread().getName() + " hasPermission? " + hasPermission);
|
||||
noRegister = false;
|
||||
registeredThreads.put(looper.getThread(), true);
|
||||
}
|
||||
|
||||
private void release() {
|
||||
noRegister = true;
|
||||
hasPermission = false;
|
||||
if (mImageAcquireLooper != null) {
|
||||
mImageAcquireLooper.quit();
|
||||
mImageAcquireLooper = null;
|
||||
}
|
||||
if (mMediaProjection != null) {
|
||||
mMediaProjection.stop();
|
||||
mMediaProjection = null;
|
||||
}
|
||||
if (mVirtualDisplay != null) {
|
||||
mVirtualDisplay.release();
|
||||
}
|
||||
if (mImageReader != null) {
|
||||
mImageReader.setOnImageAvailableListener(null, null);
|
||||
mImageReader.close();
|
||||
mImageReader = null;
|
||||
}
|
||||
if (mUnderUsingImage != null) {
|
||||
mUnderUsingImage.close();
|
||||
mUnderUsingImage = null;
|
||||
}
|
||||
Image cachedImage = mCachedImage.getAndSet(null);
|
||||
if (cachedImage != null) {
|
||||
cachedImage.close();
|
||||
}
|
||||
if (mOrientationEventListener != null) {
|
||||
mOrientationEventListener.disable();
|
||||
mOrientationEventListener = null;
|
||||
}
|
||||
mContext.stopService(new Intent(mContext, CaptureForegroundService.class));
|
||||
}
|
||||
|
||||
}
|
||||
@ -23,6 +23,9 @@ public class ScreenCaptureRequestActivity extends Activity {
|
||||
private ScreenCaptureRequester.Callback mCallback;
|
||||
|
||||
public static void request(Context context, ScreenCaptureRequester.Callback callback) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
context.startForegroundService(new Intent(context, CaptureForegroundService.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
Intent intent = new Intent(context, ScreenCaptureRequestActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
IntentExtras.newExtras()
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.stardust.autojs.core.image.capture;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.projection.MediaProjectionManager;
|
||||
@ -78,6 +79,9 @@ public interface ScreenCaptureRequester {
|
||||
|
||||
@Override
|
||||
public void request() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
mActivity.startForegroundService(new Intent(mActivity, CaptureForegroundService.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
mActivity.startActivityForResult(((MediaProjectionManager) mActivity.getSystemService(Context.MEDIA_PROJECTION_SERVICE)).createScreenCaptureIntent(), REQUEST_CODE_MEDIA_PROJECTION);
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ public class ViewExtras {
|
||||
public static ViewExtras get(View view) {
|
||||
ViewExtras extras;
|
||||
Object tag = view.getTag(R.id.view_tag_view_extras);
|
||||
Log.d(LOG_TAG, "view = " + view + ", tag = " + tag);
|
||||
// Log.d(LOG_TAG, "view = " + view + ", tag = " + tag);
|
||||
if (tag instanceof ViewExtras) {
|
||||
extras = (ViewExtras) tag;
|
||||
} else {
|
||||
|
||||
@ -50,5 +50,11 @@ public class AndroidContextFactory extends ShellContextFactory {
|
||||
return cx;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean hasFeature(Context cx, int featureIndex) {
|
||||
if (featureIndex == Context.FEATURE_ENABLE_XML_SECURE_PARSING) {
|
||||
return false;
|
||||
}
|
||||
return super.hasFeature(cx, featureIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,14 +42,14 @@ public class InterruptibleAndroidContextFactory extends AndroidContextFactory {
|
||||
protected void onContextCreated(Context cx) {
|
||||
super.onContextCreated(cx);
|
||||
int i = mContextCount.incrementAndGet();
|
||||
Log.d(LOG_TAG, "onContextCreated: count = " + i);
|
||||
// Log.d(LOG_TAG, "onContextCreated: count = " + i);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onContextReleased(Context cx) {
|
||||
super.onContextReleased(cx);
|
||||
int i = mContextCount.decrementAndGet();
|
||||
Log.d(LOG_TAG, "onContextReleased: count = " + i);
|
||||
// Log.d(LOG_TAG, "onContextReleased: count = " + i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -432,16 +432,14 @@ public class ScriptRuntime {
|
||||
ignoresException(threads::shutDownAll);
|
||||
ignoresException(events::recycle);
|
||||
ignoresException(media::recycle);
|
||||
ignoresException(images::releaseScreenCapturer);
|
||||
ignoresException(images::recycle);
|
||||
ignoresException(loopers::recycle);
|
||||
ignoresException(() -> {
|
||||
if (mRootShell != null) mRootShell.exit();
|
||||
mRootShell = null;
|
||||
mShellSupplier = null;
|
||||
});
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
ignoresException(images::releaseScreenCapturer);
|
||||
ignoresException(images::recycle);
|
||||
}
|
||||
ignoresException(sensors::unregisterAll);
|
||||
sensors = null;
|
||||
ignoresException(timers::recycle);
|
||||
|
||||
@ -12,14 +12,15 @@ import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
|
||||
import com.stardust.autojs.annotation.ScriptVariable;
|
||||
import com.stardust.autojs.core.image.ColorFinder;
|
||||
import com.stardust.autojs.core.image.ImageWrapper;
|
||||
import com.stardust.autojs.core.image.TemplateMatching;
|
||||
import com.stardust.autojs.core.image.capture.GlobalScreenCapture;
|
||||
import com.stardust.autojs.core.image.capture.ScreenCaptureRequester;
|
||||
import com.stardust.autojs.core.image.capture.ScreenCapturer;
|
||||
import com.stardust.autojs.core.opencv.Mat;
|
||||
import com.stardust.autojs.core.opencv.OpenCVHelper;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Drawables;
|
||||
@ -54,13 +55,14 @@ public class Images {
|
||||
|
||||
private WeakReference<ScriptRuntime> mScriptRuntime;
|
||||
private ScreenCaptureRequester mScreenCaptureRequester;
|
||||
private ScreenCapturer mScreenCapturer;
|
||||
private Context mContext;
|
||||
private Image mPreCapture;
|
||||
private ImageWrapper mPreCaptureImage;
|
||||
private ScreenMetrics mScreenMetrics;
|
||||
private volatile boolean mOpenCvInitialized = false;
|
||||
|
||||
private final static String TAG = "Images";
|
||||
|
||||
@ScriptVariable
|
||||
public final ColorFinder colorFinder;
|
||||
|
||||
@ -76,16 +78,23 @@ public class Images {
|
||||
public ScriptPromiseAdapter requestScreenCapture(int orientation) {
|
||||
ScriptRuntime.requiresApi(21);
|
||||
ScriptPromiseAdapter promiseAdapter = new ScriptPromiseAdapter();
|
||||
if (mScreenCapturer != null) {
|
||||
mScreenCapturer.setOrientation(orientation);
|
||||
promiseAdapter.resolve(true);
|
||||
return promiseAdapter;
|
||||
if (GlobalScreenCapture.getInstance().hasPermission()) {
|
||||
synchronized (GlobalScreenCapture.getInstance()) {
|
||||
if (GlobalScreenCapture.getInstance().hasPermission()) {
|
||||
Log.d(TAG, "requestScreenCapture hasPermission 直接注册");
|
||||
GlobalScreenCapture.getInstance().setOrientation(orientation);
|
||||
GlobalScreenCapture.getInstance().register(mScriptRuntime.get().loopers.getMainLooper());
|
||||
new Handler(mScriptRuntime.get().loopers.getMainLooper())
|
||||
.post(() -> promiseAdapter.resolve(true));
|
||||
return promiseAdapter;
|
||||
}
|
||||
}
|
||||
}
|
||||
Looper servantLooper = mScriptRuntime.get().loopers.getServantLooper();
|
||||
|
||||
mScreenCaptureRequester.setOnActivityResultCallback((result, data) -> {
|
||||
if (result == Activity.RESULT_OK) {
|
||||
mScreenCapturer = new ScreenCapturer(mContext, data, orientation, ScreenMetrics.getDeviceScreenDensity(),
|
||||
new Handler(servantLooper));
|
||||
GlobalScreenCapture.getInstance().initCapture(mContext, data, orientation);
|
||||
GlobalScreenCapture.getInstance().register(mScriptRuntime.get().loopers.getMainLooper());
|
||||
promiseAdapter.resolve(true);
|
||||
} else {
|
||||
promiseAdapter.resolve(false);
|
||||
@ -97,11 +106,12 @@ public class Images {
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public synchronized ImageWrapper captureScreen() {
|
||||
Log.d(TAG, "captureScreen: 请求截图 " + mScriptRuntime.get().loopers.getMainLooper().getThread().getName());
|
||||
ScriptRuntime.requiresApi(21);
|
||||
if (mScreenCapturer == null) {
|
||||
if (!GlobalScreenCapture.getInstance().hasPermission()) {
|
||||
throw new SecurityException("No screen capture permission");
|
||||
}
|
||||
Image capture = mScreenCapturer.capture();
|
||||
Image capture = GlobalScreenCapture.getInstance().capture();
|
||||
if (capture == mPreCapture && mPreCaptureImage != null) {
|
||||
return mPreCaptureImage;
|
||||
}
|
||||
@ -262,8 +272,10 @@ public class Images {
|
||||
}
|
||||
|
||||
public void releaseScreenCapturer() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mScreenCapturer != null) {
|
||||
mScreenCapturer.release();
|
||||
if (GlobalScreenCapture.getInstance().hasPermission()) {
|
||||
synchronized (GlobalScreenCapture.getInstance()) {
|
||||
GlobalScreenCapture.getInstance().unregister(mScriptRuntime.get().loopers.getMainLooper());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -55,9 +55,11 @@ public class VMBridge_custom extends VMBridge_jdk18 {
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
// notify the script thread to exit
|
||||
com.stardust.autojs.runtime.ScriptRuntime runtime = engine.getRuntime();
|
||||
Log.d(LOG_TAG, "runtime = " + runtime);
|
||||
runtime.exit(e);
|
||||
if (engine != null) {
|
||||
com.stardust.autojs.runtime.ScriptRuntime runtime = engine.getRuntime();
|
||||
Log.d(LOG_TAG, "runtime = " + runtime);
|
||||
runtime.exit(e);
|
||||
}
|
||||
// even if we caught the exception, we must return a value to for the method call.
|
||||
return defaultValue(method.getReturnType());
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user