Skip to content

Commit

Permalink
Merge pull request #242 from chenguangming/master
Browse files Browse the repository at this point in the history
适配Android14对截屏的严格要求
  • Loading branch information
SuperMonster003 authored Sep 1, 2024
2 parents 04277ed + 76644de commit c2f0980
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 11 deletions.
4 changes: 3 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@

<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. -->
<!-- https://stackoverflow.com/questions/27396892/what-are-advantages-of-setting-largeheap-to-true -->
<application
Expand All @@ -130,7 +132,7 @@
android:hardwareAccelerated="true"
android:icon="${icon}"
android:label="${appName}"
android:largeHeap="false"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/AppTheme"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.media.projection.MediaProjectionManager;

import org.autojs.autojs.app.OnActivityResultDelegate;
import org.autojs.autojs.util.ForegroundServiceUtils;

/**
* Created by Stardust on May 17, 2017.
Expand Down Expand Up @@ -46,9 +47,18 @@ public void request() {
public void onActivityResult(int requestCode, int resultCode, Intent data) {
mResult = data;
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 {
Expand All @@ -75,7 +85,5 @@ public void cancel() {
if (mCallback != null)
mCallback.onRequestResult(Activity.RESULT_CANCELED, null);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import org.autojs.autojs.AbstractAutoJs;
import org.autojs.autojs.app.OnActivityResultDelegate;
import org.autojs.autojs.util.ForegroundServiceUtils;

public class ScreenCaptureRequesterImpl extends ScreenCaptureRequester.AbstractScreenCaptureRequester {

Expand All @@ -25,8 +24,6 @@ public void setOnActivityResultCallback(Callback callback) {

@Override
public void request() {
ForegroundServiceUtils.requestIfNeeded(mAutoJs.getApplicationContext(), ScreenCapturerForegroundService.class);

Activity activity = mAutoJs.getAppUtils().getCurrentActivity();

if (activity instanceof OnActivityResultDelegate.DelegateHost) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;

Expand Down Expand Up @@ -38,7 +39,7 @@ public void onCreate() {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
return new Binder();
}

private void startForeground() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class MainActivityForegroundService : Service() {
.create()

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 {
ForegroundServiceUtils.startForeground(foregroundServiceCreator)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.IBinder;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand All @@ -36,6 +38,23 @@ public static void request(Context context, Class<?> className) {
}
}

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) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return context.startForegroundService(getService(context, className)) != null;
Expand Down

0 comments on commit c2f0980

Please sign in to comment.