The thing is I want to write an app to capture audio and process it in the background with foreground service, start with a button on MainActivity and it's here. I want to add the ability to take a screenshot, I've found this question, through which I found the example here.This template uses mediaproject to do it and whenever I press the icon to start it my MainActivity doesn't show up that the app will start running In the background, right. Is there any other way to start screenshot from button on MainActivity(or how to continuous shooting screen),If possible I can completely capture the screen continuously.
PS:I searched but still don't know where to do it is probably because of using onActivityResult
,
Here is the code that capture screen with mediaproject:
MainActivity.java
package com.commonsware.android.andshooter;
import android.app.Activity;
import android.content.Intent;
import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
public class MainActivity extends Activity {
private static final int REQUEST_SCREENSHOT=59706;
private MediaProjectionManager mgr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mgr=(MediaProjectionManager)getSystemService(MEDIA_PROJECTION_SERVICE);
startActivityForResult(mgr.createScreenCaptureIntent(),
REQUEST_SCREENSHOT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode==REQUEST_SCREENSHOT) {
if (resultCode==RESULT_OK) {
Intent i=
new Intent(this, ScreenshotService.class)
.putExtra(ScreenshotService.EXTRA_RESULT_CODE, resultCode)
.putExtra(ScreenshotService.EXTRA_RESULT_INTENT, data);
startService(i);
}
}
finish();
}
}
ImageTransmogrifier.java
package com.commonsware.android.andshooter;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.media.Image;
import android.media.ImageReader;
import android.view.Display;
import android.view.Surface;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
public class ImageTransmogrifier implements ImageReader.OnImageAvailableListener {
private final int width;
private final int height;
private final ImageReader imageReader;
private final ScreenshotService svc;
private Bitmap latestBitmap=null;
ImageTransmogrifier(ScreenshotService svc) {
this.svc=svc;
Display display=svc.getWindowManager().getDefaultDisplay();
Point size=new Point();
display.getRealSize(size);
int width=size.x;
int height=size.y;
while (width*height > (2<<19)) {
width=width>>1;
height=height>>1;
}
this.width=width;
this.height=height;
imageReader=ImageReader.newInstance(width, height,
PixelFormat.RGBA_8888, 2);
imageReader.setOnImageAvailableListener(this, svc.getHandler());
}
@Override
public void onImageAvailable(ImageReader reader) {
final Image image=imageReader.acquireLatestImage();
if (image!=null) {
Image.Plane[] planes=image.getPlanes();
ByteBuffer buffer=planes[0].getBuffer();
int pixelStride=planes[0].getPixelStride();
int rowStride=planes[0].getRowStride();
int rowPadding=rowStride - pixelStride * width;
int bitmapWidth=width + rowPadding / pixelStride;
if (latestBitmap == null ||
latestBitmap.getWidth() != bitmapWidth ||
latestBitmap.getHeight() != height) {
if (latestBitmap != null) {
latestBitmap.recycle();
}
latestBitmap=Bitmap.createBitmap(bitmapWidth,
height, Bitmap.Config.ARGB_8888);
}
latestBitmap.copyPixelsFromBuffer(buffer);
image.close();
ByteArrayOutputStream baos=new ByteArrayOutputStream();
Bitmap cropped=Bitmap.createBitmap(latestBitmap, 0, 0,
width, height);
cropped.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] newPng=baos.toByteArray();
svc.processImage(newPng);
}
}
Surface getSurface() {
return(imageReader.getSurface());
}
int getWidth() {
return(width);
}
int getHeight() {
return(height);
}
void close() {
imageReader.close();
}
}
ScreenshotService.java
package com.commonsware.android.andshooter;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.ToneGenerator;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.view.WindowManager;
import java.io.File;
import java.io.FileOutputStream;
public class ScreenshotService extends Service {
private static final String CHANNEL_WHATEVER="channel_whatever";
private static final int NOTIFY_ID=9906;
static final String EXTRA_RESULT_CODE="resultCode";
static final String EXTRA_RESULT_INTENT="resultIntent";
static final String ACTION_RECORD=
BuildConfig.APPLICATION_ID+".RECORD";
static final String ACTION_SHUTDOWN=
BuildConfig.APPLICATION_ID+".SHUTDOWN";
static final int VIRT_DISPLAY_FLAGS=
DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
private MediaProjection projection;
private VirtualDisplay vdisplay;
final private HandlerThread handlerThread=
new HandlerThread(getClass().getSimpleName(),
android.os.Process.THREAD_PRIORITY_BACKGROUND);
private Handler handler;
private MediaProjectionManager mgr;
private WindowManager wmgr;
private ImageTransmogrifier it;
private int resultCode;
private Intent resultData;
final private ToneGenerator beeper=
new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
@Override
public void onCreate() {
super.onCreate();
mgr=(MediaProjectionManager)getSystemService(MEDIA_PROJECTION_SERVICE);
wmgr=(WindowManager)getSystemService(WINDOW_SERVICE);
handlerThread.start();
handler=new Handler(handlerThread.getLooper());
}
@Override
public int onStartCommand(Intent i, int flags, int startId) {
if (i.getAction()==null) {
resultCode=i.getIntExtra(EXTRA_RESULT_CODE, 1337);
resultData=i.getParcelableExtra(EXTRA_RESULT_INTENT);
foregroundify();
}
else if (ACTION_RECORD.equals(i.getAction())) {
if (resultData!=null) {
startCapture();
}
else {
Intent ui=
new Intent(this, MainActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(ui);
}
}
else if (ACTION_SHUTDOWN.equals(i.getAction())) {
beeper.startTone(ToneGenerator.TONE_PROP_NACK);
stopForeground(true);
stopSelf();
}
return(START_NOT_STICKY);
}
@Override
public void onDestroy() {
stopCapture();
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
throw new IllegalStateException("Binding not supported. Go away.");
}
WindowManager getWindowManager() {
return(wmgr);
}
Handler getHandler() {
return(handler);
}
void processImage(final byte[] png) {
new Thread() {
@Override
public void run() {
File output=new File(getExternalFilesDir(null),
"screenshot.png");
try {
FileOutputStream fos=new FileOutputStream(output);
fos.write(png);
fos.flush();
fos.getFD().sync();
fos.close();
MediaScannerConnection.scanFile(ScreenshotService.this,
new String[] {output.getAbsolutePath()},
new String[] {"image/png"},
null);
}
catch (Exception e) {
Log.e(getClass().getSimpleName(), "Exception writing out screenshot", e);
}
}
}.start();
beeper.startTone(ToneGenerator.TONE_PROP_ACK);
stopCapture();
}
private void stopCapture() {
if (projection!=null) {
projection.stop();
vdisplay.release();
projection=null;
}
}
private void startCapture() {
projection=mgr.getMediaProjection(resultCode, resultData);
it=new ImageTransmogrifier(this);
MediaProjection.Callback cb=new MediaProjection.Callback() {
@Override
public void onStop() {
vdisplay.release();
}
};
vdisplay=projection.createVirtualDisplay("andshooter",
it.getWidth(), it.getHeight(),
getResources().getDisplayMetrics().densityDpi,
VIRT_DISPLAY_FLAGS, it.getSurface(), null, handler);
projection.registerCallback(cb, handler);
}
private void foregroundify() {
NotificationManager mgr=
(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O &&
mgr.getNotificationChannel(CHANNEL_WHATEVER)==null) {
mgr.createNotificationChannel(new NotificationChannel(CHANNEL_WHATEVER,
"Whatever", NotificationManager.IMPORTANCE_DEFAULT));
}
NotificationCompat.Builder b=
new NotificationCompat.Builder(this, CHANNEL_WHATEVER);
b.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL);
b.setContentTitle(getString(R.string.app_name))
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker(getString(R.string.app_name));
b.addAction(R.drawable.ic_record_white_24dp,
getString(R.string.notify_record),
buildPendingIntent(ACTION_RECORD));
b.addAction(R.drawable.ic_eject_white_24dp,
getString(R.string.notify_shutdown),
buildPendingIntent(ACTION_SHUTDOWN));
startForeground(NOTIFY_ID, b.build());
}
private PendingIntent buildPendingIntent(String action) {
Intent i=new Intent(this, getClass());
i.setAction(action);
return(PendingIntent.getService(this, 0, i, 0));
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.commonsware.android.andshooter"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<activity
android:name=".MainActivity"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ScreenshotService"
android:exported="true" />
</application>
</manifest>
In my application I simply copy the ScreenshotService ImageTransmogrifier file then run it from MainActivity as above.