diff --git a/autojs/src/main/java/com/stardust/autojs/AutoJs.java b/autojs/src/main/java/com/stardust/autojs/AutoJs.java index 320d00bb..cdc39489 100644 --- a/autojs/src/main/java/com/stardust/autojs/AutoJs.java +++ b/autojs/src/main/java/com/stardust/autojs/AutoJs.java @@ -263,6 +263,9 @@ public abstract class AutoJs { @Override public void request() { Activity activity = mAppUtils.getCurrentActivity(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + mContext.startForegroundService(new Intent(mContext, CaptureForegroundService.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } if (activity instanceof OnActivityResultDelegate.DelegateHost) { ScreenCaptureRequester requester = new ActivityScreenCaptureRequester( ((OnActivityResultDelegate.DelegateHost) activity).getOnActivityResultDelegateMediator(), activity); diff --git a/autojs/src/main/java/com/stardust/autojs/core/image/capture/CaptureForegroundService.java b/autojs/src/main/java/com/stardust/autojs/core/image/capture/CaptureForegroundService.java index b86a6bbb..f2ee0208 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/image/capture/CaptureForegroundService.java +++ b/autojs/src/main/java/com/stardust/autojs/core/image/capture/CaptureForegroundService.java @@ -11,6 +11,7 @@ import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.IBinder; +import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @@ -22,6 +23,7 @@ public class CaptureForegroundService extends Service { private static final int NOTIFICATION_ID = 2; private static final String CHANNEL_ID = CaptureForegroundService.class.getName() + ".foreground"; + private final String TAG = "CaptureForegrdService"; @Nullable @Override @@ -31,6 +33,9 @@ public class CaptureForegroundService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "onStartCommand"); + startForeground(NOTIFICATION_ID, buildNotification()); + GlobalScreenCapture.getInstance().notifyStarted(); return super.onStartCommand(intent, flags, startId); } @@ -38,6 +43,7 @@ public class CaptureForegroundService extends Service { public void onCreate() { super.onCreate(); startForeground(NOTIFICATION_ID, buildNotification()); + GlobalScreenCapture.getInstance().notifyStarted(); } private Notification buildNotification() { @@ -46,7 +52,12 @@ public class CaptureForegroundService extends Service { } int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? FLAG_IMMUTABLE : 0; PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, ScreenCaptureRequestActivity.class), flags); - + Log.d(TAG, "buildNotification: start"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationManager notificationManager = (NotificationManager) this.getSystemService(NOTIFICATION_SERVICE); + NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, "Recording", NotificationManager.IMPORTANCE_MIN); + notificationManager.createNotificationChannel(notificationChannel); + } return new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Recording") .setContentText("本通知为截图权限需要") @@ -55,6 +66,7 @@ public class CaptureForegroundService extends Service { .setContentIntent(contentIntent) .setChannelId(CHANNEL_ID) .setVibrate(new long[0]) + .setDefaults(Notification.DEFAULT_ALL | NotificationCompat.FLAG_ONLY_ALERT_ONCE) .build(); } diff --git a/autojs/src/main/java/com/stardust/autojs/core/image/capture/GlobalScreenCapture.java b/autojs/src/main/java/com/stardust/autojs/core/image/capture/GlobalScreenCapture.java index a548d55d..6759970f 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/image/capture/GlobalScreenCapture.java +++ b/autojs/src/main/java/com/stardust/autojs/core/image/capture/GlobalScreenCapture.java @@ -17,8 +17,6 @@ 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; @@ -28,6 +26,8 @@ import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; +import androidx.annotation.Nullable; + /** * Created by TonyJiangWJ on 2022/1/22 */ @@ -50,8 +50,9 @@ public class GlobalScreenCapture { private Handler mHandler; private final AtomicReference mCachedImage = new AtomicReference<>(); private volatile Exception mException; + private boolean foregroundServiceStarted = false; - private final int mScreenDensity; + private int mScreenDensity; private int mOrientation = -1; private int mDetectedOrientation; private OrientationEventListener mOrientationEventListener; @@ -59,28 +60,43 @@ public class GlobalScreenCapture { private boolean hasPermission; private boolean noRegister; + @SuppressLint("StaticFieldLeak") + private static volatile GlobalScreenCapture INSTANCE; + 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; + if (INSTANCE == null) { + synchronized (GlobalScreenCapture.class) { + if (INSTANCE == null) { + INSTANCE = new GlobalScreenCapture(); + } + } + } + return INSTANCE; } public synchronized void initCapture(Context context, Intent data, int orientation) { - Log.d(TAG, "initCapture: "); + Log.d(TAG, "initCapture: " + mScreenDensity); + if (mScreenDensity == 0) { + mScreenDensity = ScreenMetrics.getDeviceScreenDensity(); + } + if (!foregroundServiceStarted) { + try { + this.wait(); + } catch (InterruptedException e) { + throw new ScriptInterruptedException(); + } + } 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()); + mHandler = new Handler(Looper.getMainLooper()); synchronized (GlobalScreenCapture.this) { GlobalScreenCapture.this.notifyAll(); } @@ -98,6 +114,11 @@ public class GlobalScreenCapture { hasPermission = true; } + public synchronized void notifyStarted() { + this.foregroundServiceStarted = true; + this.notify(); + } + public synchronized boolean hasPermission() { return hasPermission; } @@ -144,19 +165,26 @@ public class GlobalScreenCapture { 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(); } + private void grantMediaProjection() { + try { + if (mMediaProjection != null) { + mMediaProjection.stop(); + } + mMediaProjection = mProjectionManager.getMediaProjection(Activity.RESULT_OK, (Intent) mData.clone()); + } catch (Exception e) { + Log.d(TAG, "grantMediaProjection: 获取新projection失败 可能只是MIUI的bug " + e); + } + } + @SuppressLint("WrongConstant") private void initVirtualDisplay(int width, int height, int screenDensity) { + Log.d(TAG, "initVirtualDisplay: width:" + width + ",height:" + height + ",density:" + screenDensity); mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 3); try { mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG, @@ -217,6 +245,7 @@ public class GlobalScreenCapture { if (System.currentTimeMillis() - startTime > 1000) { startTime = System.currentTimeMillis(); Log.d(TAG, "capture: 获取截图失败,刷新virtualDisplay"); + this.grantMediaProjection(); this.refreshVirtualDisplay(mOrientation); } } @@ -250,6 +279,7 @@ public class GlobalScreenCapture { noRegister = true; hasPermission = false; mOrientation = -1; + foregroundServiceStarted = false; if (mImageAcquireLooper != null) { mImageAcquireLooper.quit(); mImageAcquireLooper = null; diff --git a/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCaptureRequestActivity.java b/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCaptureRequestActivity.java index b71f2c05..4905b6f1 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCaptureRequestActivity.java +++ b/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCaptureRequestActivity.java @@ -23,9 +23,6 @@ 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() diff --git a/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCaptureRequester.java b/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCaptureRequester.java index 70672f55..f7862575 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCaptureRequester.java +++ b/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCaptureRequester.java @@ -79,9 +79,6 @@ 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); } diff --git a/autojs/src/main/java/com/stardust/autojs/core/util/ScriptPromiseAdapter.kt b/autojs/src/main/java/com/stardust/autojs/core/util/ScriptPromiseAdapter.kt index 75d3338b..2b955fd9 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/util/ScriptPromiseAdapter.kt +++ b/autojs/src/main/java/com/stardust/autojs/core/util/ScriptPromiseAdapter.kt @@ -1,5 +1,8 @@ package com.stardust.autojs.core.util +import android.util.Log +import com.stardust.concurrent.VolatileDispose + class ScriptPromiseAdapter { interface Callback { @@ -10,17 +13,25 @@ class ScriptPromiseAdapter { private var mRejectCallback: Callback? = null private var mResult: Any? = UNSET private var mError: Any? = UNSET + private val TAG = "ScriptPromiseAdapter"; + private var volatileDispose = VolatileDispose(); fun onResolve(callback: Callback): ScriptPromiseAdapter { + Log.d(TAG, "onResolve, mResult == UNSET ? " + (mResult == UNSET)) mResolveCallback = callback mResult.let { if (it !== UNSET) { callback.call(it) } } + volatileDispose.setAndNotify(true) return this } + fun awaitResolver() { + volatileDispose.blockedGet() + } + fun onReject(callback: Callback): ScriptPromiseAdapter { mRejectCallback = callback mError.let { @@ -32,6 +43,7 @@ class ScriptPromiseAdapter { } fun resolve(result: Any?) { + Log.d(TAG, "resolve, result = " + result) mResult = result mResolveCallback?.call(result) releaseCallbacks() diff --git a/autojs/src/main/java/com/stardust/autojs/rhino/DeleteOnFinalizeFile.java b/autojs/src/main/java/com/stardust/autojs/rhino/DeleteOnFinalizeFile.java index ef839e84..fbdce9c2 100644 --- a/autojs/src/main/java/com/stardust/autojs/rhino/DeleteOnFinalizeFile.java +++ b/autojs/src/main/java/com/stardust/autojs/rhino/DeleteOnFinalizeFile.java @@ -13,7 +13,7 @@ public class DeleteOnFinalizeFile { public DeleteOnFinalizeFile(File file) { fileObject = file; } - +/* @Override protected void finalize() throws Throwable { super.finalize(); @@ -23,4 +23,5 @@ public class DeleteOnFinalizeFile { fileObject.delete(); } } + */ } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java index 489d2289..ef42697b 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java @@ -84,8 +84,11 @@ public class Images { 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)); + new Handler(Looper.getMainLooper()) + .post(() -> { + promiseAdapter.awaitResolver(); + promiseAdapter.resolve(true); + }); return promiseAdapter; } }