Задача приложения такова если на моем телефоне открывается приложение вайбер то мое приложение должно делать скриншот с открывшимся вайбером, но после предоставления разрешений к медиа файлам и включения accessibility я запускаю вайбер а мое приложение падает с ошибкой.
Логи
Process: com.buratinoapps.screenshotwindow, PID: 7024
java.lang.NullPointerException: Attempt to invoke virtual method 'android.hardware.display.VirtualDisplay android.media.projection.MediaProjection.createVirtualDisplay(java.lang.String, int, int, int, int, android.view.Surface, android.hardware.display.VirtualDisplay$Callback, android.os.Handler)' on a null object reference
at com.buratinoapps.screenshotwindow.AppMonitorService.captureScreenshot(AppMonitorService.java:78)
at com.buratinoapps.screenshotwindow.AppMonitorService.onAccessibilityEvent(AppMonitorService.java:53)
at android.accessibilityservice.AccessibilityService$2.onAccessibilityEvent(AccessibilityService.java:2081)
at android.accessibilityservice.AccessibilityService$IAccessibilityServiceClientWrapper.executeMessage(AccessibilityService.java:2284)
MainActivity
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_CODE = 123; // Любое уникальное число
@RequiresApi(api = Build.VERSION_CODES.R)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Проверяем, есть ли у приложения необходимые разрешения
if (checkPermissions()) {
// Разрешения уже предоставлены, запускаем службу AppMonitorService
startAppMonitorService();
} else {
// Если разрешения не предоставлены, запрашиваем их у пользователя
requestPermissions();
}
}
@RequiresApi(api = Build.VERSION_CODES.R)
private boolean checkPermissions() {
// Проверяем разрешение на использование PACKAGE_USAGE_STATS
int usageStatsPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.PACKAGE_USAGE_STATS);
// Проверяем разрешение на использование BIND_ACCESSIBILITY_SERVICE
int accessibilityServicePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
// Проверяем разрешение на доступ к медиафайлам
int storagePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// Для Android 11 и выше, используем новый способ запроса разрешения WRITE_EXTERNAL_STORAGE
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
storagePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
int mstoragePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.MANAGE_EXTERNAL_STORAGE);
// Для Android 11 и выше, используем новый способ запроса разрешения WRITE_EXTERNAL_STORAGE
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
mstoragePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.MANAGE_EXTERNAL_STORAGE);
}
return (usageStatsPermission == PackageManager.PERMISSION_GRANTED &&
accessibilityServicePermission == PackageManager.PERMISSION_GRANTED &&
storagePermission == PackageManager.PERMISSION_GRANTED &&
mstoragePermission == PackageManager.PERMISSION_GRANTED);
}
private void requestPermissions() {
// Создаем массив разрешений для запроса
String[] permissionsToRequest = {
Manifest.permission.PACKAGE_USAGE_STATS,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.MANAGE_EXTERNAL_STORAGE // Это разрешение для Android 11 и выше
};
// Запрашиваем разрешения
ActivityCompat.requestPermissions(this, permissionsToRequest, PERMISSION_REQUEST_CODE);
// Запрашиваем разрешение на использование BIND_ACCESSIBILITY_SERVICE
Intent accessibilitySettingsIntent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(accessibilitySettingsIntent);
}
private void startAppMonitorService() {
// Запускаем службу AppMonitorService
Intent serviceIntent = new Intent(this, AppMonitorService.class);
ContextCompat.startForegroundService(this, serviceIntent);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE) {
// Проверяем результат запроса разрешений
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Разрешения предоставлены, запускаем службу AppMonitorService
startAppMonitorService();
} else {
// Разрешения не были предоставлены, обработайте это событие соответствующим образом
// Можете показать сообщение пользователю о необходимости разрешений или завершить приложение
}
}
}
}
AppMonitorService
public class AppMonitorService extends AccessibilityService {
private MediaProjectionManager mediaProjectionManager;
private MediaProjection mediaProjection;
private ImageReader imageReader;
private int screenDensity;
private Handler handler;
private boolean capturingScreenshot = false;
@Override
protected void onServiceConnected() {
super.onServiceConnected();
// Инициализируем MediaProjectionManager
mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
String packageName = event.getPackageName().toString();
if ("com.viber.voip".equals(packageName) && !capturingScreenshot) {
capturingScreenshot = true;
captureScreenshot();
}
}
}
@Override
public void onInterrupt() {
stopScreenCapture();
}
@SuppressLint("WrongConstant")
private void captureScreenshot() {
handler = new Handler();
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
Display display = windowManager.getDefaultDisplay();
display.getMetrics(metrics);
screenDensity = metrics.densityDpi;
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
int imageSize = screenWidth * screenHeight * 4;
imageReader = ImageReader.newInstance(screenWidth, screenHeight, 0x1, 2);
mediaProjection = mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, null);
mediaProjection.createVirtualDisplay("screenshot", screenWidth, screenHeight, screenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, imageReader.getSurface(), null, handler);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
FileOutputStream fos = null;
Bitmap bitmap = null;
try {
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 * image.getWidth();
bitmap = Bitmap.createBitmap(image.getWidth() + rowPadding / pixelStride, image.getHeight(), Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
// Сохранение скриншота в файл
saveScreenshot(bitmap);
if (capturingScreenshot) {
stopScreenCapture();
capturingScreenshot = false;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (image != null) {
image.close();
}
if (fos != null) {
try {
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (bitmap != null) {
bitmap.recycle();
}
}
}
}, handler);
}
private void saveScreenshot(Bitmap bitmap) {
String fileName = "screenshot.png";
File screenshotFile = new File(getFilesDir(), fileName);
try {
FileOutputStream fos = new FileOutputStream(screenshotFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void stopScreenCapture() {
if (mediaProjection != null) {
mediaProjection.stop();
}
if (imageReader != null) {
imageReader.close();
}
}
}