问题描述
在对该主题进行了大量研究之后,尽管我找到了一些答案,但我不明白MediaProjection API的工作原理.
After doing a lot of research on this topic, though I found a few answers, I could not understand how the MediaProjection API works.
我想从后台服务类中获取设备的屏幕截图.有可能做到这一点.我有一个MainActivity.java,它启动serviceIntent到另一个类,该类是服务(不是活动).因此,我想在此服务类中实现此API.请帮助我
I want to take a screenshot of the device from a background Service class. Is it possible to do it. I have one MainActivity.java which starts a serviceIntent to another class which is a service(not an activity). So I want to implement this API in this service class. Please help me
推荐答案
这是实现这一目标的棘手方法.
This is tricky way to achieve this.
首先,您需要创建透明的背景主题.
First of all you need to create transparent background theme like.
<style name="transparentTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:background">#00000000</item> <!-- Or any transparency or color you need -->
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@android:style/Animation</item>
<item name="android:navigationBarColor" tools:ignore="NewApi">#00000000</item>
<item name="android:statusBarColor" tools:ignore="NewApi">#00000000</item>
</style>
现在您需要添加此主题,将此主题应用于清单文件中的ScreenShotActivity.
Now you need to add this apply this theme on your ScreenShotActivity in Manifest file.
<activity
android:name=".Activities.ScreenShotActivity"
android:theme="@style/transparentTheme" />
<activity
您的ScreenShotActivity类.
Your ScreenShotActivity Class.
public class ScreenShotActivity extends Activity {
private static final int videoTime = 5000;
private static final int REQUEST_CODE = 1000;
private static final int REQUEST_PERMISSION = 1000;
private static final SparseIntArray ORIENTATION = new SparseIntArray();
private MediaProjectionManager mediaProjectionManager;
private MediaProjection mediaProjection;
private VirtualDisplay virtualDisplay;
private ScreenShotActivity.MediaProjectionCallback mediaProjectionCallback;
private MediaRecorder mediaRecorder;
PostWebAPIData postWebAPIData;
private int mScreenDensity;
private static int DISPLAY_WIDTH = 720;
private static int DISPLAY_HEIGHT = 1280;
static {
ORIENTATION.append(Surface.ROTATION_0, 90);
ORIENTATION.append(Surface.ROTATION_90, 0);
ORIENTATION.append(Surface.ROTATION_180, 270);
ORIENTATION.append(Surface.ROTATION_270, 180);
}
private String screenShotUri = "";
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_shot);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void init() {
//Screen tracking Code Started here..............................
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
mScreenDensity = metrics.densityDpi;
postWebAPIData = new PostWebAPIData();
DISPLAY_HEIGHT = metrics.heightPixels;
DISPLAY_WIDTH = metrics.widthPixels;
mediaRecorder = new MediaRecorder();
mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
if (ContextCompat.checkSelfPermission(ScreenShotActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ ContextCompat.checkSelfPermission(ScreenShotActivity.this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(ScreenShotActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ||
ActivityCompat.shouldShowRequestPermissionRationale(ScreenShotActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
} else {
ActivityCompat.requestPermissions(ScreenShotActivity.this, new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO
}, REQUEST_PERMISSION);
}
} else {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
toogleScreenShare();
}
}, 500);
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void toogleScreenShare() {
initRecorder();
recordScreen();
}
public void getPathScreenShot(String filePath) {
FFmpegMediaMetadataRetriever med = new FFmpegMediaMetadataRetriever();
med.setDataSource(filePath);
Bitmap bmp = med.getFrameAtTime(2 * 1000000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
String myPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + new StringBuilder("/screenshot").append(".bmp").toString();
File myDir = new File(myPath);
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Image-" + n + ".jpg";
File file = new File(myDir, fname);
Log.i(TAG, "" + myDir);
if (myDir.exists())
myDir.delete();
try {
FileOutputStream out = new FileOutputStream(myDir);
bmp.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
postScreenShot(myPath);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void recordScreen() {
if (mediaProjection == null) {
startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
} else {
virtualDisplay = createVirtualDisplay();
mediaRecorder.start();
onBackPressed();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mediaRecorder.stop();
mediaRecorder.reset();
stopRecordScreen();
destroyMediaProjection();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
getPathScreenShot(screenShotUri);
}
}, 2000);
}
}, videoTime);
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private VirtualDisplay createVirtualDisplay() {
return mediaProjection.createVirtualDisplay("MainActivity", DISPLAY_WIDTH, DISPLAY_HEIGHT, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mediaRecorder.getSurface(), null, null);
}
private void initRecorder() {
try {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
screenShotUri = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + new StringBuilder("/screenshot").append(".mp4").toString();
mediaRecorder.setOutputFile(screenShotUri);
mediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncodingBitRate(512 * 1000);
mediaRecorder.setVideoFrameRate(5);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
int orientation = ORIENTATION.get(rotation + 90);
mediaRecorder.setOrientationHint(orientation);
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
Log.d("ExceptionOccured", "" + e.getMessage());
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != REQUEST_CODE) {
stopService(new Intent(this, BackgroundService.class));
startService(new Intent(this, BackgroundService.class));
Toast.makeText(ScreenShotActivity.this, "Unknown Error", Toast.LENGTH_SHORT).show();
Log.d("Livetracking", "ScreenShot" + requestCode + " " + resultCode + " " + data);
return;
}
if (resultCode != RESULT_OK) {
stopService(new Intent(this, BackgroundService.class));
startService(new Intent(this, BackgroundService.class));
Toast.makeText(ScreenShotActivity.this, "Permission denied" + requestCode, Toast.LENGTH_SHORT).show();
Log.d("Livetracking", "Screenshot" + requestCode + " " + resultCode + " " + data);
return;
}
Log.d("Livetracking", "Screenshot" + requestCode + " " + resultCode + " " + data);
mediaProjectionCallback = new ScreenShotActivity.MediaProjectionCallback();
mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
mediaProjection.registerCallback(mediaProjectionCallback, null);
virtualDisplay = createVirtualDisplay();
mediaRecorder.start();
onBackPressed();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mediaRecorder.stop();
mediaRecorder.reset();
stopRecordScreen();
destroyMediaProjection();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
getPathScreenShot(screenShotUri);
}
}, 2000);
}
}, videoTime);
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
if (am != null) {
List<ActivityManager.AppTask> tasks = am.getAppTasks();
if (tasks != null && tasks.size() > 0) {
Log.d("RemovingApp", "recent");
tasks.get(0).setExcludeFromRecents(true);
}
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private class MediaProjectionCallback extends MediaProjection.Callback {
@Override
public void onStop() {
mediaRecorder.stop();
mediaRecorder.reset();
mediaProjection = null;
stopRecordScreen();
destroyMediaProjection();
if (mediaProjection != null) {
destroyMediaProjection();
}
super.onStop();
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void stopRecordScreen() {
if (virtualDisplay == null) {
virtualDisplay.release();
if (mediaProjection != null) {
destroyMediaProjection();
}
return;
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void destroyMediaProjection() {
if (mediaProjection != null) {
mediaProjection.unregisterCallback(mediaProjectionCallback);
mediaProjection.stop();
mediaProjection = null;
}
}
}
在您的清单文件中添加这些权限.
add these permissions in your Manifest file.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
现在神奇的开始是,您需要像这样从服务调用ScreenShotActivity.
Now the magic start here you need to call your ScreenShotActivity from your service like this.
Intent dialogIntent = new Intent(BackgroundService.this, ScreenShotActivity.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(dialogIntent);
这篇关于如何使用MediaProjection API从后台服务类中获取屏幕快照?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!