I am trying to record calls on Android 8+ but getting error. Below is my code:
File sampleDir = new File(Environment.getExternalStorageDirectory(), "/" + RECORDING_DIRECTORY);
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
String file_name = getRecordingFileName() + "-";
//String file_name = "Record";
try {
audiofile = File.createTempFile(file_name, ".amr", sampleDir);
} catch (IOException e) {
e.printStackTrace();
}
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(audiofile.getAbsolutePath());
try {
recorder.prepare();
recorder.start();
recordstarted = true;
} catch (IllegalStateException e) {
e.printStackTrace();
Log.d(e);
} catch (IOException e) {
e.printStackTrace();
Log.d(e);
} catch (Exception ex) {
Log.d(ex);
}
I get the following error message:
2020-02-20 16:38:37.893 12635-12635/com.companyname.appname
W/System.err: java.lang.IllegalStateException: phoneIsInUse
2020-02-20 16:38:37.894 12635-12635/com.companyname.appname
W/System.err: at
android.media.MediaRecorder.start(MediaRecorder.java:1017)
Has anyone dealt with this or knows what is happening?
For recording Phone Calls on Android 8+.
API level 28 or higher, apps running in the background cannot access the microphone.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
The example activity below shows how to use MediaRecorder to record an audio file. It Also uses MediaPlayer to play the audio back.
public class AudioRecordTest extends AppCompatActivity {
private static final String LOG_TAG = "AudioRecordTest";
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200;
private static String fileName = null;
private RecordButton recordButton = null;
private MediaRecorder recorder = null;
private PlayButton playButton = null;
private MediaPlayer player = null;
// Requesting permission to RECORD_AUDIO
private boolean permissionToRecordAccepted = false;
private String [] permissions = {Manifest.permission.RECORD_AUDIO};
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case REQUEST_RECORD_AUDIO_PERMISSION:
permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
break;
}
if (!permissionToRecordAccepted ) finish();
}
private void onRecord(boolean start) {
if (start) {
startRecording();
} else {
stopRecording();
}
}
private void onPlay(boolean start) {
if (start) {
startPlaying();
} else {
stopPlaying();
}
}
private void startPlaying() {
player = new MediaPlayer();
try {
player.setDataSource(fileName);
player.prepare();
player.start();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
}
private void stopPlaying() {
player.release();
player = null;
}
private void startRecording() {
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setOutputFile(fileName);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
recorder.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
recorder.start();
}
private void stopRecording() {
recorder.stop();
recorder.release();
recorder = null;
}
class RecordButton extends Button {
boolean mStartRecording = true;
OnClickListener clicker = new OnClickListener() {
public void onClick(View v) {
onRecord(mStartRecording);
if (mStartRecording) {
setText("Stop recording");
} else {
setText("Start recording");
}
mStartRecording = !mStartRecording;
}
};
public RecordButton(Context ctx) {
super(ctx);
setText("Start recording");
setOnClickListener(clicker);
}
}
class PlayButton extends Button {
boolean mStartPlaying = true;
OnClickListener clicker = new OnClickListener() {
public void onClick(View v) {
onPlay(mStartPlaying);
if (mStartPlaying) {
setText("Stop playing");
} else {
setText("Start playing");
}
mStartPlaying = !mStartPlaying;
}
};
public PlayButton(Context ctx) {
super(ctx);
setText("Start playing");
setOnClickListener(clicker);
}
}
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Record to the external cache directory for visibility
fileName = getExternalCacheDir().getAbsolutePath();
fileName += "/audiorecordtest.3gp";
ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION);
LinearLayout ll = new LinearLayout(this);
recordButton = new RecordButton(this);
ll.addView(recordButton,
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
0));
playButton = new PlayButton(this);
ll.addView(playButton,
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
0));
setContentView(ll);
}
#Override
public void onStop() {
super.onStop();
if (recorder != null) {
recorder.release();
recorder = null;
}
if (player != null) {
player.release();
player = null;
}
}
}
Make changes according to your project
this code referred from official website for more details follow official website
MediaRecorder overview
Related
I have almost a week figuring out how should I have one instance of exoplayer in background.
I want to use this instance in a playerview and in notification as well. Problem I am facing now, the player plays well, after a time it pauses (to release resource I guess), but when i click play it plays again, when i click other oudio, I get two audio playing at same time.
Here are my codes.
------------------------ BACKGROUND SERVICE --------------------------------------
public class BackgroundPlayingService extends Service {
public static PlayerNotificationManager playerNotificationManager;
public static ExoPlayer exoPlayer;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (this.exoPlayer == null){
createPlayer();
}
/////////////////THIS WAS ADDED LATER
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
exoPlayer.pause();
exoPlayer = null;
playerNotificationManager.setPlayer(null);
}
private void createPlayer(){
exoPlayer = new ExoPlayer.Builder(this).build();
MediaItem mediaItem;
try {
mediaItem = MediaItem.fromUri(Uri.parse(DataUtility.playingUrl));
}catch (Exception e){
mediaItem = MediaItem.fromUri(Uri.parse("https://server13.mp3quran.net/husr/062.mp3"));
}
exoPlayer.setMediaItem(mediaItem);
exoPlayer.prepare();
exoPlayer.addListener(new Player.Listener() {
#Override
public void onPlaybackStateChanged(int playbackState) {
Player.Listener.super.onPlaybackStateChanged(playbackState);
try {
if (ThePlayingActivity.dialog.isShowing()){
ThePlayingActivity.dialog.dismiss();}
}catch (Exception ignore){
}
if (playbackState==Player.STATE_READY){
try {
ThePlayingActivity.downloadBtn.setVisibility(View.VISIBLE);
showNotification();
}catch (Exception ignore){
}
}
if (playbackState == Player.STATE_BUFFERING) {
try {
ThePlayingActivity.myProgress.setVisibility(View.VISIBLE);
}catch (Exception e){
}
} else {
try {
ThePlayingActivity.myProgress.setVisibility(View.GONE);
}catch (Exception e){
}
}
}
#Override
public void onIsLoadingChanged(boolean isLoading) {
Player.Listener.super.onIsLoadingChanged(isLoading);
}
#Override
public void onPlayerError(PlaybackException error) {
Player.Listener.super.onPlayerError(error);
try {
if (ThePlayingActivity.dialog.isShowing()){
ThePlayingActivity.dialog.dismiss();
}
playerNotificationManager.setPlayer(null);
}catch (Exception ignore){
}
}
});
exoPlayer.play();
try {
ThePlayingActivity.myPlayerView.setPlayer(exoPlayer);
}catch (Exception e){
Log.d("background", "createPlayer: set player to view"+e.getLocalizedMessage());
}
}
public static void setNewPlayeData(){
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(DataUtility.playingUrl));
exoPlayer.setMediaItem(mediaItem);
exoPlayer.prepare();
ThePlayingActivity.myPlayerView.setPlayer(exoPlayer);
try {
ThePlayingActivity.myPlayerView.setPlayer(exoPlayer);
}catch (Exception e){
Log.d("background", "createPlayer: set player to view"+e.getLocalizedMessage());
}
}
public void showNotification() {
playerNotificationManager = new PlayerNotificationManager.Builder(this, 151,
this.getResources().getString(R.string.app_name))
.setChannelNameResourceId(R.string.app_name)
.setChannelImportance(IMPORTANCE_HIGH)
.setMediaDescriptionAdapter(new PlayerNotificationManager.MediaDescriptionAdapter() {
#Override
public CharSequence getCurrentContentTitle(Player player) {
return player.getCurrentMediaItem().mediaMetadata.displayTitle;
}
#Nullable
#Override
public PendingIntent createCurrentContentIntent(Player player) {
return null;
}
#Nullable
#Override
public CharSequence getCurrentContentText(Player player) {
return Objects.requireNonNull(player.getCurrentMediaItem()).mediaMetadata.artist;
}
#Nullable
#Override
public Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) {
return null;
}
}).setNotificationListener(new PlayerNotificationManager.NotificationListener() {
#Override
public void onNotificationCancelled(int notificationId, boolean dismissedByUser) {
}
#Override
public void onNotificationPosted(int notificationId, Notification notification, boolean ongoing) {
PlayerNotificationManager.NotificationListener.super.onNotificationPosted(notificationId, notification, ongoing);
}
})
.build();
playerNotificationManager.setUseStopAction(false);
try {
playerNotificationManager.setPlayer(exoPlayer);
}catch (Exception e){
}
}
}
-----------------------HERE IS THE ACTIVITY WITH PLAYER ----------------------------------
public class ThePlayingActivity extends AppCompatActivity {
private static final int PERMISION_STORAGE_CODE = 100;
private ProgressBar downloadingProgress;
public static ProgressBar myProgress;
public static Dialog dialog;
private ConstraintLayout layoutForSnack;
long downloadId;
private PowerManager powerManager;
private PowerManager.WakeLock wakeLock;
String myurl;
public static PlayerControlView myPlayerView;
private TextView currentPlaying, downloadingTv;
public static Button downloadBtn;
private String thePlayingSura;
private final BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1);
if (downloadId == id){
downloadingProgress.setVisibility(View.GONE);
downloadingTv.setVisibility(View.GONE);
downloadBtn.setText("DOWNLOADED");
downloadBtn.setBackgroundColor(Color.TRANSPARENT);
downloadBtn.setTextColor(Color.BLACK);
downloadBtn.setClickable(false);
Toast.makeText(context, "DOWNLOAD COMPLETED", Toast.LENGTH_SHORT).show();
}
}
};
#SuppressLint("SetTextI18n")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_the_playing);
myPlayerView = findViewById(R.id.playerView);
Intent dataIntent = getIntent();
myurl = dataIntent.getStringExtra("theUrl");
if (BackgroundPlayingService.exoPlayer == null){
startService();}else{
BackgroundPlayingService.setNewPlayeData();
myPlayerView.setPlayer(BackgroundPlayingService.exoPlayer);
}
keepActivityAlive();
registerReceiver(onDownloadComplete,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
downloadingProgress = findViewById(R.id.downloadProgress);
downloadingTv = findViewById(R.id.downloadingWaitTv);
currentPlaying = findViewById(R.id.currentPlaying);
downloadBtn = findViewById(R.id.downloadbtn);
downloadBtn.setVisibility(View.GONE);
myProgress = findViewById(R.id.progressBar2);
myProgress.setVisibility(View.GONE);
layoutForSnack = findViewById(R.id.constraintLayout);
downloadingProgress.setVisibility(View.GONE);
downloadingTv.setVisibility(View.GONE);
thePlayingSura = dataIntent.getStringExtra("sendSuraName");
currentPlaying.setText(thePlayingSura+" - " + DataUtility.theKariName);
/////////////end of ids
showLoadingDialog();
/////////////////download
downloadBtn.setOnClickListener(view -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED){
//todo ask permission
String permissions[] = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissions,PERMISION_STORAGE_CODE);
}else{
downloadStaffs();
}
}else {
//TODO DOWNLOAD
downloadStaffs();
}
});
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
}
#Override
public void onBackPressed() {
super.onBackPressed();
//todo fire service (may be)
}
private void showLoadingDialog() {
dialog = new Dialog(ThePlayingActivity.this);
dialog.setContentView(R.layout.dialog_loading_quran);
dialog.setCancelable(false);
dialog.show();
}
private void showSnackBar() {
Snackbar snackbar = Snackbar.make(layoutForSnack, "THERE WAS ON ERROR, CHECK YOUR INTERNET CONNECTION", Snackbar.LENGTH_INDEFINITE);
snackbar.setAction("RETRY", view -> {
});
snackbar.setActionTextColor(Color.YELLOW);
snackbar.show();
}
#Override
protected void onStop() {
super.onStop();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case PERMISION_STORAGE_CODE:{
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
// we have permission
//todo Download
downloadStaffs();
}else{
Toast.makeText(ThePlayingActivity.this , "PERMISSION DENIED... CAN NOT DOWNLOAD", Toast.LENGTH_SHORT).show();
}
}
}
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(onDownloadComplete);
try {
if (wakeLock.isHeld()){
wakeLock.release();}
}catch (Exception ignore){
}
}
private void downloadStaffs(){
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(DataUtility.playingUrl));
request.setDescription("Download File");
request.setTitle(thePlayingSura);
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, thePlayingSura+" - "+ DataUtility.theKariName+".mp3");
final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
final long downloadId = manager.enqueue(request);
this.downloadId = downloadId;
final ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.downloadProgress);
downloadingTv.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
new Thread(new Runnable() {
#SuppressLint("Range")
#Override
public void run() {
boolean downloading = true;
while (downloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
Cursor cursor = manager.query(q);
cursor.moveToFirst();
#SuppressLint("Range") int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
#SuppressLint("Range") int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false;
}
final double dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);
runOnUiThread(new Runnable() {
#Override
public void run() {
mProgressBar.setProgress((int) dl_progress);
}
});
Log.d("MESSAGES", statusMessage(cursor));
cursor.close();
}
}
}).start();
}
#SuppressLint("Range")
private String statusMessage(Cursor c) {
String msg = "???";
switch (c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))) {
case DownloadManager.STATUS_FAILED:
msg = "Download failed!";
break;
case DownloadManager.STATUS_PAUSED:
msg = "Download paused!";
break;
case DownloadManager.STATUS_PENDING:
msg = "Download pending!";
break;
case DownloadManager.STATUS_RUNNING:
msg = "Download in progress!";
break;
case DownloadManager.STATUS_SUCCESSFUL:
msg = "Download complete!";
break;
default:
msg = "Download is nowhere in sight";
break;
}
return (msg);
}
}
private void keepActivityAlive(){
powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"QuranAudio:WakeLock");
}
private void startService(){
Intent i = new Intent(this, BackgroundPlayingService.class);
startService(i);
}
}
I figured it out.
I had to keep most of my business inside in onStartCommand
public class BackgroundPlayingService extends Service {
public static final String TAG = "bck_service";
public static ExoPlayer player;
public static PlayerNotificationManager playerNotificationManager;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String url = DataUtility.playingUrl;
if (url==null){
url = "https://server8.mp3quran.net/afs/Rewayat-AlDorai-A-n-Al-Kisa-ai/025.mp3";
}
if (player == null){
player = createPlayerIfNull();
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(url));
player.setMediaItem(mediaItem);
player.prepare();
player.addListener(new Player.Listener() {
#Override
public void onEvents(Player player, Player.Events events) {
}
#Override
public void onPlaybackStateChanged(int playbackState) {
Player.Listener.super.onPlaybackStateChanged(playbackState);
try {
if (ThePlayingActivity.dialog.isShowing()){
ThePlayingActivity.dialog.dismiss();}
}catch (Exception ignore){
}
if (playbackState==Player.STATE_READY){
try {
ThePlayingActivity.downloadBtn.setVisibility(View.VISIBLE);
showNotification();
}catch (Exception ignore){
}
}
if (playbackState == Player.STATE_BUFFERING) {
try {
ThePlayingActivity.myProgress.setVisibility(View.VISIBLE);
}catch (Exception e){
}
} else {
try {
ThePlayingActivity.myProgress.setVisibility(View.GONE);
}catch (Exception e){
}
}
}
#Override
public void onIsLoadingChanged(boolean isLoading) {
Player.Listener.super.onIsLoadingChanged(isLoading);
}
#Override
public void onPlayerError(PlaybackException error) {
Player.Listener.super.onPlayerError(error);
try {
if (ThePlayingActivity.dialog.isShowing()){
ThePlayingActivity.dialog.dismiss();}
}catch (Exception ignore){
}
}
});
player.play();
try {
ThePlayingActivity.myPlayerView.setPlayer(player);
}catch (Exception ignore){}
}
//notification
createNotificationChannel();
Intent i = new Intent(this,BackgroundPlayingService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,i,0);
Notification notification = new NotificationCompat.Builder(this,"myChannelId")
.setContentTitle("QURAN IS PLAYING")
.setContentText("This means that Qur-an app is open. You can close it from app exit menu")
.setSmallIcon(androidx.core.R.drawable.notification_icon_background)
.setContentIntent(pendingIntent)
.build();
startForeground(1,notification);
return START_STICKY;
}
public ExoPlayer createPlayerIfNull() {
if (player == null) {
player = new ExoPlayer.Builder(BackgroundPlayingService.this).build();
ThePlayingActivity.myProgress.setVisibility(View.VISIBLE);
try {
ThePlayingActivity.dialog.show();
}catch (Exception e){
Log.d(TAG, "createPlayerIfNull: ");
}
}
return player;
}
private void createNotificationChannel(){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel channel = new NotificationChannel("myChannelId","qur-anAudiChannel", NotificationManager.IMPORTANCE_LOW);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
}
#Override
public void onDestroy() {
super.onDestroy();
player.stop();
player = null;
stopForeground(true);
}
public void showNotification() {
playerNotificationManager = new PlayerNotificationManager.Builder(this, 151,
this.getResources().getString(R.string.app_name))
.setChannelNameResourceId(R.string.app_name)
.setChannelImportance(IMPORTANCE_HIGH)
.setMediaDescriptionAdapter(new PlayerNotificationManager.MediaDescriptionAdapter() {
#Override
public CharSequence getCurrentContentTitle(Player player) {
return player.getCurrentMediaItem().mediaMetadata.displayTitle;
}
#Nullable
#Override
public PendingIntent createCurrentContentIntent(Player player) {
return null;
}
#Nullable
#Override
public CharSequence getCurrentContentText(Player player) {
return Objects.requireNonNull(player.getCurrentMediaItem()).mediaMetadata.artist;
}
#Nullable
#Override
public Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) {
return null;
}
}).setNotificationListener(new PlayerNotificationManager.NotificationListener() {
#Override
public void onNotificationCancelled(int notificationId, boolean dismissedByUser) {
}
#Override
public void onNotificationPosted(int notificationId, Notification notification, boolean ongoing) {
PlayerNotificationManager.NotificationListener.super.onNotificationPosted(notificationId, notification, ongoing);
}
})
.build();
playerNotificationManager.setUseStopAction(false);
try {
playerNotificationManager.setPlayer(player);
}catch (Exception e){
}}
}
-------------------- player view activity ------------------------------------
public class ThePlayingActivity extends AppCompatActivity {
private static final int PERMISION_STORAGE_CODE = 100;
private ProgressBar downloadingProgress;
public static ProgressBar myProgress;
public static Dialog dialog;
private ConstraintLayout layoutForSnack;
long downloadId;
private PowerManager powerManager;
private PowerManager.WakeLock wakeLock;
String myurl;
public static PlayerControlView myPlayerView;
private TextView currentPlaying, downloadingTv;
public static Button downloadBtn;
private String thePlayingSura;
private BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (downloadId == id) {
downloadingProgress.setVisibility(View.GONE);
downloadingTv.setVisibility(View.GONE);
downloadBtn.setText("DOWNLOADED");
downloadBtn.setBackgroundColor(Color.TRANSPARENT);
downloadBtn.setTextColor(Color.BLACK);
downloadBtn.setClickable(false);
Toast.makeText(context, "DOWNLOAD COMPLETED", Toast.LENGTH_SHORT).show();
}
}
};
#SuppressLint("StaticFieldLeak")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_the_playing);
myPlayerView = findViewById(R.id.playerView);
Intent dataIntent = getIntent();
myurl = dataIntent.getStringExtra("theUrl");
Intent backgroundPlayIntent = new Intent(ThePlayingActivity.this,BackgroundPlayingService.class);
try {
stopService(backgroundPlayIntent);
}catch (Exception e){}
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
startForegroundService(backgroundPlayIntent);
}else{
startService(backgroundPlayIntent);
}
keepActivityAlive();
registerReceiver(onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
downloadingProgress = findViewById(R.id.downloadProgress);
downloadingTv = findViewById(R.id.downloadingWaitTv);
currentPlaying = findViewById(R.id.currentPlaying);
downloadBtn = findViewById(R.id.downloadbtn);
downloadBtn.setVisibility(View.GONE);
myProgress = findViewById(R.id.progressBar2);
myProgress.setVisibility(View.VISIBLE);
layoutForSnack = findViewById(R.id.constraintLayout);
downloadingProgress.setVisibility(View.GONE);
downloadingTv.setVisibility(View.GONE);
thePlayingSura = dataIntent.getStringExtra("sendSuraName");
currentPlaying.setText(thePlayingSura + " - " + DataUtility.theKariName);
/////////////end of ids
showLoadingDialog();
/////////////////download
downloadBtn.setOnClickListener(view -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
String permissions[] = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissions, PERMISION_STORAGE_CODE);
} else {
downloadStaffs();
}
} else {
downloadStaffs();
}
});
}
private void showLoadingDialog() {
dialog = new Dialog(ThePlayingActivity.this);
dialog.setContentView(R.layout.dialog_loading_quran);
dialog.setCancelable(false);
dialog.show();
}
public void showSnackBar() {
Snackbar snackbar = Snackbar.make(layoutForSnack, "THERE WAS ON ERROR, CHECK YOUR INTERNET CONNECTION", Snackbar.LENGTH_INDEFINITE);
snackbar.setAction("RETRY", view -> {
//todo retry player
});
snackbar.setActionTextColor(Color.YELLOW);
snackbar.show();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISION_STORAGE_CODE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// we have permission
downloadStaffs();
} else {
Toast.makeText(ThePlayingActivity.this, "PERMISSION DENIED... CAN NOT DOWNLOAD", Toast.LENGTH_SHORT).show();
}
}
}
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(onDownloadComplete);
try {
if (wakeLock.isHeld()) {
wakeLock.release();
}
} catch (Exception ignore) {
}
}
private void downloadStaffs() {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(DataUtility.playingUrl));
request.setDescription("Download File");
request.setTitle(thePlayingSura);
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, thePlayingSura + " - " + DataUtility.theKariName + ".mp3");
final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
final long downloadId = manager.enqueue(request);
this.downloadId = downloadId;
final ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.downloadProgress);
downloadingTv.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
new Thread(new Runnable() {
#SuppressLint("Range")
#Override
public void run() {
boolean downloading = true;
while (downloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
Cursor cursor = manager.query(q);
cursor.moveToFirst();
#SuppressLint("Range") int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
#SuppressLint("Range") int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false;
}
final double dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);
runOnUiThread(new Runnable() {
#Override
public void run() {
mProgressBar.setProgress((int) dl_progress);
}
});
Log.d("MESSAGES", statusMessage(cursor));
cursor.close();
}
}
}).start();
}
#SuppressLint("Range")
private String statusMessage(Cursor c) {
String msg = "???";
switch (c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))) {
case DownloadManager.STATUS_FAILED:
msg = "Download failed!";
break;
case DownloadManager.STATUS_PAUSED:
msg = "Download paused!";
break;
case DownloadManager.STATUS_PENDING:
msg = "Download pending!";
break;
case DownloadManager.STATUS_RUNNING:
msg = "Download in progress!";
break;
case DownloadManager.STATUS_SUCCESSFUL:
msg = "Download complete!";
break;
default:
msg = "Download is nowhere in sight";
break;
}
return (msg);
}
private void keepActivityAlive() {
powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "QuranAudio:WakeLock");
}
private void startService() {
Intent i = new Intent(this, BackgroundPlayingService.class);
startService(i);
}}
--------------------- extra --------------------------------------
I also had to create other service to remove notification when the
user kill app by clearing app from recent apps.
here is it
MyAppService extends Service {
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Intent i = new Intent(MyAppService.this,BackgroundPlayingService.class);
try {
BackgroundPlayingService.playerNotificationManager.setPlayer(null);
stopService(i);
}catch (Exception ignore){}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}}
-------------------- WARNING ----------------------------------
I don't take this as a best approach, but it gave me a quick solution while waiting for a better approach.
I will pot the app link here when it's available in playstore.
Here is the code
public class MainActivity extends AppCompatActivity {
ToggleButton toggleButton;
TextView textSubHeader;
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toggleButton = (ToggleButton) findViewById(R.id.toggleButton);
textSubHeader = (TextView) findViewById(R.id.textSubHeader);
// File CallRecorder = new File("/sdcard/CallRecorder");
// CallRecorder.mkdirs();
}
#Override
protected void onResume() {
super.onResume();
// Runtime permission
try {
boolean permissionGranted_OutgoingCalls = ActivityCompat.checkSelfPermission(this, Manifest.permission.PROCESS_OUTGOING_CALLS) == PackageManager.PERMISSION_GRANTED;
boolean permissionGranted_phoneState = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED;
boolean permissionGranted_recordAudio = ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
boolean permissionGranted_WriteExternal = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
boolean permissionGranted_ReadExternal = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
if (permissionGranted_OutgoingCalls) {
if (permissionGranted_phoneState) {
if (permissionGranted_recordAudio) {
if (permissionGranted_WriteExternal) {
if (permissionGranted_ReadExternal) {
try {
toggleButton.setVisibility(View.VISIBLE);
} catch (Exception e) {
e.printStackTrace();
}
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 200);
}
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 300);
}
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 400);
}
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 500);
}
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS}, 600);
}
} catch (Exception e) {
e.printStackTrace();
}
}
#SuppressLint("ResourceAsColor")
public void toggleButtonClick(View view) {
try {
boolean checked = ((ToggleButton) view).isChecked();
if (checked) {
Intent intent = new Intent(this, CallRecorder.class);
startService(intent);
Toast.makeText(getApplicationContext(), "Call Recording is set ON", Toast.LENGTH_SHORT).show();
textSubHeader.setText("Switch on Toggle to record your calls");
} else {
Intent intent = new Intent(this, CallRecorder.class);
stopService(intent);
Toast.makeText(getApplicationContext(), "Call Recording is set OFF", Toast.LENGTH_SHORT).show();
textSubHeader.setText("Switch Off Toggle to stop recording your calls");
}
}
catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == 200 || requestCode == 300 || requestCode == 400 || requestCode == 500 || requestCode == 600) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
try {
toggleButton.setVisibility(View.VISIBLE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public class CallRecorder extends Service {
private MediaRecorder recorder;
private boolean recordStarted = false;
private String savedNumber;
public static final String ACTION_IN = "android.intent.action.PHONE_STATE";
public static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL";
public static final String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
private int lastState = TelephonyManager.CALL_STATE_IDLE;
private boolean isIncoming;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_OUT);
filter.addAction(ACTION_IN);
this.registerReceiver(new CallReceiver(), filter);
return super.onStartCommand(intent, flags, startId);
}
private void stopRecording() {
if (recordStarted) {
recorder.stop();
recordStarted = false;
}
}
public abstract class PhoneCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_OUT)) {
savedNumber = intent.getStringExtra(EXTRA_PHONE_NUMBER);
} else {
String stateStr = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
savedNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
state = TelephonyManager.CALL_STATE_IDLE;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
state = TelephonyManager.CALL_STATE_OFFHOOK;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
state = TelephonyManager.CALL_STATE_RINGING;
}
onCallStateChanged(context, state, savedNumber);
}
}
protected abstract void onIncomingCallReceived(Context ctx, String number);
protected abstract void onIncomingCallAnswered(Context ctx, String number);
protected abstract void onIncomingCallEnded(Context ctx, String number);
protected abstract void onOutgoingCallStarted(Context ctx, String number);
protected abstract void onOutgoingCallEnded(Context ctx, String number);
protected abstract void onMissedCall(Context ctx, String number);
public void onCallStateChanged(Context context, int state, String number) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
String time = dateFormat.format(new Date()) ;
File sampleDir = new File(Environment.getExternalStorageDirectory(), "/indcallrecorder");
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
if (lastState == state) {
return;
}
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
savedNumber = number;
onIncomingCallReceived(context, number );
recorder = new MediaRecorder();
// recorder.setAudioSamplingRate(8000);
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(sampleDir.getAbsolutePath() + "/" + "Incoming \n" + number + " \n" + time + " \n" + " Call.amr");
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start();
recordStarted = true;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if (lastState != TelephonyManager.CALL_STATE_RINGING) {
isIncoming = false;
recorder = new MediaRecorder();
recorder.setAudioSamplingRate(8000);
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(sampleDir.getAbsolutePath() + "/" + "Outgoing \n" + savedNumber + " \n" + time + " \n" + " Call.amr");
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start();
recordStarted = true;
onOutgoingCallStarted(context, savedNumber );
} else {
isIncoming = true;
onIncomingCallAnswered(context, savedNumber);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (lastState == TelephonyManager.CALL_STATE_RINGING) {
onMissedCall(context, savedNumber);
} else if (isIncoming) {
stopRecording();
onIncomingCallEnded(context, savedNumber);
} else {
stopRecording();
onOutgoingCallEnded(context, savedNumber);
}
break;
}
lastState = state;
}
}
public class CallReceiver extends PhoneCallReceiver {
#Override
protected void onIncomingCallReceived(Context ctx, String number) {
}
#Override
protected void onIncomingCallAnswered(Context ctx, String number) {
}
#Override
protected void onIncomingCallEnded(Context ctx, String number) {
}
#Override
protected void onOutgoingCallStarted(Context ctx, String number) {
}
#Override
protected void onOutgoingCallEnded(Context ctx, String number) {
}
#Override
protected void onMissedCall(Context ctx, String number) {
}
}
}
I am implementing call recording option in my Android application and all the calls are recoding fine below Android version 10 but from Android version 10 to above versions calls are recorded and when I try to play the recorded calls its silent. I am not able to listen the recorded voice.
What can I try to resolve this?
am writing a body measurement app. I have been able to create the camera and it stores the image. I want to use the captured image in another activity where i called the method 'bodyMeasurement'
I really need help in achieving this. Further corrections are also welcomed. Thanks
Here is my Camera Activity;
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice camera) {
cameraDevice = camera;
createCameraPreview();
}
#Override
public void onDisconnected(#NonNull CameraDevice cameraDevice) {
cameraDevice.close();
}
#Override
public void onError(#NonNull CameraDevice cameraDevice, int i) {
cameraDevice.close();
cameraDevice=null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textureView = (TextureView)findViewById(R.id.textureView);
//From Java 1.4 , you can use keyword 'assert' to check expression true or false
assert textureView != null;
textureView.setSurfaceTextureListener(textureListener);
btnCapture = (ImageButton)findViewById(R.id.btnCapture);
/* Dexter.withActivity(this)
.withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (!report.areAllPermissionsGranted()) {
Toast.makeText(MainActivity.this, "You need to grant all permission to use this app features", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
}
})
.check();*/
btnCapture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
takePicture();
}
});
}
private void takePicture() {
if(cameraDevice == null)
return;
CameraManager manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
try{
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if(characteristics != null)
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(ImageFormat.JPEG);
//Capture image with custom size
int width = 4608;
int height = 3456;
if(jpegSizes != null && jpegSizes.length > 0)
{
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
final ImageReader reader = ImageReader.newInstance(width,height,ImageFormat.JPEG,1);
List<Surface> outputSurface = new ArrayList<>(2);
outputSurface.add(reader.getSurface());
outputSurface.add(new Surface(textureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
//Check orientation base on device
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(rotation));
file = new File(Environment.getExternalStorageDirectory()+"/"+ ".CnatraSamp"+".jpg");
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader imageReader) {
Image image = null;
try{
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
finally {
{
if(image != null)
image.close();
}
}
}
private void save(byte[] bytes) throws IOException {
OutputStream outputStream = null;
try{
outputStream = new FileOutputStream(file);
outputStream.write(bytes);
}finally {
if(outputStream != null)
outputStream.close();
}
}
};
reader.setOnImageAvailableListener(readerListener,mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request, #NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(MainActivity.this, "Saved "+file, Toast.LENGTH_SHORT).show();
finish();
Intent i = new Intent(MainActivity.this,BlankActivity.class);
startActivity(i);
finish();
}
};
cameraDevice.createCaptureSession(outputSurface, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
try{
cameraCaptureSession.capture(captureBuilder.build(),captureListener,mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
}
},mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void createCameraPreview() {
try{
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(imageDimension.getWidth(),imageDimension.getHeight());
Surface surface = new Surface(texture);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
if(cameraDevice == null)
return;
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(MainActivity.this, "Changed", Toast.LENGTH_SHORT).show();
}
},null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void updatePreview() {
if(cameraDevice == null)
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE,CaptureRequest.CONTROL_MODE_AUTO);
try{
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera() {
CameraManager manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
try{
cameraId = manager.getCameraIdList()[1];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[1];
//Check realtime permission if run higher API 23
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(this,new String[]{
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
},REQUEST_CAMERA_PERMISSION);
return;
}
manager.openCamera(cameraId,stateCallback,null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
openCamera();
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if(requestCode == REQUEST_CAMERA_PERMISSION)
{
if(grantResults[0] != PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(this, "You can't use camera without permission", Toast.LENGTH_SHORT).show();
finish();
}
}
}
#Override
protected void onResume() {
super.onResume();
startBackgroundThread();
if(textureView.isAvailable())
openCamera();
else
textureView.setSurfaceTextureListener(textureListener);
}
#Override
protected void onPause() {
stopBackgroundThread();
super.onPause();
}
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try{
mBackgroundThread.join();
mBackgroundThread= null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("Camera Background");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
the activity i need the image;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_blank);
height = findViewById(R.id.height);
cancel = findViewById(R.id.cancel);
btnctn = findViewById(R.id.continuebtn);
cmIn = findViewById(R.id.cmIn);
height.setInputType(InputType.TYPE_CLASS_NUMBER |
InputType.TYPE_NUMBER_FLAG_DECIMAL |
InputType.TYPE_NUMBER_FLAG_SIGNED);
btnctn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (height.getText().toString().trim().isEmpty()){
Toast.makeText(BlankActivity.this,"Please input your height..",Toast.LENGTH_LONG).show();
}else {
final ProgressDialog progressDialog = new ProgressDialog(BlankActivity.this);
progressDialog.setMessage("Getting Your Measurement");
progressDialog.setTitle("Please wait!");
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show(); // Display Progress Dialog
progressDialog.setCancelable(false);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent i = new Intent(BlankActivity.this, SettingsActivity.class);
startActivity(i);
progressDialog.dismiss();
}
},5000);
}
//place measurement object
bodyMeasurement();
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
BlankActivity.this.finish();
Intent i = new Intent(BlankActivity.this, HomeActivity.class);
startActivity(i);
finish();
}
});
cmIn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
num = Double.parseDouble(String.valueOf(height.getText()));
in = 0.3937 * num;
String r = String.valueOf(in);
height.setText(r);
}else {
num = Double.parseDouble(String.valueOf(height.getText()));
cm = num / 0.3937;
String r = String.valueOf(cm);
height.setText(r);
}
}
});
}
private void bodyMeasurement() {
}
}
As mentioned in the comment, you can get the absolute path from the saved image and pass it through an intent to the Activity that it needs it.
To achieve this, you might want to convert your image file to a BitMap first, which will give you the actual path of the image (sometimes .getAbsolutePath() method returns a wrong file path, so it is a better solution to convert your image to a bitmap first).
This can be achieved:
String filePath = file.getPath();
Bitmap imgBitmap = BitmapFactory.decodeFile(filePath);
Then to obtain the real path of the image you saved you need to
1) Obtain the Uri of the created Bitmap:
public Uri getUri(Context context, Bitmap imgBitmap) {
ByteArrayOutputStream bOutputStream = new ByteArrayOutputStream();
String path = MediaStore.Images.Media.insertImage(context.getContentResolver(),
imgBitmap, "Title", null);
return Uri.parse(path);
}
2) Fetch the real path from Uri:
public String getRealPath(Uri uri) {
String [] proj={MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(column_index);
cursor.close();
return path;
}
In your first activity you can pass the path of your image through an intent to the other activity, then fetch it and display it/etc.
Intent intent = new Intent(context,OtherActivity.class);
intent.putExtra("PATH",path);
startActivity(intent);
Receive the data you passed:
Intent intent = getIntent();
String path = intent.getStringExtra("PATH");
//convert the path to image/bitmap and display the image
You can also pass the entire Bitmap to the Activity you need it, but I strongly recommend that you don't, because it will use a lot of memory.
I'm aware that this question has been asked before but all of the answers I have looked at have failed to give me the answer (most probably because some of them I can't understand but also because there are a lot of different solutions it seems and I can't see the wood for the trees).
I'm hoping that by providing my code that someone will be able to point me in the right direction.
Here is my class used to take the picture:
public class CameraPhotoActivity extends AppCompatActivity {
private Button btnCapture;
private TextureView textureView;
// to check the state orientation of the output image
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
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);
}
private String cameraId;
private CameraDevice cameraDevice;
private CameraCaptureSession cameraCaptureSessions;
private CaptureRequest.Builder captureRequestBuilder;
private Size imageDimension;
private ImageReader imageReader;
// save to file
private File file;
private static final int REQUEST_CAMERA_PERMISSION = 200;
private boolean mFlashSupported;
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice camera) {
cameraDevice = camera;
createCameraPreview();
}
#Override
public void onDisconnected(#NonNull CameraDevice cameraDevice) {
cameraDevice.close();
}
#Override
public void onError(#NonNull CameraDevice cameraDevice, int i) {
cameraDevice.close();
cameraDevice = null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_photo);
textureView = (TextureView) findViewById(R.id.textureView);
assert textureView != null;
textureView.setSurfaceTextureListener(textureListener);
btnCapture = (Button) findViewById(R.id.btnCapture);
btnCapture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
takePicture();
}
});
}
private void takePicture() {
if (cameraDevice == null)
return;
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null)
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(ImageFormat.JPEG);
// capture the image with custom size
int width = 640;
int height = 480;
if (jpegSizes != null && jpegSizes.length > 0) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
final ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurface = new ArrayList<>(2);
outputSurface.add(reader.getSurface());
outputSurface.add(new Surface(textureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
// check the orientation on the device
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
file = new File(Environment.getExternalStorageDirectory() + "/" + UUID.randomUUID().toString()
+ ".jpg");
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader imageReader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
{
if (image != null)
image.close();
}
}
}
private void save(byte[] bytes) throws IOException {
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
outputStream.write(bytes);
} finally {
if (outputStream != null)
outputStream.close();
}
}
};
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request, #NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(CameraPhotoActivity.this, "Saved " + file, Toast.LENGTH_SHORT).show();
createCameraPreview();
}
};
cameraDevice.createCaptureSession(outputSurface, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
try {
cameraCaptureSession.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void createCameraPreview() {
try {
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
Surface surface = new Surface(texture);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
if (cameraDevice == null)
return;
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(CameraPhotoActivity.this, "Changed", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void updatePreview() {
if (cameraDevice == null)
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];
// check realtime permission if run higher than API 23
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_CAMERA_PERMISSION);
return;
}
manager.openCamera(cameraId, stateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
openCamera();
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "You can't use the camera without permission", Toast.LENGTH_SHORT).show();
finish();
}
}
}
#Override
protected void onResume() {
super.onResume();
startBackgroundThread();
if (textureView.isAvailable())
openCamera();
else
textureView.setSurfaceTextureListener(textureListener);
}
#Override
protected void onPause() {
stopBackgroundThread();
super.onPause();
}
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("Camera Background");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
}
I have tried adding the following but, if it's correct, I can't seem to put it in the correct place:
MediaScannerConnection.scanFile(this, new String[]{file.toString()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("External Storage", "Scanned" + path + ":");
Log.i("External Storage", "-> uri=" + uri);
}
});
Thanks for any help. Much appreciated.
This means "context". You need to place the code within the activity class, once the image has been fetched from the camera. Also call connect before calling scanFile. You can try below code.
MediaScannerConnection.scanFile(CameraPhotoActivity.this, new String[]{file.toString()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("External Storage", "Scanned" + path + ":");
Log.i("External Storage", "-> uri=" + uri);
}
});
I am trying to develop an application in Android with the following feature: record video and audio seamlessly, even if the user has another application in the foreground. A common scenario for it would be: the user opens the app, starts recording, then opens a navigation app or receives a call. I want my app to keep recording.
I have put together some code, mainly inspired by this tutorial, which will be quoted below. I have encountered two problems, however:
1. When I press the "home" key, video recording freezes, but sound is fine
2. When I navigate back to the app, the preview is black
My questions are:
Is my goal possible on Android?
What am I doing wrong?
My code:
public class GlobalState extends Application {
private boolean recording = false;
private boolean loggingEnabled = true;
private Camera serviceCamera = null;
private CameraPreview cameraPreview = null;
#Override
public void onCreate() {
try {
serviceCamera = Camera.open();
} catch (Exception e) {
}
super.onCreate();
}
public boolean isRecording() {
return recording;
}
public boolean isLoggingEnabled() {
return loggingEnabled;
}
public void setRecording(boolean recording) {
this.recording = recording;
}
public void setCamera(Camera serviceCamera) {
this.serviceCamera = serviceCamera;
}
public Camera getCamera() {
return serviceCamera;
}
public void setCameraPreview(CameraPreview cameraPreview) {
this.cameraPreview = cameraPreview;
}
public CameraPreview getCameraPreview() {
return this.cameraPreview;
}
}
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private static final String TAG = "CameraPreview";
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
}
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
public class MainActivity extends Activity {
public String TAG = "DE-MainActivity";
ImageView mRecordView;
ImageView mMenuButtonView;
LinearLayout mMenuView;
TextView mVideosTextView;
TextView mSettingsTextView;
private Camera mCamera;
private CameraPreview mPreview;
GlobalState mAppState = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAppState = (GlobalState) getApplicationContext();
if (mAppState.isLoggingEnabled()) {
Log.v(TAG, "Activity: onCreate");
}
mCamera = mAppState.getCamera();
if (mAppState.getCameraPreview() == null) {
mPreview = new CameraPreview(this, mCamera);
mAppState.setCameraPreview(mPreview);
}
FrameLayout preview = (FrameLayout) findViewById(R.id.fl_camera);
preview.addView(mPreview);
mMenuView = (LinearLayout) findViewById(R.id.ll_menu_list);
mVideosTextView = (TextView) findViewById(R.id.tv_menu_item_videos);
mSettingsTextView = (TextView) findViewById(R.id.tv_menu_item_settings);
mRecordView = (ImageView) findViewById(R.id.iv_record);
mRecordView.setImageResource(R.drawable.btn_not_recording);
mRecordView.setAlpha((float) 0.5);
mRecordView.bringToFront();
mRecordView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mAppState.isRecording()) {
mRecordView.setImageResource(R.drawable.btn_recording);
mRecordView.setAlpha((float) 0.3);
startService(new Intent(MainActivity.this,
RecorderService.class));
} else {
mRecordView.setImageResource(R.drawable.btn_not_recording);
mRecordView.setAlpha((float) 0.5);
stopService(new Intent(MainActivity.this,
RecorderService.class));
}
}
});
mMenuButtonView = (ImageView) findViewById(R.id.iv_menu);
mMenuButtonView.setImageResource(R.drawable.btn_menu);
mMenuButtonView.setAlpha((float) 0.5);
mMenuButtonView.bringToFront();
mMenuButtonView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mMenuView.getVisibility() == View.VISIBLE) {
mMenuView.setVisibility(View.INVISIBLE);
} else {
mMenuView.setVisibility(View.VISIBLE);
}
}
});
mSettingsTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mAppState.isLoggingEnabled())
Log.v(TAG, "settings clicked!");
}
});
mVideosTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mAppState.isLoggingEnabled())
Log.v(TAG, "videos clicked!");
}
});
}
#Override
protected void onDestroy() {
if (mAppState.isLoggingEnabled())
Log.v(TAG, "APPLICATION EXIT!");
if (mCamera != null) {
mCamera.release(); // release the camera for other applications
mCamera = null;
}
super.onDestroy();
}
public boolean onCreateOptionsMenu(Menu menu) {
if (mMenuView.getVisibility() == View.VISIBLE) {
mMenuView.setVisibility(View.INVISIBLE);
} else {
mMenuView.setVisibility(View.VISIBLE);
}
return false;
}
}
public class RecorderService extends Service {
private static final String TAG = "RecorderService";
private static Camera mServiceCamera;
private MediaRecorder mMediaRecorder;
private GlobalState mAppState;
public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
#Override
public void onCreate() {
mAppState = (GlobalState) getApplicationContext();
mServiceCamera = mAppState.getCamera();
if (mAppState.isLoggingEnabled())
Log.v(TAG, "onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (!mAppState.isRecording()) {
if (prepareVideoRecorder()) {
mMediaRecorder.start();
mAppState.setRecording(true);
} else {
releaseMediaRecorder();
}
}
return 5;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
if (mAppState.isLoggingEnabled())
Log.v(TAG, "onDestroy");
// stop recording and release camera
mMediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
mServiceCamera.lock(); // take camera access back from MediaRecorder
mAppState.setRecording(false);
super.onDestroy();
}
private void releaseMediaRecorder() {
if (mMediaRecorder != null) {
mMediaRecorder.reset(); // clear recorder configuration
mMediaRecorder.release(); // release the recorder object
mMediaRecorder = null;
}
}
/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type) {
return Uri.fromFile(getOutputMediaFile(type));
}
/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type) {
File mediaStorageDir = new File(
Environment.getExternalStorageDirectory(), "DashEyeApp");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
} else if (type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "VID_" + timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
private boolean prepareVideoRecorder() {
mMediaRecorder = new MediaRecorder();
mServiceCamera.unlock();
mMediaRecorder.setCamera(mServiceCamera);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_HIGH));
mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO)
.toString());
// Step 5: Set the preview output
// mMediaRecorder.setPreviewDisplay(mAppState.getCameraPreview().getHolder().getSurface());
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
Log.d(TAG,
"IllegalStateException preparing MediaRecorder: "
+ e.getMessage());
releaseMediaRecorder();
return false;
} catch (IOException e) {
Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
}
return true;
}
}
I am sorry for the wall of text and I greatly appreciate any help!
my solution is fine, try it:
Service android:
import java.util.Calendar;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
public class BackgroundVideoRecorder extends Service implements
SurfaceHolder.Callback {
private WindowManager windowManager;
private SurfaceView surfaceView;
private Camera camera = null;
private MediaRecorder mediaRecorder = null;
int contTime = 0, duracaoGravacao = 30; //interval in seconds to record video
private class thread implements Runnable {
public void run() {
contTime++;
if (contTime >= duracaoGravacao) {
StopService();
}
tick_Handler.postDelayed(tick_thread, 1000);
}
}
Handler tick_Handler;
thread tick_thread;
Preferences pref;
#Override
public void onCreate() {
windowManager = (WindowManager) this
.getSystemService(Context.WINDOW_SERVICE);
surfaceView = new SurfaceView(this);
LayoutParams layoutParams = new WindowManager.LayoutParams(1, 1,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
windowManager.addView(surfaceView, layoutParams);
surfaceView.getHolder().addCallback(this);
tick_Handler = new Handler();
tick_thread = new thread();
VIDEO_RECORDER_FOLDER = new _Path().getPathVideo();
}
#Override
public void onStart(Intent intent, int startId) {
tick_Handler.post(tick_thread);
}
// Method called right after Surface created (initializing and starting
// MediaRecorder)
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
boolean found = false;
int i = 0;
try {
for (i = 0; i < Camera.getNumberOfCameras(); i++) {
Camera.CameraInfo newInfo = new Camera.CameraInfo();
Camera.getCameraInfo(i, newInfo);
if (newInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
found = true;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
if (found) {
camera = Camera.open(i);
} else {
camera = Camera.open();
}
Calendar lCDateTime = Calendar.getInstance();
String t = String.valueOf(lCDateTime.getTimeInMillis());
nomeArquivo = "hire_me_now_" + t + ".mp4";
nomeArquivo = nomeArquivo.replace(" ", "_").replace(":", "_")
.replace("-", "_");
String caminhoArquivo = VIDEO_RECORDER_FOLDER + "/" + nomeArquivo;
mediaRecorder = new MediaRecorder();
camera.unlock();
mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
mediaRecorder.setCamera(camera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_QVGA));
mediaRecorder.setVideoFrameRate(15);
mediaRecorder.setOutputFile(caminhoArquivo);
try {
mediaRecorder.prepare();
} catch (Exception e) {
e.printStackTrace();
}
mediaRecorder.start();
}
// Stop recording and remove SurfaceView
#Override
public void onDestroy() {
mediaRecorder.stop();
mediaRecorder.reset();
mediaRecorder.release();
camera.lock();
camera.release();
windowManager.removeView(surfaceView);
}
protected void StopService() {
try {
this.stopSelf();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
It turns out that Android doesn't like that the preview gets destroyed (when, for example, the user hits the "Home" button) so it cuts out video recording.
The workaround to this is using WindowManager to set an overlay and, when the user hits the "Home" button, resize it to 1x1. I found the solution here. Many thanks to cman!
it can be done but from API level 23 you will need ask for camera permissions, you can refer to this answer https://stackoverflow.com/a/49919386/4604234