@Chesterfield25

Почему я получаю NullPointerException?

Задача приложения такова если на моем телефоне открывается приложение вайбер то мое приложение должно делать скриншот с открывшимся вайбером, но после предоставления разрешений к медиа файлам и включения 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();
        }
    }
}
  • Вопрос задан
  • 143 просмотра
Пригласить эксперта
Ответы на вопрос 2
@WaterSmith
Android-разработчик. Java, Kotlin
mediaProjection = mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, null);

очевидно что здесь у вас в результате mediaProjection = null
в документации к методу getMediaProjection написано:

Parameters
resultCode int: The result code from onActivityResult(int, int, Intent).
resultData Intent: The result data from onActivityResult(int, int, Intent). This value cannot be null.

т.е. вторым параметром должен быть интент, и прямо сказано что он не может быть null, а вы таки ему пытаетесь подсунуть null.
Ответ написан
402d
@402d
начинал с бейсика на УКНЦ в 1988
createScreenCaptureIntent забыли вызвать. getMediaProjection используется для извлечения данных из интента ответа
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы