@@ -122,6 +122,8 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_SMS" />
|
<uses-permission android:name="android.permission.READ_SMS" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
|
||||||
|
|
||||||
<!-- Property "largeHeap" is not recommended to set to true. -->
|
<!-- Property "largeHeap" is not recommended to set to true. -->
|
||||||
<!-- https://stackoverflow.com/questions/27396892/what-are-advantages-of-setting-largeheap-to-true -->
|
<!-- https://stackoverflow.com/questions/27396892/what-are-advantages-of-setting-largeheap-to-true -->
|
||||||
<application
|
<application
|
||||||
@@ -130,7 +132,7 @@
|
|||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:icon="${icon}"
|
android:icon="${icon}"
|
||||||
android:label="${appName}"
|
android:label="${appName}"
|
||||||
android:largeHeap="false"
|
android:largeHeap="true"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.content.Intent;
|
|||||||
import android.media.projection.MediaProjectionManager;
|
import android.media.projection.MediaProjectionManager;
|
||||||
|
|
||||||
import org.autojs.autojs.app.OnActivityResultDelegate;
|
import org.autojs.autojs.app.OnActivityResultDelegate;
|
||||||
|
import org.autojs.autojs.util.ForegroundServiceUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on May 17, 2017.
|
* Created by Stardust on May 17, 2017.
|
||||||
@@ -46,9 +47,18 @@ public interface ScreenCaptureRequester {
|
|||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
mResult = data;
|
mResult = data;
|
||||||
mMediator.removeDelegate(this);
|
mMediator.removeDelegate(this);
|
||||||
onResult(resultCode, data);
|
// 按照官方文档,https://developer.android.com/reference/android/media/projection/MediaProjectionManager,启动媒体投影的示例流程如下:
|
||||||
}
|
// 1. AndroidManifest.xml声明mediaProjection类型前台服务
|
||||||
|
// 2. 通过调用MediaProjectionManager#createScreenCaptureIntent()创建intent并传递给Activity#startActivityForResult(Intent, int)
|
||||||
|
// 3. 在得到用户授权后,回调Activity#onActivityResult中,使用 ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION类型 启动前台服务
|
||||||
|
// 4. 再通过MediaProjectionManager#getMediaProjection(int, Intent)得到MediaProjection
|
||||||
|
// 5. 通过MediaProjection#createVirtualDisplay调用启动媒体投影的屏幕捕获会话
|
||||||
|
// 总结就是,要保证:先授权,再启动服务,再录屏的顺序
|
||||||
|
|
||||||
|
// 原代码在ScreenCaptureRequesterImpl#requst中startService会有时序问题,此时用户还没授权完成时,Android 14+启动前台服务实测会崩溃
|
||||||
|
// 改成bindService并等待onServiceConnected回调
|
||||||
|
ForegroundServiceUtils.requestReadyIfNeeded(mActivity.getApplicationContext(), ScreenCapturerForegroundService.class, () -> onResult(resultCode, data));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractScreenCaptureRequester implements ScreenCaptureRequester {
|
abstract class AbstractScreenCaptureRequester implements ScreenCaptureRequester {
|
||||||
@@ -75,7 +85,5 @@ public interface ScreenCaptureRequester {
|
|||||||
if (mCallback != null)
|
if (mCallback != null)
|
||||||
mCallback.onRequestResult(Activity.RESULT_CANCELED, null);
|
mCallback.onRequestResult(Activity.RESULT_CANCELED, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import android.app.Activity;
|
|||||||
|
|
||||||
import org.autojs.autojs.AbstractAutoJs;
|
import org.autojs.autojs.AbstractAutoJs;
|
||||||
import org.autojs.autojs.app.OnActivityResultDelegate;
|
import org.autojs.autojs.app.OnActivityResultDelegate;
|
||||||
import org.autojs.autojs.util.ForegroundServiceUtils;
|
|
||||||
|
|
||||||
public class ScreenCaptureRequesterImpl extends ScreenCaptureRequester.AbstractScreenCaptureRequester {
|
public class ScreenCaptureRequesterImpl extends ScreenCaptureRequester.AbstractScreenCaptureRequester {
|
||||||
|
|
||||||
@@ -25,8 +24,6 @@ public class ScreenCaptureRequesterImpl extends ScreenCaptureRequester.AbstractS
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void request() {
|
public void request() {
|
||||||
ForegroundServiceUtils.requestIfNeeded(mAutoJs.getApplicationContext(), ScreenCapturerForegroundService.class);
|
|
||||||
|
|
||||||
Activity activity = mAutoJs.getAppUtils().getCurrentActivity();
|
Activity activity = mAutoJs.getAppUtils().getCurrentActivity();
|
||||||
|
|
||||||
if (activity instanceof OnActivityResultDelegate.DelegateHost) {
|
if (activity instanceof OnActivityResultDelegate.DelegateHost) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Service;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ public class ScreenCapturerForegroundService extends Service {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
return null;
|
return new Binder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startForeground() {
|
private void startForeground() {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class MainActivityForegroundService : Service() {
|
|||||||
.create()
|
.create()
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
ForegroundServiceUtils.startForeground(foregroundServiceCreator, ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED)
|
ForegroundServiceUtils.startForeground(foregroundServiceCreator, ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
|
||||||
} else {
|
} else {
|
||||||
ForegroundServiceUtils.startForeground(foregroundServiceCreator)
|
ForegroundServiceUtils.startForeground(foregroundServiceCreator)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import android.app.NotificationChannel;
|
|||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.ServiceConnection;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -36,6 +38,23 @@ public class ForegroundServiceUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void requestReadyIfNeeded(Context context, Class<?> className, Runnable runnable) {
|
||||||
|
if (isRunning(context, className)) {
|
||||||
|
runnable.run();
|
||||||
|
} else {
|
||||||
|
context.bindService(getService(context, className), new ServiceConnection() {
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
}
|
||||||
|
}, Context.BIND_AUTO_CREATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean startService(Context context, Class<?> className) {
|
public static boolean startService(Context context, Class<?> className) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
return context.startForegroundService(getService(context, className)) != null;
|
return context.startForegroundService(getService(context, className)) != null;
|
||||||
|
|||||||
Reference in New Issue
Block a user