Restarting CountDownTimer on finish is slower than using buttons to reset - java

I have a timer that I want to loop as soon as it reaches 0.
Resetting the timer in onFinish() seems to be slower than manually resetting the timer via the timer's reset button.
When the timer finishes, it doesn't restart until "0" has shown for a second (maybe at the end of the tick,) effectively adding an extra second to the timer that I don't want.
How can I make this timer restart the instant "0" is displayed?
Imports and fragment
package com.example.datacollector;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import java.util.Locale;
public class fragmentdro extends Fragment {
private EditText session_edit_text;
private EditText dro_edit_text;
private TextView session_text_view;
private TextView dro_text_view;
private Button session_start_button;
private Button dro_start_button;
private Button session_reset_button;
private Button dro_reset_button;
private Button session_set_button;
private Button dro_set_button;
private CountDownTimer sessionTimer;
private CountDownTimer droTimer;
private boolean SessionTimerRunning;
private boolean DROTimerRunning;
private long SessionStartTimeInMillis;
private long DROStartTimeInMillis;
private long SessionTimeLeftInMillis = SessionStartTimeInMillis;
private long DROTimeLeftInMillis = DROStartTimeInMillis;
private long SessionEndTime;
private long DROEndTime;
View View;
public View onCreateView(#NonNull LayoutInflater inflater, #NonNull ViewGroup container, #NonNull Bundle savedInstanceState) {
View = inflater.inflate(R.layout.dro_fragment, container, false);
session_edit_text = View.findViewById(R.id.session_edit_text);
dro_edit_text = View.findViewById(R.id.dro_edit_text);
session_text_view = View.findViewById(R.id.session_text_view);
dro_text_view = View.findViewById(R.id.dro_text_view);
session_start_button = View.findViewById(R.id.session_start_button);
dro_start_button = View.findViewById(R.id.dro_start_button);
session_reset_button = View.findViewById(R.id.session_reset_button);
dro_reset_button = View.findViewById(R.id.dro_reset_button);
session_set_button = View.findViewById(R.id.session_set_button);
dro_set_button = View.findViewById(R.id.dro_set_button);
InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_ALARM, 100);
Buttons
dro_set_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
String DROinput = dro_edit_text.getText().toString();
if (DROinput.length() == 0) {
Toast.makeText(getActivity(), "Fill it in", Toast.LENGTH_SHORT).show();
return;
}
long millisInput = Long.parseLong(DROinput) * 1000;
if (millisInput == 0) {
Toast.makeText(getActivity(), "Please enter a positive number", Toast.LENGTH_SHORT).show();
return;
}
setDROTime(millisInput);
dro_edit_text.setText("");
imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
}
});
dro_start_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
if (DROTimerRunning) {
pauseDROTimer();
} else {
startDROTimer();
}
}
});
dro_reset_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
if (DROTimerRunning) {
resetDROTimer();
} else {
resetDROTimer();
}
}
});
return View;
}
Timer
public void setDROTime(long milliseconds) {
DROStartTimeInMillis = milliseconds;
resetDROTimer();
}
public void startDROTimer() {
DROEndTime = System.currentTimeMillis() + DROTimeLeftInMillis;
final int[] secondsLeft = {0};
droTimer = new CountDownTimer(DROTimeLeftInMillis, 100) {
#Override
public void onTick(long ms) {
if (Math.round((float)ms/1000.0f) != secondsLeft[0])
{
secondsLeft[0] = (int) (Math.round((float)ms)/1000.0f);
}
DROTimeLeftInMillis = ms;
updateDROText();
}
#Override
public void onFinish() {
dro_text_view.setText("0");
DROTimerRunning = false;
DROTimeLeftInMillis = DROStartTimeInMillis + 1000;
updateDROText();
updateDROInterface();
startDROTimer();
}
}.start();
DROTimerRunning = true;
dro_start_button.setText("Pause");
}
public void pauseDROTimer() {
droTimer.cancel();
DROTimerRunning = false;
dro_start_button.setText("Start");
updateDROText();
}
public void resetDROTimer() {
if (DROTimerRunning) {
droTimer.cancel();
DROTimeLeftInMillis = (DROStartTimeInMillis + 1000);
updateDROInterface();
startDROTimer();
} else {
DROTimeLeftInMillis = (DROStartTimeInMillis);
updateDROText();
updateDROInterface();
dro_reset_button.setVisibility(android.view.View.VISIBLE);
dro_start_button.setVisibility(android.view.View.VISIBLE);
}
}
public void updateDROText() {
int seconds = (int) (DROTimeLeftInMillis/1000)%60;
String timeLeftFormatted = String.format(Locale.getDefault(),
timeLeftFormatted = String.format(Locale.getDefault(), ":%02d", seconds));
dro_text_view.setText(timeLeftFormatted);
}
public void updateDROInterface() {
if (DROTimerRunning) {
dro_edit_text.setVisibility(android.view.View.INVISIBLE);
dro_set_button.setVisibility(android.view.View.INVISIBLE);
dro_reset_button.setVisibility(android.view.View.VISIBLE);
dro_start_button.setText("Pause");
} else {
dro_edit_text.setVisibility(android.view.View.VISIBLE);
dro_set_button.setVisibility(android.view.View.VISIBLE);
dro_reset_button.setVisibility(android.view.View.VISIBLE);
dro_start_button.setText("Start");
}
}
Prefs
#Override
public void onStop() {
super.onStop();
SharedPreferences preferences = this.getActivity().getSharedPreferences("prefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putLong("SessionStartTimeInMillis", SessionStartTimeInMillis);
editor.putLong("DROStartTimeInMillis", DROStartTimeInMillis);
editor.putLong("MillisLeft", SessionTimeLeftInMillis);
editor.putLong("DROMillisLeft", DROTimeLeftInMillis);
editor.putBoolean("TimerRunning", SessionTimerRunning);
editor.putBoolean("DROTimerRunning", DROTimerRunning);
editor.putLong("EndTime", SessionEndTime);
editor.putLong("DROEndTime", DROEndTime);
if (sessionTimer !=null); {
sessionTimer.cancel();
}
}
#Override
public void onStart() {
super.onStart();
SharedPreferences preferences = this.getActivity().getSharedPreferences("prefs", Context.MODE_PRIVATE);
SessionStartTimeInMillis = preferences.getLong("SessionStartTimeInMillis", 0);
SessionTimeLeftInMillis = preferences.getLong("MillisLeft", SessionTimeLeftInMillis);
SessionTimerRunning = preferences.getBoolean("TimerRunning", false);
DROStartTimeInMillis = preferences.getLong("DROStartTimeInMillis", 0);
DROTimeLeftInMillis = preferences.getLong("DROMillisLeft", DROTimeLeftInMillis);
DROTimerRunning = preferences.getBoolean("DROTimerRunning", false);
updateSessionText();
updateSessionInterface();
updateDROText();
updateDROInterface();
if (SessionTimerRunning) {
SessionEndTime = preferences.getLong("EndTime", 0);
SessionTimeLeftInMillis = SessionEndTime - System.currentTimeMillis();
if (SessionTimeLeftInMillis <0) {
SessionTimeLeftInMillis = 0;
SessionTimerRunning = false;
} else {
startSessionTimer();
}
}
if (DROTimerRunning) {
DROEndTime = preferences.getLong("EndTime", 0);
DROTimeLeftInMillis = DROEndTime - System.currentTimeMillis();
if (DROTimeLeftInMillis <0) {
DROTimeLeftInMillis = 0;
ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_ALARM, 200);
toneGenerator.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 100);
DROTimerRunning = false;
} else {
startDROTimer();
}
}
}
}

You can add an extra 100 ms to your DROTimeLeftInMillis
so it should look like: new CountDownTimer(DROTimeLeftInMillis + 100, 100) { ..
because the onTick method doesn't call immediately, it called a few milliseconds after, so by adding the 100 ms it should deal with the delay and give you the result you expect.

Related

Why won't my android app increase time when it loops through?

I'm working on making an app for myself that will help me do sprints outside. The idea is that a sound will play after two minutes to signify the time to sprint. After one minute of sprinting it will play another sound to signify the time to walk. And repeat. For some reason I can't get the time to be increased each time it goes through the loop. It's currently set to 10 and 15 seconds due to ease of trial and error. Thank you for any help! Here's the code:
package com.example.sprinttrial;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.Chronometer;
import android.widget.Toast;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
private Chronometer chronometer;
private long pauseOffset;
private boolean running;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
this.getSupportActionBar().hide();
}
catch (NullPointerException e){}
chronometer = findViewById(R.id.chronometer);
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onChronometerTick(Chronometer chronometer) {
System.out.println(SystemClock.elapsedRealtime() - chronometer.getBase());
int walkTimeVariable = 10000;
int walkTimeVariableDiff = 10999;
int runTimeVariable = 15000;
int runTimeVariableDiff = 15999;
boolean walkedPlayed = false;
boolean runPlayed = false;
if (SystemClock.elapsedRealtime() - chronometer.getBase() >= walkTimeVariable && SystemClock.elapsedRealtime() - chronometer.getBase() < walkTimeVariableDiff && walkedPlayed == false) {
walkedPlayed = true;
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
System.out.println("Working");
} else if ((SystemClock.elapsedRealtime() - chronometer.getBase()) >= runTimeVariable && SystemClock.elapsedRealtime() - chronometer.getBase() < runTimeVariableDiff && runPlayed == false) {
System.out.println("Working As Well");
runPlayed = true;
long ringDelay = 500;
Uri notification = RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_ALARM);
final Ringtone alarmRingtone = RingtoneManager
.getRingtone(getApplicationContext(), notification);
alarmRingtone.play();
TimerTask task = new TimerTask() {
#Override
public void run() {
alarmRingtone.stop();
}
};
Timer timer = new Timer();
timer.schedule(task, ringDelay);
} else {
System.out.println("Please work");
if(walkedPlayed){
System.out.println("WORK MAN");
walkTimeVariable += 10000;
walkTimeVariableDiff += 10000;
walkedPlayed = false;
}
if(runPlayed) {
System.out.println("WORK OMG");
runTimeVariable += 10000;
runTimeVariableDiff += 10000;
runPlayed = false;
}
}
}
});
}
public void startChronometer(View v) {
System.out.println("SIGH");
if (!running){
chronometer.setBase(SystemClock.elapsedRealtime() - pauseOffset);
chronometer.start();
running = true;
}
}
public void pauseChronometer(View v) {
if (running){
chronometer.stop();
pauseOffset = SystemClock.elapsedRealtime() - chronometer.getBase();
running = false;
}
}
public void resetChronometer(View v) {
chronometer.setBase(SystemClock.elapsedRealtime());
pauseOffset = 0;
}
}

CountDownTimer adds time with each loop

I'm working on a fragment that includes two timers that take user input. Timer B is linked to timer A such that when timer A is started, so is timer B. The purpose of timer A is to count down once. The purpose of timer B is to count down, beep once at 0, reset to the original value, and repeat. The problem I'm having is that when timer B reaches 0, it doesn't reset and start counting down right away. The timer seems to be delayed further by calling ToneGenerator. This results in the two timers becoming more and more out of sync each time timer B resets.
For example, say timer A is set to 10 seconds and timer B is set to 2 seconds.
-The timers are started-
timer A:10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
timer B: 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1
The timer only beeps 3 times (when timer B is at 0,) when it should beep 5 times (5 sets of 2 second intervals = 10 seconds: the value of timer A.) In other words, I'd like timer B to beep when timer A is at 8, 6, 4, 2, and 0.
How might I accomplish this?
I've consulted the forums, YT, and have tried playing around with the value for millisInFuture.
Fragment
public class fragmentdro extends Fragment {
private EditText session_edit_text;
private EditText dro_edit_text;
private TextView session_text_view;
private TextView dro_text_view;
private Button session_start_button;
private Button dro_start_button;
private Button session_reset_button;
private Button dro_reset_button;
private Button session_set_button;
private Button dro_set_button;
private CountDownTimer sessionTimer;
private CountDownTimer droTimer;
private boolean SessionTimerRunning;
private boolean DROTimerRunning;
private long SessionStartTimeInMillis;
private long DROStartTimeInMillis;
private long SessionTimeLeftInMillis = SessionStartTimeInMillis;
private long DROTimeLeftInMillis = DROStartTimeInMillis;
private long SessionEndTime;
private long DROEndTime;
View View;
public View onCreateView(#NonNull LayoutInflater inflater, #NonNull ViewGroup container, #NonNull Bundle savedInstanceState) {
View = inflater.inflate(R.layout.dro_fragment, container, false);
session_edit_text = View.findViewById(R.id.session_edit_text);
dro_edit_text = View.findViewById(R.id.dro_edit_text);
session_text_view = View.findViewById(R.id.session_text_view);
dro_text_view = View.findViewById(R.id.dro_text_view);
session_start_button = View.findViewById(R.id.session_start_button);
dro_start_button = View.findViewById(R.id.dro_start_button);
session_reset_button = View.findViewById(R.id.session_reset_button);
dro_reset_button = View.findViewById(R.id.dro_reset_button);
session_set_button = View.findViewById(R.id.session_set_button);
dro_set_button = View.findViewById(R.id.dro_set_button);
InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_ALARM, 100);
Timer A
session_set_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
String Sessioninput = session_edit_text.getText().toString();
if (Sessioninput.length() == 0) {
Toast.makeText(getActivity(), "Fill it in", Toast.LENGTH_SHORT).show();
return;
}
long millisInput = Long.parseLong(Sessioninput) * 1000;
if (millisInput == 0) {
Toast.makeText(getActivity(), "Please enter a positive number", Toast.LENGTH_SHORT).show();
return;
}
setSessionTime(millisInput);
session_edit_text.setText("");
imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
}
});
session_start_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
if (SessionTimerRunning) {
pauseSessionTimer();
resetDROTimer();
} else {
startSessionTimer();
startDROTimer();
}
}
});
session_reset_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
if (SessionTimerRunning) {
resetSessionTimer();
} else {
resetSessionTimer();
}
}
});
public void setSessionTime(long milliseconds) {
SessionStartTimeInMillis = milliseconds;
resetSessionTimer();
}
public void startSessionTimer() {
SessionEndTime = System.currentTimeMillis() + SessionTimeLeftInMillis;
sessionTimer = new CountDownTimer(SessionTimeLeftInMillis, 100) {
#Override
public void onTick(long millisUntilFinished) {
SessionTimeLeftInMillis = millisUntilFinished;
updateSessionText();
}
#Override
public void onFinish() {
SessionTimerRunning = false;
session_start_button.setText("Start");
session_start_button.setVisibility(android.view.View.INVISIBLE);
session_reset_button.setVisibility(android.view.View.VISIBLE);
}
}.start();
SessionTimerRunning = true;
session_start_button.setText("Pause");
}
public void pauseSessionTimer() {
sessionTimer.cancel();
droTimer.cancel();
SessionTimerRunning = false;
DROTimerRunning = false;
session_start_button.setText("Start");
updateSessionText();
}
public void resetSessionTimer() {
if (SessionTimerRunning) {
sessionTimer.cancel();
SessionTimeLeftInMillis = (SessionStartTimeInMillis);
updateSessionInterface();
startSessionTimer();
} else {
SessionTimeLeftInMillis = (SessionStartTimeInMillis);
updateSessionText();
updateSessionInterface();
session_reset_button.setVisibility(android.view.View.VISIBLE);
session_start_button.setVisibility(android.view.View.VISIBLE);
}
}
public void updateSessionText() {
int minutes = (int) (SessionTimeLeftInMillis/1000/60);
int seconds = (int) (SessionTimeLeftInMillis/1000)%60;
String timeLeftFormatted = String.format(Locale.getDefault(),
timeLeftFormatted = String.format(Locale.getDefault(), "%2d:%02d", minutes, seconds));
session_text_view.setText(timeLeftFormatted);
}
public void updateSessionInterface() {
if (SessionTimerRunning) {
session_edit_text.setVisibility(android.view.View.INVISIBLE);
session_set_button.setVisibility(android.view.View.INVISIBLE);
session_reset_button.setVisibility(android.view.View.VISIBLE);
session_start_button.setText("Pause");
} else {
session_edit_text.setVisibility(android.view.View.VISIBLE);
session_set_button.setVisibility(android.view.View.VISIBLE);
session_reset_button.setVisibility(android.view.View.VISIBLE);
session_start_button.setText("Start");
}
}
Timer B
dro_set_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
String DROinput = dro_edit_text.getText().toString();
if (DROinput.length() == 0) {
Toast.makeText(getActivity(), "Fill it in", Toast.LENGTH_SHORT).show();
return;
}
long millisInput = Long.parseLong(DROinput) * 1000;
if (millisInput == 0) {
Toast.makeText(getActivity(), "Please enter a positive number", Toast.LENGTH_SHORT).show();
return;
}
setDROTime(millisInput);
dro_edit_text.setText("");
imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
}
});
dro_start_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
if (DROTimerRunning) {
pauseDROTimer();
} else {
startDROTimer();
}
}
});
dro_reset_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
if (DROTimerRunning) {
resetDROTimer();
} else {
resetDROTimer();
}
}
});
return View;
}
public void setDROTime(long milliseconds) {
DROStartTimeInMillis = milliseconds;
resetDROTimer();
}
public void startDROTimer() {
DROEndTime = System.currentTimeMillis() + DROTimeLeftInMillis;
droTimer = new CountDownTimer(DROTimeLeftInMillis, 100) {
#Override
public void onTick(long millisUntilFinished) {
DROTimeLeftInMillis = millisUntilFinished;
updateDROText();
}
#Override
public void onFinish() {
ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_ALARM, 400);
toneGenerator.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 200);
DROTimerRunning = false;
DROTimeLeftInMillis = DROStartTimeInMillis;
updateDROText();
updateDROInterface();
startDROTimer();
}
}.start();
DROTimerRunning = true;
dro_start_button.setText("Pause");
}
public void pauseDROTimer() {
droTimer.cancel();
DROTimerRunning = false;
dro_start_button.setText("Start");
updateDROText();
}
public void resetDROTimer() {
if (DROTimerRunning) {
droTimer.cancel();
DROTimeLeftInMillis = (DROStartTimeInMillis);
updateDROInterface();
startDROTimer();
} else {
DROTimeLeftInMillis = (DROStartTimeInMillis);
updateDROText();
updateDROInterface();
dro_reset_button.setVisibility(android.view.View.VISIBLE);
dro_start_button.setVisibility(android.view.View.VISIBLE);
}
}
public void updateDROText() {
int seconds = (int) (DROTimeLeftInMillis/1000)%60;
String timeLeftFormatted = String.format(Locale.getDefault(),
timeLeftFormatted = String.format(Locale.getDefault(), ":%02d", seconds));
dro_text_view.setText(timeLeftFormatted);
}
public void updateDROInterface() {
if (DROTimerRunning) {
dro_edit_text.setVisibility(android.view.View.INVISIBLE);
dro_set_button.setVisibility(android.view.View.INVISIBLE);
dro_reset_button.setVisibility(android.view.View.VISIBLE);
dro_start_button.setText("Pause");
} else {
dro_edit_text.setVisibility(android.view.View.VISIBLE);
dro_set_button.setVisibility(android.view.View.VISIBLE);
dro_reset_button.setVisibility(android.view.View.VISIBLE);
dro_start_button.setText("Start");
}
}
#Override
public void onStop() {
super.onStop();
SharedPreferences preferences = this.getActivity().getSharedPreferences("prefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putLong("SessionStartTimeInMillis", SessionStartTimeInMillis);
editor.putLong("DROStartTimeInMillis", DROStartTimeInMillis);
editor.putLong("MillisLeft", SessionTimeLeftInMillis);
editor.putLong("DROMillisLeft", DROTimeLeftInMillis);
editor.putBoolean("TimerRunning", SessionTimerRunning);
editor.putBoolean("DROTimerRunning", DROTimerRunning);
editor.putLong("EndTime", SessionEndTime);
editor.putLong("DROEndTime", DROEndTime);
if (sessionTimer !=null); {
sessionTimer.cancel();
}
}
#Override
public void onStart() {
super.onStart();
SharedPreferences preferences = this.getActivity().getSharedPreferences("prefs", Context.MODE_PRIVATE);
SessionStartTimeInMillis = preferences.getLong("SessionStartTimeInMillis", 0);
SessionTimeLeftInMillis = preferences.getLong("MillisLeft", SessionTimeLeftInMillis);
SessionTimerRunning = preferences.getBoolean("TimerRunning", false);
DROStartTimeInMillis = preferences.getLong("DROStartTimeInMillis", 0);
DROTimeLeftInMillis = preferences.getLong("DROMillisLeft", DROTimeLeftInMillis);
DROTimerRunning = preferences.getBoolean("DROTimerRunning", false);
updateSessionText();
updateSessionInterface();
updateDROText();
updateDROInterface();
if (SessionTimerRunning) {
SessionEndTime = preferences.getLong("EndTime", 0);
SessionTimeLeftInMillis = SessionEndTime - System.currentTimeMillis();
if (SessionTimeLeftInMillis <0) {
SessionTimeLeftInMillis = 0;
SessionTimerRunning = false;
} else {
startSessionTimer();
}
}
if (DROTimerRunning) {
DROEndTime = preferences.getLong("EndTime", 0);
DROTimeLeftInMillis = DROEndTime - System.currentTimeMillis();
if (DROTimeLeftInMillis <0) {
DROTimeLeftInMillis = 0;
DROTimerRunning = false;
} else {
startDROTimer();
}
}
}
}

Dividing numbers returns infinity

I'm working on a fragment that includes a timer and a counter. The initial timer value is an edit text. When the timer reaches 0, I want to calculate a rate (# displayed on counter/edit text input.) I've tried to convert both values to doubles, but it seems I went wrong somewhere. When the timer reaches 0, the rate displays "infinity." Any help would be greatly appreciated!
IDs
package com.example.datacollector;
import android.content.ClipData;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.EditText;
import android.widget.Toast;
import androidx.fragment.app.Fragment;
import androidx.annotation.NonNull;
import java.util.Locale;
public class fragmentrate extends Fragment {
private EditText edit_text_input;
private TextView text_view_countdown;
private TextView text_view_frequency;
private TextView text_view_rate;
private TextView rate_equals;
private Button button_start_pause;
private Button button_reset;
private Button button_set;
private Button button_frequency;
private Button button_reset_frequency;
private CountDownTimer countDownTimer;
private boolean mTimerRunning;
private long mStartTimeInMillis;
private long mTimeLeftInMillis = mStartTimeInMillis;
private long mEndTime;
private int mCounter;
private double denominator;
View View;
public View onCreateView(#NonNull LayoutInflater inflater, #NonNull ViewGroup container, #NonNull Bundle savedInstanceState) {
View = inflater.inflate(R.layout.rate_fragment, container, false);
text_view_countdown = View.findViewById(R.id.text_view_countdown);
button_start_pause = View.findViewById(R.id.button_start_pause);
button_reset = View.findViewById(R.id.button_reset);
button_frequency = View.findViewById(R.id.button_frequency);
button_reset_frequency = View.findViewById(R.id.button_reset_frequency);
edit_text_input = View.findViewById(R.id.edit_text_input);
button_set = View.findViewById(R.id.button_set);
text_view_frequency = View.findViewById(R.id.text_view_frequency);
text_view_rate = View.findViewById(R.id.text_view_rate);
rate_equals = View.findViewById(R.id.rate_equals);
Counter
button_frequency.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
mCounter ++;
text_view_frequency.setText(Integer.toString(mCounter));
}
});
button_reset_frequency.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
mCounter = 0;
text_view_frequency.setText(Integer.toString(mCounter));
}
});
Timer and rate calculation
button_set.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
String input = edit_text_input.getText().toString();
if (input.length() == 0) {
Toast.makeText(getActivity(), "Fill it in, loser", Toast.LENGTH_SHORT).show();
return;
}
long millisInput = Long.parseLong(input) * 60000;
if (millisInput == 0) {
Toast.makeText(getActivity(), "Please enter a positive number", Toast.LENGTH_SHORT).show();
return;
}
setTime(millisInput);
edit_text_input.setText("");
}
});
button_start_pause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
if (mTimerRunning) {
pauseTimer();
} else {
startTimer();
}
}
});
button_reset.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(android.view.View view) {
if(mTimerRunning) {
resetTimer();
} else{
resetTimer();
}
}
});
return View;
}
private void setTime(long milliseconds) {
mStartTimeInMillis = milliseconds;
resetTimer();
}
private void startTimer() {
mEndTime = System.currentTimeMillis() + mTimeLeftInMillis;
countDownTimer = new CountDownTimer(mTimeLeftInMillis, 100) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
mTimerRunning = false;
button_start_pause.setText("Start");
button_start_pause.setVisibility(android.view.View.INVISIBLE);
button_reset.setVisibility(android.view.View.VISIBLE);
try {
double denominator = Integer.parseInt(edit_text_input.getText().toString());
}
catch (NumberFormatException e)
{
double denominator = 0;
}
double rate = ((double)mCounter/denominator);
text_view_rate.setText(Double.toString(rate));
}
}.start();
mTimerRunning = true;
button_start_pause.setText("Pause");
}
private void pauseTimer() {
countDownTimer.cancel();
mTimerRunning = false;
updateCountDownText();
button_start_pause.setText("Start");
}
private void resetTimer() {
if (mTimerRunning) {
countDownTimer.cancel();
mTimeLeftInMillis = (mStartTimeInMillis + 1000);
updateWatchInterface();
startTimer();
} else {
}
mTimeLeftInMillis = (mStartTimeInMillis);
updateCountDownText();
updateWatchInterface();
button_reset.setVisibility(android.view.View.VISIBLE);
button_start_pause.setVisibility(android.view.View.VISIBLE);
}
private void updateCountDownText() {
int minutes = (int) (mTimeLeftInMillis/1000)/60;
int seconds = (int) (mTimeLeftInMillis/1000)%60;
String timeLeftFormatted = String.format(Locale.getDefault(),
timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds));
text_view_countdown.setText(timeLeftFormatted);
}
private void updateWatchInterface() {
if (mTimerRunning) {
edit_text_input.setVisibility(android.view.View.INVISIBLE);
button_set.setVisibility(android.view.View.INVISIBLE);
button_reset.setVisibility(android.view.View.VISIBLE);
button_start_pause.setText("Pause");
} else {
edit_text_input.setVisibility(android.view.View.VISIBLE);
button_set.setVisibility(android.view.View.VISIBLE);
button_reset.setVisibility(android.view.View.VISIBLE);
button_start_pause.setText("Start");
if (mTimeLeftInMillis <100) {
button_start_pause.setVisibility(android.view.View.INVISIBLE);
} else {
button_start_pause.setVisibility(android.view.View.VISIBLE);
}
}
}
#Override
public void onStop() {
super.onStop();
SharedPreferences preferences = this.getActivity().getSharedPreferences("prefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putLong("startTimeInMillis", mStartTimeInMillis);
editor.putLong("millisLeft", mTimeLeftInMillis);
editor.putBoolean("timerRunning", mTimerRunning);
editor.putLong("endTime", mEndTime);
editor.apply();
if(countDownTimer !=null); {
countDownTimer.cancel();
}
}
#Override
public void onStart() {
super.onStart();
SharedPreferences preferences = this.getActivity().getSharedPreferences("prefs", Context.MODE_PRIVATE);
mStartTimeInMillis = preferences.getLong("startTimeInMillis", 0);
mTimeLeftInMillis = preferences.getLong("millisLeft", mStartTimeInMillis);
mTimerRunning = preferences.getBoolean("timerRunning", false);
updateCountDownText();
updateWatchInterface();
if (mTimerRunning) {
mEndTime = preferences.getLong("endTime", 0);
mTimeLeftInMillis = mEndTime - System.currentTimeMillis();
if (mTimeLeftInMillis <0) {
mTimeLeftInMillis = 0;
mTimerRunning = false;
updateCountDownText();
updateWatchInterface();
} else {
startTimer();
}
}
}
You are specifically capturing a NumberFormatException, setting the denominator to zero, and then you're dividing by that number. By design, your result will be Infinity.
Quoting from the Java 8 JLS:
Division of a nonzero finite value by a zero results in a signed infinity. The sign is determined by the rule stated above.
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.17.2

Android/Java - CountDown Timer not working

I am making a timer as part of my app. I followed a tutorial, and made some modifications to the program to better suit my needs. However, when I run the app, I get the default value of the timerTextView (defined in xml), or just random numbers. What is going wrong?
Update: Here is the coomplete code for the activity:
public class Main7Activity extends AppCompatActivity {
private TextView countDownText;
private CountDownTimer countDownTimer;
//private long timeLeftInMilliseconds = 1000*60*60*24*7*1;
public TextView textView3;
public TextView textView4;
public TextView textView5;
public TextView textView6;
public long timeLeftInMilliseconds;
//private int daysToGo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main7);
textView3 = (TextView) findViewById(R.id.testText);
textView4 = (TextView) findViewById(R.id.testText2);
textView5 = (TextView) findViewById(R.id.testText3);
textView6 = (TextView) findViewById(R.id.testText4);
//textView3.setText(Integer.toString(Main6Activity.progress2));
Calendar now = Calendar.getInstance();
textView3.setText("LMP date : " + Main6Activity.textView.getText());
int currentDayOfYear = now.get(Calendar.DAY_OF_YEAR);
//Day of year is the LMP date
now.set(Calendar.DAY_OF_YEAR, Main6Activity.progress2);
int lmpDate = now.get(Calendar.DAY_OF_YEAR);
//Day of year is due date
now.add(Calendar.DAY_OF_YEAR, 7*40);
textView4.setText("Due Date: " + now.get(Calendar.DATE) + "-"
+ (now.get(Calendar.MONTH) + 1) + "-" + now.get(Calendar.YEAR));
int dueDate = now.get(Calendar.DAY_OF_YEAR);
if (dueDate < 365 && lmpDate > 82){
dueDate = dueDate + (365);
}
if (lmpDate<82 && lmpDate>49){
dueDate = dueDate + lmpDate;
}
if (lmpDate<50) {
textView5.setText("Congratulations on Delivery");
}
else {
textView5.setText(Integer.toString(dueDate));
}
//textView5.setText(now.getTime().toString());
//int currentDayOfYear = Calendar.DAY_OF_YEAR;
int daysToGo = dueDate - currentDayOfYear;
textView6.setText(Integer.toString(daysToGo));
timeLeftInMilliseconds = 1000*60*60*24*daysToGo;
countDownText = (TextView) findViewById(R.id.weeks);
startTimer();
}
public void startTimer(){
countDownTimer = new CountDownTimer(timeLeftInMilliseconds, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timeLeftInMilliseconds = millisUntilFinished;
updateTimer();
}
#Override
public void onFinish() {
}
}.start();
}
public void updateTimer(){
int weeks = (int) timeLeftInMilliseconds / 604800000;
int days = (int) (timeLeftInMilliseconds % 604800000) / 86400000;
//int hours = (int) (timeLeftInMilliseconds % 86400000) / 3600000;
//int minutes = (int) (timeLeftInMilliseconds % 3600000) / 60000;
int seconds = (int) (timeLeftInMilliseconds % 60000) / 1000;
String timeLeftText;
timeLeftText = "";
if (weeks < 10) timeLeftText += "0";
timeLeftText += weeks;
timeLeftText += ":";
if (days < 10) timeLeftText += "0";
timeLeftText += days;
//timeLeftText += ":";
//if (hours < 10) timeLeftText += "0";
//timeLeftText += hours;
//timeLeftText += ":";
//timeLeftText += minutes;
//timeLeftText += ":";
if (seconds < 10) timeLeftText += "0";
timeLeftText += seconds;
countDownText.setText(timeLeftText);
}
public void editInfo(View v){
Intent intent = new Intent(Main7Activity.this, Main6Activity.class);
startActivity(intent);
}
}
I also need the timer to run in the background. Will this code do that?
Thanks.
Try to declare those variables :
Handler countHandler ;
Runnable countRunnable ;
private final long INTERVAL = 1000 ; // this the interval period which the timer will be triggered each time
Then change your method like this :
public void startTimer(){
countHandler = new Handler() ;
countRunnable = new Runnable() {
#Override
public void run() {
updateTimer();
timeLeftInMilliseconds= timeLeftInMilliseconds - INTERVAL ;
if(timeLeftInMilliseconds>=0){
countHandler.postDelayed(this, INTERVAL) ;
} else {
cancelTimer(); // here timer is finished
}
}
} ;
countHandler.post(countRunnable) ;
}
public void cancelTimer(){
countHandler.removeCallbacks(countRunnable);
}
Try the code below.
Timer_Service.java
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.util.Log;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
public class Timer_Service extends Service {
public static String str_receiver = "your_package_name.receiver";
private Handler mHandler = new Handler();
Calendar calendar;
SimpleDateFormat simpleDateFormat;
String strDate;
Date date_current, date_diff;
SharedPreferences mpref;
SharedPreferences.Editor mEditor;
private Timer mTimer = null;
public static final long NOTIFY_INTERVAL = 1000;
Intent intent;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mpref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mEditor = mpref.edit();
calendar = Calendar.getInstance();
simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
mTimer = new Timer();
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 5, NOTIFY_INTERVAL);
intent = new Intent(str_receiver);
}
class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
calendar = Calendar.getInstance();
simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
strDate = simpleDateFormat.format(calendar.getTime());
Log.e("strDate", strDate);
twoDatesBetweenTime();
}
});
}
}
public String twoDatesBetweenTime() {
try {
date_current = simpleDateFormat.parse(strDate);
} catch (Exception e) {
}
try {
date_diff = simpleDateFormat.parse(mpref.getString("data", ""));
} catch (Exception e) {
}
try {
long diff = date_current.getTime() - date_diff.getTime();
int int_hours = Integer.valueOf(mpref.getString("hours", ""));
long int_timer = TimeUnit.HOURS.toMillis(int_hours);
long long_hours = int_timer - diff;
long diffSeconds2 = long_hours / 1000 % 60;
long diffMinutes2 = long_hours / (60 * 1000) % 60;
long diffHours2 = long_hours / (60 * 60 * 1000) % 24;
if (long_hours > 0) {
String str_testing = diffHours2 + ":" + diffMinutes2 + ":" + diffSeconds2;
Log.e("TIME", str_testing);
fn_update(str_testing);
} else {
mEditor.putBoolean("finish", true).commit();
mTimer.cancel();
}
} catch (Exception e) {
mTimer.cancel();
mTimer.purge();
}
return "";
}
#Override
public void onDestroy() {
super.onDestroy();
Log.e("Service finish", "Finish");
}
private void fn_update(String str_time) {
intent.putExtra("time", str_time);
sendBroadcast(intent);
}
}
Your Timer.java activity:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class Timer extends AppCompatActivity implements View.OnClickListener {
private Button btn_start, btn_cancel;
private TextView tv_timer;
String date_time;
Calendar calendar;
SimpleDateFormat simpleDateFormat;
EditText et_hours;
SharedPreferences mpref;
SharedPreferences.Editor mEditor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
init();
}
private void init() {
btn_start = (Button) findViewById(R.id.btn_timer);
tv_timer = (TextView) findViewById(R.id.tv_timer);
et_hours = (EditText) findViewById(R.id.et_hours);
btn_cancel = (Button) findViewById(R.id.btn_cancel);
btn_start.setOnClickListener(this);
btn_cancel.setOnClickListener(this);
mpref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mEditor = mpref.edit();
try {
String str_value = mpref.getString("data", "");
if (str_value.matches("")) {
et_hours.setEnabled(true);
btn_start.setEnabled(true);
tv_timer.setText("");
} else {
if (mpref.getBoolean("finish", false)) {
et_hours.setEnabled(true);
btn_start.setEnabled(true);
tv_timer.setText("");
} else {
et_hours.setEnabled(false);
btn_start.setEnabled(false);
tv_timer.setText(str_value);
}
}
} catch (Exception e) {
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_timer:
if (et_hours.getText().toString().length() > 0) {
int int_hours = Integer.valueOf(et_hours.getText().toString());
if (int_hours <= 24) {
et_hours.setEnabled(false);
btn_start.setEnabled(false);
calendar = Calendar.getInstance();
simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
date_time = simpleDateFormat.format(calendar.getTime());
mEditor.putString("data", date_time).commit();
mEditor.putString("hours", et_hours.getText().toString()).commit();
Intent intent_service = new Intent(getApplicationContext(), Timer_Service.class);
startService(intent_service);
} else {
Toast.makeText(getApplicationContext(), "Please select the value below 24 hours", Toast.LENGTH_SHORT).show();
}
/*
mTimer = new Timer();
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 5, NOTIFY_INTERVAL);*/
} else {
Toast.makeText(getApplicationContext(), "Please select value", Toast.LENGTH_SHORT).show();
}
break;
case R.id.btn_cancel:
Intent intent = new Intent(getApplicationContext(), Timer_Service.class);
stopService(intent);
mEditor.clear().commit();
et_hours.setEnabled(true);
btn_start.setEnabled(true);
tv_timer.setText("");
break;
}
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String str_time = intent.getStringExtra("time");
tv_timer.setText(str_time);
}
};
#Override
protected void onResume() {
super.onResume();
registerReceiver(broadcastReceiver, new IntentFilter(Timer_Service.str_receiver));
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
}
}
Your activity_timer.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="#+id/et_hours"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:hint="Hours"
android:inputType="time" />
<Button
android:id="#+id/btn_timer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/btn_cancel"
android:text="Start Timer" />
<Button
android:id="#+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="cancel timer" />
<TextView
android:id="#+id/tv_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="00:00:00"
android:textColor="#000000"
android:textSize="25dp" />
</RelativeLayout>
Resource reference: this link.
You need to do some modifications according to your requirement. The countdown will continue even if you close the app.

How to auto refresh to list messages?

I have small problem. My problem is auto refresh to list messages.
How can instantly check data such as WhatsApp ?
If you would like to automatically update data came from.
I do not know exactly how I can do , so I'm waiting for your help .
Code
MessagingActivity.java
package com.socialnetwork.activities;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.SystemClock;
import android.os.Vibrator;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.socialnetwork.R;
import com.socialnetwork.adapters.MessagesAdapter;
import com.socialnetwork.animation.ViewAudioProxy;
import com.socialnetwork.api.APIService;
import com.socialnetwork.api.ChatAPI;
import com.socialnetwork.api.UsersAPI;
import com.socialnetwork.data.MessagesItem;
import com.socialnetwork.data.userItem;
import com.socialnetwork.helpers.M;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;
public class MessagingActivity extends AppCompatActivity implements OnClickListener {
public Intent mIntent = null;
private MediaRecorder recorder = null;
private String outFile = null;
private TextView recordTimeText;
private ImageButton audioSendButton;
private View recordPanel;
private View slideText;
private float startedDraggingX = -1;
private float distCanMove = dp(80);
private long startTime = 0L;
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
private Timer timer;
public int RECIPIENT_ID = 0,
CONVERSATION_ID = 0;
public LinearLayoutManager layoutManager;
private EditText messageField;
private String messageBody, USERNAME;
private MessagesAdapter messageAdapter;
private List<MessagesItem> mMessages = new ArrayList<MessagesItem>();
public BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
Bundle data = intent.getBundleExtra("data");
if (Integer.parseInt(data.getString("ownerID")) == RECIPIENT_ID) {
MessagesItem newMsg = new MessagesItem();
newMsg.setOwnerName(data.getString("ownerName"));
newMsg.setId(Integer.parseInt(data.getString("id")));
newMsg.setMessage(data.getString("message"));
newMsg.setDate(data.getString("date"));
newMsg.setOwnerUsername(data.getString("ownerUsername"));
newMsg.setOwnerPicture(data.getString("ownerPicture"));
newMsg.setOwnerID(Integer.parseInt(data.getString("ownerID")));
newMsg.setConversationID(Integer.parseInt(data.getString("conversationID")));
addMessage(newMsg);
} else {
Intent resultIntent = new Intent(MessagingActivity.this, MessagingActivity.class);
resultIntent.putExtra("data", intent);
M.showNotification(MessagingActivity.this, resultIntent,
data.getString("ownerUsername"),
data.getString("message"),
Integer.parseInt(data.getString("conversationID")));
}
}
};
private RecyclerView messagesList;
private LinearLayout attachLayout;
private RelativeLayout recordPannel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (M.getToken(this) == null) {
Intent mIntent = new Intent(this, LoginActivity.class);
startActivity(mIntent);
finish();
} else {
setContentView(R.layout.messaging);
initializer();
if (getIntent().hasExtra("conversationID")) {
CONVERSATION_ID = getIntent().getExtras().getInt("conversationID");
}
if (getIntent().hasExtra("recipientID")) {
RECIPIENT_ID = getIntent().getExtras().getInt("recipientID");
}
getUser();
getMessages();
}
}
public void initializer() {
messagesList = (RecyclerView) findViewById(R.id.listMessages);
messageAdapter = new MessagesAdapter(this, mMessages);
messagesList.setAdapter(messageAdapter);
//
layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.setStackFromEnd(true);
messagesList.setLayoutManager(layoutManager);
messageField = (EditText) findViewById(R.id.messageField);
attachLayout = (LinearLayout) findViewById(R.id.attachLayout);
recordPannel = (RelativeLayout) findViewById(R.id.record_pannel);
recordPanel = findViewById(R.id.record_panel);
recordTimeText = (TextView) findViewById(R.id.recording_time_text);
slideText = findViewById(R.id.slideText);
audioSendButton = (ImageButton) findViewById(R.id.chat_audio_send_button);
TextView textView = (TextView) findViewById(R.id.slideToCancelTextView);
textView.setText("Slide To Cancel");
//including toolbar and enabling the home button
Toolbar toolbar = (Toolbar) findViewById(R.id.app_bar);
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
findViewById(R.id.attachBtn).setOnClickListener(this);
findViewById(R.id.sendBtn).setOnClickListener(this);
findViewById(R.id.micBtn).setOnClickListener(this);
audioSendButton.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) slideText
.getLayoutParams();
params.leftMargin = dp(30);
slideText.setLayoutParams(params);
ViewAudioProxy.setAlpha(slideText, 1);
startedDraggingX = -1;
startRecording();
audioSendButton.getParent()
.requestDisallowInterceptTouchEvent(true);
recordPanel.setVisibility(View.VISIBLE);
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP
|| motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
startedDraggingX = -1;
stopRecording();
recordPannel.setVisibility(View.GONE);
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
float x = motionEvent.getX();
if (x < -distCanMove) {
stopRecording();
}
x = x + ViewAudioProxy.getX(audioSendButton);
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) slideText
.getLayoutParams();
if (startedDraggingX != -1) {
float dist = (x - startedDraggingX);
params.leftMargin = dp(30) + (int) dist;
slideText.setLayoutParams(params);
float alpha = 1.0f + dist / distCanMove;
if (alpha > 1) {
alpha = 1;
} else if (alpha < 0) {
alpha = 0;
}
ViewAudioProxy.setAlpha(slideText, alpha);
}
if (x <= ViewAudioProxy.getX(slideText) + slideText.getWidth()
+ dp(30)) {
if (startedDraggingX == -1) {
startedDraggingX = x;
distCanMove = (recordPanel.getMeasuredWidth()
- slideText.getMeasuredWidth() - dp(48)) / 2.0f;
if (distCanMove <= 0) {
distCanMove = dp(80);
} else if (distCanMove > dp(80)) {
distCanMove = dp(80);
}
}
}
if (params.leftMargin > dp(30)) {
params.leftMargin = dp(30);
slideText.setLayoutParams(params);
ViewAudioProxy.setAlpha(slideText, 1);
startedDraggingX = -1;
}
}
view.onTouchEvent(motionEvent);
return true;
}
});
}
private void getUser() {
UsersAPI mUsersAPI = APIService.createService(UsersAPI.class, M.getToken(this));
mUsersAPI.getUser(RECIPIENT_ID, new Callback<userItem>() {
#Override
public void success(userItem userItem, retrofit.client.Response response) {
if (userItem.getName() != null) {
getSupportActionBar().setTitle(userItem.getName());
} else {
getSupportActionBar().setTitle(userItem.getUsername());
}
}
#Override
public void failure(RetrofitError error) {
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
messageAdapter.stop();
}
public void getMessages() {
M.showLoadingDialog(this);
ChatAPI mChatAPI = APIService.createService(ChatAPI.class, M.getToken(this));
mChatAPI.getMessages(CONVERSATION_ID, RECIPIENT_ID, 1, new Callback<List<MessagesItem>>() {
#Override
public void success(List<MessagesItem> messagesItems, Response response) {
mMessages = messagesItems;
messageAdapter.setMessages(messagesItems);
M.hideLoadingDialog();
}
#Override
public void failure(RetrofitError error) {
M.hideLoadingDialog();
M.L(getString(R.string.ServerError));
}
});
}
private void sendMessage() {
messageBody = messageField.getText().toString().trim();
if (!messageBody.isEmpty()) {
ChatAPI mChatAPI = APIService.createService(ChatAPI.class, M.getToken(this));
mChatAPI.addMessage(messageBody, CONVERSATION_ID, RECIPIENT_ID, new Callback<MessagesItem>() {
#Override
public void success(MessagesItem messagesItem, Response response) {
if (messagesItem != null) {
mMessages.add(messagesItem);
messageAdapter.setMessages(mMessages);
messagesList.smoothScrollToPosition(mMessages.size());
messageField.setText("");
} else {
M.T(MessagingActivity.this, getString(R.string.SomethingWentWrong));
}
}
#Override
public void failure(RetrofitError error) {
M.T(MessagingActivity.this, getString(R.string.ServerError));
}
});
}
}
#Override
public void onClick(View v) {
if (v.getId() == R.id.attachBtn) {
if (attachLayout.getVisibility() == View.GONE) {
attachLayout.setVisibility(View.VISIBLE);
} else {
attachLayout.setVisibility(View.GONE);
}
if (recordPannel.getVisibility() == View.VISIBLE) {
recordPannel.setVisibility(View.GONE);
}
} else if (v.getId() == R.id.sendBtn) {
sendMessage();
} else if (v.getId() == R.id.micBtn) {
attachLayout.setVisibility(View.GONE);
recordPannel.setVisibility(View.VISIBLE);
}
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mMessageReceiver, new IntentFilter("update_messages_list"));
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mMessageReceiver);
}
public void addMessage(MessagesItem newMsg) {
mMessages.add(newMsg);
messageAdapter.setMessages(mMessages);
messagesList.smoothScrollToPosition(mMessages.size());
}
private void startRecording() {
try {
startRecordingAudio();
} catch (IOException e) {
e.printStackTrace();
}
startTime = SystemClock.uptimeMillis();
timer = new Timer();
MyTimerTask myTimerTask = new MyTimerTask();
timer.schedule(myTimerTask, 1000, 1000);
vibrate();
}
private void stopRecording() {
if (timer != null) {
timer.cancel();
}
if (recordTimeText.getText().toString().equals("00:00")) {
return;
}
recordTimeText.setText("00:00");
vibrate();
Toast.makeText(getApplicationContext(), "Stop Recording", Toast.LENGTH_SHORT).show();
stopRecordingAudio();
}
public void startRecordingAudio() throws IOException {
Toast.makeText(getApplicationContext(), "Start Recording...", Toast.LENGTH_SHORT).show();
SimpleDateFormat timeStampFormat = new SimpleDateFormat(
"yyyy-MM-dd-HH.mm.ss");
String fileName = "audio_" + timeStampFormat.format(new Date())
+ ".mp3";
outFile = "/sdcard/";// Environment.getExternalStorageDirectory().getAbsolutePath();
stopRecordingAudio();
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(outFile + fileName);
recorder.setOnErrorListener(errorListener);
recorder.setOnInfoListener(infoListener);
recorder.prepare();
recorder.start();
}
public void stopRecordingAudio() {
if (recorder != null) {
recorder.stop();
recorder.reset();
recorder.release();
recorder = null;
}
}
private MediaRecorder.OnErrorListener errorListener = new MediaRecorder.OnErrorListener() {
#Override
public void onError(MediaRecorder mr, int what, int extra) {
Toast.makeText(MessagingActivity.this, "Error: " + what + ", " + extra, Toast.LENGTH_SHORT).show();
}
};
private MediaRecorder.OnInfoListener infoListener = new MediaRecorder.OnInfoListener() {
#Override
public void onInfo(MediaRecorder mr, int what, int extra) {
Toast.makeText(MessagingActivity.this, "Warning: " + what + ", " + extra, Toast.LENGTH_SHORT).show();
}
};
private void vibrate() {
// TODO Auto-generated method stub
try {
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(200);
} catch (Exception e) {
e.printStackTrace();
}
}
public static int dp(float value) {
return (int) Math.ceil(1 * value);
}
class MyTimerTask extends TimerTask {
#Override
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
final String hms = String.format(
"%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(updatedTime)
- TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS
.toHours(updatedTime)),
TimeUnit.MILLISECONDS.toSeconds(updatedTime)
- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS
.toMinutes(updatedTime)));
long lastsec = TimeUnit.MILLISECONDS.toSeconds(updatedTime)
- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS
.toMinutes(updatedTime));
System.out.println(lastsec + " hms " + hms);
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
if (recordTimeText != null)
recordTimeText.setText(hms);
} catch (Exception e) {
// TODO: handle exception
}
}
});
}
}
}
MessagesFragment.java
public class MessagesFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
public RecyclerView conversationList;
public ConversationsAdapter mConversationsAdapter;
public List<ConversationItem> mConversations = new ArrayList<ConversationItem>();
public Intent mIntent = null;
public int currentPage = 1;
public LinearLayoutManager layoutManager;
private View mView;
private SwipeRefreshLayout mSwipeRefreshLayout;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_messages, container, false);
conversationList = (RecyclerView) mView
.findViewById(R.id.conversationsList);
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.title_messages);
initializeView();
conversationList.setOnScrollListener(new HidingScrollListener(layoutManager) {
#Override
public void onHide() {
}
#Override
public void onShow() {
}
#Override
public void onLoadMore(int currentPage) {
setCurrentPage(currentPage);
getConversations();
}
});
mSwipeRefreshLayout = (SwipeRefreshLayout) mView.findViewById(R.id.swipeMessages);
mSwipeRefreshLayout.setOnRefreshListener(this);
getConversations();
return mView;
}
public void initializeView() {
mConversationsAdapter = new ConversationsAdapter(getActivity(),
mConversations);
conversationList.setAdapter(mConversationsAdapter);
layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
conversationList.setLayoutManager(layoutManager);
}
public void getConversations() {
M.showLoadingDialog(getActivity());
ChatAPI mChatAPI = APIService.createService(ChatAPI.class, M.getToken(getActivity()));
mChatAPI.getConversations(getCurrentPage(), new Callback<List<ConversationItem>>() {
#Override
public void success(List<ConversationItem> conversationItems, retrofit.client.Response response) {
M.L(response.getBody().mimeType());
mConversationsAdapter.setConversations(conversationItems);
M.hideLoadingDialog();
if (mSwipeRefreshLayout.isRefreshing()) {
mSwipeRefreshLayout.setRefreshing(false);
}
}
#Override
public void failure(RetrofitError error) {
M.hideLoadingDialog();
}
});
}
#Override
public void onRefresh() {
setCurrentPage(1);
getConversations();
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
}
WhatsApp is not instant check. It's is more like:
Screen off, check 10x after 30s, next 10x after 1m, next 3x after 5m and so on. and start again if the screen turns off again. WhatsApp is checkin in the background also when you close the app. They are using a service.

Categories