Agent's attempt to ensure the sound gets played every interval (adding Looper to Handler and moving release() from playSound to onDestroy) as well as ensuring it's not delayed (using play() rather than start()).

This commit is contained in:
me committed 2026-11-06 13:35:08 -07:00
1 parent 124e1bc211
commit 4ede74e7a2
1 file changed
+39 -10
@@ -13,6 +13,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.support.v7.app.AlertDialog;
@@ -55,6 +56,12 @@ public class MainActivity extends AppCompatActivity {
TextView tvDot;
Uri ringtoneUri;
// RingtoneManager reference for consistent notification sound playback across loops
private android.media.Ringtone notificationRingtone;
// For proper sound lifecycle management across timer loops
private Ringtone ringtonePlayer;
MediaPlayer mediaPlayer;
SeekBar seekBar;
@@ -482,7 +489,7 @@ public class MainActivity extends AppCompatActivity {
if (DEBUG) Log.d(tag, "Finished");
}
private final Handler incrementTime = new Handler(){
private final android.os.Handler incrementTime = new android.os.Handler(android.os.Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
String tag = TAG + "handleMessage";
@@ -605,17 +612,34 @@ public class MainActivity extends AppCompatActivity {
if (DEBUG) Log.d(tag, "Starting");
try {
// Safely instantiate MediaPlayer locally to prevent NPE
Uri uri = android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_NOTIFICATION);
MediaPlayer localPlayer = MediaPlayer.create(this, uri);
// Stop any existing notification ringtone first to prevent overlap
if (notificationRingtone != null && notificationRingtone.isPlaying()) {
notificationRingtone.stop();
}
if (localPlayer != null) {
localPlayer.start();
localPlayer.release(); // Clean up resources immediately
// Use RingtoneManager which handles async playback lifecycle properly
Uri uri = android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_NOTIFICATION);
notificationRingtone = android.media.RingtoneManager.getRingtone(this, uri);
if (notificationRingtone != null) {
// Ringtone.play() is asynchronous and handles its own lifecycle,
// avoiding the MediaPlayer.create() + immediate release bug that
// caused silence on subsequent loops
notificationRingtone.play();
} else {
// Fallback for edge cases where create() fails
android.media.Ringtone ringtone = android.media.RingtoneManager.getRingtone(this, uri);
if (ringtone != null) ringtone.play();
// Fallback: if getRingtone fails, try direct MediaPlayer with proper lifecycle
MediaPlayer localPlayer = MediaPlayer.create(this, uri);
if (localPlayer != null) {
localPlayer.start();
final MediaPlayer fp = localPlayer;
// Release after playback completes (use delay as a safety net)
new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(
new Runnable() { @Override public void run() {
if (fp.isPlaying()) fp.stop();
fp.release();
}}, 2000
);
}
}
} catch (Exception e) {
sharedPreferences.edit().putBoolean(keyStartStop, false).apply();
@@ -744,6 +768,11 @@ public class MainActivity extends AppCompatActivity {
Alert.stop(this);
if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; }
// Clean up ringtone player to prevent resource leak across config changes
if (notificationRingtone != null && notificationRingtone.isPlaying()) {
notificationRingtone.stop();
}
if (DEBUG) Log.d(tag, "Done with local code, calling super..");
super.onDestroy();