Приложение крашится, если человек не дал доступ к изображению на экране
Я пишу приложение для записи экрана. В нём я прошу все разрешения и доступ к записи, но когда нажимается непосредственно кнопка начала записи, андроид ещё раз спрашивает пользователя о том чтобы предоставлять доступ (картинка снизу)
Если пользователь нажмёт отмена то ошибку поймает onActivityResult() и выведет специальной тост, но если человек опять нажмет на кнопку начать запись, то приложение крашнится и выдаст вот эту ошибку (ошибка снизу)
E/MediaRecorder: video source has already been set
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.screen_recording, PID: 24608
java.lang.IllegalStateException
at android.media.MediaRecorder.setVideoSource(Native Method)
at com.example.screen_recording.screens.main.MainFragment.initRecorder(MainFragment.java:245)
at com.example.screen_recording.screens.main.MainFragment.toggleScreenShare(MainFragment.java:188)
at com.example.screen_recording.screens.main.MainFragment.access$300(MainFragment.java:52)
at com.example.screen_recording.screens.main.MainFragment$1.onClick(MainFragment.java:150)
at android.view.View.performClick(View.java:5647)
at android.widget.CompoundButton.performClick(CompoundButton.java:122)
at android.view.View$PerformClick.run(View.java:22465)
at android.os.Handler.handleCallback(Handler.java:754)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:163)
at android.app.ActivityThread.main(ActivityThread.java:6238)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:933)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
Вот мой фрагмент, где происходит вся логика приложения
public class MainFragment extends Fragment {
private static final int REQUEST_CODE = 1000;
private static final int REQUEST_PERMISSION = 1001;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private boolean isRecord = false;
private boolean isPause = false;
private String videoUri = "";
private MediaProjectionManager mediaProjectionManager;
private MediaProjection mediaProjection;
private VirtualDisplay virtualDisplay;
private MediaProjectionCallBack mediaProjectionCallBack;
private MediaRecorder mediaRecorder;
private int mScreenDensity;
private static int DISPLAY_WIDTH;
private static int DISPLAY_HEIGHT;
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
//View
private CardView rootLayout;
private VideoView videoView;
private ImageButton imageTogglePauseAndResume;
private ToggleButton toggleButton;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
mScreenDensity = metrics.densityDpi;
DISPLAY_WIDTH = metrics.widthPixels;
DISPLAY_HEIGHT = metrics.heightPixels;
mediaRecorder = new MediaRecorder();
mediaProjectionManager = (MediaProjectionManager) getActivity().getBaseContext().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
// View
videoView = view.findViewById(R.id.videoView);
rootLayout = view.findViewById(R.id.cardView);
imageTogglePauseAndResume = view.findViewById(R.id.imageTogglePauseAndResume);
toggleButton = view.findViewById(R.id.toggleButton);
// Event
//Record Start and Stop
toggleButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(getActivity().getBaseContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ ContextCompat.checkSelfPermission(getActivity().getBaseContext(), Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
isRecord = false;
toggleButton.setChecked(false);
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
|| ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.RECORD_AUDIO)) {
isRecord = false;
toggleButton.setChecked(false);
Snackbar.make(rootLayout, "Разрешения", Snackbar.LENGTH_INDEFINITE)
.setAction("Включить", new View.OnClickListener() {
@Override
public void onClick(View v) {
ActivityCompat.requestPermissions(getActivity(),
new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO
}, REQUEST_PERMISSION);
}
}).show();
} else {
ActivityCompat.requestPermissions(getActivity(),
new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO
}, REQUEST_PERMISSION);
}
} else {
toggleScreenShare(toggleButton);
}
}
});
// Pause and Resume record
imageTogglePauseAndResume.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onClick(View v) {
if (isRecord) {
if (!isPause) {
mediaRecorder.pause();
isPause = true;
imageTogglePauseAndResume.setImageResource(R.drawable.pause);
} else {
mediaRecorder.resume();
isPause = false;
imageTogglePauseAndResume.setImageResource(R.drawable.play);
}
} else {
Snackbar.make(rootLayout, "Включите запись перед тем как её останавливать", Snackbar.LENGTH_SHORT)
.show();
}
}
});
return view;
}
private void toggleScreenShare(View v) {
SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(getActivity().getBaseContext());
if (((ToggleButton) v).isChecked()) {
int quality = p.getInt("quality", 480);
boolean micro = p.getBoolean("micro", false);
int fps = p.getInt("FPS", 15);
initRecorder(quality, micro, fps);
recorderScreen();
isRecord = true;
p.edit().putBoolean("isRecord", isRecord).apply();
} else {
mediaRecorder.stop();
mediaRecorder.reset();
stopRecordScreen();
videoView.setVisibility(View.VISIBLE);
videoView.setVideoURI(Uri.parse(videoUri));
videoView.start();
isRecord = false;
p.edit().putBoolean("isRecord", isRecord).apply();
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void recorderScreen() {
if (mediaProjection == null) {
startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
return;
}
virtualDisplay = createVirtualDisplay();
mediaRecorder.start();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private VirtualDisplay createVirtualDisplay() {
return mediaProjection.createVirtualDisplay("MainFragment", DISPLAY_WIDTH, DISPLAY_HEIGHT, mScreenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mediaRecorder.getSurface(), null, null);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initRecorder(int QUALITY, boolean isMicro, int fps) {
try {
CamcorderProfile cpHigh;
switch (QUALITY) {
case 1080:
cpHigh = CamcorderProfile.get(CamcorderProfile.QUALITY_1080P);
break;
case 720:
cpHigh = CamcorderProfile.get(CamcorderProfile.QUALITY_720P);
break;
default:
cpHigh = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
break;
}
if (isMicro) {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
}
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
if (isMicro) {
mediaRecorder.setAudioSamplingRate(44100);
mediaRecorder.setAudioEncodingBitRate(16 * 44100);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
}
videoUri = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
+ new StringBuilder("/FreeRecord_").append(new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss")
.format(new Date())).append(".mp4").toString();
mediaRecorder.setOutputFile(videoUri);
mediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setVideoEncodingBitRate(cpHigh.videoBitRate);
mediaRecorder.setCaptureRate(fps);
mediaRecorder.setVideoFrameRate(fps);
int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
int orientation = ORIENTATIONS.get(rotation + 90);
mediaRecorder.setOrientationHint(orientation);
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != REQUEST_CODE) {
Toast.makeText(getActivity().getBaseContext(), "Unk error", Toast.LENGTH_SHORT).show();
isRecord = false;
toggleButton.setChecked(false);
return;
}
if (resultCode != Activity.RESULT_OK) {
Toast.makeText(getActivity().getBaseContext(), "Доступ запрещен", Toast.LENGTH_SHORT).show();
isRecord = false;
toggleButton.setChecked(false);
return;
}
mediaProjectionCallBack = new MediaProjectionCallBack();
if (data != null) {
mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
mediaProjection.registerCallback(mediaProjectionCallBack, null);
virtualDisplay = createVirtualDisplay();
mediaRecorder.start();
} else {
Toast.makeText(getActivity().getBaseContext(), "Не удалось запустить запись", Toast.LENGTH_SHORT).show();
Log.i("dataActivity", "data = null");
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private class MediaProjectionCallBack extends MediaProjection.Callback {
@Override
public void onStop() {
if (toggleButton.isChecked()) {
isRecord = false;
toggleButton.setChecked(false);
mediaRecorder.stop();
mediaRecorder.reset();
}
mediaProjection = null;
stopRecordScreen();
super.onStop();
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void stopRecordScreen() {
if (virtualDisplay == null) {
return;
}
virtualDisplay.release();
destroyMediaProject();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void destroyMediaProject() {
if (mediaProjection != null) {
mediaProjection.unregisterCallback(mediaProjectionCallBack);
mediaProjection.stop();
mediaProjection = null;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_PERMISSION: {
if ((grantResults.length > 0) && (grantResults[0] + grantResults[1] == PackageManager.PERMISSION_GRANTED)) {
toggleScreenShare(toggleButton);
} else {
isRecord = false;
toggleButton.setChecked(false);
Snackbar.make(rootLayout, "Права доступа", Snackbar.LENGTH_INDEFINITE)
.setAction("Включить", new View.OnClickListener() {
@Override
public void onClick(View v) {
ActivityCompat.requestPermissions(getActivity(),
new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO
}, REQUEST_PERMISSION);
}
}).show();
}
return;
}
}
}
}
Надеюсь на вашу помощь
