Unable To start mediaprojection twise

1

hey there i have a complete running app witch starts capturing screen contents from a foreground service however it's crash when i attempt to record for second time after stopping

here's the the whole scenario: i'm starting a foreground service from main activity like this:

 @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (resultCode == RESULT_CANCELED && requestCode == Const.SCREEN_RECORD_REQUEST_CODE) {
        Toast.makeText(this,
                getString(R.string.screen_recording_permission_denied), Toast.LENGTH_SHORT).show();
        if (getIntent().getAction().equals(getString(R.string.app_shortcut_action)))
            finish();
        return;

    }

    Intent recorderService = new Intent(this, IZIGaapsRecordingSession.class);
    recorderService.putExtra(Const.RECORDER_INTENT_DATA, data);
    recorderService.putExtra(Const.RECORDER_INTENT_RESULT, resultCode);
    recorderService.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
    startService(recorderService);
    finish();
}

and then the service is like this:

 @Override
public int onStartCommand(Intent intent, int flags, int startId) {

    if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
        data = intent.getParcelableExtra(Const.RECORDER_INTENT_DATA);
        result = intent.getIntExtra(Const.RECORDER_INTENT_RESULT, Activity.RESULT_OK);

            Intent recordStartIntent = new Intent(this, IZIGaapsRecordingSession.class);
            recordStartIntent.setAction(Const.SCREEN_RECORDING_START);
            PendingIntent precordStartIntent = PendingIntent.getService(this, 0, recordStartIntent, 0);
            NotificationCompat.Action action = new NotificationCompat.Action(R.drawable.ic_pause_black_24dp,
                    getString(R.string.screen_notification_action_start), precordStartIntent);
            startNotificationForeGround(createRecordingNotification(action).build(), Const.SCREEN_RECORDER_NOTIFICATION_ID);

    switch (intent.getAction()) {
        case Const.SCREEN_RECORDING_START:
            if (!isRecording) {
                getValues();

                        startRecording();
                }

            } else {

                Toast.makeText(this, R.string.screenrecording_already_active_toast, Toast.LENGTH_SHORT).show();
            }
            break;
        case Const.SCREEN_RECORDING_PAUSE:
            pauseScreenRecording();
            break;
        case Const.SCREEN_RECORDING_RESUME:
            resumeScreenRecording();
            break;
        case Const.SCREEN_RECORDING_STOP:

            stopScreenSharing();
            stopForeground(true);
            break;
    }
    return START_STICKY;
}

@TargetApi(24)
private void pauseScreenRecording() {
    mMediaRecorder.pause();
    elapsedTime += (System.currentTimeMillis() - startTime);

    Intent recordResumeIntent = new Intent(this, IZIGaapsRecordingSession.class);
    recordResumeIntent.setAction(Const.SCREEN_RECORDING_RESUME);
    PendingIntent precordResumeIntent = PendingIntent.getService(this, 0, recordResumeIntent, 0);
    NotificationCompat.Action action = new NotificationCompat.Action(android.R.drawable.ic_media_play,
            getString(R.string.screen_recording_notification_action_resume), precordResumeIntent);
    updateNotification(createRecordingNotification(action).setUsesChronometer(false).build(), Const.SCREEN_RECORDER_NOTIFICATION_ID);
    //Toast.makeText(this, R.string.screen_recording_paused_toast, Toast.LENGTH_SHORT).show();
}

@TargetApi(24)
private void resumeScreenRecording() {
    mMediaRecorder.resume();
    startTime = System.currentTimeMillis();
    Intent recordPauseIntent = new Intent(this, IZIGaapsRecordingSession.class);
    recordPauseIntent.setAction(Const.SCREEN_RECORDING_PAUSE);
    PendingIntent precordPauseIntent = PendingIntent.getService(this, 0, recordPauseIntent, 0);
    NotificationCompat.Action action = new NotificationCompat.Action(android.R.drawable.ic_media_pause,
            getString(R.string.screen_recording_notification_action_pause), precordPauseIntent);
    updateNotification(createRecordingNotification(action).setUsesChronometer(true)
            .setWhen((System.currentTimeMillis() - elapsedTime)).build(), Const.SCREEN_RECORDER_NOTIFICATION_ID);
}

private void startRecording() {
    mMediaRecorder = new MediaRecorder();
    initRecorder();

    mMediaProjectionCallback = new MediaProjectionCallback();
    MediaProjectionManager mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);

    mMediaProjection = mProjectionManager.getMediaProjection(result, data);
    mMediaProjection.registerCallback(mMediaProjectionCallback, null);
    if (mVirtualDisplay == null)
        mVirtualDisplay = createVirtualDisplay();

    try {
        mMediaRecorder.start();
        isRecording = true;

    } catch (IllegalStateException e){
        isRecording = false;
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        startTime = System.currentTimeMillis();
        Intent recordPauseIntent = new Intent(this, IZIGaapsRecordingSession.class);
        recordPauseIntent.setAction(Const.SCREEN_RECORDING_PAUSE);
        PendingIntent precordPauseIntent = PendingIntent.getService(this, 0, recordPauseIntent, 0);
        NotificationCompat.Action action = new NotificationCompat.Action(android.R.drawable.ic_media_pause,
                getString(R.string.screen_recording_notification_action_pause), precordPauseIntent);
        startNotificationForeGround(createRecordingNotification(action).build(), Const.SCREEN_RECORDER_NOTIFICATION_ID);
    }else if (isRecording) {
        stopScreenRecording();
    }
}

private void stopScreenRecording() {
    Intent recordStopIntent = new Intent(this, IZIGaapsRecordingSession.class);
    recordStopIntent.setAction(Const.SCREEN_RECORDING_STOP);
    PendingIntent precordStopIntent = PendingIntent.getService(this, 0, recordStopIntent, 0);
    NotificationCompat.Action action = new NotificationCompat.Action(R.drawable.ic_notification_stop,
            getString(R.string.screen_recording_notification_action_stop), precordStopIntent);
    updateNotification(createRecordingNotification(action).build(), Const.SCREEN_RECORDER_NOTIFICATION_ID);
}


private VirtualDisplay createVirtualDisplay() {
    return mMediaProjection.createVirtualDisplay("IZIGaapsMain",
            WIDTH, HEIGHT, DENSITY_DPI,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            mMediaRecorder.getSurface(), null , null);
}

private void initRecorder() {
    try {
        if (mustRecAudio)
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mMediaRecorder.setOutputFile(SAVEPATH);
        mMediaRecorder.setVideoSize(WIDTH, HEIGHT);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        if (mustRecAudio)
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mMediaRecorder.setVideoEncodingBitRate(BITRATE);
        mMediaRecorder.setVideoFrameRate(FPS);
        int rotation = window.getDefaultDisplay().getRotation();
        int orientation = ORIENTATIONS.get(rotation + 90);
        mMediaRecorder.setOrientationHint(orientation);
        mMediaRecorder.prepare();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private NotificationCompat.Builder createRecordingNotification(NotificationCompat.Action action) {
    Bitmap icon = BitmapFactory.decodeResource(getResources(),
            R.drawable.rec_icon);

    Intent UIIntent = new Intent(this, IZIGaapsMain.class);
    PendingIntent notificationContentIntent = PendingIntent.getActivity(this, 0, UIIntent, 0);

    NotificationCompat.Builder notification = new NotificationCompat.Builder(this, Const.RECORDING_NOTIFICATION_CHANNEL_ID)
            .setContentTitle(getResources().getString(R.string.screen_recording_notification_title))
            .setTicker(getResources().getString(R.string.screen_recording_notification_title))
            .setSmallIcon(R.drawable.rec_icon)
            .setLargeIcon(
                    Bitmap.createScaledBitmap(icon, 128, 128, false))
            .setPriority(Notification.PRIORITY_MIN);
           /* .addAction(R.drawable.ic_pause_black_24dp, getResources().getString(R.string.screen_notification_action_start),
                    precordStartIntent); */
    if (action != null)
        notification.addAction(action);
    return notification;
}

private void startNotificationForeGround(Notification notification, int ID) {
    startForeground(ID, notification);
}

private void updateNotification(Notification notification, int ID) {
    getManager().notify(ID, notification);
}

private NotificationManager getManager() {
    if (mNotificationManager == null) {
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    }
    return mNotificationManager;
}

@Override
public void onDestroy() {
    super.onDestroy();
    stopScreenSharing();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

public void getValues() {

    prefs = PreferenceManager.getDefaultSharedPreferences(this);
    String res = prefs.getString(getString(R.string.res_key), getResolution());
    setWidthHeight(res);
    FPS = Integer.parseInt(prefs.getString(getString(R.string.fps_key), "30"));
    BITRATE = Integer.parseInt(prefs.getString(getString(R.string.bitrate_key), "7130317"));
    mustRecAudio = prefs.getBoolean(getString(R.string.audiorec_key), false);
    String saveLocation = prefs.getString(getString(R.string.savelocation_key),
            Environment.getExternalStorageDirectory() + File.separator + Const.APPDIR);
    File saveDir = new File(saveLocation);
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) && !saveDir.isDirectory()) {
        saveDir.mkdirs();
    }
    useFloatingControls = prefs.getBoolean(getString(R.string.preference_floating_control_key), false);
    counters = prefs.getInt("key",0);
    SAVEPATH = saveLocation + File.separator + "Recording" + "- " + counters + ".mp4";
}

private void setWidthHeight(String res) {
    String[] widthHeight = res.split("x");
    WIDTH = Integer.parseInt(widthHeight[0]);
    HEIGHT = Integer.parseInt(widthHeight[1]);
}

private String getResolution() {
    DisplayMetrics metrics = new DisplayMetrics();
    window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    window.getDefaultDisplay().getMetrics(metrics);
    DENSITY_DPI = metrics.densityDpi;
    int width = metrics.widthPixels;
    int height = metrics.heightPixels;
    return width + "x" + height;
}

private void destroyMediaProjection() {
    try {
        mMediaRecorder.stop();
        indexFile();
    } catch (RuntimeException e) {
        if (new File(SAVEPATH).delete())
        Toast.makeText(this, getString(R.string.fatal_exception_message), Toast.LENGTH_SHORT).show();
    } finally {
        mMediaRecorder.reset();
        mVirtualDisplay.release();
        mVirtualDisplay = null;
        mMediaRecorder.release();
        if (mMediaProjection != null) {
            mMediaProjection.unregisterCallback(mMediaProjectionCallback);
            mMediaProjection.stop();
            mMediaProjection = null;
        }
    }
    isRecording = false;
    Intent recordStartIntent = new Intent(this, IZIGaapsRecordingSession.class);
    recordStartIntent.setAction(Const.SCREEN_RECORDING_START);
    PendingIntent precordStartIntent = PendingIntent.getService(this, 0, recordStartIntent, 0);
    NotificationCompat.Action action = new NotificationCompat.Action(R.drawable.ic_pause_black_24dp,
            getString(R.string.screen_notification_action_start), precordStartIntent);
    updateNotification(createRecordingNotification(action).build(), Const.SCREEN_RECORDER_NOTIFICATION_ID);
}

private void indexFile() {
    ArrayList<String> toBeScanned = new ArrayList<>();
    toBeScanned.add(SAVEPATH);
    String[] toBeScannedStr = new String[toBeScanned.size()];
    toBeScannedStr = toBeScanned.toArray(toBeScannedStr);

    MediaScannerConnection.scanFile(this, toBeScannedStr, null, (path, uri) -> {
        Message message = mHandler.obtainMessage();
        message.sendToTarget();
        stopSelf();
    });
}

Handler mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message message) {
    }
};

private void stopScreenSharing() {
    if (mVirtualDisplay == null) {
        return;
    }
    destroyMediaProjection();
    counters = counters + 1;
    prefs.edit().putInt("key", counters).apply();
}

private class MediaProjectionCallback extends MediaProjection.Callback {
    @Override
    public void onStop() {
        stopScreenSharing();
    }
} 

}

however its crashing with this logcat error

12-06 19:49:03.681 9454-9454/com.IZIGaaps.MyRecorder E/AndroidRuntime: FATAL EXCEPTION: main
                                                                   Process: com.IZIGaaps.MyRecorder, PID: 9454
                                                                   java.lang.RuntimeException: Unable to start service com.IZIGaaps.MyRecorder.IZIGaapsRecordingSession@859c9ab with Intent { act=com.IZIGaaps.MyRecorder.services.action.startrecording flg=0x10000000 cmp=com.IZIGaaps.MyRecorder/.IZIGaapsRecordingSession VirtualScreenParam=Params{mDisplayId=-1, null, mFlags=0x00000000)} bnds=[743,691][1075,805] }: 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 android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4150)
                                                                       at android.app.ActivityThread.access$2400(ActivityThread.java:230)
                                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1925)
                                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                       at android.os.Looper.loop(Looper.java:148)
                                                                       at android.app.ActivityThread.main(ActivityThread.java:7409)
                                                                       at java.lang.reflect.Method.invoke(Native Method)
                                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
                                                                    Caused by: 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.IZIGaaps.MyRecorder.IZIGaapsRecordingSession.createVirtualDisplay(IZIGaapsRecordingSession.java:321)
                                                                       at com.IZIGaaps.MyRecorder.IZIGaapsRecordingSession.startRecording(IZIGaapsRecordingSession.java:276)
                                                                       at com.IZIGaaps.MyRecorder.IZIGaapsRecordingSession.onStartCommand(IZIGaapsRecordingSession.java:194)
                                                                       at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4133)
                                                                       at android.app.ActivityThread.access$2400(ActivityThread.java:230) 
                                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1925) 
                                                                       at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                       at android.os.Looper.loop(Looper.java:148) 
                                                                       at android.app.ActivityThread.main(ActivityThread.java:7409) 
                                                                       at java.lang.reflect.Method.invoke(Native Method) 
                                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
                                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 

dont know wheres the problem i already know about nullpointers and i did something about it but that doesnt worked

btw any help wil greatly appreciated

android
nullpointerexception
android-notifications
foreground-service
android-mediaprojection
asked on Stack Overflow Dec 6, 2017 by pourya011 • edited Dec 6, 2017 by pourya011

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0