Easy way to show Decimal of Long via CountDownTimer - Android - java

I have working code but it seems a bit strange that I have to gimmick my way around showing a decimal place on CountDownTimer but I haven't found anything that does it easier (obviously).
Here is the working Code I currently have:
final String tempTitle = TextView.getText().toString();
new CountDownTimer(10000, 100) {
public void onTick(long millisUntilFinished) {
String timeDown = String.valueOf(millisUntilFinished / 100);
String secTime="0";
String sec10th="0";
if (Long.valueOf(millisUntilFinished) < 1000) {
secTime ="0";
sec10th = timeDown.substring(0,1);
}else{
secTime=timeDown.substring(0,1);
sec10th = timeDown.substring(1,2);
}
TextView.setText("Start in: " + secTime + "." + sec10th);
}
public void onFinish() {
TextView.setText(tempTitle);
}
}.start();
}

divide by 100.0 so you dont do integer division.
Edit per your comment:
you could do
DecimalFormat df=new DecimalFormat("#.##"); //import java.text.DecimalFormat;
String timeDown=df.format(millisUntilFinished/100.0);
or #.### etc depending on how many decimals you want...

Related

Cannot use timestamp in Android Studio(Java), when the button is clicked, Simulator would shout down

long millis = System.currentTimeMillis();
ts.setText((int) millis);
Now trying to show timestamp when "buttonEqual" is clicked, but suddenly it does not work.
I tried to change long -> int and just put millis in side the setText(), but not appropriate.
buttonEqual.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onClick(View v) {
if (Addition || Subtract || Multiplication || Division || mRemainder) {
input2 = Float.parseFloat(edt1.getText() + "");
}
if (Addition) {
edt1.setText(input1 + "+" + input2);
Addition = false;
ans.setText(" = " + (input1 + input2) + "");
long millis = System.currentTimeMillis();
ts.setText((int) millis);
}
EditText.setText() expects either a resource id (as int value, specifying a text resource) or a string (with the text to display). Your timestamp is neither.
Assuming that you want to display the timestamp as value, you should write
ts.setText(Long.toString(millis));

How can I make the loudness of the music playing oscillate with my timer?

I'm trying to make the second sound on this app. oscillate in volume based on a Sin curve as a function of time passing. How would you suggest I edit what I already have to make that work? Any help would be amazing!
I'm sorry If some of the code is bad, I stepped away from this for some time and I added some sections back in that I previously commented out. I wasn't sure if it was for a good reason or not, so I added it back in.
MediaPlayer beep;
MediaPlayer sound2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //call superclass onCreate
setContentView(R.layout.activity_main); //inflate the GUI
minutesChanged = (TextView) findViewById(R.id.minutesChanged);
secondsChanged = (TextView) findViewById(R.id.secondsChanged);
minutesTotal = (TextView) findViewById(R.id.totalMinutesEntered);
secondsTotal = (TextView) findViewById(R.id.totalSecondsEntered);
percentageFinishedAmount = (TextView) findViewById(R.id.percentageFinishedAmount);
errorMessage = (TextView) findViewById(R.id.errorMessage);
secondEditText =
(EditText) findViewById(R.id.secondEditText);
secondEditText.addTextChangedListener(secondEditTextWatcher);
minuteEditText =
(EditText) findViewById(R.id.minuteEditText);
minuteEditText.addTextChangedListener(minuteEditTextWatcher);
whichSound =
(EditText) findViewById(R.id.whichSound);
whichSound.addTextChangedListener(whichSoundTextWatcher);
seekBarSeconds =
(SeekBar) findViewById(R.id.seekBarSeconds);
seekBarSeconds.setOnSeekBarChangeListener(seekBarListener);
seekBarMinutes =
(SeekBar) findViewById(R.id.seekBarMinutes);
seekBarMinutes.setOnSeekBarChangeListener(seekBarListener);
percentSeekBar =
(SeekBar) findViewById(R.id.seekBarTotal);
beep = MediaPlayer.create(MainActivity.this, R.raw.beep);
sound2 = MediaPlayer.create(MainActivity.this, R.raw.sound);
}
private void calculate() {
totalmili = minutesT + secondsT;
new CountDownTimer(totalmili + 2000, interv) {
public void onTick(long millisUntilFinished) {
secondsEllapsed = (int) ((totalmili + 2000 - millisUntilFinished) / 1000);
minutesEllapsed = secondsEllapsed / 60;
secondsEllapsed = secondsEllapsed % 60;
totalTimeEllapsed = secondsEllapsed + (minutesEllapsed * 60);
Log.d("Lucas", "total time elapsed " + totalTimeEllapsed);
if (totalTimeEllapsed < 10) {
errorMessage.setText("Elapsed Time: " + minutesEllapsed + " : 0" + secondsEllapsed);
} else if (totalTimeEllapsed >= 10) {
errorMessage.setText("Elapsed Time: " + minutesEllapsed + " : " + secondsEllapsed);
}
//set seekBar minutes/seconds and changing minute/seconds textView
seekBarMinutes.setProgress(minutesEllapsed);
minutesChanged.setText(Integer.toString(minutesEllapsed));
seekBarSeconds.setProgress(secondsEllapsed);
secondsChanged.setText(Integer.toString(secondsEllapsed));
double t = sin((360/totalmili) *(totalTimeEllapsed*1000));
float left = (float) ((t+1.0)*0.9/2.0+0.1);
float right = (float) ((t+1.0)*0.9/2.0+0.1);
sound2.setVolume(left,right);
Log.d("Lucas", "value of left and red respectively " + left + ", " +right);
if(sound == 1){
musicPlaying = beep.isPlaying();
if(musicPlaying == true){
beep.pause();
beep.seekTo(0);
beep.start();
} else {
beep.start();
}
}else if (sound == 2){
if(start ==1) {
sound2.seekTo(19);
sound2.start();
start = 2;
float left = (float) ((sin(totalTimeEllapsed)+1.0)*0.9/2.0+0.1);
float right = (float) ((sin(totalTimeEllapsed)+1.0)*0.9/2.0+0.1);
sound2.setVolume(left, right);
Log.d("Lucas", "value of left and red respectively " + left + ", " +right);
musicPlaying = sound2.isPlaying();
}else if(start ==2){
if (totalTimeEllapsed == 11) {
sound2.pause();
sound2.seekTo(34);
sound2.start();
} else if (totalTimeEllapsed == 22) {
sound2.pause();
}
}
//calculate total percentage finished, set percentage text, set total percentage seekBar
int percentProgress = (int) Math.round(((double) totalTimeEllapsed) / ((double) (totalmili) / 1000) * 100);
percentageFinishedAmount.setText(percentProgress + "% ");
percentSeekBar.setProgress(percentProgress);
//change background and text color bassed on increasing progress
errorMessage.setBackgroundColor(Color.argb(255, (int) (percentProgress * 2.5), 0, 0));
errorMessage.setTextColor(Color.argb(255, (int) (255 - (percentProgress * 2.5)), 255, 255));
}
public void onFinish() {
//display on finish text
errorMessage.setText("Done!");
}
}.start();
}
//listener object for the EditText's text-changed events
private final TextWatcher minuteEditTextWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
// set hours Total and converts minutes to milliseconds
if (s.charAt(start + count - 1) == '\n') {
minuteEditText.getText().replace(start + count - 1, start + count, " ");
s = minuteEditText.getText();
Log.d("Lucas", "in enter key min, s = " + s);
try {
minutesT = Integer.parseInt(s.toString());
minutesTotal.setText(String.valueOf(minutesT) + " Minutes");
percentageFinishedAmount.setText(" ");
minutesT *= 60000;
} catch (NumberFormatException e) {
minutesTotal.setText("");
minutesT = 0;
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(
CharSequence s, int start, int count, int after) {
}
};
// listener object for the EditText's text-changed events
private final TextWatcher secondEditTextWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
// set minutes Total when text is changed, calls calculate, changes seconds to milliseconds
if (s.charAt(start + count - 1) == '\n') {
secondEditText.getText().replace(start + count - 1, start + count, " ");
s = secondEditText.getText();
Log.d("Lucas", "in enter key sec, s = " + s);
try {
secondsT = Integer.parseInt(s.toString());
secondsTotal.setText(String.valueOf(secondsT) + " Seconds");
secondsT *= 1000;
percentageFinishedAmount.setText(" ");
calculate();
} catch (NumberFormatException e) {
secondsTotal.setText("");
secondsT = 0;
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(
CharSequence s, int start, int count, int after) {
}
};
Yowza. I'm not really clear on what the requirements are here or what you are doing.
My approach would be radically different, and maybe missing the point of what you are attempting. It would have these elements:
1) Output via a SourceDataLine, as this gives you a handle to affect the volume of every frame.
2) Per frame, consult a pointer into a Sin LUT that has the same number of elements as needed to correspond to the desired rate. (But it could also be fine to just create an argument into a sine function that increments the correct amount each frame to get your desired rate. No need to get into a war about whether the function or the LUT performs better.)
3) Multiply the SDL frame by the Sin LUT value.
For example an LFO of 1 Hz would imply either an LUT of 44100 elements, or an argument that increments by 1/44100 per frame.
As for getting access to the individual sound frames, see the tutorial Using Files and Format Converters/Reading Sound Files and look for the point in the example with the comment "Here, do something useful with the audio data that's now in the audioBytes array". That useful thing would be to convert the bytes to PCM (there are other StackOverflow explain how), get your next sin function value and multiply, then convert back to bytes.
EDIT:
Looking into the MediaPlayer API, I'm not clear you will be able to efficiently do what you want with this class.
A player is not prepared to respond to commands quasi-immediately
until its status has transitioned to MediaPlayer.Status.READY, which
in effect generally occurs when media pre-roll completes.
Does this imply some sort of buffer-size that will limit the frequency at which you can make the volume updates? IDK. When we get into buffer-size issues that in effect enforce a maximum number of updates per second, one has to listen carefully to check that there are no clicks or zippering due to discontinuities when the volume jumps from one level to another. A lot also depends on the amount of overhead happening under the hood when you set the position for each volume change.
With a SourceDataLine output, you have clean access to each frame which pretty much eliminates the potential zippering problems. I should add disclaimer though that I haven't grappled with MediaPlayer and may be ignorant of capabilities that you can take advantage of. Regardless, SDL is low level, powerful and efficient.

Format number so that it's in scientific notation when it's too big without dot

I have the following problem:
I have big values stored in the String, and I can only display number that is 7 digit long. Here are the examples after converting from string to float -
I have String 300 which should be 300, but it is 300.0
Everything that's bigger than 7 digits should be written in scientific notation (700000000 should be 7E+8)
It also could be 7.0E8, but I prefer 7E+8.
I have tried formatting the string but when I wasn't able to get rid of .0 without getting rid of scientific notation. Is this even possible ?
The class DecimalFormat from the package java.text handles this almost effortlessly. A tad bit of business logic for your specific case seals the deal.
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class NumberFormatter
{
public static void main(String args[])
{
String stringInput = "1234.5678";
String outputString = null;
if (stringInput.length() < 8)
{
outputString = stringInput;
}
else
{
outputString = scientificOutput(stringInput);
}
System.out.println(outputString);
}
private String scientificOutput(String input)
{
NumberFormat formatter = new DecimalFormat("0.###E0");
Double d = Double.parseDouble(input);
if (d % 1 == 0)
{
// is int
return formatter.format(d.intValue());
}
else
{
// is a double
return formatter.format(d);
}
}
}
Try this:
String inputValue = "700000000";
String result;
DecimalFormat df1 = new DecimalFormat("#######");
df1.setMinimumFractionDigits(0);
DecimalFormat df2 = new DecimalFormat("######E0");
df2.setMinimumFractionDigits(1);
if (inputValue.length() <= 7) {
result = df1.format(Double.parseDouble(inputValue));
} else {
result = df2.format(Double.parseDouble(inputValue));
}

problems converting CountDownTimer to my SimpleDateFormat output

I have a timer that counts down. I want the displayed format to be 00.00 or "ss.SS". However I haven't made any progress in hours. Without the SimpleDateFormat it displays 01.91 then goes to 01.9. This makes it hard to watch as it flickers to keep the view centered. All I really want is a way to keep the format 01.90 and not allow the 0 to be dropped. Could I accomplish this with my original code without the SimpleDateFormat?
/*
* This is my original code before I tried the SimpleDateFormat
*
* This code is fully functional and works good, it just keeps dropping the 0 every
* 10 milliseconds and makes the view shake
*
* getTimeSecs() could return 5, 10, 15, 30, 90 seconds converted to milliseconds
* getCountDownInterval() returns 10
*
*/
public void createTimer() {
myCounter = new CountDownTimer(getTimeSecs(), getCountDownInterval()) {
public void onTick(long millisUntilFinished) {
timerIsRunning = true;
if(millisUntilFinished < 10000) {
TVcountDown.setText("0" + ((millisUntilFinished / 10) / 100.0));
} else {
TVcountDown.setText("" + ((millisUntilFinished / 10) / 100.0));
}
} //end onTick()
#Override
public void onFinish() {
timerIsRunning = false;
TVcountDown.setBackgroundColor(myRes.getColor(R.color.solid_red));
TVcountDown.setTextColor(myRes.getColor(R.color.white));
TVcountDown.setText("Expired");
// Make sure vibrate feature is enabled
if(wantsVib == true) {
vib.vibrate(300);
}
} //end onFinish()
}.start();
} //end createTimer()
Here is my code after trying the SimpleDateFormat
public void createTimer() {
myCounter = new CountDownTimer(getTimeSecs(), getCountDownInterval()) {
public void onTick(long millisUntilFinished) {
timerIsRunning = true;
long current = (long) ((millisUntilFinished / 10) / 100.0);
TVcountDown.setText("" + timerDisplay.format(current));
}
#Override
public void onFinish() {
timerIsRunning = false;
TVcountDown.setBackgroundColor(myRes.getColor(R.color.solid_red));
TVcountDown.setTextColor(myRes.getColor(R.color.white));
TVcountDown.setText("Expired");
// Make sure vibrate feature is enabled
if(wantsVib == true) {
vib.vibrate(300);
}
}
}.start();
} //end createTimer()
I know! I don't even think I'm close to getting it with the SimpleDateFormat and I'm getting frustrated. It runs, but counts down only seconds, on the milliseconds side. So 15 seconds shows 00.15 not 15.00.
I don't expect someone to code it all out for me just need pointed in the right direction. All the tutorials I can find involve years, days, and such and I can't grasp the concept from that.
I'd prefer not to use the SimpleDateFormat -- cuz it hasn't been to simple for me -- and just use my original code and add a zero to the end of the milliseconds side every 10 milliseconds.
Thanks in advance.
Try this:
TVcountDown.setText(convertToMyFormat(millisUntilFinished));
and convertToMyFormat() method:
public String convertToMyFormat(long ms) {
String secString, msecString;
//constructing the sec format:
int sec = (int) (ms / 1000);
if(sec < 10) secString = "0"+sec;
else if(sec == 0) secString = "00";
else secString = ""+sec;
//constructing the msec format:
int msec = (int) ((ms-(sec*1000))/10.0);
if(msec < 10) msecString = "0"+msec;
else if(msec == 0) msecString = "00";
else msecString = ""+msec;
return secString+":"+msecString;
}
I'm not sure if I did the msec part correctly but you can tweek it as you want.
convert the number to a string and it will keep formatting. additionally you can do something like this
public String NumToStr(long i){
if (i < 10 ) {
return ("0" + Long.toString(i));
}
return Long.toString(i);
}
to make sure "9" will always come back as "09". Now set the string to the text.
actually what might be easier is this
if(millisUntilFinished < 10000) {
TVcountDown.setText("0" + Long.toString((millisUntilFinished / 10) / 100.0));
} else {
TVcountDown.setText("" + Long.toString((millisUntilFinished / 10) / 100.0));
}
Use Float.toString() or Double.toString, or whatever you need. Dont be afraid to write a little function to edit the string to make it appear as you want if you need to.
public String KeepFirstTwoCharOfString(String string){
//code to store first two Char into string
// return the string containing only first 2 chars
}

Format double to at least one significant digit in Java/Android

I have a DecimalFormat object which I'm using to format all of my double values to a set number of digits (let's say 2) when I'm displaying them. I would like it to normally format to 2 decimal places, but I always want at least one significant digit. For example, if my value is 0.2 then my formatter spits out 0.20 and that's great. However, if my value is 0.000034 my formatter will spit out 0.00 and I would prefer my formatter spit out 0.00003.
The number formatters in Objective-C do this very simply, I can just set a max number of digits I want to show at 2 and the minimum number of significant digits at 1 and it produces my desired output, but how can I do it in Java?
I appreciate any help anyone can offer me.
Kyle
Edit: I'm interested in rounding the values so 0.000037 displays as 0.00004.
It's not efficient, so if you perform this operation often I'd try another solution, but if you only call it occasionally this method will work.
import java.text.DecimalFormat;
public class Rounder {
public static void main(String[] args) {
double value = 0.0000037d;
// size to the maximum number of digits you'd like to show
// used to avoid representing the number using scientific notation
// when converting to string
DecimalFormat maxDigitsFormatter = new DecimalFormat("#.###################");
StringBuilder pattern = new StringBuilder().append("0.00");
if(value < 0.01d){
String s = maxDigitsFormatter.format(value);
int i = s.indexOf(".") + 3;
while(i < s.length()-1){
pattern.append("0");
i++;
}
}
DecimalFormat df = new DecimalFormat(pattern.toString());
System.out.println("value = " + value);
System.out.println("formatted value = " + maxDigitsFormatter.format(value));
System.out.println("pattern = " + pattern);
System.out.println("rounded = " + df.format(value));
}
}
import java.math.BigDecimal;
import java.math.MathContext;
public class Test {
public static void main(String[] args) {
String input = 0.000034+"";
//String input = 0.20+"";
int max = 2;
int min =1;
System.out.println(getRes(input,max,min));
}
private static String getRes(String input,int max,int min) {
double x = Double.parseDouble(((new BigDecimal(input)).unscaledValue().intValue()+"").substring(0,min));
int n = (new BigDecimal(input)).scale();
String res = new BigDecimal(x/Math.pow(10,n)).round(MathContext.DECIMAL64).setScale(n).toString();
if(n<max){
for(int i=0;i<max;i++){
res+="0";
}
}
return res;
}
}

Categories

Resources