diff --git a/app/build.gradle b/app/build.gradle index c0598ce2..78bba16f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "com.stardust.scriptdroid" minSdkVersion 19 targetSdkVersion 23 - versionCode 139 - versionName "2.0.13 Alpha2" + versionCode 140 + versionName "2.0.13 Alpha3" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { diff --git a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java b/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java index 2cac412b..a24768bd 100644 --- a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java +++ b/app/src/main/java/com/stardust/scriptdroid/sublime/SublimePluginClient.java @@ -13,6 +13,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** @@ -39,7 +40,7 @@ public class SublimePluginClient { private String host; private int port; private OutputStream mOutputStream; - private Executor mExecutor; + private ExecutorService mExecutor; public SublimePluginClient(String host, int port) { this.host = host; @@ -105,8 +106,10 @@ public class SublimePluginClient { public void close() throws IOException { if (mSocket != null) { mSocket.close(); + mExecutor.shutdownNow(); mSocket = null; mOutputStream = null; + mExecutor = null; EventBus.getDefault().post(new ConnectionStateChangeEvent(false)); } } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/image/ScreenCapturer.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/image/ScreenCapturer.java index a1d3456c..7c1bc04d 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/image/ScreenCapturer.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/image/ScreenCapturer.java @@ -13,23 +13,34 @@ import android.media.projection.MediaProjectionManager; import android.os.Build; import android.os.Looper; import android.support.annotation.RequiresApi; +import android.util.Log; +import android.widget.ImageView; +import com.stardust.autojs.runtime.ScriptInterruptedException; import com.stardust.util.ScreenMetrics; +import java.util.HashSet; +import java.util.concurrent.ConcurrentHashMap; + /** * Created by Stardust on 2017/5/17. */ @RequiresApi(Build.VERSION_CODES.LOLLIPOP) public class ScreenCapturer { + private static final String LOG_TAG = "ScreenCapturer"; private ImageReader mImageReader; private MediaProjection mMediaProjection; private VirtualDisplay mVirtualDisplay; - private Image mImage; + private volatile Looper mImageAcquireLooper; + private final Object mImageWaitingLock = new Object(); + private volatile Image mImage; + private volatile Image mLatestImage; public ScreenCapturer(Context context, Intent data, int screenWidth, int screenHeight, int screenDensity) { MediaProjectionManager manager = (MediaProjectionManager) context.getSystemService(Context.MEDIA_PROJECTION_SERVICE); initVirtualDisplay(manager, data, screenWidth, screenHeight, screenDensity); + startAcquireImageLoop(); } public ScreenCapturer(Context context, Intent data, int screenWidth, int screenHeight) { @@ -41,32 +52,65 @@ public class ScreenCapturer { } private void initVirtualDisplay(MediaProjectionManager manager, Intent data, int screenWidth, int screenHeight, int screenDensity) { - mImageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 1); + mImageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 2); mMediaProjection = manager.getMediaProjection(Activity.RESULT_OK, data); mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror", screenWidth, screenHeight, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null); + + } + + private void startAcquireImageLoop() { + new Thread(new Runnable() { + @Override + public void run() { + Looper.prepare(); + mImageAcquireLooper = Looper.myLooper(); + mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { + @Override + public void onImageAvailable(ImageReader reader) { + if (mLatestImage != null) { + mLatestImage.close(); + } + mLatestImage = reader.acquireNextImage(); + if (mLatestImage != null) { + synchronized (mImageWaitingLock) { + mImageWaitingLock.notify(); + } + } + } + }, null); + Looper.loop(); + } + }).start(); } public Image capture() { + if (mLatestImage == null) { + if (mImage != null) { + return mImage; + } + waitForImageAvailable(); + } if (mImage != null) { mImage.close(); } - mImage = mImageReader.acquireLatestImage(); - if (mImage == null) { - Looper.prepare(); - mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { - @Override - public void onImageAvailable(ImageReader reader) { - Looper.myLooper().quit(); - } - }, null); - Looper.loop(); - mImage = mImageReader.acquireLatestImage(); - } + mImage = mLatestImage; + mLatestImage = null; return mImage; } + private void waitForImageAvailable() { + Log.d(LOG_TAG, "waitForImageAvailable"); + synchronized (mImageWaitingLock) { + try { + mImageWaitingLock.wait(); + } catch (InterruptedException e) { + throw new ScriptInterruptedException(); + } + } + } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void release() { @@ -76,8 +120,17 @@ public class ScreenCapturer { if (mVirtualDisplay != null) { mVirtualDisplay.release(); } + if (mImageReader != null) { + mImageReader.close(); + } + if (mImageAcquireLooper != null) { + mImageAcquireLooper.quitSafely(); + } if (mImage != null) { mImage.close(); } + if (mLatestImage != null) { + mLatestImage.close(); + } } }